[openwrt/openwrt] ramips: add support for kernel 5.10

LEDE Commits lede-commits at lists.infradead.org
Fri Mar 5 23:56:21 GMT 2021


dangole pushed a commit to openwrt/openwrt.git, branch master:
https://git.openwrt.org/b4aad29a1d7ad77d67073c1c54b28c429c64ed9b

commit b4aad29a1d7ad77d67073c1c54b28c429c64ed9b
Author: Ilya Lipnitskiy <ilya.lipnitskiy at gmail.com>
AuthorDate: Sat Feb 27 15:12:21 2021 -0800

    ramips: add support for kernel 5.10
    
    Enable testing kernel.
    
    Delete upstreamed patches:
     0098-disable_cm.patch can be dropped, upstream fixed CM handling.
    
    Fix compile errors by using new kernel APIs.
    
    Fix fuzz by manually editing patches to ensure the code goes in the
    right place.
    
    For 721-NET-no-auto-carrier-off-support.patch, revert upstream commit
    a307593a6 to keep the OpenWrt ralink driver operational.
    
    Add mt7621-pci-phy patch to select REGMAP_MMIO as discussed in PR #3693
    and #3952.
    
    Rename patches to follow the 3-digit classification from the OpenWrt
    Developer Guide.
    
    Run automatic quilt refresh.
    
    Signed-off-by: Ilya Lipnitskiy <ilya.lipnitskiy at gmail.com>
---
 target/linux/ramips/Makefile                       |    2 +-
 .../files/drivers/net/ethernet/ralink/mdio.c       |    9 +
 .../drivers/net/ethernet/ralink/mdio_rt2880.c      |    8 +
 .../drivers/net/ethernet/ralink/mtk_eth_soc.c      |    4 +
 .../files/drivers/net/ethernet/ralink/soc_mt7620.c |   11 +-
 target/linux/ramips/mt7620/config-5.10             |  193 +++
 target/linux/ramips/mt7621/config-5.10             |  288 ++++
 target/linux/ramips/mt76x8/config-5.10             |  191 +++
 .../020-mips-ralink-manage-low-reset-lines.patch   |   45 +
 .../ramips/patches-5.10/200-add-ralink-eth.patch   |   20 +
 .../ramips/patches-5.10/202-weak_reordering.patch  |   10 +
 ...mt7621-pci-phy-kconfig-select-regmap-mmio.patch |   10 +
 .../300-mt7620-export-chip-version-and-pkg.patch   |   19 +
 ...mory-reservation-in-bootmem_init-for-cert.patch |   45 +
 ...t_mode-to-enable-disable-the-cevt-r4k-irq.patch |  100 ++
 ...312-MIPS-ralink-add-cpu-frequency-scaling.patch |  195 +++
 ...-copy-the-commandline-from-the-devicetree.patch |   21 +
 .../314-MIPS-add-bootargs-override-property.patch  |   63 +
 .../315-owrt-hack-fix-mt7688-cache-issue.patch     |   29 +
 ...o-not-select-illegal-access-driver-by-def.patch |   25 +
 .../patches-5.10/320-mt7621-core-detect-hack.patch |   61 +
 .../ramips/patches-5.10/321-mt7621-timer.patch     |   87 ++
 .../322-mt7621-fix-cpu-clk-add-clkdev.patch        |  187 +++
 .../patches-5.10/323-mt7621-memory-detect.patch    |  129 ++
 .../patches-5.10/324-mt7621-perfctr-fix.patch      |   15 +
 .../patches-5.10/330-fix-pci-init-mt7620.patch     |   21 +
 .../400-mtd-cfi-cmdset-0002-force-word-write.patch |   20 +
 ...-add-driver-support-for-MT7621-nand-flash.patch | 1403 ++++++++++++++++++++
 ...-add-documentation-for-mt7621-nand-driver.patch |   85 ++
 .../patches-5.10/420-spi-nor-add-gd25q512.patch    |   12 +
 ...-net-ethernet-mediatek-support-net-labels.patch |   34 +
 target/linux/ramips/patches-5.10/710-at803x.patch  |  149 +++
 ...et-phy-simplify-phy_link_change-arguments.patch |  118 ++
 .../721-NET-no-auto-carrier-off-support.patch      |   47 +
 .../800-GPIO-add-named-gpio-exports.patch          |  165 +++
 .../801-DT-Add-documentation-for-gpio-ralink.patch |   59 +
 ...IPS-ralink-add-gpio-driver-for-ralink-SoC.patch |  416 ++++++
 ...-Add-support-for-GPIO-as-interrupt-contro.patch |   44 +
 .../810-uvc-add-iPassion-iP2970-support.patch      |  246 ++++
 .../820-DT-Add-documentation-for-spi-rt2880.patch  |   44 +
 .../821-SPI-ralink-add-Ralink-SoC-spi-driver.patch |  574 ++++++++
 .../825-i2c-MIPS-adds-ralink-I2C-driver.patch      |  507 +++++++
 ...mmc-MIPS-ralink-add-sdhci-for-mt7620a-SoC.patch |   43 +
 .../patches-5.10/835-asoc-add-mt7620-support.patch | 1046 +++++++++++++++
 ...840-serial-add-ugly-custom-baud-rate-hack.patch |   22 +
 .../845-pwm-add-mediatek-support.patch             |  217 +++
 .../850-awake-rt305x-dwc2-controller.patch         |   15 +
 .../ramips/patches-5.10/855-linkit_bootstrap.patch |   97 ++
 target/linux/ramips/rt288x/config-5.10             |  177 +++
 target/linux/ramips/rt305x/config-5.10             |  176 +++
 target/linux/ramips/rt3883/config-5.10             |  177 +++
 51 files changed, 7679 insertions(+), 2 deletions(-)

diff --git a/target/linux/ramips/Makefile b/target/linux/ramips/Makefile
index 2cfb3c5cef..d3f2d4b8fc 100644
--- a/target/linux/ramips/Makefile
+++ b/target/linux/ramips/Makefile
@@ -11,7 +11,7 @@ SUBTARGETS:=mt7620 mt7621 mt76x8 rt288x rt305x rt3883
 FEATURES:=squashfs gpio
 
 KERNEL_PATCHVER:=5.4
-KERNEL_TESTING_PATCHVER:=5.4
+KERNEL_TESTING_PATCHVER:=5.10
 
 define Target/Description
 	Build firmware images for Ralink RT288x/RT3xxx based boards.
diff --git a/target/linux/ramips/files/drivers/net/ethernet/ralink/mdio.c b/target/linux/ramips/files/drivers/net/ethernet/ralink/mdio.c
index 33f973bed3..dceb08b835 100644
--- a/target/linux/ramips/files/drivers/net/ethernet/ralink/mdio.c
+++ b/target/linux/ramips/files/drivers/net/ethernet/ralink/mdio.c
@@ -64,7 +64,11 @@ int fe_connect_phy_node(struct fe_priv *priv, struct device_node *phy_node, int
 {
 	const __be32 *_phy_addr = NULL;
 	struct phy_device *phydev;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
 	int phy_mode;
+#else
+	phy_interface_t phy_mode = PHY_INTERFACE_MODE_NA;
+#endif
 
 	_phy_addr = of_get_property(phy_node, "reg", NULL);
 
@@ -73,8 +77,13 @@ int fe_connect_phy_node(struct fe_priv *priv, struct device_node *phy_node, int
 		return -EINVAL;
 	}
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
 	phy_mode = of_get_phy_mode(phy_node);
 	if (phy_mode < 0) {
+#else
+	of_get_phy_mode(phy_node, &phy_mode);
+	if (phy_mode == PHY_INTERFACE_MODE_NA) {
+#endif
 		dev_err(priv->dev, "incorrect phy-mode %d\n", phy_mode);
 		priv->phy->phy_node[port] = NULL;
 		return -EINVAL;
diff --git a/target/linux/ramips/files/drivers/net/ethernet/ralink/mdio_rt2880.c b/target/linux/ramips/files/drivers/net/ethernet/ralink/mdio_rt2880.c
index 8d82c8f7ad..6242cf9b42 100644
--- a/target/linux/ramips/files/drivers/net/ethernet/ralink/mdio_rt2880.c
+++ b/target/linux/ramips/files/drivers/net/ethernet/ralink/mdio_rt2880.c
@@ -156,7 +156,11 @@ void rt2880_port_init(struct fe_priv *priv, struct device_node *np)
 	const __be32 *id = of_get_property(np, "reg", NULL);
 	const __be32 *link;
 	int size;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
 	int phy_mode;
+#else
+	phy_interface_t phy_mode = PHY_INTERFACE_MODE_NA;
+#endif
 
 	if (!id || (be32_to_cpu(*id) != 0)) {
 		pr_err("%s: invalid port id\n", np->name);
@@ -172,7 +176,11 @@ void rt2880_port_init(struct fe_priv *priv, struct device_node *np)
 		return;
 	}
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
 	phy_mode = of_get_phy_mode(np);
+#else
+	of_get_phy_mode(np, &phy_mode);
+#endif
 	switch (phy_mode) {
 	case PHY_INTERFACE_MODE_RGMII:
 		break;
diff --git a/target/linux/ramips/files/drivers/net/ethernet/ralink/mtk_eth_soc.c b/target/linux/ramips/files/drivers/net/ethernet/ralink/mtk_eth_soc.c
index f8301ad3ca..b6e321b78c 100644
--- a/target/linux/ramips/files/drivers/net/ethernet/ralink/mtk_eth_soc.c
+++ b/target/linux/ramips/files/drivers/net/ethernet/ralink/mtk_eth_soc.c
@@ -1085,7 +1085,11 @@ poll_again:
 	return rx_done;
 }
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
 static void fe_tx_timeout(struct net_device *dev)
+#else
+static void fe_tx_timeout(struct net_device *dev, unsigned int txqueue)
+#endif
 {
 	struct fe_priv *priv = netdev_priv(dev);
 	struct fe_tx_ring *ring = &priv->tx_ring;
diff --git a/target/linux/ramips/files/drivers/net/ethernet/ralink/soc_mt7620.c b/target/linux/ramips/files/drivers/net/ethernet/ralink/soc_mt7620.c
index f442d558e1..7317bc30aa 100644
--- a/target/linux/ramips/files/drivers/net/ethernet/ralink/soc_mt7620.c
+++ b/target/linux/ramips/files/drivers/net/ethernet/ralink/soc_mt7620.c
@@ -131,7 +131,12 @@ static void mt7620_port_init(struct fe_priv *priv, struct device_node *np)
 	struct mt7620_gsw *gsw = (struct mt7620_gsw *)priv->soc->swpriv;
 	const __be32 *_id = of_get_property(np, "reg", NULL);
 	const __be32 *phy_addr;
-	int phy_mode, size, id;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
+	int phy_mode;
+#else
+	phy_interface_t phy_mode = PHY_INTERFACE_MODE_NA;
+#endif
+	int size, id;
 	int shift = 12;
 	u32 val, mask = 0;
 	u32 val_delay = 0;
@@ -161,7 +166,11 @@ static void mt7620_port_init(struct fe_priv *priv, struct device_node *np)
 		return;
 	}
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
 	phy_mode = of_get_phy_mode(np);
+#else
+	of_get_phy_mode(np, &phy_mode);
+#endif
 	switch (phy_mode) {
 	case PHY_INTERFACE_MODE_RGMII:
 		mask = 0;
diff --git a/target/linux/ramips/mt7620/config-5.10 b/target/linux/ramips/mt7620/config-5.10
new file mode 100644
index 0000000000..063ff1a43a
--- /dev/null
+++ b/target/linux/ramips/mt7620/config-5.10
@@ -0,0 +1,193 @@
+CONFIG_AR8216_PHY=y
+CONFIG_ARCH_32BIT_OFF_T=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_MMAP_RND_BITS_MAX=15
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_BLK_MQ_PCI=y
+CONFIG_CEVT_R4K=y
+CONFIG_CEVT_SYSTICK_QUIRK=y
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLKEVT_RT3352=y
+CONFIG_CLKSRC_MMIO=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
+CONFIG_CMDLINE_BOOL=y
+# CONFIG_CMDLINE_OVERRIDE is not set
+CONFIG_COMPAT_32BIT_TIME=y
+CONFIG_CPU_GENERIC_DUMP_TLB=y
+CONFIG_CPU_HAS_DIEI=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_CPU_HAS_RIXI=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_CPU_MIPS32=y
+# CONFIG_CPU_MIPS32_R1 is not set
+CONFIG_CPU_MIPS32_R2=y
+CONFIG_CPU_MIPSR2=y
+CONFIG_CPU_MIPSR2_IRQ_VI=y
+CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
+CONFIG_CPU_R4K_CACHE_TLB=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_CPU_SUPPORTS_MSA=y
+CONFIG_CRYPTO_LIB_POLY1305_RSIZE=2
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CSRC_R4K=y
+CONFIG_DEBUG_PINCTRL=y
+CONFIG_DMA_NONCOHERENT=y
+# CONFIG_DTB_MT7620A_EVAL is not set
+# CONFIG_DTB_OMEGA2P is not set
+CONFIG_DTB_RT_NONE=y
+# CONFIG_DTB_VOCORE2 is not set
+CONFIG_DTC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_FIXED_PHY=y
+CONFIG_FW_LOADER_PAGED_BUF=y
+CONFIG_GENERIC_ATOMIC64=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_CPU_AUTOPROBE=y
+CONFIG_GENERIC_GETTIMEOFDAY=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_GENERIC_IRQ_CHIP=y
+CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_LIB_ASHLDI3=y
+CONFIG_GENERIC_LIB_ASHRDI3=y
+CONFIG_GENERIC_LIB_CMPDI2=y
+CONFIG_GENERIC_LIB_LSHRDI3=y
+CONFIG_GENERIC_LIB_UCMPDI2=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_PHY=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GPIOLIB=y
+# CONFIG_GPIO_MT7621 is not set
+CONFIG_GPIO_RALINK=y
+CONFIG_HANDLE_DOMAIN_IRQ=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HZ=250
+CONFIG_HZ_250=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_ICPLUS_PHY=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_INTC=y
+CONFIG_IRQ_MIPS_CPU=y
+CONFIG_IRQ_WORK=y
+# CONFIG_KERNEL_ZSTD is not set
+CONFIG_LIBFDT=y
+CONFIG_LLD_VERSION=0
+CONFIG_LOCK_DEBUGGING_SUPPORT=y
+CONFIG_MARVELL_PHY=y
+CONFIG_MDIO_BUS=y
+CONFIG_MDIO_DEVICE=y
+CONFIG_MEMFD_CREATE=y
+CONFIG_MFD_SYSCON=y
+CONFIG_MIGRATION=y
+CONFIG_MIPS=y
+CONFIG_MIPS_ASID_BITS=8
+CONFIG_MIPS_ASID_SHIFT=0
+CONFIG_MIPS_CBPF_JIT=y
+CONFIG_MIPS_CLOCK_VSYSCALL=y
+# CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND is not set
+# CONFIG_MIPS_CMDLINE_DTB_EXTEND is not set
+# CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER is not set
+CONFIG_MIPS_CMDLINE_FROM_DTB=y
+# CONFIG_MIPS_ELF_APPENDED_DTB is not set
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+CONFIG_MIPS_LD_CAN_LINK_VDSO=y
+# CONFIG_MIPS_NO_APPENDED_DTB is not set
+CONFIG_MIPS_RAW_APPENDED_DTB=y
+CONFIG_MIPS_SPRAM=y
+CONFIG_MODULES_USE_ELF_REL=y
+# CONFIG_MT7621_WDT is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y
+CONFIG_MTD_SPI_NOR_USE_4K_SECTORS_LIMIT=16384
+CONFIG_MTD_SPLIT_JIMAGE_FW=y
+CONFIG_MTD_SPLIT_SEAMA_FW=y
+CONFIG_MTD_SPLIT_TPLINK_FW=y
+CONFIG_MTD_SPLIT_UIMAGE_FW=y
+CONFIG_MTD_VIRT_CONCAT=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_PER_CPU_KM=y
+CONFIG_NET_RALINK_GSW_MT7620=y
+CONFIG_NET_RALINK_MDIO=y
+CONFIG_NET_RALINK_MDIO_MT7620=y
+CONFIG_NET_RALINK_MT7620=y
+# CONFIG_NET_RALINK_RT3050 is not set
+CONFIG_NET_RALINK_SOC=y
+# CONFIG_NET_VENDOR_MEDIATEK is not set
+CONFIG_NET_VENDOR_RALINK=y
+CONFIG_NO_GENERIC_PCI_IOPORT_MAP=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_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_DRIVERS_LEGACY=y
+# CONFIG_PCI_MT7621 is not set
+# CONFIG_PCI_MT7621_PHY is not set
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYLIB=y
+CONFIG_PHY_RALINK_USB=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_RT2880=y
+# CONFIG_PINCTRL_SINGLE is not set
+CONFIG_RALINK=y
+CONFIG_RALINK_WDT=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_RESET_CONTROLLER=y
+CONFIG_SERIAL_8250_RT288X=y
+CONFIG_SERIAL_MCTRL_GPIO=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SOC_MT7620=y
+# CONFIG_SOC_MT7621 is not set
+# CONFIG_SOC_RT288X is not set
+# CONFIG_SOC_RT305X is not set
+# CONFIG_SOC_RT3883 is not set
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_MEM=y
+# CONFIG_SPI_MT7621 is not set
+CONFIG_SPI_RT2880=y
+CONFIG_SRCU=y
+CONFIG_SWCONFIG=y
+CONFIG_SWCONFIG_LEDS=y
+CONFIG_SWPHY=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_SYS_HAS_CPU_MIPS32_R2=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_MIPS16=y
+CONFIG_SYS_SUPPORTS_ZBOOT=y
+CONFIG_TARGET_ISA_REV=2
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TIMER_OF=y
+CONFIG_TIMER_PROBE=y
+CONFIG_TINY_SRCU=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USE_OF=y
+CONFIG_WATCHDOG_CORE=y
diff --git a/target/linux/ramips/mt7621/config-5.10 b/target/linux/ramips/mt7621/config-5.10
new file mode 100644
index 0000000000..430ea9513c
--- /dev/null
+++ b/target/linux/ramips/mt7621/config-5.10
@@ -0,0 +1,288 @@
+CONFIG_ARCH_32BIT_OFF_T=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_MMAP_RND_BITS_MAX=15
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_AT803X_PHY=y
+CONFIG_BLK_MQ_PCI=y
+CONFIG_BOARD_SCACHE=y
+CONFIG_BOUNCE=y
+CONFIG_CEVT_R4K=y
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLKSRC_MIPS_GIC=y
+CONFIG_CLOCKSOURCE_WATCHDOG=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
+CONFIG_CMDLINE_BOOL=y
+# CONFIG_CMDLINE_OVERRIDE is not set
+CONFIG_COMMON_CLK=y
+# CONFIG_COMMON_CLK_BOSTON is not set
+CONFIG_COMPAT_32BIT_TIME=y
+CONFIG_CPU_GENERIC_DUMP_TLB=y
+CONFIG_CPU_HAS_DIEI=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_CPU_HAS_RIXI=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_CPU_MIPS32=y
+# CONFIG_CPU_MIPS32_R1 is not set
+CONFIG_CPU_MIPS32_R2=y
+CONFIG_CPU_MIPSR2=y
+CONFIG_CPU_MIPSR2_IRQ_EI=y
+CONFIG_CPU_MIPSR2_IRQ_VI=y
+CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
+CONFIG_CPU_R4K_CACHE_TLB=y
+CONFIG_CPU_RMAP=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_CPU_SUPPORTS_MSA=y
+CONFIG_CRC16=y
+CONFIG_CRYPTO_ACOMP2=y
+CONFIG_CRYPTO_AEAD=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_HASH_INFO=y
+CONFIG_CRYPTO_LIB_POLY1305_RSIZE=2
+CONFIG_CRYPTO_LZO=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_NULL2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CSRC_R4K=y
+CONFIG_DEBUG_PINCTRL=y
+CONFIG_DIMLIB=y
+CONFIG_DMA_NONCOHERENT=y
+# CONFIG_DTB_GNUBEE1 is not set
+# CONFIG_DTB_GNUBEE2 is not set
+CONFIG_DTB_RT_NONE=y
+CONFIG_DTC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_FIXED_PHY=y
+CONFIG_FW_LOADER_PAGED_BUF=y
+CONFIG_GENERIC_ATOMIC64=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_CPU_AUTOPROBE=y
+CONFIG_GENERIC_GETTIMEOFDAY=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_GENERIC_IRQ_CHIP=y
+CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_LIB_ASHLDI3=y
+CONFIG_GENERIC_LIB_ASHRDI3=y
+CONFIG_GENERIC_LIB_CMPDI2=y
+CONFIG_GENERIC_LIB_LSHRDI3=y
+CONFIG_GENERIC_LIB_UCMPDI2=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_PHY=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GLOB=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIOLIB_IRQCHIP=y
+CONFIG_GPIO_GENERIC=y
+CONFIG_GPIO_MT7621=y
+# CONFIG_GPIO_RALINK is not set
+CONFIG_GPIO_WATCHDOG=y
+# CONFIG_GPIO_WATCHDOG_ARCH_INITCALL is not set
+CONFIG_GRO_CELLS=y
+CONFIG_HANDLE_DOMAIN_IRQ=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HIGHMEM=y
+CONFIG_HZ=250
+CONFIG_HZ_250=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_MT7621=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_MIPS_CPU=y
+CONFIG_IRQ_WORK=y
+# CONFIG_KERNEL_ZSTD is not set
+CONFIG_LED_TRIGGER_PHY=y
+CONFIG_LIBFDT=y
+CONFIG_LLD_VERSION=0
+CONFIG_LOCK_DEBUGGING_SUPPORT=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_MDIO_BUS=y
+CONFIG_MDIO_DEVICE=y
+CONFIG_MEMFD_CREATE=y
+CONFIG_MFD_SYSCON=y
+CONFIG_MIGRATION=y
+CONFIG_MIKROTIK=y
+CONFIG_MIKROTIK_RB_SYSFS=y
+CONFIG_MIPS=y
+CONFIG_MIPS_ASID_BITS=8
+CONFIG_MIPS_ASID_SHIFT=0
+CONFIG_MIPS_CBPF_JIT=y
+CONFIG_MIPS_CLOCK_VSYSCALL=y
+CONFIG_MIPS_CM=y
+# CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND is not set
+# CONFIG_MIPS_CMDLINE_DTB_EXTEND is not set
+# CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER is not set
+CONFIG_MIPS_CMDLINE_FROM_DTB=y
+CONFIG_MIPS_CPC=y
+CONFIG_MIPS_CPS=y
+# CONFIG_MIPS_CPS_NS16550_BOOL is not set
+CONFIG_MIPS_CPU_SCACHE=y
+# CONFIG_MIPS_ELF_APPENDED_DTB is not set
+CONFIG_MIPS_GIC=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+CONFIG_MIPS_LD_CAN_LINK_VDSO=y
+CONFIG_MIPS_MT=y
+CONFIG_MIPS_MT_FPAFF=y
+CONFIG_MIPS_MT_SMP=y
+# CONFIG_MIPS_NO_APPENDED_DTB is not set
+CONFIG_MIPS_NR_CPU_NR_MAP=4
+CONFIG_MIPS_PERF_SHARED_TC_COUNTERS=y
+CONFIG_MIPS_RAW_APPENDED_DTB=y
+CONFIG_MIPS_SPRAM=y
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_MT7621_WDT=y
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_NAND_CORE=y
+CONFIG_MTD_NAND_ECC=y
+CONFIG_MTD_NAND_ECC_SW_HAMMING=y
+CONFIG_MTD_NAND_MT7621=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_RAW_NAND=y
+CONFIG_MTD_ROUTERBOOT_PARTS=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_SPLIT_FIT_FW=y
+CONFIG_MTD_SPLIT_MINOR_FW=y
+CONFIG_MTD_SPLIT_SEAMA_FW=y
+CONFIG_MTD_SPLIT_TPLINK_FW=y
+CONFIG_MTD_SPLIT_TRX_FW=y
+CONFIG_MTD_SPLIT_UIMAGE_FW=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_BEB_LIMIT=20
+CONFIG_MTD_UBI_BLOCK=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_VIRT_CONCAT=y
+# CONFIG_MTK_HSDMA is not set
+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_NET_VENDOR_RALINK is not set
+CONFIG_NR_CPUS=4
+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_PADATA=y
+CONFIG_PCI=y
+CONFIG_PCI_DISABLE_COMMON_QUIRKS=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_DOMAINS_GENERIC=y
+CONFIG_PCI_DRIVERS_GENERIC=y
+CONFIG_PCI_MT7621=y
+CONFIG_PCI_MT7621_PHY=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYLIB=y
+CONFIG_PHYLINK=y
+# CONFIG_PHY_RALINK_USB is not set
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_RT2880=y
+# CONFIG_PINCTRL_SINGLE is not set
+CONFIG_PINCTRL_SX150X=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_GPIO=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_QUEUED_RWLOCKS=y
+CONFIG_QUEUED_SPINLOCKS=y
+CONFIG_RALINK=y
+# CONFIG_RALINK_WDT is not set
+CONFIG_RATIONAL=y
+CONFIG_RCU_NEED_SEGCBLIST=y
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_RESET_CONTROLLER=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RPS=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_BQ32K=y
+CONFIG_RTC_DRV_PCF8563=y
+CONFIG_RTC_I2C_AND_SPI=y
+CONFIG_RTC_MC146818_LIB=y
+CONFIG_SCHED_SMT=y
+CONFIG_SERIAL_8250_NR_UARTS=3
+CONFIG_SERIAL_8250_RUNTIME_UARTS=3
+CONFIG_SERIAL_MCTRL_GPIO=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SGL_ALLOC=y
+CONFIG_SMP=y
+CONFIG_SMP_UP=y
+CONFIG_SOC_BUS=y
+# CONFIG_SOC_MT7620 is not set
+CONFIG_SOC_MT7621=y
+# CONFIG_SOC_RT288X is not set
+# CONFIG_SOC_RT305X is not set
+# CONFIG_SOC_RT3883 is not set
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_MEM=y
+CONFIG_SPI_MT7621=y
+# CONFIG_SPI_RT2880 is not set
+CONFIG_SRCU=y
+CONFIG_SWPHY=y
+CONFIG_SYNC_R4K=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_SYS_HAS_CPU_MIPS32_R2=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_SYS_SUPPORTS_HIGHMEM=y
+CONFIG_SYS_SUPPORTS_HOTPLUG_CPU=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_MIPS16=y
+CONFIG_SYS_SUPPORTS_MIPS_CPS=y
+CONFIG_SYS_SUPPORTS_MULTITHREADING=y
+CONFIG_SYS_SUPPORTS_SCHED_SMT=y
+CONFIG_SYS_SUPPORTS_SMP=y
+CONFIG_SYS_SUPPORTS_ZBOOT=y
+CONFIG_TARGET_ISA_REV=2
+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_USB_SUPPORT=y
+CONFIG_USE_OF=y
+CONFIG_WATCHDOG_CORE=y
+CONFIG_WEAK_ORDERING=y
+CONFIG_WEAK_REORDERING_BEYOND_LLSC=y
+CONFIG_XPS=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_ZLIB_INFLATE=y
diff --git a/target/linux/ramips/mt76x8/config-5.10 b/target/linux/ramips/mt76x8/config-5.10
new file mode 100644
index 0000000000..7829174319
--- /dev/null
+++ b/target/linux/ramips/mt76x8/config-5.10
@@ -0,0 +1,191 @@
+CONFIG_ARCH_32BIT_OFF_T=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_MMAP_RND_BITS_MAX=15
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_AT803X_PHY=y
+CONFIG_BLK_MQ_PCI=y
+CONFIG_CEVT_R4K=y
+CONFIG_CEVT_SYSTICK_QUIRK=y
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLKEVT_RT3352=y
+CONFIG_CLKSRC_MMIO=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
+CONFIG_CMDLINE_BOOL=y
+# CONFIG_CMDLINE_OVERRIDE is not set
+CONFIG_COMPAT_32BIT_TIME=y
+CONFIG_CPU_GENERIC_DUMP_TLB=y
+CONFIG_CPU_HAS_DIEI=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_CPU_HAS_RIXI=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_CPU_MIPS32=y
+# CONFIG_CPU_MIPS32_R1 is not set
+CONFIG_CPU_MIPS32_R2=y
+CONFIG_CPU_MIPSR2=y
+CONFIG_CPU_MIPSR2_IRQ_VI=y
+CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
+CONFIG_CPU_R4K_CACHE_TLB=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_CPU_SUPPORTS_MSA=y
+CONFIG_CRYPTO_LIB_POLY1305_RSIZE=2
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CSRC_R4K=y
+CONFIG_DEBUG_PINCTRL=y
+CONFIG_DMA_NONCOHERENT=y
+# CONFIG_DTB_MT7620A_EVAL is not set
+# CONFIG_DTB_OMEGA2P is not set
+CONFIG_DTB_RT_NONE=y
+# CONFIG_DTB_VOCORE2 is not set
+CONFIG_DTC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_FIXED_PHY=y
+CONFIG_FW_LOADER_PAGED_BUF=y
+CONFIG_GENERIC_ATOMIC64=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_CPU_AUTOPROBE=y
+CONFIG_GENERIC_GETTIMEOFDAY=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_GENERIC_IRQ_CHIP=y
+CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_LIB_ASHLDI3=y
+CONFIG_GENERIC_LIB_ASHRDI3=y
+CONFIG_GENERIC_LIB_CMPDI2=y
+CONFIG_GENERIC_LIB_LSHRDI3=y
+CONFIG_GENERIC_LIB_UCMPDI2=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_PHY=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIOLIB_IRQCHIP=y
+CONFIG_GPIO_GENERIC=y
+CONFIG_GPIO_MT7621=y
+# CONFIG_GPIO_RALINK is not set
+CONFIG_HANDLE_DOMAIN_IRQ=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HZ=250
+CONFIG_HZ_250=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_ICPLUS_PHY=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_INTC=y
+CONFIG_IRQ_MIPS_CPU=y
+CONFIG_IRQ_WORK=y
+# CONFIG_KERNEL_ZSTD is not set
+CONFIG_LIBFDT=y
+CONFIG_LLD_VERSION=0
+CONFIG_LOCK_DEBUGGING_SUPPORT=y
+CONFIG_MDIO_BUS=y
+CONFIG_MDIO_DEVICE=y
+CONFIG_MEMFD_CREATE=y
+CONFIG_MFD_SYSCON=y
+CONFIG_MIGRATION=y
+CONFIG_MIPS=y
+CONFIG_MIPS_ASID_BITS=8
+CONFIG_MIPS_ASID_SHIFT=0
+CONFIG_MIPS_CBPF_JIT=y
+CONFIG_MIPS_CLOCK_VSYSCALL=y
+# CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND is not set
+# CONFIG_MIPS_CMDLINE_DTB_EXTEND is not set
+# CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER is not set
+CONFIG_MIPS_CMDLINE_FROM_DTB=y
+# CONFIG_MIPS_ELF_APPENDED_DTB is not set
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+CONFIG_MIPS_LD_CAN_LINK_VDSO=y
+# CONFIG_MIPS_NO_APPENDED_DTB is not set
+CONFIG_MIPS_RAW_APPENDED_DTB=y
+CONFIG_MIPS_SPRAM=y
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_MT7621_WDT=y
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_SPLIT_TPLINK_FW=y
+CONFIG_MTD_SPLIT_TRX_FW=y
+CONFIG_MTD_SPLIT_UIMAGE_FW=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_PER_CPU_KM=y
+CONFIG_NET_RALINK_ESW_RT3050=y
+# CONFIG_NET_RALINK_MT7620 is not set
+CONFIG_NET_RALINK_RT3050=y
+CONFIG_NET_RALINK_SOC=y
+# CONFIG_NET_VENDOR_MEDIATEK is not set
+CONFIG_NET_VENDOR_RALINK=y
+CONFIG_NO_GENERIC_PCI_IOPORT_MAP=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_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_DRIVERS_LEGACY=y
+# CONFIG_PCI_MT7621 is not set
+# CONFIG_PCI_MT7621_PHY is not set
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYLIB=y
+CONFIG_PHY_RALINK_USB=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_RT2880=y
+# CONFIG_PINCTRL_SINGLE is not set
+CONFIG_RALINK=y
+# CONFIG_RALINK_WDT is not set
+CONFIG_REGMAP=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_RESET_CONTROLLER=y
+CONFIG_SERIAL_8250_NR_UARTS=3
+CONFIG_SERIAL_8250_RUNTIME_UARTS=3
+CONFIG_SERIAL_MCTRL_GPIO=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SOC_MT7620=y
+# CONFIG_SOC_MT7621 is not set
+# CONFIG_SOC_RT288X is not set
+# CONFIG_SOC_RT305X is not set
+# CONFIG_SOC_RT3883 is not set
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_MEM=y
+CONFIG_SPI_MT7621=y
+# CONFIG_SPI_RT2880 is not set
+CONFIG_SRCU=y
+CONFIG_SWCONFIG=y
+CONFIG_SWCONFIG_LEDS=y
+CONFIG_SWPHY=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_SYS_HAS_CPU_MIPS32_R2=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_MIPS16=y
+CONFIG_SYS_SUPPORTS_ZBOOT=y
+CONFIG_TARGET_ISA_REV=2
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TIMER_OF=y
+CONFIG_TIMER_PROBE=y
+CONFIG_TINY_SRCU=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USE_OF=y
+CONFIG_WATCHDOG_CORE=y
diff --git a/target/linux/ramips/patches-5.10/020-mips-ralink-manage-low-reset-lines.patch b/target/linux/ramips/patches-5.10/020-mips-ralink-manage-low-reset-lines.patch
new file mode 100644
index 0000000000..bdf98f223c
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/020-mips-ralink-manage-low-reset-lines.patch
@@ -0,0 +1,45 @@
+From 3f9ef7785a9cd69cb75f5e2ea4ca79a24752e496 Mon Sep 17 00:00:00 2001
+From: Sander Vanheule <sander at svanheule.net>
+Date: Wed, 3 Feb 2021 10:21:41 +0100
+Subject: MIPS: ralink: manage low reset lines
+
+Reset lines with indices smaller than 8 are currently considered invalid
+by the rt2880-reset reset controller.
+
+The MT7621 SoC uses a number of these low reset lines. The DTS defines
+reset lines "hsdma", "fe", and "mcm" with respective values 5, 6, and 2.
+As a result of the above restriction, these resets cannot be asserted or
+de-asserted by the reset controller. In cases where the bootloader does
+not de-assert these lines, this results in e.g. the MT7621's internal
+switch staying in reset.
+
+Change the reset controller to only ignore the system reset, so all
+reset lines with index greater than 0 are considered valid.
+
+Signed-off-by: Sander Vanheule <sander at svanheule.net>
+Acked-by: John Crispin <john at phrozen.org>
+Signed-off-by: Thomas Bogendoerfer <tsbogend at alpha.franken.de>
+---
+ arch/mips/ralink/reset.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/mips/ralink/reset.c
++++ b/arch/mips/ralink/reset.c
+@@ -27,7 +27,7 @@ static int ralink_assert_device(struct r
+ {
+ 	u32 val;
+ 
+-	if (id < 8)
++	if (id == 0)
+ 		return -1;
+ 
+ 	val = rt_sysc_r32(SYSC_REG_RESET_CTRL);
+@@ -42,7 +42,7 @@ static int ralink_deassert_device(struct
+ {
+ 	u32 val;
+ 
+-	if (id < 8)
++	if (id == 0)
+ 		return -1;
+ 
+ 	val = rt_sysc_r32(SYSC_REG_RESET_CTRL);
diff --git a/target/linux/ramips/patches-5.10/200-add-ralink-eth.patch b/target/linux/ramips/patches-5.10/200-add-ralink-eth.patch
new file mode 100644
index 0000000000..9aa8cb5180
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/200-add-ralink-eth.patch
@@ -0,0 +1,20 @@
+--- a/drivers/net/ethernet/Kconfig
++++ b/drivers/net/ethernet/Kconfig
+@@ -158,6 +158,7 @@ source "drivers/net/ethernet/pasemi/Kcon
+ source "drivers/net/ethernet/pensando/Kconfig"
+ source "drivers/net/ethernet/qlogic/Kconfig"
+ source "drivers/net/ethernet/qualcomm/Kconfig"
++source "drivers/net/ethernet/ralink/Kconfig"
+ source "drivers/net/ethernet/rdc/Kconfig"
+ source "drivers/net/ethernet/realtek/Kconfig"
+ source "drivers/net/ethernet/renesas/Kconfig"
+--- a/drivers/net/ethernet/Makefile
++++ b/drivers/net/ethernet/Makefile
+@@ -71,6 +71,7 @@ obj-$(CONFIG_NET_VENDOR_PACKET_ENGINES)
+ obj-$(CONFIG_NET_VENDOR_PASEMI) += pasemi/
+ obj-$(CONFIG_NET_VENDOR_QLOGIC) += qlogic/
+ obj-$(CONFIG_NET_VENDOR_QUALCOMM) += qualcomm/
++obj-$(CONFIG_NET_VENDOR_RALINK) += ralink/
+ obj-$(CONFIG_NET_VENDOR_REALTEK) += realtek/
+ obj-$(CONFIG_NET_VENDOR_RENESAS) += renesas/
+ obj-$(CONFIG_NET_VENDOR_RDC) += rdc/
diff --git a/target/linux/ramips/patches-5.10/202-weak_reordering.patch b/target/linux/ramips/patches-5.10/202-weak_reordering.patch
new file mode 100644
index 0000000000..074e16642f
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/202-weak_reordering.patch
@@ -0,0 +1,10 @@
+--- a/arch/mips/ralink/Kconfig
++++ b/arch/mips/ralink/Kconfig
+@@ -57,6 +57,7 @@ choice
+ 		select CLKSRC_MIPS_GIC
+ 		select HAVE_PCI if PCI_MT7621
+ 		select SOC_BUS
++		select WEAK_REORDERING_BEYOND_LLSC
+ endchoice
+ 
+ choice
diff --git a/target/linux/ramips/patches-5.10/203-staging-mt7621-pci-phy-kconfig-select-regmap-mmio.patch b/target/linux/ramips/patches-5.10/203-staging-mt7621-pci-phy-kconfig-select-regmap-mmio.patch
new file mode 100644
index 0000000000..e6c5db4db7
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/203-staging-mt7621-pci-phy-kconfig-select-regmap-mmio.patch
@@ -0,0 +1,10 @@
+--- a/drivers/staging/mt7621-pci-phy/Kconfig
++++ b/drivers/staging/mt7621-pci-phy/Kconfig
+@@ -3,6 +3,7 @@ config PCI_MT7621_PHY
+ 	tristate "MediaTek MT7621 PCI PHY Driver"
+ 	depends on RALINK && OF
+ 	select GENERIC_PHY
++	select REGMAP_MMIO
+ 	help
+ 	  Say 'Y' here to add support for MediaTek MT7621 PCI PHY driver,
+ 
diff --git a/target/linux/ramips/patches-5.10/300-mt7620-export-chip-version-and-pkg.patch b/target/linux/ramips/patches-5.10/300-mt7620-export-chip-version-and-pkg.patch
new file mode 100644
index 0000000000..8b4335eb03
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/300-mt7620-export-chip-version-and-pkg.patch
@@ -0,0 +1,19 @@
+--- a/arch/mips/include/asm/mach-ralink/mt7620.h
++++ b/arch/mips/include/asm/mach-ralink/mt7620.h
+@@ -135,4 +135,16 @@ static inline int mt7620_get_eco(void)
+ 	return rt_sysc_r32(SYSC_REG_CHIP_REV) & CHIP_REV_ECO_MASK;
+ }
+ 
++static inline int mt7620_get_chipver(void)
++{
++	return (rt_sysc_r32(SYSC_REG_CHIP_REV) >> CHIP_REV_VER_SHIFT) &
++		CHIP_REV_VER_MASK;
++}
++
++static inline int mt7620_get_pkg(void)
++{
++	return (rt_sysc_r32(SYSC_REG_CHIP_REV) >> CHIP_REV_PKG_SHIFT) &
++		CHIP_REV_PKG_MASK;
++}
++
+ #endif
diff --git a/target/linux/ramips/patches-5.10/310-MIPS-Fix-memory-reservation-in-bootmem_init-for-cert.patch b/target/linux/ramips/patches-5.10/310-MIPS-Fix-memory-reservation-in-bootmem_init-for-cert.patch
new file mode 100644
index 0000000000..987ffbf3c4
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/310-MIPS-Fix-memory-reservation-in-bootmem_init-for-cert.patch
@@ -0,0 +1,45 @@
+From: Tobias Wolf <dev-NTEO at vplace.de>
+Subject: [v2] MIPS: Fix memory reservation in bootmem_init for certain non-usermem setups
+
+Commit 67a3ba25aa95 ("MIPS: Fix incorrect mem=X at Y handling") introduced a new
+issue for rt288x where "PHYS_OFFSET" is 0x0 but the calculated "ramstart" is
+not. As the prerequisite of custom memory map has been removed, this results
+in the full memory range of 0x0 - 0x8000000 to be marked as reserved for this
+platform.
+
+v2: Correctly compare that usermem is not null.
+
+This patch adds the originally intended prerequisite again.
+
+Signed-off-by: Tobias Wolf <dev-NTEO at vplace.de>
+---
+
+--- a/arch/mips/kernel/setup.c
++++ b/arch/mips/kernel/setup.c
+@@ -249,6 +249,8 @@ static unsigned long __init init_initrd(
+  * Initialize the bootmem allocator. It also setup initrd related data
+  * if needed.
+  */
++static int usermem __initdata;
++
+ #if defined(CONFIG_SGI_IP27) || (defined(CONFIG_CPU_LOONGSON64) && defined(CONFIG_NUMA))
+ 
+ static void __init bootmem_init(void)
+@@ -288,7 +290,7 @@ static void __init bootmem_init(void)
+ 	/*
+ 	 * Reserve any memory between the start of RAM and PHYS_OFFSET
+ 	 */
+-	if (ramstart > PHYS_OFFSET)
++	if (usermem && ramstart > PHYS_OFFSET)
+ 		memblock_reserve(PHYS_OFFSET, ramstart - PHYS_OFFSET);
+ 
+ 	if (PFN_UP(ramstart) > ARCH_PFN_OFFSET) {
+@@ -336,8 +338,6 @@ static void __init bootmem_init(void)
+ 
+ #endif	/* CONFIG_SGI_IP27 */
+ 
+-static int usermem __initdata;
+-
+ static int __init early_parse_mem(char *p)
+ {
+ 	phys_addr_t start, size;
diff --git a/target/linux/ramips/patches-5.10/311-MIPS-use-set_mode-to-enable-disable-the-cevt-r4k-irq.patch b/target/linux/ramips/patches-5.10/311-MIPS-use-set_mode-to-enable-disable-the-cevt-r4k-irq.patch
new file mode 100644
index 0000000000..a0b81bc6c5
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/311-MIPS-use-set_mode-to-enable-disable-the-cevt-r4k-irq.patch
@@ -0,0 +1,100 @@
+From ce3d4a4111a5f7e6b4e74bceae5faa6ce388e8ec Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic at openwrt.org>
+Date: Sun, 14 Jul 2013 23:08:11 +0200
+Subject: [PATCH 05/53] MIPS: use set_mode() to enable/disable the cevt-r4k
+ irq
+
+Signed-off-by: John Crispin <blogic at openwrt.org>
+---
+ arch/mips/ralink/Kconfig |    5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/arch/mips/ralink/Kconfig
++++ b/arch/mips/ralink/Kconfig
+@@ -1,12 +1,17 @@
+ # SPDX-License-Identifier: GPL-2.0
+ if RALINK
+ 
++config CEVT_SYSTICK_QUIRK
++	bool
++	default n
++
+ config CLKEVT_RT3352
+ 	bool
+ 	depends on SOC_RT305X || SOC_MT7620
+ 	default y
+ 	select TIMER_OF
+ 	select CLKSRC_MMIO
++	select CEVT_SYSTICK_QUIRK
+ 
+ config RALINK_ILL_ACC
+ 	bool
+--- a/arch/mips/kernel/cevt-r4k.c
++++ b/arch/mips/kernel/cevt-r4k.c
+@@ -16,6 +16,31 @@
+ #include <asm/time.h>
+ #include <asm/cevt-r4k.h>
+ 
++#ifdef CONFIG_CEVT_SYSTICK_QUIRK
++static int mips_state_oneshot(struct clock_event_device *evt)
++{
++	unsigned long flags = IRQF_PERCPU | IRQF_TIMER | IRQF_SHARED;
++	if (!cp0_timer_irq_installed) {
++		cp0_timer_irq_installed = 1;
++		if (request_irq(evt->irq, c0_compare_interrupt, flags, "timer",
++					c0_compare_interrupt))
++			pr_err("Failed to request irq %d (timer)\n", evt->irq);
++	}
++
++	return 0;
++}
++
++static int mips_state_shutdown(struct clock_event_device *evt)
++{
++	if (cp0_timer_irq_installed) {
++		cp0_timer_irq_installed = 0;
++		free_irq(evt->irq, NULL);
++	}
++
++	return 0;
++}
++#endif
++
+ static int mips_next_event(unsigned long delta,
+ 			   struct clock_event_device *evt)
+ {
+@@ -296,7 +321,9 @@ core_initcall(r4k_register_cpufreq_notif
+ 
+ int r4k_clockevent_init(void)
+ {
++#ifndef CONFIG_CEVT_SYSTICK_QUIRK
+ 	unsigned long flags = IRQF_PERCPU | IRQF_TIMER | IRQF_SHARED;
++#endif
+ 	unsigned int cpu = smp_processor_id();
+ 	struct clock_event_device *cd;
+ 	unsigned int irq, min_delta;
+@@ -326,11 +353,16 @@ int r4k_clockevent_init(void)
+ 	cd->rating		= 300;
+ 	cd->irq			= irq;
+ 	cd->cpumask		= cpumask_of(cpu);
++#ifdef CONFIG_CEVT_SYSTICK_QUIRK
++	cd->set_state_shutdown	= mips_state_shutdown;
++	cd->set_state_oneshot	= mips_state_oneshot;
++#endif
+ 	cd->set_next_event	= mips_next_event;
+ 	cd->event_handler	= mips_event_handler;
+ 
+ 	clockevents_config_and_register(cd, mips_hpt_frequency, min_delta, 0x7fffffff);
+ 
++#ifndef CONFIG_CEVT_SYSTICK_QUIRK
+ 	if (cp0_timer_irq_installed)
+ 		return 0;
+ 
+@@ -339,6 +371,7 @@ int r4k_clockevent_init(void)
+ 	if (request_irq(irq, c0_compare_interrupt, flags, "timer",
+ 			c0_compare_interrupt))
+ 		pr_err("Failed to request irq %d (timer)\n", irq);
++#endif
+ 
+ 	return 0;
+ }
diff --git a/target/linux/ramips/patches-5.10/312-MIPS-ralink-add-cpu-frequency-scaling.patch b/target/linux/ramips/patches-5.10/312-MIPS-ralink-add-cpu-frequency-scaling.patch
new file mode 100644
index 0000000000..0d70770941
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/312-MIPS-ralink-add-cpu-frequency-scaling.patch
@@ -0,0 +1,195 @@
+From bd30f19a006fb52bac80c6463c49dd2f4159f4ac Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic at openwrt.org>
+Date: Sun, 28 Jul 2013 16:26:41 +0200
+Subject: [PATCH 06/53] MIPS: ralink: add cpu frequency scaling
+
+This feature will break udelay() and cause the delay loop to have longer delays
+when the frequency is scaled causing a performance hit.
+
+Signed-off-by: John Crispin <blogic at openwrt.org>
+---
+ arch/mips/ralink/cevt-rt3352.c |   38 ++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 38 insertions(+)
+
+--- a/arch/mips/ralink/cevt-rt3352.c
++++ b/arch/mips/ralink/cevt-rt3352.c
+@@ -29,6 +29,10 @@
+ /* enable the counter */
+ #define CFG_CNT_EN		0x1
+ 
++/* mt7620 frequency scaling defines */
++#define CLK_LUT_CFG	0x40
++#define SLEEP_EN	BIT(31)
++
+ struct systick_device {
+ 	void __iomem *membase;
+ 	struct clock_event_device dev;
+@@ -36,21 +40,53 @@ struct systick_device {
+ 	int freq_scale;
+ };
+ 
++static void (*systick_freq_scaling)(struct systick_device *sdev, int status);
++
+ static int systick_set_oneshot(struct clock_event_device *evt);
+ static int systick_shutdown(struct clock_event_device *evt);
+ 
++static inline void mt7620_freq_scaling(struct systick_device *sdev, int status)
++{
++	if (sdev->freq_scale == status)
++		return;
++
++	sdev->freq_scale = status;
++
++	pr_info("%s: %s autosleep mode\n", sdev->dev.name,
++			(status) ? ("enable") : ("disable"));
++	if (status)
++		rt_sysc_w32(rt_sysc_r32(CLK_LUT_CFG) | SLEEP_EN, CLK_LUT_CFG);
++	else
++		rt_sysc_w32(rt_sysc_r32(CLK_LUT_CFG) & ~SLEEP_EN, CLK_LUT_CFG);
++}
++
++static inline unsigned int read_count(struct systick_device *sdev)
++{
++	return ioread32(sdev->membase + SYSTICK_COUNT);
++}
++
++static inline unsigned int read_compare(struct systick_device *sdev)
++{
++	return ioread32(sdev->membase + SYSTICK_COMPARE);
++}
++
++static inline void write_compare(struct systick_device *sdev, unsigned int val)
++{
++	iowrite32(val, sdev->membase + SYSTICK_COMPARE);
++}
++
+ static int systick_next_event(unsigned long delta,
+ 				struct clock_event_device *evt)
+ {
+ 	struct systick_device *sdev;
+-	u32 count;
++	int res;
+ 
+ 	sdev = container_of(evt, struct systick_device, dev);
+-	count = ioread32(sdev->membase + SYSTICK_COUNT);
+-	count = (count + delta) % SYSTICK_FREQ;
+-	iowrite32(count, sdev->membase + SYSTICK_COMPARE);
++	delta += read_count(sdev);
++	write_compare(sdev, delta);
++	res = ((int)(read_count(sdev) - delta) >= 0) ? -ETIME : 0;
+ 
+-	return 0;
++	return res;
+ }
+ 
+ static void systick_event_handler(struct clock_event_device *dev)
+@@ -60,20 +96,25 @@ static void systick_event_handler(struct
+ 
+ static irqreturn_t systick_interrupt(int irq, void *dev_id)
+ {
+-	struct clock_event_device *dev = (struct clock_event_device *) dev_id;
++	int ret = 0;
++	struct clock_event_device *cdev;
++	struct systick_device *sdev;
+ 
+-	dev->event_handler(dev);
++	if (read_c0_cause() & STATUSF_IP7) {
++		cdev = (struct clock_event_device *) dev_id;
++		sdev = container_of(cdev, struct systick_device, dev);
++
++		/* Clear Count/Compare Interrupt */
++		write_compare(sdev, read_compare(sdev));
++		cdev->event_handler(cdev);
++		ret = 1;
++	}
+ 
+-	return IRQ_HANDLED;
++	return IRQ_RETVAL(ret);
+ }
+ 
+ static struct systick_device systick = {
+ 	.dev = {
+-		/*
+-		 * cevt-r4k uses 300, make sure systick
+-		 * gets used if available
+-		 */
+-		.rating			= 310,
+ 		.features		= CLOCK_EVT_FEAT_ONESHOT,
+ 		.set_next_event		= systick_next_event,
+ 		.set_state_shutdown	= systick_shutdown,
+@@ -91,7 +132,13 @@ static int systick_shutdown(struct clock
+ 	if (sdev->irq_requested)
+ 		free_irq(systick.dev.irq, &systick.dev);
+ 	sdev->irq_requested = 0;
+-	iowrite32(0, systick.membase + SYSTICK_CONFIG);
++	iowrite32(CFG_CNT_EN, systick.membase + SYSTICK_CONFIG);
++
++	if (systick_freq_scaling)
++		systick_freq_scaling(sdev, 0);
++
++	if (systick_freq_scaling)
++		systick_freq_scaling(sdev, 1);
+ 
+ 	return 0;
+ }
+@@ -116,33 +163,46 @@ static int systick_set_oneshot(struct cl
+ 	return 0;
+ }
+ 
++static const struct of_device_id systick_match[] = {
++	{ .compatible = "ralink,mt7620a-systick", .data = mt7620_freq_scaling},
++	{},
++};
++
+ static int __init ralink_systick_init(struct device_node *np)
+ {
+-	int ret;
++	const struct of_device_id *match;
++	int rating = 200;
+ 
+ 	systick.membase = of_iomap(np, 0);
+ 	if (!systick.membase)
+ 		return -ENXIO;
+ 
+-	systick.dev.name = np->name;
+-	clockevents_calc_mult_shift(&systick.dev, SYSTICK_FREQ, 60);
+-	systick.dev.max_delta_ns = clockevent_delta2ns(0x7fff, &systick.dev);
+-	systick.dev.max_delta_ticks = 0x7fff;
+-	systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev);
+-	systick.dev.min_delta_ticks = 0x3;
++	match = of_match_node(systick_match, np);
++	if (match) {
++		systick_freq_scaling = match->data;
++		/*
++		 * cevt-r4k uses 300, make sure systick
++		 * gets used if available
++		 */
++		rating = 310;
++	}
++
++	/* enable counter than register clock source */
++	iowrite32(CFG_CNT_EN, systick.membase + SYSTICK_CONFIG);
++	clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
++			SYSTICK_FREQ, rating, 16, clocksource_mmio_readl_up);
++
++	/* register clock event */
+ 	systick.dev.irq = irq_of_parse_and_map(np, 0);
+ 	if (!systick.dev.irq) {
+ 		pr_err("%pOFn: request_irq failed", np);
+ 		return -EINVAL;
+ 	}
+ 
+-	ret = clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
+-				    SYSTICK_FREQ, 301, 16,
+-				    clocksource_mmio_readl_up);
+-	if (ret)
+-		return ret;
+-
+-	clockevents_register_device(&systick.dev);
++	systick.dev.name = np->name;
++	systick.dev.rating = rating;
++	systick.dev.cpumask = cpumask_of(0);
++	clockevents_config_and_register(&systick.dev, SYSTICK_FREQ, 0x3, 0x7fff);
+ 
+ 	pr_info("%pOFn: running - mult: %d, shift: %d\n",
+ 			np, systick.dev.mult, systick.dev.shift);
diff --git a/target/linux/ramips/patches-5.10/313-MIPS-ralink-copy-the-commandline-from-the-devicetree.patch b/target/linux/ramips/patches-5.10/313-MIPS-ralink-copy-the-commandline-from-the-devicetree.patch
new file mode 100644
index 0000000000..54af571d85
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/313-MIPS-ralink-copy-the-commandline-from-the-devicetree.patch
@@ -0,0 +1,21 @@
+From 67b7bff0fd364c194e653f69baa623ba2141bd4c Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic at openwrt.org>
+Date: Mon, 4 Aug 2014 18:46:02 +0200
+Subject: [PATCH 07/53] MIPS: ralink: copy the commandline from the devicetree
+
+Signed-off-by: John Crispin <blogic at openwrt.org>
+---
+ arch/mips/ralink/of.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/arch/mips/ralink/of.c
++++ b/arch/mips/ralink/of.c
+@@ -80,6 +80,8 @@ void __init plat_mem_setup(void)
+ 
+ 	__dt_setup_arch(dtb);
+ 
++	strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
++
+ 	of_scan_flat_dt(early_init_dt_find_memory, NULL);
+ 	if (memory_dtb)
+ 		of_scan_flat_dt(early_init_dt_scan_memory, NULL);
diff --git a/target/linux/ramips/patches-5.10/314-MIPS-add-bootargs-override-property.patch b/target/linux/ramips/patches-5.10/314-MIPS-add-bootargs-override-property.patch
new file mode 100644
index 0000000000..a5df046ba7
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/314-MIPS-add-bootargs-override-property.patch
@@ -0,0 +1,63 @@
+From f15d27f9c90ede4b16eb37f9ae573ef81c2b6996 Mon Sep 17 00:00:00 2001
+From: David Bauer <mail at david-bauer.net>
+Date: Thu, 31 Dec 2020 18:49:12 +0100
+Subject: [PATCH] MIPS: add bootargs-override property
+
+Add support for the bootargs-override property to the chosen node
+similar to the one used on ipq806x or mpc85xx.
+
+This is necessary, as the U-Boot used on some boards, notably the
+Ubiquiti UniFi 6 Lite, overwrite the bootargs property of the chosen
+node leading to a kernel panic when loading OpenWrt.
+
+Signed-off-by: David Bauer <mail at david-bauer.net>
+---
+ arch/mips/kernel/setup.c | 30 ++++++++++++++++++++++++++++++
+ 1 file changed, 30 insertions(+)
+
+--- a/arch/mips/kernel/setup.c
++++ b/arch/mips/kernel/setup.c
+@@ -542,8 +542,28 @@ static int __init bootcmdline_scan_chose
+ 
+ #endif /* CONFIG_OF_EARLY_FLATTREE */
+ 
++static int __init bootcmdline_scan_chosen_override(unsigned long node, const char *uname,
++						   int depth, void *data)
++{
++	bool *dt_bootargs = data;
++	const char *p;
++	int l;
++
++	if (depth != 1 || !data || strcmp(uname, "chosen") != 0)
++		return 0;
++
++	p = of_get_flat_dt_prop(node, "bootargs-override", &l);
++	if (p != NULL && l > 0) {
++		strlcpy(boot_command_line, p, COMMAND_LINE_SIZE);
++		*dt_bootargs = true;
++	}
++
++	return 1;
++}
++
+ static void __init bootcmdline_init(void)
+ {
++	bool dt_bootargs_override = false;
+ 	bool dt_bootargs = false;
+ 
+ 	/*
+@@ -557,6 +577,14 @@ static void __init bootcmdline_init(void
+ 	}
+ 
+ 	/*
++	 * If bootargs-override in the chosen node is set, use this as the
++	 * command line
++	 */
++	of_scan_flat_dt(bootcmdline_scan_chosen_override, &dt_bootargs_override);
++	if (dt_bootargs_override)
++		return;
++
++	/*
+ 	 * If the user specified a built-in command line &
+ 	 * MIPS_CMDLINE_BUILTIN_EXTEND, then the built-in command line is
+ 	 * prepended to arguments from the bootloader or DT so we'll copy them
diff --git a/target/linux/ramips/patches-5.10/315-owrt-hack-fix-mt7688-cache-issue.patch b/target/linux/ramips/patches-5.10/315-owrt-hack-fix-mt7688-cache-issue.patch
new file mode 100644
index 0000000000..59d4b3ce56
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/315-owrt-hack-fix-mt7688-cache-issue.patch
@@ -0,0 +1,29 @@
+From 5ede027f6c4a57ed25da872420508b7f1168b36b Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic at openwrt.org>
+Date: Mon, 7 Dec 2015 17:15:32 +0100
+Subject: [PATCH 13/53] owrt: hack: fix mt7688 cache issue
+
+Signed-off-by: John Crispin <blogic at openwrt.org>
+---
+ arch/mips/kernel/setup.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/mips/kernel/setup.c
++++ b/arch/mips/kernel/setup.c
+@@ -694,8 +694,6 @@ static void __init arch_mem_init(char **
+ 	if (crashk_res.start != crashk_res.end)
+ 		memblock_reserve(crashk_res.start, resource_size(&crashk_res));
+ #endif
+-	device_tree_init();
+-
+ 	/*
+ 	 * In order to reduce the possibility of kernel panic when failed to
+ 	 * get IO TLB memory under CONFIG_SWIOTLB, it is better to allocate
+@@ -815,6 +813,7 @@ void __init setup_arch(char **cmdline_p)
+ 
+ 	cpu_cache_init();
+ 	paging_init();
++	device_tree_init();
+ }
+ 
+ unsigned long kernelsp[NR_CPUS];
diff --git a/target/linux/ramips/patches-5.10/316-arch-mips-do-not-select-illegal-access-driver-by-def.patch b/target/linux/ramips/patches-5.10/316-arch-mips-do-not-select-illegal-access-driver-by-def.patch
new file mode 100644
index 0000000000..1dc54ccf23
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/316-arch-mips-do-not-select-illegal-access-driver-by-def.patch
@@ -0,0 +1,25 @@
+From 9e6ce539092a1dd605a20bf73c655a9de58d8641 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic at openwrt.org>
+Date: Mon, 7 Dec 2015 17:18:05 +0100
+Subject: [PATCH 15/53] arch: mips: do not select illegal access driver by
+ default
+
+Signed-off-by: John Crispin <blogic at openwrt.org>
+---
+ arch/mips/ralink/Kconfig |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/mips/ralink/Kconfig
++++ b/arch/mips/ralink/Kconfig
+@@ -14,9 +14,9 @@ config CLKEVT_RT3352
+ 	select CEVT_SYSTICK_QUIRK
+ 
+ config RALINK_ILL_ACC
+-	bool
++	bool "illegal access irq"
+ 	depends on SOC_RT305X
+-	default y
++	default n
+ 
+ config IRQ_INTC
+ 	bool
diff --git a/target/linux/ramips/patches-5.10/320-mt7621-core-detect-hack.patch b/target/linux/ramips/patches-5.10/320-mt7621-core-detect-hack.patch
new file mode 100644
index 0000000000..c63f0f4c1e
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/320-mt7621-core-detect-hack.patch
@@ -0,0 +1,61 @@
+There is a variant of MT7621 which contains only one CPU core instead of 2.
+This is not reflected in the config register, so the kernel detects more
+physical cores, which leads to a hang on SMP bringup.
+Add a hack to detect missing cores.
+
+Signed-off-by: Felix Fietkau <nbd at nbd.name>
+
+--- a/arch/mips/kernel/smp-cps.c
++++ b/arch/mips/kernel/smp-cps.c
+@@ -43,6 +43,11 @@ static unsigned core_vpe_count(unsigned
+ 	return mips_cps_numvps(cluster, core);
+ }
+ 
++bool __weak plat_cpu_core_present(int core)
++{
++	return true;
++}
++
+ static void __init cps_smp_setup(void)
+ {
+ 	unsigned int nclusters, ncores, nvpes, core_vpes;
+@@ -60,6 +65,8 @@ static void __init cps_smp_setup(void)
+ 
+ 		ncores = mips_cps_numcores(cl);
+ 		for (c = 0; c < ncores; c++) {
++			if (!plat_cpu_core_present(c))
++				continue;
+ 			core_vpes = core_vpe_count(cl, c);
+ 
+ 			if (c > 0)
+--- a/arch/mips/ralink/mt7621.c
++++ b/arch/mips/ralink/mt7621.c
+@@ -15,6 +15,7 @@
+ #include <asm/mips-cps.h>
+ #include <asm/mach-ralink/ralink_regs.h>
+ #include <asm/mach-ralink/mt7621.h>
++#include <asm/mips-boards/launch.h>
+ 
+ #include <pinmux.h>
+ 
+@@ -146,6 +147,20 @@ static void soc_dev_init(struct ralink_s
+ 	}
+ }
+ 
++bool plat_cpu_core_present(int core)
++{
++	struct cpulaunch *launch = (struct cpulaunch *)CKSEG0ADDR(CPULAUNCH);
++
++	if (!core)
++		return true;
++	launch += core * 2; /* 2 VPEs per core */
++	if (!(launch->flags & LAUNCH_FREADY))
++		return false;
++	if (launch->flags & (LAUNCH_FGO | LAUNCH_FGONE))
++		return false;
++	return true;
++}
++
+ void prom_soc_init(struct ralink_soc_info *soc_info)
+ {
+ 	void __iomem *sysc = (void __iomem *) KSEG1ADDR(MT7621_SYSC_BASE);
diff --git a/target/linux/ramips/patches-5.10/321-mt7621-timer.patch b/target/linux/ramips/patches-5.10/321-mt7621-timer.patch
new file mode 100644
index 0000000000..91e14ad63b
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/321-mt7621-timer.patch
@@ -0,0 +1,87 @@
+--- a/arch/mips/ralink/mt7621.c
++++ b/arch/mips/ralink/mt7621.c
+@@ -9,6 +9,7 @@
+ #include <linux/init.h>
+ #include <linux/slab.h>
+ #include <linux/sys_soc.h>
++#include <linux/jiffies.h>
+ 
+ #include <asm/mipsregs.h>
+ #include <asm/smp-ops.h>
+@@ -16,6 +17,7 @@
+ #include <asm/mach-ralink/ralink_regs.h>
+ #include <asm/mach-ralink/mt7621.h>
+ #include <asm/mips-boards/launch.h>
++#include <asm/delay.h>
+ 
+ #include <pinmux.h>
+ 
+@@ -161,6 +163,58 @@ bool plat_cpu_core_present(int core)
+ 	return true;
+ }
+ 
++#define LPS_PREC 8
++/*
++*  Re-calibration lpj(loop-per-jiffy).
++*  (derived from kernel/calibrate.c)
++*/
++static int udelay_recal(void)
++{
++	unsigned int i, lpj = 0;
++	unsigned long ticks, loopbit;
++	int lps_precision = LPS_PREC;
++
++	lpj = (1<<12);
++
++	while ((lpj <<= 1) != 0) {
++		/* wait for "start of" clock tick */
++		ticks = jiffies;
++		while (ticks == jiffies)
++			/* nothing */;
++
++		/* Go .. */
++		ticks = jiffies;
++		__delay(lpj);
++		ticks = jiffies - ticks;
++		if (ticks)
++			break;
++	}
++
++	/*
++	 * Do a binary approximation to get lpj set to
++	 * equal one clock (up to lps_precision bits)
++	 */
++	lpj >>= 1;
++	loopbit = lpj;
++	while (lps_precision-- && (loopbit >>= 1)) {
++		lpj |= loopbit;
++		ticks = jiffies;
++		while (ticks == jiffies)
++			/* nothing */;
++		ticks = jiffies;
++		__delay(lpj);
++		if (jiffies != ticks)   /* longer than 1 tick */
++			lpj &= ~loopbit;
++	}
++	printk(KERN_INFO "%d CPUs re-calibrate udelay(lpj = %d)\n", NR_CPUS, lpj);
++
++	for(i=0; i< NR_CPUS; i++)
++		cpu_data[i].udelay_val = lpj;
++
++	return 0;
++}
++device_initcall(udelay_recal);
++
+ void prom_soc_init(struct ralink_soc_info *soc_info)
+ {
+ 	void __iomem *sysc = (void __iomem *) KSEG1ADDR(MT7621_SYSC_BASE);
+--- a/arch/mips/ralink/Kconfig
++++ b/arch/mips/ralink/Kconfig
+@@ -63,6 +63,7 @@ choice
+ 		select HAVE_PCI if PCI_MT7621
+ 		select SOC_BUS
+ 		select WEAK_REORDERING_BEYOND_LLSC
++		select GENERIC_CLOCKEVENTS_BROADCAST
+ endchoice
+ 
+ choice
diff --git a/target/linux/ramips/patches-5.10/322-mt7621-fix-cpu-clk-add-clkdev.patch b/target/linux/ramips/patches-5.10/322-mt7621-fix-cpu-clk-add-clkdev.patch
new file mode 100644
index 0000000000..723c628790
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/322-mt7621-fix-cpu-clk-add-clkdev.patch
@@ -0,0 +1,187 @@
+--- a/arch/mips/include/asm/mach-ralink/mt7621.h
++++ b/arch/mips/include/asm/mach-ralink/mt7621.h
+@@ -17,6 +17,10 @@
+ #define SYSC_REG_CHIP_REV		0x0c
+ #define SYSC_REG_SYSTEM_CONFIG0		0x10
+ #define SYSC_REG_SYSTEM_CONFIG1		0x14
++#define SYSC_REG_CLKCFG0		0x2c
++#define SYSC_REG_CUR_CLK_STS		0x44
++
++#define MEMC_REG_CPU_PLL		0x648
+ 
+ #define CHIP_REV_PKG_MASK		0x1
+ #define CHIP_REV_PKG_SHIFT		16
+@@ -24,6 +28,22 @@
+ #define CHIP_REV_VER_SHIFT		8
+ #define CHIP_REV_ECO_MASK		0xf
+ 
++#define XTAL_MODE_SEL_MASK		0x7
++#define XTAL_MODE_SEL_SHIFT		6
++
++#define CPU_CLK_SEL_MASK		0x3
++#define CPU_CLK_SEL_SHIFT		30
++
++#define CUR_CPU_FDIV_MASK		0x1f
++#define CUR_CPU_FDIV_SHIFT		8
++#define CUR_CPU_FFRAC_MASK		0x1f
++#define CUR_CPU_FFRAC_SHIFT		0
++
++#define CPU_PLL_PREDIV_MASK		0x3
++#define CPU_PLL_PREDIV_SHIFT		12
++#define CPU_PLL_FBDIV_MASK		0x7f
++#define CPU_PLL_FBDIV_SHIFT		4
++
+ #define MT7621_DRAM_BASE                0x0
+ #define MT7621_DDR2_SIZE_MIN		32
+ #define MT7621_DDR2_SIZE_MAX		256
+--- a/arch/mips/ralink/mt7621.c
++++ b/arch/mips/ralink/mt7621.c
+@@ -10,6 +10,10 @@
+ #include <linux/slab.h>
+ #include <linux/sys_soc.h>
+ #include <linux/jiffies.h>
++#include <linux/clk.h>
++#include <linux/clkdev.h>
++#include <linux/clk-provider.h>
++#include <dt-bindings/clock/mt7621-clk.h>
+ 
+ #include <asm/mipsregs.h>
+ #include <asm/smp-ops.h>
+@@ -18,6 +22,7 @@
+ #include <asm/mach-ralink/mt7621.h>
+ #include <asm/mips-boards/launch.h>
+ #include <asm/delay.h>
++#include <asm/time.h>
+ 
+ #include <pinmux.h>
+ 
+@@ -108,11 +113,89 @@ static struct rt2880_pmx_group mt7621_pi
+ 	{ 0 }
+ };
+ 
++static struct clk *clks[MT7621_CLK_MAX];
++static struct clk_onecell_data clk_data = {
++	.clks = clks,
++	.clk_num = ARRAY_SIZE(clks),
++};
++
+ phys_addr_t mips_cpc_default_phys_base(void)
+ {
+ 	panic("Cannot detect cpc address");
+ }
+ 
++static struct clk *__init mt7621_add_sys_clkdev(
++	const char *id, unsigned long rate)
++{
++	struct clk *clk;
++	int err;
++
++	clk = clk_register_fixed_rate(NULL, id, NULL, 0, rate);
++	if (IS_ERR(clk))
++		panic("failed to allocate %s clock structure", id);
++
++	err = clk_register_clkdev(clk, id, NULL);
++	if (err)
++		panic("unable to register %s clock device", id);
++
++	return clk;
++}
++
++void __init ralink_clk_init(void)
++{
++	u32 syscfg, xtal_sel, clkcfg, clk_sel, curclk, ffiv, ffrac;
++	u32 pll, prediv, fbdiv;
++	u32 xtal_clk, cpu_clk, bus_clk;
++	const static u32 prediv_tbl[] = {0, 1, 2, 2};
++
++	syscfg = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0);
++	xtal_sel = (syscfg >> XTAL_MODE_SEL_SHIFT) & XTAL_MODE_SEL_MASK;
++
++	clkcfg = rt_sysc_r32(SYSC_REG_CLKCFG0);
++	clk_sel = (clkcfg >> CPU_CLK_SEL_SHIFT) & CPU_CLK_SEL_MASK;
++
++	curclk = rt_sysc_r32(SYSC_REG_CUR_CLK_STS);
++	ffiv = (curclk >> CUR_CPU_FDIV_SHIFT) & CUR_CPU_FDIV_MASK;
++	ffrac = (curclk >> CUR_CPU_FFRAC_SHIFT) & CUR_CPU_FFRAC_MASK;
++
++	if (xtal_sel <= 2)
++		xtal_clk = 20 * 1000 * 1000;
++	else if (xtal_sel <= 5)
++		xtal_clk = 40 * 1000 * 1000;
++	else
++		xtal_clk = 25 * 1000 * 1000;
++
++	switch (clk_sel) {
++	case 0:
++		cpu_clk = 500 * 1000 * 1000;
++		break;
++	case 1:
++		pll = rt_memc_r32(MEMC_REG_CPU_PLL);
++		fbdiv = (pll >> CPU_PLL_FBDIV_SHIFT) & CPU_PLL_FBDIV_MASK;
++		prediv = (pll >> CPU_PLL_PREDIV_SHIFT) & CPU_PLL_PREDIV_MASK;
++		cpu_clk = ((fbdiv + 1) * xtal_clk) >> prediv_tbl[prediv];
++		break;
++	default:
++		cpu_clk = xtal_clk;
++	}
++
++	cpu_clk = cpu_clk / ffiv * ffrac;
++	bus_clk = cpu_clk / 4;
++
++	clks[MT7621_CLK_CPU] = mt7621_add_sys_clkdev("cpu", cpu_clk);
++	clks[MT7621_CLK_BUS] = mt7621_add_sys_clkdev("bus", bus_clk);
++
++	pr_info("CPU Clock: %dMHz\n", cpu_clk / 1000000);
++	mips_hpt_frequency = cpu_clk / 2;
++}
++
++static void __init mt7621_clocks_init_dt(struct device_node *np)
++{
++	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
++}
++
++CLK_OF_DECLARE(mt7621, "mediatek,mt7621-pll", mt7621_clocks_init_dt);
++
+ void __init ralink_of_remap(void)
+ {
+ 	rt_sysc_membase = plat_of_remap_node("mtk,mt7621-sysc");
+--- a/arch/mips/ralink/timer-gic.c
++++ b/arch/mips/ralink/timer-gic.c
+@@ -9,14 +9,14 @@
+ 
+ #include <linux/of.h>
+ #include <linux/of_clk.h>
+-#include <linux/clocksource.h>
++#include <asm/time.h>
+ 
+ #include "common.h"
+ 
+ void __init plat_time_init(void)
+ {
+ 	ralink_of_remap();
+-
++	ralink_clk_init();
+ 	of_clk_init(NULL);
+ 	timer_probe();
+ }
+--- /dev/null
++++ b/include/dt-bindings/clock/mt7621-clk.h
+@@ -0,0 +1,18 @@
++/*
++ * Copyright (C) 2018 Weijie Gao <hackpascal at 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.
++ *
++ */
++
++#ifndef __DT_BINDINGS_MT7621_CLK_H
++#define __DT_BINDINGS_MT7621_CLK_H
++
++#define MT7621_CLK_CPU		0
++#define MT7621_CLK_BUS		1
++
++#define MT7621_CLK_MAX		2
++
++#endif /* __DT_BINDINGS_MT7621_CLK_H */
diff --git a/target/linux/ramips/patches-5.10/323-mt7621-memory-detect.patch b/target/linux/ramips/patches-5.10/323-mt7621-memory-detect.patch
new file mode 100644
index 0000000000..07c7588661
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/323-mt7621-memory-detect.patch
@@ -0,0 +1,129 @@
+From b5a52351a66f3c2a7a207548aa87d78ff2d336c0 Mon Sep 17 00:00:00 2001
+From: Chuanhong Guo <gch981213 at gmail.com>
+Date: Wed, 10 Jul 2019 00:24:48 +0800
+Subject: [PATCH] MIPS: ralink: mt7621: add memory detection support
+
+mt7621 has the following memory map:
+0x0-0x1c000000: lower 448m memory
+0x1c000000-0x2000000: peripheral registers
+0x20000000-0x2400000: higher 64m memory
+
+detect_memory_region in arch/mips/kernel/setup.c only add the first
+memory region and isn't suitable for 512m memory detection because
+it may accidentally read the memory area for peripheral registers.
+
+This commit adds memory detection capability for mt7621:
+1. add the highmem area when 512m is detected.
+2. guard memcmp from accessing peripheral registers:
+     This only happens when some weird user decided to change
+     kernel load address to 256m or higher address. Since this
+     is a quite unusual case, we just skip 512m testing and return
+     256m as memory size.
+
+Signed-off-by: Chuanhong Guo <gch981213 at gmail.com>
+---
+ arch/mips/include/asm/mach-ralink/mt7621.h |  7 ++---
+ arch/mips/ralink/mt7621.c                  | 30 +++++++++++++++++++---
+ 2 files changed, 30 insertions(+), 7 deletions(-)
+
+--- a/arch/mips/include/asm/mach-ralink/mt7621.h
++++ b/arch/mips/include/asm/mach-ralink/mt7621.h
+@@ -44,9 +44,10 @@
+ #define CPU_PLL_FBDIV_MASK		0x7f
+ #define CPU_PLL_FBDIV_SHIFT		4
+ 
+-#define MT7621_DRAM_BASE                0x0
+-#define MT7621_DDR2_SIZE_MIN		32
+-#define MT7621_DDR2_SIZE_MAX		256
++#define MT7621_LOWMEM_BASE		0x0
++#define MT7621_LOWMEM_MAX_SIZE		0x1C000000
++#define MT7621_HIGHMEM_BASE		0x20000000
++#define MT7621_HIGHMEM_SIZE		0x4000000
+ 
+ #define MT7621_CHIP_NAME0		0x3637544D
+ #define MT7621_CHIP_NAME1		0x20203132
+--- a/arch/mips/ralink/mt7621.c
++++ b/arch/mips/ralink/mt7621.c
+@@ -10,11 +10,13 @@
+ #include <linux/slab.h>
+ #include <linux/sys_soc.h>
+ #include <linux/jiffies.h>
++#include <linux/memblock.h>
+ #include <linux/clk.h>
+ #include <linux/clkdev.h>
+ #include <linux/clk-provider.h>
+ #include <dt-bindings/clock/mt7621-clk.h>
+ 
++#include <asm/bootinfo.h>
+ #include <asm/mipsregs.h>
+ #include <asm/smp-ops.h>
+ #include <asm/mips-cps.h>
+@@ -57,6 +59,8 @@
+ #define MT7621_GPIO_MODE_SDHCI_SHIFT	18
+ #define MT7621_GPIO_MODE_SDHCI_GPIO	1
+ 
++static void *detect_magic __initdata = detect_memory_region;
++
+ static struct rt2880_pmx_func uart1_grp[] =  { FUNC("uart1", 0, 1, 2) };
+ static struct rt2880_pmx_func i2c_grp[] =  { FUNC("i2c", 0, 3, 2) };
+ static struct rt2880_pmx_func uart3_grp[] = {
+@@ -141,6 +145,26 @@ static struct clk *__init mt7621_add_sys
+ 	return clk;
+ }
+ 
++void __init mt7621_memory_detect(void)
++{
++	void *dm = &detect_magic;
++	phys_addr_t size;
++
++	for (size = 32 * SZ_1M; size < 256 * SZ_1M; size <<= 1) {
++		if (!__builtin_memcmp(dm, dm + size, sizeof(detect_magic)))
++			break;
++	}
++
++	if ((size == 256 * SZ_1M) &&
++	    (CPHYSADDR(dm + size) < MT7621_LOWMEM_MAX_SIZE) &&
++	    __builtin_memcmp(dm, dm + size, sizeof(detect_magic))) {
++		memblock_add(MT7621_LOWMEM_BASE, MT7621_LOWMEM_MAX_SIZE);
++		memblock_add(MT7621_HIGHMEM_BASE, MT7621_HIGHMEM_SIZE);
++	} else {
++		memblock_add(MT7621_LOWMEM_BASE, size);
++	}
++}
++
+ void __init ralink_clk_init(void)
+ {
+ 	u32 syscfg, xtal_sel, clkcfg, clk_sel, curclk, ffiv, ffrac;
+@@ -346,10 +370,7 @@ void prom_soc_init(struct ralink_soc_inf
+ 		(rev >> CHIP_REV_VER_SHIFT) & CHIP_REV_VER_MASK,
+ 		(rev & CHIP_REV_ECO_MASK));
+ 
+-	soc_info->mem_size_min = MT7621_DDR2_SIZE_MIN;
+-	soc_info->mem_size_max = MT7621_DDR2_SIZE_MAX;
+-	soc_info->mem_base = MT7621_DRAM_BASE;
+-
++	soc_info->mem_detect = mt7621_memory_detect;
+ 	rt2880_pinmux_data = mt7621_pinmux_data;
+ 
+ 	soc_dev_init(soc_info, rev);
+--- a/arch/mips/ralink/common.h
++++ b/arch/mips/ralink/common.h
+@@ -17,6 +17,7 @@ struct ralink_soc_info {
+ 	unsigned long mem_size;
+ 	unsigned long mem_size_min;
+ 	unsigned long mem_size_max;
++	void (*mem_detect)(void);
+ };
+ extern struct ralink_soc_info soc_info;
+ 
+--- a/arch/mips/ralink/of.c
++++ b/arch/mips/ralink/of.c
+@@ -85,6 +85,8 @@ void __init plat_mem_setup(void)
+ 	of_scan_flat_dt(early_init_dt_find_memory, NULL);
+ 	if (memory_dtb)
+ 		of_scan_flat_dt(early_init_dt_scan_memory, NULL);
++	else if (soc_info.mem_detect)
++		soc_info.mem_detect();
+ 	else if (soc_info.mem_size)
+ 		memblock_add(soc_info.mem_base, soc_info.mem_size * SZ_1M);
+ 	else
diff --git a/target/linux/ramips/patches-5.10/324-mt7621-perfctr-fix.patch b/target/linux/ramips/patches-5.10/324-mt7621-perfctr-fix.patch
new file mode 100644
index 0000000000..dfeac7eb99
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/324-mt7621-perfctr-fix.patch
@@ -0,0 +1,15 @@
+--- a/arch/mips/ralink/irq-gic.c
++++ b/arch/mips/ralink/irq-gic.c
+@@ -13,6 +13,12 @@
+ 
+ int get_c0_perfcount_int(void)
+ {
++	/*
++	 * Performance counter events are routed through GIC.
++	 * Prevent them from firing on CPU IRQ7 as well
++	 */
++	clear_c0_status(IE_SW0 << 7);
++
+ 	return gic_get_c0_perfcount_int();
+ }
+ EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
diff --git a/target/linux/ramips/patches-5.10/330-fix-pci-init-mt7620.patch b/target/linux/ramips/patches-5.10/330-fix-pci-init-mt7620.patch
new file mode 100644
index 0000000000..7c00d4c9ae
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/330-fix-pci-init-mt7620.patch
@@ -0,0 +1,21 @@
+--- a/arch/mips/pci/pci-mt7620.c
++++ b/arch/mips/pci/pci-mt7620.c
+@@ -32,6 +32,7 @@
+ #define PPLL_CFG1			0x9c
+ 
+ #define PPLL_DRV			0xa0
++#define PPLL_LD			BIT(23)
+ #define PDRV_SW_SET			BIT(31)
+ #define LC_CKDRVPD			BIT(19)
+ #define LC_CKDRVOHZ			BIT(18)
+@@ -239,8 +240,8 @@ static int mt7620_pci_hw_init(struct pla
+ 	rt_sysc_m32(0, RALINK_PCIE0_CLK_EN, RALINK_CLKCFG1);
+ 	mdelay(100);
+ 
+-	if (!(rt_sysc_r32(PPLL_CFG1) & PDRV_SW_SET)) {
+-		dev_err(&pdev->dev, "MT7620 PPLL unlock\n");
++	if (!(rt_sysc_r32(PPLL_CFG1) & PPLL_LD)) {
++		dev_err(&pdev->dev, "MT7620 PPLL is unlocked, aborting init\n");
+ 		reset_control_assert(rstpcie0);
+ 		rt_sysc_m32(RALINK_PCIE0_CLK_EN, 0, RALINK_CLKCFG1);
+ 		return -1;
diff --git a/target/linux/ramips/patches-5.10/400-mtd-cfi-cmdset-0002-force-word-write.patch b/target/linux/ramips/patches-5.10/400-mtd-cfi-cmdset-0002-force-word-write.patch
new file mode 100644
index 0000000000..7011bbe50b
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/400-mtd-cfi-cmdset-0002-force-word-write.patch
@@ -0,0 +1,20 @@
+From ee9081b2726a5ca8cde5497afdc5425e21ff8f8b Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic at openwrt.org>
+Date: Mon, 15 Jul 2013 00:39:21 +0200
+Subject: [PATCH 37/53] mtd: cfi cmdset 0002 force word write
+
+---
+ drivers/mtd/chips/cfi_cmdset_0002.c |    9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+--- a/drivers/mtd/chips/cfi_cmdset_0002.c
++++ b/drivers/mtd/chips/cfi_cmdset_0002.c
+@@ -40,7 +40,7 @@
+ #include <linux/mtd/xip.h>
+ 
+ #define AMD_BOOTLOC_BUG
+-#define FORCE_WORD_WRITE 0
++#define FORCE_WORD_WRITE 1
+ 
+ #define MAX_RETRIES 3
+ 
diff --git a/target/linux/ramips/patches-5.10/410-mtd-rawnand-add-driver-support-for-MT7621-nand-flash.patch b/target/linux/ramips/patches-5.10/410-mtd-rawnand-add-driver-support-for-MT7621-nand-flash.patch
new file mode 100644
index 0000000000..a37426edec
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/410-mtd-rawnand-add-driver-support-for-MT7621-nand-flash.patch
@@ -0,0 +1,1403 @@
+From e84e2430ee0e483842b4ff013ae8a6e7e2fa2734 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao at mediatek.com>
+Date: Wed, 1 Apr 2020 02:07:58 +0800
+Subject: [PATCH 1/2] mtd: rawnand: add driver support for MT7621 nand
+ flash controller
+
+This patch adds NAND flash controller driver for MediaTek MT7621 SoC.
+
+The NAND flash controller is similar with controllers described in
+mtk_nand.c, except that the controller from MT7621 doesn't support DMA
+transmission, and some registers' offset and fields are different.
+
+Signed-off-by: Weijie Gao <weijie.gao at mediatek.com>
+---
+ drivers/mtd/nand/raw/Kconfig       |    8 +
+ drivers/mtd/nand/raw/Makefile      |    1 +
+ drivers/mtd/nand/raw/mt7621_nand.c | 1348 ++++++++++++++++++++++++++++++++++++
+ 3 files changed, 1357 insertions(+)
+ create mode 100644 drivers/mtd/nand/raw/mt7621_nand.c
+
+--- a/drivers/mtd/nand/raw/Kconfig
++++ b/drivers/mtd/nand/raw/Kconfig
+@@ -387,6 +387,14 @@ config MTD_NAND_QCOM
+ 	  Enables support for NAND flash chips on SoCs containing the EBI2 NAND
+ 	  controller. This controller is found on IPQ806x SoC.
+ 
++config MTD_NAND_MT7621
++	tristate "MT7621 NAND controller"
++	depends on SOC_MT7621 || COMPILE_TEST
++	depends on HAS_IOMEM
++	help
++	  Enables support for NAND controller on MT7621 SoC.
++	  This driver uses PIO mode for data transmission instead of DMA mode.
++
+ config MTD_NAND_MTK
+ 	tristate "MTK NAND controller"
+ 	depends on ARCH_MEDIATEK || COMPILE_TEST
+--- a/drivers/mtd/nand/raw/Makefile
++++ b/drivers/mtd/nand/raw/Makefile
+@@ -51,6 +51,7 @@ obj-$(CONFIG_MTD_NAND_SUNXI)		+= sunxi_n
+ obj-$(CONFIG_MTD_NAND_HISI504)	        += hisi504_nand.o
+ obj-$(CONFIG_MTD_NAND_BRCMNAND)		+= brcmnand/
+ obj-$(CONFIG_MTD_NAND_QCOM)		+= qcom_nandc.o
++obj-$(CONFIG_MTD_NAND_MT7621)		+= mt7621_nand.o
+ obj-$(CONFIG_MTD_NAND_MTK)		+= mtk_ecc.o mtk_nand.o
+ obj-$(CONFIG_MTD_NAND_MXIC)		+= mxic_nand.o
+ obj-$(CONFIG_MTD_NAND_TEGRA)		+= tegra_nand.o
+--- /dev/null
++++ b/drivers/mtd/nand/raw/mt7621_nand.c
+@@ -0,0 +1,1353 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * MediaTek MT7621 NAND Flash Controller driver
++ *
++ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
++ *
++ * Author: Weijie Gao <weijie.gao at mediatek.com>
++ */
++
++#include <linux/io.h>
++#include <linux/clk.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/sizes.h>
++#include <linux/iopoll.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/platform_device.h>
++#include <asm/addrspace.h>
++
++/* NFI core registers */
++#define NFI_CNFG			0x000
++#define   CNFG_OP_MODE_S		12
++#define   CNFG_OP_MODE_M		GENMASK(14, 12)
++#define     CNFG_OP_CUSTOM		6
++#define   CNFG_AUTO_FMT_EN		BIT(9)
++#define   CNFG_HW_ECC_EN		BIT(8)
++#define   CNFG_BYTE_RW			BIT(6)
++#define   CNFG_READ_MODE		BIT(1)
++
++#define NFI_PAGEFMT			0x004
++#define   PAGEFMT_FDM_ECC_S		12
++#define   PAGEFMT_FDM_ECC_M		GENMASK(15, 12)
++#define   PAGEFMT_FDM_S			8
++#define   PAGEFMT_FDM_M			GENMASK(11, 8)
++#define   PAGEFMT_SPARE_S		4
++#define   PAGEFMT_SPARE_M		GENMASK(5, 4)
++#define   PAGEFMT_PAGE_S		0
++#define   PAGEFMT_PAGE_M		GENMASK(1, 0)
++
++#define NFI_CON				0x008
++#define   CON_NFI_SEC_S			12
++#define   CON_NFI_SEC_M			GENMASK(15, 12)
++#define   CON_NFI_BWR			BIT(9)
++#define   CON_NFI_BRD			BIT(8)
++#define   CON_NFI_RST			BIT(1)
++#define   CON_FIFO_FLUSH		BIT(0)
++
++#define NFI_ACCCON			0x00c
++#define   ACCCON_POECS_S		28
++#define   ACCCON_POECS_MAX		0x0f
++#define   ACCCON_POECS_DEF		3
++#define   ACCCON_PRECS_S		22
++#define   ACCCON_PRECS_MAX		0x3f
++#define   ACCCON_PRECS_DEF		3
++#define   ACCCON_C2R_S			16
++#define   ACCCON_C2R_MAX		0x3f
++#define   ACCCON_C2R_DEF		7
++#define   ACCCON_W2R_S			12
++#define   ACCCON_W2R_MAX		0x0f
++#define   ACCCON_W2R_DEF		7
++#define   ACCCON_WH_S			8
++#define   ACCCON_WH_MAX			0x0f
++#define   ACCCON_WH_DEF			15
++#define   ACCCON_WST_S			4
++#define   ACCCON_WST_MAX		0x0f
++#define   ACCCON_WST_DEF		15
++#define   ACCCON_WST_MIN		3
++#define   ACCCON_RLT_S			0
++#define   ACCCON_RLT_MAX		0x0f
++#define   ACCCON_RLT_DEF		15
++#define   ACCCON_RLT_MIN		3
++
++#define NFI_CMD				0x020
++
++#define NFI_ADDRNOB			0x030
++#define   ADDR_ROW_NOB_S		4
++#define   ADDR_ROW_NOB_M		GENMASK(6, 4)
++#define   ADDR_COL_NOB_S		0
++#define   ADDR_COL_NOB_M		GENMASK(2, 0)
++
++#define NFI_COLADDR			0x034
++#define NFI_ROWADDR			0x038
++
++#define NFI_STRDATA			0x040
++#define   STR_DATA			BIT(0)
++
++#define NFI_CNRNB			0x044
++#define   CB2R_TIME_S			4
++#define   CB2R_TIME_M			GENMASK(7, 4)
++#define   STR_CNRNB			BIT(0)
++
++#define NFI_DATAW			0x050
++#define NFI_DATAR			0x054
++
++#define NFI_PIO_DIRDY			0x058
++#define   PIO_DIRDY			BIT(0)
++
++#define NFI_STA				0x060
++#define   STA_NFI_FSM_S			16
++#define   STA_NFI_FSM_M			GENMASK(19, 16)
++#define     STA_FSM_CUSTOM_DATA		14
++#define   STA_BUSY			BIT(8)
++#define   STA_ADDR			BIT(1)
++#define   STA_CMD			BIT(0)
++
++#define NFI_ADDRCNTR			0x070
++#define   SEC_CNTR_S			12
++#define   SEC_CNTR_M			GENMASK(15, 12)
++#define   SEC_ADDR_S			0
++#define   SEC_ADDR_M			GENMASK(9, 0)
++
++#define NFI_CSEL			0x090
++#define   CSEL_S			0
++#define   CSEL_M			GENMASK(1, 0)
++
++#define NFI_FDM0L			0x0a0
++#define NFI_FDML(n)			(0x0a0 + ((n) << 3))
++
++#define NFI_FDM0M			0x0a4
++#define NFI_FDMM(n)			(0x0a4 + ((n) << 3))
++
++#define NFI_MASTER_STA			0x210
++#define   MAS_ADDR			GENMASK(11, 9)
++#define   MAS_RD			GENMASK(8, 6)
++#define   MAS_WR			GENMASK(5, 3)
++#define   MAS_RDDLY			GENMASK(2, 0)
++
++/* ECC engine registers */
++#define ECC_ENCCON			0x000
++#define   ENC_EN			BIT(0)
++
++#define ECC_ENCCNFG			0x004
++#define   ENC_CNFG_MSG_S		16
++#define   ENC_CNFG_MSG_M		GENMASK(28, 16)
++#define   ENC_MODE_S			4
++#define   ENC_MODE_M			GENMASK(5, 4)
++#define     ENC_MODE_NFI		1
++#define   ENC_TNUM_S			0
++#define   ENC_TNUM_M			GENMASK(2, 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_CS_M			GENMASK(28, 16)
++#define   DEC_CON_S			12
++#define   DEC_CON_M			GENMASK(13, 12)
++#define     DEC_CON_EL			2
++#define   DEC_MODE_S			4
++#define   DEC_MODE_M			GENMASK(5, 4)
++#define     DEC_MODE_NFI		1
++#define   DEC_TNUM_S			0
++#define   DEC_TNUM_M			GENMASK(2, 0)
++
++#define ECC_DECIDLE			0x10c
++#define   DEC_IDLE			BIT(1)
++
++#define ECC_DECENUM			0x114
++#define   ERRNUM_S			2
++#define   ERRNUM_M			GENMASK(3, 0)
++
++#define ECC_DECDONE			0x118
++#define   DEC_DONE7			BIT(7)
++#define   DEC_DONE6			BIT(6)
++#define   DEC_DONE5			BIT(5)
++#define   DEC_DONE4			BIT(4)
++#define   DEC_DONE3			BIT(3)
++#define   DEC_DONE2			BIT(2)
++#define   DEC_DONE1			BIT(1)
++#define   DEC_DONE0			BIT(0)
++
++#define ECC_DECEL(n)			(0x11c + (n) * 4)
++#define   DEC_EL_ODD_S			16
++#define   DEC_EL_EVEN_S			0
++#define   DEC_EL_M			0x1fff
++#define   DEC_EL_BYTE_POS_S		3
++#define   DEC_EL_BIT_POS_M		GENMASK(3, 0)
++
++#define ECC_FDMADDR			0x13c
++
++/* ENCIDLE and DECIDLE */
++#define   ECC_IDLE			BIT(0)
++
++#define ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt) \
++	((tpoecs) << ACCCON_POECS_S | (tprecs) << ACCCON_PRECS_S | \
++	(tc2r) << ACCCON_C2R_S | (tw2r) << ACCCON_W2R_S | \
++	(twh) << ACCCON_WH_S | (twst) << ACCCON_WST_S | (trlt))
++
++#define MASTER_STA_MASK			(MAS_ADDR | MAS_RD | MAS_WR | \
++					 MAS_RDDLY)
++#define NFI_RESET_TIMEOUT		1000000
++#define NFI_CORE_TIMEOUT		500000
++#define ECC_ENGINE_TIMEOUT		500000
++
++#define ECC_SECTOR_SIZE			512
++#define ECC_PARITY_BITS			13
++
++#define NFI_FDM_SIZE		8
++
++#define MT7621_NFC_NAME			"mt7621-nand"
++
++struct mt7621_nfc {
++	struct nand_controller controller;
++	struct nand_chip nand;
++	struct clk *nfi_clk;
++	struct device *dev;
++
++	void __iomem *nfi_regs;
++	void __iomem *ecc_regs;
++
++	u32 spare_per_sector;
++};
++
++static const u16 mt7621_nfi_page_size[] = { SZ_512, SZ_2K, SZ_4K };
++static const u8 mt7621_nfi_spare_size[] = { 16, 26, 27, 28 };
++static const u8 mt7621_ecc_strength[] = { 4, 6, 8, 10, 12 };
++
++static inline u32 nfi_read32(struct mt7621_nfc *nfc, u32 reg)
++{
++	return readl(nfc->nfi_regs + reg);
++}
++
++static inline void nfi_write32(struct mt7621_nfc *nfc, u32 reg, u32 val)
++{
++	writel(val, nfc->nfi_regs + reg);
++}
++
++static inline u16 nfi_read16(struct mt7621_nfc *nfc, u32 reg)
++{
++	return readw(nfc->nfi_regs + reg);
++}
++
++static inline void nfi_write16(struct mt7621_nfc *nfc, u32 reg, u16 val)
++{
++	writew(val, nfc->nfi_regs + reg);
++}
++
++static inline void ecc_write16(struct mt7621_nfc *nfc, u32 reg, u16 val)
++{
++	writew(val, nfc->ecc_regs + reg);
++}
++
++static inline u32 ecc_read32(struct mt7621_nfc *nfc, u32 reg)
++{
++	return readl(nfc->ecc_regs + reg);
++}
++
++static inline void ecc_write32(struct mt7621_nfc *nfc, u32 reg, u32 val)
++{
++	return writel(val, nfc->ecc_regs + reg);
++}
++
++static inline u8 *oob_fdm_ptr(struct nand_chip *nand, int sect)
++{
++	return nand->oob_poi + sect * NFI_FDM_SIZE;
++}
++
++static inline u8 *oob_ecc_ptr(struct mt7621_nfc *nfc, int sect)
++{
++	struct nand_chip *nand = &nfc->nand;
++
++	return nand->oob_poi + nand->ecc.steps * NFI_FDM_SIZE +
++		sect * (nfc->spare_per_sector - NFI_FDM_SIZE);
++}
++
++static inline u8 *page_data_ptr(struct nand_chip *nand, const u8 *buf,
++				int sect)
++{
++	return (u8 *)buf + sect * nand->ecc.size;
++}
++
++static int mt7621_ecc_wait_idle(struct mt7621_nfc *nfc, u32 reg)
++{
++	struct device *dev = nfc->dev;
++	u32 val;
++	int ret;
++
++	ret = readw_poll_timeout_atomic(nfc->ecc_regs + reg, val,
++					val & ECC_IDLE, 10,
++					ECC_ENGINE_TIMEOUT);
++	if (ret) {
++		dev_warn(dev, "ECC engine timed out entering idle mode\n");
++		return -EIO;
++	}
++
++	return 0;
++}
++
++static int mt7621_ecc_decoder_wait_done(struct mt7621_nfc *nfc, u32 sect)
++{
++	struct device *dev = nfc->dev;
++	u32 val;
++	int ret;
++
++	ret = readw_poll_timeout_atomic(nfc->ecc_regs + ECC_DECDONE, val,
++					val & (1 << sect), 10,
++					ECC_ENGINE_TIMEOUT);
++
++	if (ret) {
++		dev_warn(dev, "ECC decoder for sector %d timed out\n",
++			 sect);
++		return -ETIMEDOUT;
++	}
++
++	return 0;
++}
++
++static void mt7621_ecc_encoder_op(struct mt7621_nfc *nfc, bool enable)
++{
++	mt7621_ecc_wait_idle(nfc, ECC_ENCIDLE);
++	ecc_write16(nfc, ECC_ENCCON, enable ? ENC_EN : 0);
++}
++
++static void mt7621_ecc_decoder_op(struct mt7621_nfc *nfc, bool enable)
++{
++	mt7621_ecc_wait_idle(nfc, ECC_DECIDLE);
++	ecc_write16(nfc, ECC_DECCON, enable ? DEC_EN : 0);
++}
++
++static int mt7621_ecc_correct_check(struct mt7621_nfc *nfc, u8 *sector_buf,
++				   u8 *fdm_buf, u32 sect)
++{
++	struct nand_chip *nand = &nfc->nand;
++	u32 decnum, num_error_bits, fdm_end_bits;
++	u32 error_locations, error_bit_loc;
++	u32 error_byte_pos, error_bit_pos;
++	int bitflips = 0;
++	u32 i;
++
++	decnum = ecc_read32(nfc, ECC_DECENUM);
++	num_error_bits = (decnum >> (sect << ERRNUM_S)) & ERRNUM_M;
++	fdm_end_bits = (nand->ecc.size + NFI_FDM_SIZE) << 3;
++
++	if (!num_error_bits)
++		return 0;
++
++	if (num_error_bits == ERRNUM_M)
++		return -1;
++
++	for (i = 0; i < num_error_bits; i++) {
++		error_locations = ecc_read32(nfc, ECC_DECEL(i / 2));
++		error_bit_loc = (error_locations >> ((i % 2) * DEC_EL_ODD_S)) &
++				DEC_EL_M;
++		error_byte_pos = error_bit_loc >> DEC_EL_BYTE_POS_S;
++		error_bit_pos = error_bit_loc & DEC_EL_BIT_POS_M;
++
++		if (error_bit_loc < (nand->ecc.size << 3)) {
++			if (sector_buf) {
++				sector_buf[error_byte_pos] ^=
++					(1 << error_bit_pos);
++			}
++		} else if (error_bit_loc < fdm_end_bits) {
++			if (fdm_buf) {
++				fdm_buf[error_byte_pos - nand->ecc.size] ^=
++					(1 << error_bit_pos);
++			}
++		}
++
++		bitflips++;
++	}
++
++	return bitflips;
++}
++
++static int mt7621_nfc_wait_write_completion(struct mt7621_nfc *nfc,
++					    struct nand_chip *nand)
++{
++	struct device *dev = nfc->dev;
++	u16 val;
++	int ret;
++
++	ret = readw_poll_timeout_atomic(nfc->nfi_regs + NFI_ADDRCNTR, val,
++		((val & SEC_CNTR_M) >> SEC_CNTR_S) >= nand->ecc.steps, 10,
++		NFI_CORE_TIMEOUT);
++
++	if (ret) {
++		dev_warn(dev, "NFI core write operation timed out\n");
++		return -ETIMEDOUT;
++	}
++
++	return ret;
++}
++
++static void mt7621_nfc_hw_reset(struct mt7621_nfc *nfc)
++{
++	u32 val;
++	int ret;
++
++	/* reset all registers and force the NFI master to terminate */
++	nfi_write16(nfc, NFI_CON, CON_FIFO_FLUSH | CON_NFI_RST);
++
++	/* wait for the master to finish the last transaction */
++	ret = readw_poll_timeout(nfc->nfi_regs + NFI_MASTER_STA, val,
++				 !(val & MASTER_STA_MASK), 50,
++				 NFI_RESET_TIMEOUT);
++	if (ret) {
++		dev_warn(nfc->dev, "Failed to reset NFI master in %dms\n",
++			 NFI_RESET_TIMEOUT);
++	}
++
++	/* ensure any status register affected by the NFI master is reset */
++	nfi_write16(nfc, NFI_CON, CON_FIFO_FLUSH | CON_NFI_RST);
++	nfi_write16(nfc, NFI_STRDATA, 0);
++}
++
++static inline void mt7621_nfc_hw_init(struct mt7621_nfc *nfc)
++{
++	u32 acccon;
++
++	/*
++	 * CNRNB: nand ready/busy register
++	 * -------------------------------
++	 * 7:4: timeout register for polling the NAND busy/ready signal
++	 * 0  : poll the status of the busy/ready signal after [7:4]*16 cycles.
++	 */
++	nfi_write16(nfc, NFI_CNRNB, CB2R_TIME_M | STR_CNRNB);
++
++	mt7621_nfc_hw_reset(nfc);
++
++	/* Apply default access timing */
++	acccon = ACCTIMING(ACCCON_POECS_DEF, ACCCON_PRECS_DEF, ACCCON_C2R_DEF,
++			   ACCCON_W2R_DEF, ACCCON_WH_DEF, ACCCON_WST_DEF,
++			   ACCCON_RLT_DEF);
++
++	nfi_write32(nfc, NFI_ACCCON, acccon);
++}
++
++static int mt7621_nfc_send_command(struct mt7621_nfc *nfc, u8 command)
++{
++	struct device *dev = nfc->dev;
++	u32 val;
++	int ret;
++
++	nfi_write32(nfc, NFI_CMD, command);
++
++	ret = readl_poll_timeout_atomic(nfc->nfi_regs + NFI_STA, val,
++					!(val & STA_CMD), 10,
++					NFI_CORE_TIMEOUT);
++	if (ret) {
++		dev_warn(dev, "NFI core timed out entering command mode\n");
++		return -EIO;
++	}
++
++	return 0;
++}
++
++static int mt7621_nfc_send_address_byte(struct mt7621_nfc *nfc, int addr)
++{
++	struct device *dev = nfc->dev;
++	u32 val;
++	int ret;
++
++	nfi_write32(nfc, NFI_COLADDR, addr);
++	nfi_write32(nfc, NFI_ROWADDR, 0);
++	nfi_write16(nfc, NFI_ADDRNOB, 1);
++
++	ret = readl_poll_timeout_atomic(nfc->nfi_regs + NFI_STA, val,
++					!(val & STA_ADDR), 10,
++					NFI_CORE_TIMEOUT);
++	if (ret) {
++		dev_warn(dev, "NFI core timed out entering address mode\n");
++		return -EIO;
++	}
++
++	return 0;
++}
++
++static int mt7621_nfc_send_address(struct mt7621_nfc *nfc, const u8 *addr,
++				   unsigned int naddrs)
++{
++	int ret;
++
++	while (naddrs) {
++		ret = mt7621_nfc_send_address_byte(nfc, *addr);
++		if (ret)
++			return ret;
++
++		addr++;
++		naddrs--;
++	}
++
++	return 0;
++}
++
++static void mt7621_nfc_wait_pio_ready(struct mt7621_nfc *nfc)
++{
++	struct device *dev = nfc->dev;
++	int ret;
++	u16 val;
++
++	ret = readw_poll_timeout_atomic(nfc->nfi_regs + NFI_PIO_DIRDY, val,
++					val & PIO_DIRDY, 10,
++					NFI_CORE_TIMEOUT);
++	if (ret < 0)
++		dev_err(dev, "NFI core PIO mode not ready\n");
++}
++
++static u32 mt7621_nfc_pio_read(struct mt7621_nfc *nfc, bool br)
++{
++	u32 reg;
++
++	/* after each byte read, the NFI_STA reg is reset by the hardware */
++	reg = (nfi_read32(nfc, NFI_STA) & STA_NFI_FSM_M) >> STA_NFI_FSM_S;
++	if (reg != STA_FSM_CUSTOM_DATA) {
++		reg = nfi_read16(nfc, NFI_CNFG);
++		reg |= CNFG_READ_MODE | CNFG_BYTE_RW;
++		if (!br)
++			reg &= ~CNFG_BYTE_RW;
++		nfi_write16(nfc, NFI_CNFG, reg);
++
++		/*
++		 * set to max sector to allow the HW to continue reading over
++		 * unaligned accesses
++		 */
++		nfi_write16(nfc, NFI_CON, CON_NFI_SEC_M | CON_NFI_BRD);
++
++		/* trigger to fetch data */
++		nfi_write16(nfc, NFI_STRDATA, STR_DATA);
++	}
++
++	mt7621_nfc_wait_pio_ready(nfc);
++
++	return nfi_read32(nfc, NFI_DATAR);
++}
++
++static void mt7621_nfc_read_data(struct mt7621_nfc *nfc, u8 *buf, u32 len)
++{
++	while (((uintptr_t)buf & 3) && len) {
++		*buf = mt7621_nfc_pio_read(nfc, true);
++		buf++;
++		len--;
++	}
++
++	while (len >= 4) {
++		*(u32 *)buf = mt7621_nfc_pio_read(nfc, false);
++		buf += 4;
++		len -= 4;
++	}
++
++	while (len) {
++		*buf = mt7621_nfc_pio_read(nfc, true);
++		buf++;
++		len--;
++	}
++}
++
++static void mt7621_nfc_read_data_discard(struct mt7621_nfc *nfc, u32 len)
++{
++	while (len >= 4) {
++		mt7621_nfc_pio_read(nfc, false);
++		len -= 4;
++	}
++
++	while (len) {
++		mt7621_nfc_pio_read(nfc, true);
++		len--;
++	}
++}
++
++static void mt7621_nfc_pio_write(struct mt7621_nfc *nfc, u32 val, bool bw)
++{
++	u32 reg;
++
++	reg = (nfi_read32(nfc, NFI_STA) & STA_NFI_FSM_M) >> STA_NFI_FSM_S;
++	if (reg != STA_FSM_CUSTOM_DATA) {
++		reg = nfi_read16(nfc, NFI_CNFG);
++		reg &= ~(CNFG_READ_MODE | CNFG_BYTE_RW);
++		if (bw)
++			reg |= CNFG_BYTE_RW;
++		nfi_write16(nfc, NFI_CNFG, reg);
++
++		nfi_write16(nfc, NFI_CON, CON_NFI_SEC_M | CON_NFI_BWR);
++		nfi_write16(nfc, NFI_STRDATA, STR_DATA);
++	}
++
++	mt7621_nfc_wait_pio_ready(nfc);
++	nfi_write32(nfc, NFI_DATAW, val);
++}
++
++static void mt7621_nfc_write_data(struct mt7621_nfc *nfc, const u8 *buf,
++				  u32 len)
++{
++	while (((uintptr_t)buf & 3) && len) {
++		mt7621_nfc_pio_write(nfc, *buf, true);
++		buf++;
++		len--;
++	}
++
++	while (len >= 4) {
++		mt7621_nfc_pio_write(nfc, *(const u32 *)buf, false);
++		buf += 4;
++		len -= 4;
++	}
++
++	while (len) {
++		mt7621_nfc_pio_write(nfc, *buf, true);
++		buf++;
++		len--;
++	}
++}
++
++static void mt7621_nfc_write_data_empty(struct mt7621_nfc *nfc, u32 len)
++{
++	while (len >= 4) {
++		mt7621_nfc_pio_write(nfc, 0xffffffff, false);
++		len -= 4;
++	}
++
++	while (len) {
++		mt7621_nfc_pio_write(nfc, 0xff, true);
++		len--;
++	}
++}
++
++static int mt7621_nfc_dev_ready(struct mt7621_nfc *nfc,
++				unsigned int timeout_ms)
++{
++	u32 val;
++
++	return readl_poll_timeout_atomic(nfc->nfi_regs + NFI_STA, val,
++					 !(val & STA_BUSY), 10,
++					 timeout_ms * 1000);
++}
++
++static int mt7621_nfc_exec_instr(struct nand_chip *nand,
++				 const struct nand_op_instr *instr)
++{
++	struct mt7621_nfc *nfc = nand_get_controller_data(nand);
++
++	switch (instr->type) {
++	case NAND_OP_CMD_INSTR:
++		mt7621_nfc_hw_reset(nfc);
++		nfi_write16(nfc, NFI_CNFG, CNFG_OP_CUSTOM << CNFG_OP_MODE_S);
++		return mt7621_nfc_send_command(nfc, instr->ctx.cmd.opcode);
++	case NAND_OP_ADDR_INSTR:
++		return mt7621_nfc_send_address(nfc, instr->ctx.addr.addrs,
++					       instr->ctx.addr.naddrs);
++	case NAND_OP_DATA_IN_INSTR:
++		mt7621_nfc_read_data(nfc, instr->ctx.data.buf.in,
++				     instr->ctx.data.len);
++		return 0;
++	case NAND_OP_DATA_OUT_INSTR:
++		mt7621_nfc_write_data(nfc, instr->ctx.data.buf.out,
++				      instr->ctx.data.len);
++		return 0;
++	case NAND_OP_WAITRDY_INSTR:
++		return mt7621_nfc_dev_ready(nfc,
++					    instr->ctx.waitrdy.timeout_ms);
++	default:
++		WARN_ONCE(1, "unsupported NAND instruction type: %d\n",
++			  instr->type);
++
++		return -EINVAL;
++	}
++}
++
++static int mt7621_nfc_exec_op(struct nand_chip *nand,
++			      const struct nand_operation *op, bool check_only)
++{
++	struct mt7621_nfc *nfc = nand_get_controller_data(nand);
++	int i, ret;
++
++	if (check_only)
++		return 0;
++
++	/* Only CS0 available */
++	nfi_write16(nfc, NFI_CSEL, 0);
++
++	for (i = 0; i < op->ninstrs; i++) {
++		ret = mt7621_nfc_exec_instr(nand, &op->instrs[i]);
++		if (ret)
++			return ret;
++	}
++
++	return 0;
++}
++
++static int mt7621_nfc_setup_interface(struct nand_chip *nand, int csline,
++				      const struct nand_interface_config *conf)
++{
++	struct mt7621_nfc *nfc = nand_get_controller_data(nand);
++	const struct nand_sdr_timings *timings;
++	u32 acccon, temp, rate, tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt;
++
++	if (!nfc->nfi_clk)
++		return -ENOTSUPP;
++
++	timings = nand_get_sdr_timings(conf);
++	if (IS_ERR(timings))
++		return -ENOTSUPP;
++
++	rate = clk_get_rate(nfc->nfi_clk);
++
++	/* turn clock rate into KHZ */
++	rate /= 1000;
++
++	tpoecs = max(timings->tALH_min, timings->tCLH_min) / 1000;
++	tpoecs = DIV_ROUND_UP(tpoecs * rate, 1000000);
++	tpoecs = min_t(u32, tpoecs, ACCCON_POECS_MAX);
++
++	tprecs = max(timings->tCLS_min, timings->tALS_min) / 1000;
++	tprecs = DIV_ROUND_UP(tprecs * rate, 1000000);
++	tprecs = min_t(u32, tprecs, ACCCON_PRECS_MAX);
++
++	/* sdr interface has no tCR which means CE# low to RE# low */
++	tc2r = 0;
++
++	tw2r = timings->tWHR_min / 1000;
++	tw2r = DIV_ROUND_UP(tw2r * rate, 1000000);
++	tw2r = DIV_ROUND_UP(tw2r - 1, 2);
++	tw2r = min_t(u32, tw2r, ACCCON_W2R_MAX);
++
++	twh = max(timings->tREH_min, timings->tWH_min) / 1000;
++	twh = DIV_ROUND_UP(twh * rate, 1000000) - 1;
++	twh = min_t(u32, twh, ACCCON_WH_MAX);
++
++	/* Calculate real WE#/RE# hold time in nanosecond */
++	temp = (twh + 1) * 1000000 / rate;
++	/* nanosecond to picosecond */
++	temp *= 1000;
++
++	/*
++	 * WE# low level time should be expaned to meet WE# pulse time
++	 * and WE# cycle time at the same time.
++	 */
++	if (temp < timings->tWC_min)
++		twst = timings->tWC_min - temp;
++	else
++		twst = 0;
++	twst = max(timings->tWP_min, twst) / 1000;
++	twst = DIV_ROUND_UP(twst * rate, 1000000) - 1;
++	twst = min_t(u32, twst, ACCCON_WST_MAX);
++
++	/*
++	 * RE# low level time should be expaned to meet RE# pulse time
++	 * and RE# cycle time at the same time.
++	 */
++	if (temp < timings->tRC_min)
++		trlt = timings->tRC_min - temp;
++	else
++		trlt = 0;
++	trlt = max(trlt, timings->tRP_min) / 1000;
++	trlt = DIV_ROUND_UP(trlt * rate, 1000000) - 1;
++	trlt = min_t(u32, trlt, ACCCON_RLT_MAX);
++
++	if (csline == NAND_DATA_IFACE_CHECK_ONLY) {
++		if (twst < ACCCON_WST_MIN || trlt < ACCCON_RLT_MIN)
++			return -ENOTSUPP;
++	}
++
++	acccon = ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt);
++
++	dev_info(nfc->dev, "Using programmed access timing: %08x\n", acccon);
++
++	nfi_write32(nfc, NFI_ACCCON, acccon);
++
++	return 0;
++}
++
++static int mt7621_nfc_calc_ecc_strength(struct mt7621_nfc *nfc,
++					u32 avail_ecc_bytes)
++{
++	struct nand_chip *nand = &nfc->nand;
++	struct mtd_info *mtd = nand_to_mtd(nand);
++	u32 strength;
++	int i;
++
++	strength = avail_ecc_bytes * 8 / ECC_PARITY_BITS;
++
++	/* Find the closest supported ecc strength */
++	for (i = ARRAY_SIZE(mt7621_ecc_strength) - 1; i >= 0; i--) {
++		if (mt7621_ecc_strength[i] <= strength)
++			break;
++	}
++
++	if (unlikely(i < 0)) {
++		dev_err(nfc->dev, "OOB size (%u) is not supported\n",
++			mtd->oobsize);
++		return -EINVAL;
++	}
++
++	nand->ecc.strength = mt7621_ecc_strength[i];
++	nand->ecc.bytes =
++		DIV_ROUND_UP(nand->ecc.strength * ECC_PARITY_BITS, 8);
++
++	dev_info(nfc->dev, "ECC strength adjusted to %u bits\n",
++		 nand->ecc.strength);
++
++	return i;
++}
++
++static int mt7621_nfc_set_spare_per_sector(struct mt7621_nfc *nfc)
++{
++	struct nand_chip *nand = &nfc->nand;
++	struct mtd_info *mtd = nand_to_mtd(nand);
++	u32 size;
++	int i;
++
++	size = nand->ecc.bytes + NFI_FDM_SIZE;
++
++	/* Find the closest supported spare size */
++	for (i = 0; i < ARRAY_SIZE(mt7621_nfi_spare_size); i++) {
++		if (mt7621_nfi_spare_size[i] >= size)
++			break;
++	}
++
++	if (unlikely(i >= ARRAY_SIZE(mt7621_nfi_spare_size))) {
++		dev_err(nfc->dev, "OOB size (%u) is not supported\n",
++			mtd->oobsize);
++		return -EINVAL;
++	}
++
++	nfc->spare_per_sector = mt7621_nfi_spare_size[i];
++
++	return i;
++}
++
++static int mt7621_nfc_ecc_init(struct mt7621_nfc *nfc)
++{
++	struct nand_chip *nand = &nfc->nand;
++	struct mtd_info *mtd = nand_to_mtd(nand);
++	u32 spare_per_sector, encode_block_size, decode_block_size;
++	u32 ecc_enccfg, ecc_deccfg;
++	int ecc_cap;
++
++	/* Only hardware ECC mode is supported */
++	if (nand->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST) {
++		dev_err(nfc->dev, "Only hardware ECC mode is supported\n");
++		return -EINVAL;
++	}
++
++	nand->ecc.size = ECC_SECTOR_SIZE;
++	nand->ecc.steps = mtd->writesize / nand->ecc.size;
++
++	spare_per_sector = mtd->oobsize / nand->ecc.steps;
++
++	ecc_cap = mt7621_nfc_calc_ecc_strength(nfc,
++		spare_per_sector - NFI_FDM_SIZE);
++	if (ecc_cap < 0)
++		return ecc_cap;
++
++	/* Sector + FDM */
++	encode_block_size = (nand->ecc.size + NFI_FDM_SIZE) * 8;
++	ecc_enccfg = ecc_cap | (ENC_MODE_NFI << ENC_MODE_S) |
++		     (encode_block_size << ENC_CNFG_MSG_S);
++
++	/* Sector + FDM + ECC parity bits */
++	decode_block_size = ((nand->ecc.size + NFI_FDM_SIZE) * 8) +
++			    nand->ecc.strength * ECC_PARITY_BITS;
++	ecc_deccfg = ecc_cap | (DEC_MODE_NFI << DEC_MODE_S) |
++		     (decode_block_size << DEC_CS_S) |
++		     (DEC_CON_EL << DEC_CON_S) | DEC_EMPTY_EN;
++
++	mt7621_ecc_encoder_op(nfc, false);
++	ecc_write32(nfc, ECC_ENCCNFG, ecc_enccfg);
++
++	mt7621_ecc_decoder_op(nfc, false);
++	ecc_write32(nfc, ECC_DECCNFG, ecc_deccfg);
++
++	return 0;
++}
++
++static int mt7621_nfc_set_page_format(struct mt7621_nfc *nfc)
++{
++	struct nand_chip *nand = &nfc->nand;
++	struct mtd_info *mtd = nand_to_mtd(nand);
++	int i, spare_size;
++	u32 pagefmt;
++
++	spare_size = mt7621_nfc_set_spare_per_sector(nfc);
++	if (spare_size < 0)
++		return spare_size;
++
++	for (i = 0; i < ARRAY_SIZE(mt7621_nfi_page_size); i++) {
++		if (mt7621_nfi_page_size[i] == mtd->writesize)
++			break;
++	}
++
++	if (unlikely(i >= ARRAY_SIZE(mt7621_nfi_page_size))) {
++		dev_err(nfc->dev, "Page size (%u) is not supported\n",
++			mtd->writesize);
++		return -EINVAL;
++	}
++
++	pagefmt = i | (spare_size << PAGEFMT_SPARE_S) |
++		  (NFI_FDM_SIZE << PAGEFMT_FDM_S) |
++		  (NFI_FDM_SIZE << PAGEFMT_FDM_ECC_S);
++
++	nfi_write16(nfc, NFI_PAGEFMT, pagefmt);
++
++	return 0;
++}
++
++static int mt7621_nfc_attach_chip(struct nand_chip *nand)
++{
++	struct mt7621_nfc *nfc = nand_get_controller_data(nand);
++	int ret;
++
++	if (nand->options & NAND_BUSWIDTH_16) {
++		dev_err(nfc->dev, "16-bit buswidth is not supported");
++		return -EINVAL;
++	}
++
++	ret = mt7621_nfc_ecc_init(nfc);
++	if (ret)
++		return ret;
++
++	return mt7621_nfc_set_page_format(nfc);
++}
++
++static const struct nand_controller_ops mt7621_nfc_controller_ops = {
++	.attach_chip = mt7621_nfc_attach_chip,
++	.exec_op = mt7621_nfc_exec_op,
++	.setup_interface = mt7621_nfc_setup_interface,
++};
++
++static int mt7621_nfc_ooblayout_free(struct mtd_info *mtd, int section,
++				     struct mtd_oob_region *oob_region)
++{
++	struct nand_chip *nand = mtd_to_nand(mtd);
++
++	if (section >= nand->ecc.steps)
++		return -ERANGE;
++
++	oob_region->length = NFI_FDM_SIZE - 1;
++	oob_region->offset = section * NFI_FDM_SIZE + 1;
++
++	return 0;
++}
++
++static int mt7621_nfc_ooblayout_ecc(struct mtd_info *mtd, int section,
++				    struct mtd_oob_region *oob_region)
++{
++	struct nand_chip *nand = mtd_to_nand(mtd);
++
++	if (section)
++		return -ERANGE;
++
++	oob_region->offset = NFI_FDM_SIZE * nand->ecc.steps;
++	oob_region->length = mtd->oobsize - oob_region->offset;
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops mt7621_nfc_ooblayout_ops = {
++	.free = mt7621_nfc_ooblayout_free,
++	.ecc = mt7621_nfc_ooblayout_ecc,
++};
++
++static void mt7621_nfc_write_fdm(struct mt7621_nfc *nfc)
++{
++	struct nand_chip *nand = &nfc->nand;
++	u32 vall, valm;
++	u8 *oobptr;
++	int i, j;
++
++	for (i = 0; i < nand->ecc.steps; i++) {
++		vall = 0;
++		valm = 0;
++		oobptr = oob_fdm_ptr(nand, i);
++
++		for (j = 0; j < 4; j++)
++			vall |= (u32)oobptr[j] << (j * 8);
++
++		for (j = 0; j < 4; j++)
++			valm |= (u32)oobptr[j + 4] << ((j - 4) * 8);
++
++		nfi_write32(nfc, NFI_FDML(i), vall);
++		nfi_write32(nfc, NFI_FDMM(i), valm);
++	}
++}
++
++static void mt7621_nfc_read_sector_fdm(struct mt7621_nfc *nfc, u32 sect)
++{
++	struct nand_chip *nand = &nfc->nand;
++	u32 vall, valm;
++	u8 *oobptr;
++	int i;
++
++	vall = nfi_read32(nfc, NFI_FDML(sect));
++	valm = nfi_read32(nfc, NFI_FDMM(sect));
++	oobptr = oob_fdm_ptr(nand, sect);
++
++	for (i = 0; i < 4; i++)
++		oobptr[i] = (vall >> (i * 8)) & 0xff;
++
++	for (i = 0; i < 4; i++)
++		oobptr[i + 4] = (valm >> (i * 8)) & 0xff;
++}
++
++static int mt7621_nfc_read_page_hwecc(struct nand_chip *nand, uint8_t *buf,
++				      int oob_required, int page)
++{
++	struct mt7621_nfc *nfc = nand_get_controller_data(nand);
++	struct mtd_info *mtd = nand_to_mtd(nand);
++	int bitflips = 0;
++	int rc, i;
++
++	nand_read_page_op(nand, page, 0, NULL, 0);
++
++	nfi_write16(nfc, NFI_CNFG, (CNFG_OP_CUSTOM << CNFG_OP_MODE_S) |
++		    CNFG_READ_MODE | CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
++
++	mt7621_ecc_decoder_op(nfc, true);
++
++	nfi_write16(nfc, NFI_CON,
++		    CON_NFI_BRD | (nand->ecc.steps << CON_NFI_SEC_S));
++
++	for (i = 0; i < nand->ecc.steps; i++) {
++		if (buf)
++			mt7621_nfc_read_data(nfc, page_data_ptr(nand, buf, i),
++					     nand->ecc.size);
++		else
++			mt7621_nfc_read_data_discard(nfc, nand->ecc.size);
++
++		rc = mt7621_ecc_decoder_wait_done(nfc, i);
++
++		mt7621_nfc_read_sector_fdm(nfc, i);
++
++		if (rc < 0) {
++			bitflips = -EIO;
++			continue;
++		}
++
++		rc = mt7621_ecc_correct_check(nfc,
++			buf ? page_data_ptr(nand, buf, i) : NULL,
++			oob_fdm_ptr(nand, i), i);
++
++		if (rc < 0) {
++			dev_warn(nfc->dev,
++				 "Uncorrectable ECC error at page %d.%d\n",
++				 page, i);
++			bitflips = -EBADMSG;
++			mtd->ecc_stats.failed++;
++		} else if (bitflips >= 0) {
++			bitflips += rc;
++			mtd->ecc_stats.corrected += rc;
++		}
++	}
++
++	mt7621_ecc_decoder_op(nfc, false);
++
++	nfi_write16(nfc, NFI_CON, 0);
++
++	return bitflips;
++}
++
++static int mt7621_nfc_read_page_raw(struct nand_chip *nand, uint8_t *buf,
++				    int oob_required, int page)
++{
++	struct mt7621_nfc *nfc = nand_get_controller_data(nand);
++	int i;
++
++	nand_read_page_op(nand, page, 0, NULL, 0);
++
++	nfi_write16(nfc, NFI_CNFG, (CNFG_OP_CUSTOM << CNFG_OP_MODE_S) |
++		    CNFG_READ_MODE);
++
++	nfi_write16(nfc, NFI_CON,
++		    CON_NFI_BRD | (nand->ecc.steps << CON_NFI_SEC_S));
++
++	for (i = 0; i < nand->ecc.steps; i++) {
++		/* Read data */
++		if (buf)
++			mt7621_nfc_read_data(nfc, page_data_ptr(nand, buf, i),
++					     nand->ecc.size);
++		else
++			mt7621_nfc_read_data_discard(nfc, nand->ecc.size);
++
++		/* Read FDM */
++		mt7621_nfc_read_data(nfc, oob_fdm_ptr(nand, i), NFI_FDM_SIZE);
++
++		/* Read ECC parity data */
++		mt7621_nfc_read_data(nfc, oob_ecc_ptr(nfc, i),
++				     nfc->spare_per_sector - NFI_FDM_SIZE);
++	}
++
++	nfi_write16(nfc, NFI_CON, 0);
++
++	return 0;
++}
++
++static int mt7621_nfc_read_oob_hwecc(struct nand_chip *nand, int page)
++{
++	return mt7621_nfc_read_page_hwecc(nand, NULL, 1, page);
++}
++
++static int mt7621_nfc_read_oob_raw(struct nand_chip *nand, int page)
++{
++	return mt7621_nfc_read_page_raw(nand, NULL, 1, page);
++}
++
++static int mt7621_nfc_check_empty_page(struct nand_chip *nand, const u8 *buf)
++{
++	struct mtd_info *mtd = nand_to_mtd(nand);
++	uint32_t i, j;
++	u8 *oobptr;
++
++	if (buf) {
++		for (i = 0; i < mtd->writesize; i++)
++			if (buf[i] != 0xff)
++				return 0;
++	}
++
++	for (i = 0; i < nand->ecc.steps; i++) {
++		oobptr = oob_fdm_ptr(nand, i);
++		for (j = 0; j < NFI_FDM_SIZE; j++)
++			if (oobptr[j] != 0xff)
++				return 0;
++	}
++
++	return 1;
++}
++
++static int mt7621_nfc_write_page_hwecc(struct nand_chip *nand,
++				       const uint8_t *buf, int oob_required,
++				       int page)
++{
++	struct mt7621_nfc *nfc = nand_get_controller_data(nand);
++	struct mtd_info *mtd = nand_to_mtd(nand);
++
++	if (mt7621_nfc_check_empty_page(nand, buf)) {
++		/*
++		 * MT7621 ECC engine always generates parity code for input
++		 * pages, even for empty pages. Doing so will write back ECC
++		 * parity code to the oob region, which means such pages will
++		 * no longer be empty pages.
++		 *
++		 * To avoid this, stop write operation if current page is an
++		 * empty page.
++		 */
++		return 0;
++	}
++
++	nand_prog_page_begin_op(nand, page, 0, NULL, 0);
++
++	nfi_write16(nfc, NFI_CNFG, (CNFG_OP_CUSTOM << CNFG_OP_MODE_S) |
++		   CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
++
++	mt7621_ecc_encoder_op(nfc, true);
++
++	mt7621_nfc_write_fdm(nfc);
++
++	nfi_write16(nfc, NFI_CON,
++		    CON_NFI_BWR | (nand->ecc.steps << CON_NFI_SEC_S));
++
++	if (buf)
++		mt7621_nfc_write_data(nfc, buf, mtd->writesize);
++	else
++		mt7621_nfc_write_data_empty(nfc, mtd->writesize);
++
++	mt7621_nfc_wait_write_completion(nfc, nand);
++
++	mt7621_ecc_encoder_op(nfc, false);
++
++	nfi_write16(nfc, NFI_CON, 0);
++
++	return nand_prog_page_end_op(nand);
++}
++
++static int mt7621_nfc_write_page_raw(struct nand_chip *nand,
++				     const uint8_t *buf, int oob_required,
++				     int page)
++{
++	struct mt7621_nfc *nfc = nand_get_controller_data(nand);
++	int i;
++
++	nand_prog_page_begin_op(nand, page, 0, NULL, 0);
++
++	nfi_write16(nfc, NFI_CNFG, (CNFG_OP_CUSTOM << CNFG_OP_MODE_S));
++
++	nfi_write16(nfc, NFI_CON,
++		    CON_NFI_BWR | (nand->ecc.steps << CON_NFI_SEC_S));
++
++	for (i = 0; i < nand->ecc.steps; i++) {
++		/* Write data */
++		if (buf)
++			mt7621_nfc_write_data(nfc, page_data_ptr(nand, buf, i),
++					      nand->ecc.size);
++		else
++			mt7621_nfc_write_data_empty(nfc, nand->ecc.size);
++
++		/* Write FDM */
++		mt7621_nfc_write_data(nfc, oob_fdm_ptr(nand, i),
++				      NFI_FDM_SIZE);
++
++		/* Write dummy ECC parity data */
++		mt7621_nfc_write_data_empty(nfc, nfc->spare_per_sector -
++					    NFI_FDM_SIZE);
++	}
++
++	mt7621_nfc_wait_write_completion(nfc, nand);
++
++	nfi_write16(nfc, NFI_CON, 0);
++
++	return nand_prog_page_end_op(nand);
++}
++
++static int mt7621_nfc_write_oob_hwecc(struct nand_chip *nand, int page)
++{
++	return mt7621_nfc_write_page_hwecc(nand, NULL, 1, page);
++}
++
++static int mt7621_nfc_write_oob_raw(struct nand_chip *nand, int page)
++{
++	return mt7621_nfc_write_page_raw(nand, NULL, 1, page);
++}
++
++static int mt7621_nfc_init_chip(struct mt7621_nfc *nfc)
++{
++	struct nand_chip *nand = &nfc->nand;
++	struct mtd_info *mtd;
++	int ret;
++
++	nand->controller = &nfc->controller;
++	nand_set_controller_data(nand, (void *)nfc);
++	nand_set_flash_node(nand, nfc->dev->of_node);
++
++	nand->options |= NAND_USES_DMA | NAND_NO_SUBPAGE_WRITE;
++	if (!nfc->nfi_clk)
++		nand->options |= NAND_KEEP_TIMINGS;
++
++	nand->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
++	nand->ecc.read_page = mt7621_nfc_read_page_hwecc;
++	nand->ecc.read_page_raw = mt7621_nfc_read_page_raw;
++	nand->ecc.write_page = mt7621_nfc_write_page_hwecc;
++	nand->ecc.write_page_raw = mt7621_nfc_write_page_raw;
++	nand->ecc.read_oob = mt7621_nfc_read_oob_hwecc;
++	nand->ecc.read_oob_raw = mt7621_nfc_read_oob_raw;
++	nand->ecc.write_oob = mt7621_nfc_write_oob_hwecc;
++	nand->ecc.write_oob_raw = mt7621_nfc_write_oob_raw;
++
++	mtd = nand_to_mtd(nand);
++	mtd->owner = THIS_MODULE;
++	mtd->dev.parent = nfc->dev;
++	mtd->name = MT7621_NFC_NAME;
++	mtd_set_ooblayout(mtd, &mt7621_nfc_ooblayout_ops);
++
++	mt7621_nfc_hw_init(nfc);
++
++	ret = nand_scan(nand, 1);
++	if (ret)
++		return ret;
++
++	ret = mtd_device_register(mtd, NULL, 0);
++	if (ret) {
++		dev_err(nfc->dev, "Failed to register MTD: %d\n", ret);
++		nand_cleanup(nand);
++		return ret;
++	}
++
++	return 0;
++}
++
++static int mt7621_nfc_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct mt7621_nfc *nfc;
++	struct resource *res;
++	int ret;
++
++	nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
++	if (!nfc)
++		return -ENOMEM;
++
++	nand_controller_init(&nfc->controller);
++	nfc->controller.ops = &mt7621_nfc_controller_ops;
++	nfc->dev = dev;
++
++	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nfi");
++	nfc->nfi_regs = devm_ioremap_resource(dev, res);
++	if (IS_ERR(nfc->nfi_regs)) {
++		ret = PTR_ERR(nfc->nfi_regs);
++		return ret;
++	}
++
++	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ecc");
++	nfc->ecc_regs = devm_ioremap_resource(dev, res);
++	if (IS_ERR(nfc->ecc_regs)) {
++		ret = PTR_ERR(nfc->ecc_regs);
++		return ret;
++	}
++
++	nfc->nfi_clk = devm_clk_get(dev, "nfi_clk");
++	if (IS_ERR(nfc->nfi_clk)) {
++		dev_warn(dev, "nfi clk not provided\n");
++		nfc->nfi_clk = NULL;
++	} else {
++		ret = clk_prepare_enable(nfc->nfi_clk);
++		if (ret) {
++			dev_err(dev, "Failed to enable nfi core clock\n");
++			return ret;
++		}
++	}
++
++	platform_set_drvdata(pdev, nfc);
++
++	ret = mt7621_nfc_init_chip(nfc);
++	if (ret) {
++		dev_err(dev, "Failed to initialize nand chip\n");
++		goto clk_disable;
++	}
++
++	return 0;
++
++clk_disable:
++	clk_disable_unprepare(nfc->nfi_clk);
++
++	return ret;
++}
++
++static int mt7621_nfc_remove(struct platform_device *pdev)
++{
++	struct mt7621_nfc *nfc = platform_get_drvdata(pdev);
++	struct nand_chip *nand = &nfc->nand;
++	struct mtd_info *mtd = nand_to_mtd(nand);
++
++	mtd_device_unregister(mtd);
++	nand_cleanup(nand);
++	clk_disable_unprepare(nfc->nfi_clk);
++
++	return 0;
++}
++
++static const struct of_device_id mt7621_nfc_id_table[] = {
++	{ .compatible = "mediatek,mt7621-nfc" },
++	{ },
++};
++MODULE_DEVICE_TABLE(of, match);
++
++static struct platform_driver mt7621_nfc_driver = {
++	.probe = mt7621_nfc_probe,
++	.remove = mt7621_nfc_remove,
++	.driver = {
++		.name = MT7621_NFC_NAME,
++		.owner = THIS_MODULE,
++		.of_match_table = mt7621_nfc_id_table,
++	},
++};
++module_platform_driver(mt7621_nfc_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Weijie Gao <weijie.gao at mediatek.com>");
++MODULE_DESCRIPTION("MediaTek MT7621 NAND Flash Controller driver");
diff --git a/target/linux/ramips/patches-5.10/411-dt-bindings-add-documentation-for-mt7621-nand-driver.patch b/target/linux/ramips/patches-5.10/411-dt-bindings-add-documentation-for-mt7621-nand-driver.patch
new file mode 100644
index 0000000000..3d122c10c0
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/411-dt-bindings-add-documentation-for-mt7621-nand-driver.patch
@@ -0,0 +1,85 @@
+From 3d5f4da8296b23eb3abf8b13122b0d06a215e79c Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao at mediatek.com>
+Date: Wed, 1 Apr 2020 02:07:59 +0800
+Subject: [PATCH 2/2] dt-bindings: add documentation for mt7621-nand driver
+
+This patch adds documentation for MediaTek MT7621 NAND flash controller
+driver.
+
+Signed-off-by: Weijie Gao <weijie.gao at mediatek.com>
+---
+ .../bindings/mtd/mediatek,mt7621-nfc.yaml          | 68 ++++++++++++++++++++++
+ 1 file changed, 68 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/mtd/mediatek,mt7621-nfc.yaml
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mtd/mediatek,mt7621-nfc.yaml
+@@ -0,0 +1,68 @@
++# SPDX-License-Identifier: GPL-2.0
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/mtd/mediatek,mt7621-nfc.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: MediaTek MT7621 SoC NAND Flash Controller (NFC) DT binding
++
++maintainers:
++  - Weijie Gao <weijie.gao at mediatek.com>
++
++description: |
++  This driver uses a single node to describe both NAND Flash controller
++  interface (NFI) and ECC engine for MT7621 SoC.
++  MT7621 supports only one chip select.
++
++properties:
++  "#address-cells": false
++  "#size-cells": false
++
++  compatible:
++    enum:
++      - mediatek,mt7621-nfc
++
++  reg:
++    items:
++      - description: Register base of NFI core
++      - description: Register base of ECC engine
++
++  reg-names:
++    items:
++      - const: nfi
++      - const: ecc
++
++  clocks:
++    items:
++      - description: Source clock for NFI core, fixed 125MHz
++
++  clock-names:
++    items:
++      - const: nfi_clk
++
++required:
++  - compatible
++  - reg
++  - reg-names
++  - clocks
++  - clock-names
++
++examples:
++  - |
++    nficlock: nficlock {
++    	#clock-cells = <0>;
++    	compatible = "fixed-clock";
++
++    	clock-frequency = <125000000>;
++    };
++
++    nand at 1e003000 {
++    	compatible = "mediatek,mt7621-nfc";
++
++    	reg = <0x1e003000 0x800
++    	       0x1e003800 0x800>;
++    	reg-names = "nfi", "ecc";
++
++    	clocks = <&nficlock>;
++    	clock-names = "nfi_clk";
++    };
diff --git a/target/linux/ramips/patches-5.10/420-spi-nor-add-gd25q512.patch b/target/linux/ramips/patches-5.10/420-spi-nor-add-gd25q512.patch
new file mode 100644
index 0000000000..6f41546964
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/420-spi-nor-add-gd25q512.patch
@@ -0,0 +1,12 @@
+--- a/drivers/mtd/spi-nor/gigadevice.c
++++ b/drivers/mtd/spi-nor/gigadevice.c
+@@ -53,6 +53,9 @@ static const struct flash_info gigadevic
+ 			   SPI_NOR_4B_OPCODES | SPI_NOR_HAS_LOCK |
+ 			   SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6)
+ 		.fixups = &gd25q256_fixups },
++	{ "gd25q512", INFO(0xc84020, 0, 64 * 1024, 1024,
++			   SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
++			   SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4B_OPCODES) },
+ };
+ 
+ const struct spi_nor_manufacturer spi_nor_gigadevice = {
diff --git a/target/linux/ramips/patches-5.10/700-net-ethernet-mediatek-support-net-labels.patch b/target/linux/ramips/patches-5.10/700-net-ethernet-mediatek-support-net-labels.patch
new file mode 100644
index 0000000000..ec3ca93770
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/700-net-ethernet-mediatek-support-net-labels.patch
@@ -0,0 +1,34 @@
+From bd0f89de5476ca25e73fae829ba3e1dafae1d90d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= <opensource at vdorst.com>
+Date: Fri, 21 Jun 2019 10:04:05 +0200
+Subject: [PATCH] net: ethernet: mediatek: support net-labels
+
+With this patch, device name can be set within dts file in the same way as dsa
+port can.
+Add: label = "wan"; to GMAC node.
+
+Signed-off-by: René van Dorst <opensource at vdorst.com>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -2901,6 +2901,7 @@ static const struct net_device_ops mtk_n
+ 
+ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
+ {
++	const char *name = of_get_property(np, "label", NULL);
+ 	const __be32 *_id = of_get_property(np, "reg", NULL);
+ 	phy_interface_t phy_mode;
+ 	struct phylink *phylink;
+@@ -2993,6 +2994,9 @@ static int mtk_add_mac(struct mtk_eth *e
+ 
+ 	eth->netdev[id]->max_mtu = MTK_MAX_RX_LENGTH - MTK_RX_ETH_HLEN;
+ 
++	if (name)
++		strlcpy(eth->netdev[id]->name, name, IFNAMSIZ);
++
+ 	return 0;
+ 
+ free_netdev:
diff --git a/target/linux/ramips/patches-5.10/710-at803x.patch b/target/linux/ramips/patches-5.10/710-at803x.patch
new file mode 100644
index 0000000000..2b0407d525
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/710-at803x.patch
@@ -0,0 +1,149 @@
+From 924453aa9d2324e5611f8e2b71df746d8f0c79f1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= <opensource at vdorst.com>
+Date: Fri, 13 Nov 2020 16:11:32 +0100
+Subject: [PATCH] net: phy: at803x: add support for SFP module in
+ RGMII-to-x-base mode
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: René van Dorst <opensource at vdorst.com>
+---
+ drivers/net/phy/at803x.c | 91 ++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 91 insertions(+)
+
+--- a/drivers/net/phy/at803x.c
++++ b/drivers/net/phy/at803x.c
+@@ -20,6 +20,8 @@
+ #include <linux/regulator/driver.h>
+ #include <linux/regulator/consumer.h>
+ #include <dt-bindings/net/qca-ar803x.h>
++#include <linux/sfp.h>
++#include <linux/phylink.h>
+ 
+ #define AT803X_SPECIFIC_FUNCTION_CONTROL	0x10
+ #define AT803X_SFC_ASSERT_CRS			BIT(11)
+@@ -83,9 +85,18 @@
+ 
+ #define AT803X_MODE_CFG_MASK			0x0F
+ #define AT803X_MODE_CFG_SGMII			0x01
++#define AT803X_MODE_CFG_BX1000_RGMII_50		0x02
++#define AT803X_MODE_CFG_BX1000_RGMII_75		0x03
++#define AT803X_MODE_FIBER			0x01
++#define AT803X_MODE_COPPER			0x00
+ 
+ #define AT803X_PSSR			0x11	/*PHY-Specific Status Register*/
+ #define AT803X_PSSR_MR_AN_COMPLETE	0x0200
++#define	 PSSR_LINK			BIT(10)
++#define	 PSSR_SYNC_STATUS		BIT(8)
++#define	 PSSR_DUPLEX			BIT(13)
++#define	 PSSR_SPEED_1000		BIT(15)
++#define	 PSSR_SPEED_100			BIT(14)
+ 
+ #define AT803X_DEBUG_REG_0			0x00
+ #define AT803X_DEBUG_RX_CLK_DLY_EN		BIT(15)
+@@ -505,10 +516,72 @@ static int at803x_parse_dt(struct phy_de
+ 	return 0;
+ }
+ 
++static int at803x_mode(struct phy_device *phydev)
++{
++	int mode;
++
++	mode = phy_read(phydev, AT803X_REG_CHIP_CONFIG) & AT803X_MODE_CFG_MASK;
++
++	if (mode == AT803X_MODE_CFG_BX1000_RGMII_50 ||
++	    mode == AT803X_MODE_CFG_BX1000_RGMII_75)
++		return AT803X_MODE_FIBER;
++	return AT803X_MODE_COPPER;
++}
++
++static int at803x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
++{
++	__ETHTOOL_DECLARE_LINK_MODE_MASK(at803x_support) = { 0, };
++	__ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
++	struct phy_device *phydev = upstream;
++	phy_interface_t iface;
++
++	phylink_set(at803x_support, 1000baseX_Full);
++	/* AT803x only support 1000baseX but SGMII works fine when module runs
++	 * at 1Gbit.
++	 */
++	phylink_set(at803x_support, 1000baseT_Full);
++
++	sfp_parse_support(phydev->sfp_bus, id, support);
++
++	// Limit to interfaces that both sides support
++	linkmode_and(support, support, at803x_support);
++
++	if (linkmode_empty(support))
++		goto unsupported_mode;
++
++	iface = sfp_select_interface(phydev->sfp_bus, support);
++
++	if (iface != PHY_INTERFACE_MODE_SGMII &&
++	    iface != PHY_INTERFACE_MODE_1000BASEX)
++		goto unsupported_mode;
++
++	dev_info(&phydev->mdio.dev, "SFP interface %s", phy_modes(iface));
++
++	return 0;
++
++unsupported_mode:
++	dev_info(&phydev->mdio.dev, "incompatible SFP module inserted;"
++		 "Only SGMII at 1Gbit/1000BASEX are supported!\n");
++	return -EINVAL;
++}
++
++static const struct sfp_upstream_ops at803x_sfp_ops = {
++	.attach = phy_sfp_attach,
++	.detach = phy_sfp_detach,
++	.module_insert = at803x_sfp_insert,
++};
++
+ static int at803x_probe(struct phy_device *phydev)
+ {
+ 	struct device *dev = &phydev->mdio.dev;
+ 	struct at803x_priv *priv;
++	int ret;
++
++	if (at803x_mode(phydev) == AT803X_MODE_FIBER) {
++		ret = phy_sfp_probe(phydev, &at803x_sfp_ops);
++		if (ret < 0)
++			return ret;
++	}
+ 
+ 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ 	if (!priv)
+@@ -709,6 +782,10 @@ static int at803x_read_status(struct phy
+ {
+ 	int ss, err, old_link = phydev->link;
+ 
++	/* Handle (Fiber) SGMII to RGMII mode */
++	if (at803x_mode(phydev) == AT803X_MODE_FIBER)
++		return genphy_c37_read_status(phydev);
++
+ 	/* Update the link, but return if there was an error */
+ 	err = genphy_update_link(phydev);
+ 	if (err)
+@@ -809,6 +886,12 @@ static int at803x_config_aneg(struct phy
+ {
+ 	int ret;
+ 
++	/* Handle (Fiber) SerDes to RGMII mode */
++	if (at803x_mode(phydev) == AT803X_MODE_FIBER) {
++		pr_warn("%s: fiber\n", __func__);
++		return genphy_c37_config_aneg(phydev);
++	}
++
+ 	ret = at803x_config_mdix(phydev, phydev->mdix_ctrl);
+ 	if (ret < 0)
+ 		return ret;
+@@ -1120,6 +1203,7 @@ static struct phy_driver at803x_driver[]
+ 	.suspend		= at803x_suspend,
+ 	.resume			= at803x_resume,
+ 	/* PHY_GBIT_FEATURES */
++	.config_aneg		= at803x_config_aneg,
+ 	.read_status		= at803x_read_status,
+ 	.aneg_done		= at803x_aneg_done,
+ 	.ack_interrupt		= &at803x_ack_interrupt,
diff --git a/target/linux/ramips/patches-5.10/720-Revert-net-phy-simplify-phy_link_change-arguments.patch b/target/linux/ramips/patches-5.10/720-Revert-net-phy-simplify-phy_link_change-arguments.patch
new file mode 100644
index 0000000000..c53b11ea31
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/720-Revert-net-phy-simplify-phy_link_change-arguments.patch
@@ -0,0 +1,118 @@
+From ffbb1b37a3e1ce1a5c574a6bd4f5aede8bc468ac Mon Sep 17 00:00:00 2001
+From: Ilya Lipnitskiy <ilya.lipnitskiy at gmail.com>
+Date: Sat, 27 Feb 2021 20:20:07 -0800
+Subject: [PATCH] Revert "net: phy: simplify phy_link_change arguments"
+
+This reverts commit a307593a644443db12888f45eed0dafb5869e2cc.
+
+This brings back the do_carrier flags used by the (hacky) next patch,
+still required by target/linux/ramips/files/drivers/net/ethernet/ralink/mdio.c
+---
+ drivers/net/phy/phy.c        | 12 ++++++------
+ drivers/net/phy/phy_device.c | 12 +++++++-----
+ drivers/net/phy/phylink.c    |  3 ++-
+ include/linux/phy.h          |  2 +-
+ 4 files changed, 16 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -58,13 +58,13 @@ static const char *phy_state_to_str(enum
+ 
+ static void phy_link_up(struct phy_device *phydev)
+ {
+-	phydev->phy_link_change(phydev, true);
++	phydev->phy_link_change(phydev, true, true);
+ 	phy_led_trigger_change_speed(phydev);
+ }
+ 
+-static void phy_link_down(struct phy_device *phydev)
++static void phy_link_down(struct phy_device *phydev, bool do_carrier)
+ {
+-	phydev->phy_link_change(phydev, false);
++	phydev->phy_link_change(phydev, false, do_carrier);
+ 	phy_led_trigger_change_speed(phydev);
+ }
+ 
+@@ -616,7 +616,7 @@ int phy_start_cable_test(struct phy_devi
+ 		goto out;
+ 
+ 	/* Mark the carrier down until the test is complete */
+-	phy_link_down(phydev);
++	phy_link_down(phydev, true);
+ 
+ 	netif_testing_on(dev);
+ 	err = phydev->drv->cable_test_start(phydev);
+@@ -687,7 +687,7 @@ int phy_start_cable_test_tdr(struct phy_
+ 		goto out;
+ 
+ 	/* Mark the carrier down until the test is complete */
+-	phy_link_down(phydev);
++	phy_link_down(phydev, true);
+ 
+ 	netif_testing_on(dev);
+ 	err = phydev->drv->cable_test_tdr_start(phydev, config);
+@@ -758,7 +758,7 @@ static int phy_check_link_status(struct
+ 		phy_link_up(phydev);
+ 	} else if (!phydev->link && phydev->state != PHY_NOLINK) {
+ 		phydev->state = PHY_NOLINK;
+-		phy_link_down(phydev);
++		phy_link_down(phydev, true);
+ 	}
+ 
+ 	return 0;
+@@ -1162,7 +1162,7 @@ void phy_state_machine(struct work_struc
+ 	case PHY_HALTED:
+ 		if (phydev->link) {
+ 			phydev->link = 0;
+-			phy_link_down(phydev);
++			phy_link_down(phydev, true);
+ 		}
+ 		do_suspend = true;
+ 		break;
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -937,14 +937,16 @@ struct phy_device *phy_find_first(struct
+ }
+ EXPORT_SYMBOL(phy_find_first);
+ 
+-static void phy_link_change(struct phy_device *phydev, bool up)
++static void phy_link_change(struct phy_device *phydev, bool up, bool do_carrier)
+ {
+ 	struct net_device *netdev = phydev->attached_dev;
+ 
+-	if (up)
+-		netif_carrier_on(netdev);
+-	else
+-		netif_carrier_off(netdev);
++	if (do_carrier) {
++		if (up)
++			netif_carrier_on(netdev);
++		else
++			netif_carrier_off(netdev);
++	}
+ 	phydev->adjust_link(netdev);
+ 	if (phydev->mii_ts && phydev->mii_ts->link_state)
+ 		phydev->mii_ts->link_state(phydev->mii_ts, phydev);
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -907,7 +907,8 @@ void phylink_destroy(struct phylink *pl)
+ }
+ EXPORT_SYMBOL_GPL(phylink_destroy);
+ 
+-static void phylink_phy_change(struct phy_device *phydev, bool up)
++static void phylink_phy_change(struct phy_device *phydev, bool up,
++			       bool do_carrier)
+ {
+ 	struct phylink *pl = phydev->phylink;
+ 	bool tx_pause, rx_pause;
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -636,7 +636,7 @@ struct phy_device {
+ 	u8 mdix;
+ 	u8 mdix_ctrl;
+ 
+-	void (*phy_link_change)(struct phy_device *phydev, bool up);
++	void (*phy_link_change)(struct phy_device *, bool up, bool do_carrier);
+ 	void (*adjust_link)(struct net_device *dev);
+ 
+ #if IS_ENABLED(CONFIG_MACSEC)
diff --git a/target/linux/ramips/patches-5.10/721-NET-no-auto-carrier-off-support.patch b/target/linux/ramips/patches-5.10/721-NET-no-auto-carrier-off-support.patch
new file mode 100644
index 0000000000..09170ab632
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/721-NET-no-auto-carrier-off-support.patch
@@ -0,0 +1,47 @@
+From 0b6eb1e68290243d439ee330ea8d0b239a5aec69 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic at openwrt.org>
+Date: Sun, 27 Jul 2014 09:38:50 +0100
+Subject: [PATCH 34/53] NET: multi phy support
+
+Signed-off-by: John Crispin <blogic at openwrt.org>
+---
+ drivers/net/phy/phy.c |    9 ++++++---
+ include/linux/phy.h   |    1 +
+ 2 files changed, 7 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -758,7 +758,10 @@ static int phy_check_link_status(struct
+ 		phy_link_up(phydev);
+ 	} else if (!phydev->link && phydev->state != PHY_NOLINK) {
+ 		phydev->state = PHY_NOLINK;
+-		phy_link_down(phydev, true);
++		if (!phydev->no_auto_carrier_off)
++			phy_link_down(phydev, true);
++		else
++			phy_link_down(phydev, false);
+ 	}
+ 
+ 	return 0;
+@@ -1162,7 +1165,10 @@ void phy_state_machine(struct work_struc
+ 	case PHY_HALTED:
+ 		if (phydev->link) {
+ 			phydev->link = 0;
+-			phy_link_down(phydev, true);
++			if (!phydev->no_auto_carrier_off)
++				phy_link_down(phydev, true);
++			else
++				phy_link_down(phydev, false);
+ 		}
+ 		do_suspend = true;
+ 		break;
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -556,6 +556,7 @@ struct phy_device {
+ 	unsigned sysfs_links:1;
+ 	unsigned loopback_enabled:1;
+ 	unsigned downshifted_rate:1;
++	unsigned no_auto_carrier_off:1;
+ 
+ 	unsigned autoneg:1;
+ 	/* The most recently read link state */
diff --git a/target/linux/ramips/patches-5.10/800-GPIO-add-named-gpio-exports.patch b/target/linux/ramips/patches-5.10/800-GPIO-add-named-gpio-exports.patch
new file mode 100644
index 0000000000..fe34f0b21b
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/800-GPIO-add-named-gpio-exports.patch
@@ -0,0 +1,165 @@
+From 4267880319bc1a2270d352e0ded6d6386242a7ef Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic at openwrt.org>
+Date: Tue, 12 Aug 2014 20:49:27 +0200
+Subject: [PATCH 24/53] GPIO: add named gpio exports
+
+Signed-off-by: John Crispin <blogic at openwrt.org>
+---
+ drivers/gpio/gpiolib-of.c     |   68 +++++++++++++++++++++++++++++++++++++++++
+ drivers/gpio/gpiolib-sysfs.c  |   10 +++++-
+ include/asm-generic/gpio.h    |    6 ++++
+ include/linux/gpio/consumer.h |    8 +++++
+ 4 files changed, 91 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpio/gpiolib-of.c
++++ b/drivers/gpio/gpiolib-of.c
+@@ -19,6 +19,8 @@
+ #include <linux/pinctrl/pinctrl.h>
+ #include <linux/slab.h>
+ #include <linux/gpio/machine.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
+ 
+ #include "gpiolib.h"
+ #include "gpiolib-of.h"
+@@ -1039,3 +1041,68 @@ void of_gpiochip_remove(struct gpio_chip
+ {
+ 	of_node_put(chip->of_node);
+ }
++
++static struct of_device_id gpio_export_ids[] = {
++	{ .compatible = "gpio-export" },
++	{ /* sentinel */ }
++};
++
++static int of_gpio_export_probe(struct platform_device *pdev)
++{
++	struct device_node *np = pdev->dev.of_node;
++	struct device_node *cnp;
++	u32 val;
++	int nb = 0;
++
++	for_each_child_of_node(np, cnp) {
++		const char *name = NULL;
++		int gpio;
++		bool dmc;
++		int max_gpio = 1;
++		int i;
++
++		of_property_read_string(cnp, "gpio-export,name", &name);
++
++		if (!name)
++			max_gpio = of_gpio_count(cnp);
++
++		for (i = 0; i < max_gpio; i++) {
++			unsigned flags = 0;
++			enum of_gpio_flags of_flags;
++
++			gpio = of_get_gpio_flags(cnp, i, &of_flags);
++			if (!gpio_is_valid(gpio))
++				return gpio;
++
++			if (of_flags == OF_GPIO_ACTIVE_LOW)
++				flags |= GPIOF_ACTIVE_LOW;
++
++			if (!of_property_read_u32(cnp, "gpio-export,output", &val))
++				flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
++			else
++				flags |= GPIOF_IN;
++
++			if (devm_gpio_request_one(&pdev->dev, gpio, flags, name ? name : of_node_full_name(np)))
++				continue;
++
++			dmc = of_property_read_bool(cnp, "gpio-export,direction_may_change");
++			gpio_export_with_name(gpio, dmc, name);
++			nb++;
++		}
++	}
++
++	dev_info(&pdev->dev, "%d gpio(s) exported\n", nb);
++
++	return 0;
++}
++
++static struct platform_driver gpio_export_driver = {
++	.driver		= {
++		.name		= "gpio-export",
++		.owner	= THIS_MODULE,
++		.of_match_table	= of_match_ptr(gpio_export_ids),
++	},
++	.probe		= of_gpio_export_probe,
++};
++
++module_platform_driver(gpio_export_driver);
+--- a/drivers/gpio/gpiolib-sysfs.c
++++ b/drivers/gpio/gpiolib-sysfs.c
+@@ -564,7 +564,7 @@ static struct class gpio_class = {
+  *
+  * Returns zero on success, else an error.
+  */
+-int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
++int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name)
+ {
+ 	struct gpio_chip	*chip;
+ 	struct gpio_device	*gdev;
+@@ -626,6 +626,8 @@ int gpiod_export(struct gpio_desc *desc,
+ 	offset = gpio_chip_hwgpio(desc);
+ 	if (chip->names && chip->names[offset])
+ 		ioname = chip->names[offset];
++	if (name)
++		ioname = name;
+ 
+ 	dev = device_create_with_groups(&gpio_class, &gdev->dev,
+ 					MKDEV(0, 0), data, gpio_groups,
+@@ -647,6 +649,12 @@ err_unlock:
+ 	gpiod_dbg(desc, "%s: status %d\n", __func__, status);
+ 	return status;
+ }
++EXPORT_SYMBOL_GPL(__gpiod_export);
++
++int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
++{
++	return __gpiod_export(desc, direction_may_change, NULL);
++}
+ EXPORT_SYMBOL_GPL(gpiod_export);
+ 
+ static int match_export(struct device *dev, const void *desc)
+--- a/include/asm-generic/gpio.h
++++ b/include/asm-generic/gpio.h
+@@ -125,6 +125,12 @@ static inline int gpio_export(unsigned g
+ 	return gpiod_export(gpio_to_desc(gpio), direction_may_change);
+ }
+ 
++int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
++static inline int gpio_export_with_name(unsigned gpio, bool direction_may_change, const char *name)
++{
++	return __gpiod_export(gpio_to_desc(gpio), direction_may_change, name);
++}
++
+ static inline int gpio_export_link(struct device *dev, const char *name,
+ 				   unsigned gpio)
+ {
+--- a/include/linux/gpio/consumer.h
++++ b/include/linux/gpio/consumer.h
+@@ -713,6 +713,7 @@ static inline void devm_acpi_dev_remove_
+ 
+ #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS)
+ 
++int _gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
+ int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
+ int gpiod_export_link(struct device *dev, const char *name,
+ 		      struct gpio_desc *desc);
+@@ -720,6 +721,13 @@ void gpiod_unexport(struct gpio_desc *de
+ 
+ #else  /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */
+ 
++static inline int _gpiod_export(struct gpio_desc *desc,
++			       bool direction_may_change,
++			       const char *name)
++{
++	return -ENOSYS;
++}
++
+ static inline int gpiod_export(struct gpio_desc *desc,
+ 			       bool direction_may_change)
+ {
diff --git a/target/linux/ramips/patches-5.10/801-DT-Add-documentation-for-gpio-ralink.patch b/target/linux/ramips/patches-5.10/801-DT-Add-documentation-for-gpio-ralink.patch
new file mode 100644
index 0000000000..7d5f98f647
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/801-DT-Add-documentation-for-gpio-ralink.patch
@@ -0,0 +1,59 @@
+From d410e5478c622c01fcf31427533df5f433df9146 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic at openwrt.org>
+Date: Sun, 28 Jul 2013 19:45:30 +0200
+Subject: [PATCH 26/53] DT: Add documentation for gpio-ralink
+
+Describe gpio-ralink binding.
+
+Signed-off-by: John Crispin <blogic at openwrt.org>
+Cc: linux-mips at linux-mips.org
+Cc: devicetree at vger.kernel.org
+Cc: linux-gpio at vger.kernel.org
+---
+ .../devicetree/bindings/gpio/gpio-ralink.txt       |   40 ++++++++++++++++++++
+ 1 file changed, 40 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/gpio/gpio-ralink.txt
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/gpio/gpio-ralink.txt
+@@ -0,0 +1,40 @@
++Ralink SoC GPIO controller bindings
++
++Required properties:
++- compatible:
++  - "ralink,rt2880-gpio" for Ralink controllers
++- #gpio-cells : Should be two.
++  - first cell is the pin number
++  - second cell is used to specify optional parameters (unused)
++- gpio-controller : Marks the device node as a GPIO controller
++- reg : Physical base address and length of the controller's registers
++- interrupt-parent: phandle to the INTC device node
++- interrupts : Specify the INTC interrupt number
++- ralink,num-gpios : Specify the number of GPIOs
++- ralink,register-map : The register layout depends on the GPIO bank and actual
++		SoC type. Register offsets need to be in this order.
++		[ INT, EDGE, RENA, FENA, DATA, DIR, POL, SET, RESET, TOGGLE ]
++
++Optional properties:
++- ralink,gpio-base : Specify the GPIO chips base number
++
++Example:
++
++	gpio0: gpio at 600 {
++		compatible = "ralink,rt5350-gpio", "ralink,rt2880-gpio";
++
++		#gpio-cells = <2>;
++		gpio-controller;
++
++		reg = <0x600 0x34>;
++
++		interrupt-parent = <&intc>;
++		interrupts = <6>;
++
++		ralink,gpio-base = <0>;
++		ralink,num-gpios = <24>;
++		ralink,register-map = [ 00 04 08 0c
++				20 24 28 2c
++				30 34 ];
++
++	};
diff --git a/target/linux/ramips/patches-5.10/802-GPIO-MIPS-ralink-add-gpio-driver-for-ralink-SoC.patch b/target/linux/ramips/patches-5.10/802-GPIO-MIPS-ralink-add-gpio-driver-for-ralink-SoC.patch
new file mode 100644
index 0000000000..141d29f940
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/802-GPIO-MIPS-ralink-add-gpio-driver-for-ralink-SoC.patch
@@ -0,0 +1,416 @@
+From 69fdd2c4f937796b934e89c33acde9d082e27bfd Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic at openwrt.org>
+Date: Mon, 4 Aug 2014 20:36:29 +0200
+Subject: [PATCH 27/53] GPIO: MIPS: ralink: add gpio driver for ralink SoC
+
+Add gpio driver for Ralink SoC. This driver makes the gpio core on
+RT2880, RT305x, rt3352, rt3662, rt3883, rt5350 and mt7620 work.
+
+Signed-off-by: John Crispin <blogic at openwrt.org>
+Cc: linux-mips at linux-mips.org
+Cc: linux-gpio at vger.kernel.org
+---
+ arch/mips/include/asm/mach-ralink/gpio.h |   24 ++
+ drivers/gpio/Kconfig                     |    6 +
+ drivers/gpio/Makefile                    |    1 +
+ drivers/gpio/gpio-ralink.c               |  355 ++++++++++++++++++++++++++++++
+ 4 files changed, 386 insertions(+)
+ create mode 100644 arch/mips/include/asm/mach-ralink/gpio.h
+ create mode 100644 drivers/gpio/gpio-ralink.c
+
+--- /dev/null
++++ b/arch/mips/include/asm/mach-ralink/gpio.h
+@@ -0,0 +1,24 @@
++/*
++ *  Ralink SoC GPIO API support
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg at openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz at 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 __ASM_MACH_RALINK_GPIO_H
++#define __ASM_MACH_RALINK_GPIO_H
++
++#define ARCH_NR_GPIOS	128
++#include <asm-generic/gpio.h>
++
++#define gpio_get_value	__gpio_get_value
++#define gpio_set_value	__gpio_set_value
++#define gpio_cansleep	__gpio_cansleep
++#define gpio_to_irq	__gpio_to_irq
++
++#endif /* __ASM_MACH_RALINK_GPIO_H */
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -535,6 +535,12 @@ config GPIO_SNPS_CREG
+ 	  where only several fields in register belong to GPIO lines and
+ 	  each GPIO line owns a field with different length and on/off value.
+ 
++config GPIO_RALINK
++	bool "Ralink GPIO Support"
++	depends on RALINK
++	help
++	  Say yes here to support the Ralink SoC GPIO device
++
+ config GPIO_SPEAR_SPICS
+ 	bool "ST SPEAr13xx SPI Chip Select as GPIO support"
+ 	depends on PLAT_SPEAR
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -119,6 +119,7 @@ obj-$(CONFIG_GPIO_PISOSR)		+= gpio-pisos
+ obj-$(CONFIG_GPIO_PL061)		+= gpio-pl061.o
+ obj-$(CONFIG_GPIO_PMIC_EIC_SPRD)	+= gpio-pmic-eic-sprd.o
+ obj-$(CONFIG_GPIO_PXA)			+= gpio-pxa.o
++obj-$(CONFIG_GPIO_RALINK)		+= gpio-ralink.o
+ obj-$(CONFIG_GPIO_RASPBERRYPI_EXP)	+= gpio-raspberrypi-exp.o
+ obj-$(CONFIG_GPIO_RC5T583)		+= gpio-rc5t583.o
+ obj-$(CONFIG_GPIO_RCAR)			+= gpio-rcar.o
+--- /dev/null
++++ b/drivers/gpio/gpio-ralink.c
+@@ -0,0 +1,341 @@
++/*
++ * 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.
++ *
++ * Copyright (C) 2009-2011 Gabor Juhos <juhosg at openwrt.org>
++ * Copyright (C) 2013 John Crispin <blogic at openwrt.org>
++ */
++
++#include <linux/module.h>
++#include <linux/io.h>
++#include <linux/gpio.h>
++#include <linux/spinlock.h>
++#include <linux/platform_device.h>
++#include <linux/of_irq.h>
++#include <linux/irqdomain.h>
++#include <linux/interrupt.h>
++
++enum ralink_gpio_reg {
++	GPIO_REG_INT = 0,
++	GPIO_REG_EDGE,
++	GPIO_REG_RENA,
++	GPIO_REG_FENA,
++	GPIO_REG_DATA,
++	GPIO_REG_DIR,
++	GPIO_REG_POL,
++	GPIO_REG_SET,
++	GPIO_REG_RESET,
++	GPIO_REG_TOGGLE,
++	GPIO_REG_MAX
++};
++
++struct ralink_gpio_chip {
++	struct gpio_chip chip;
++	u8 regs[GPIO_REG_MAX];
++
++	spinlock_t lock;
++	void __iomem *membase;
++	struct irq_domain *domain;
++	int irq;
++
++	u32 rising;
++	u32 falling;
++};
++
++#define MAP_MAX	4
++static struct irq_domain *irq_map[MAP_MAX];
++static int irq_map_count;
++static atomic_t irq_refcount = ATOMIC_INIT(0);
++
++static inline struct ralink_gpio_chip *to_ralink_gpio(struct gpio_chip *chip)
++{
++	struct ralink_gpio_chip *rg;
++
++	rg = container_of(chip, struct ralink_gpio_chip, chip);
++
++	return rg;
++}
++
++static inline void rt_gpio_w32(struct ralink_gpio_chip *rg, u8 reg, u32 val)
++{
++	iowrite32(val, rg->membase + rg->regs[reg]);
++}
++
++static inline u32 rt_gpio_r32(struct ralink_gpio_chip *rg, u8 reg)
++{
++	return ioread32(rg->membase + rg->regs[reg]);
++}
++
++static void ralink_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
++{
++	struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
++
++	rt_gpio_w32(rg, (value) ? GPIO_REG_SET : GPIO_REG_RESET, BIT(offset));
++}
++
++static int ralink_gpio_get(struct gpio_chip *chip, unsigned offset)
++{
++	struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
++
++	return !!(rt_gpio_r32(rg, GPIO_REG_DATA) & BIT(offset));
++}
++
++static int ralink_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
++{
++	struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
++	unsigned long flags;
++	u32 t;
++
++	spin_lock_irqsave(&rg->lock, flags);
++	t = rt_gpio_r32(rg, GPIO_REG_DIR);
++	t &= ~BIT(offset);
++	rt_gpio_w32(rg, GPIO_REG_DIR, t);
++	spin_unlock_irqrestore(&rg->lock, flags);
++
++	return 0;
++}
++
++static int ralink_gpio_direction_output(struct gpio_chip *chip,
++					unsigned offset, int value)
++{
++	struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
++	unsigned long flags;
++	u32 t;
++
++	spin_lock_irqsave(&rg->lock, flags);
++	ralink_gpio_set(chip, offset, value);
++	t = rt_gpio_r32(rg, GPIO_REG_DIR);
++	t |= BIT(offset);
++	rt_gpio_w32(rg, GPIO_REG_DIR, t);
++	spin_unlock_irqrestore(&rg->lock, flags);
++
++	return 0;
++}
++
++static int ralink_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
++{
++	struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
++
++	if (rg->irq < 1)
++		return -1;
++
++	return irq_create_mapping(rg->domain, pin);
++}
++
++static void ralink_gpio_irq_handler(struct irq_desc *desc)
++{
++	int i;
++
++	for (i = 0; i < irq_map_count; i++) {
++		struct irq_domain *domain = irq_map[i];
++		struct ralink_gpio_chip *rg;
++		unsigned long pending;
++		int bit;
++
++		rg = (struct ralink_gpio_chip *) domain->host_data;
++		pending = rt_gpio_r32(rg, GPIO_REG_INT);
++
++		for_each_set_bit(bit, &pending, rg->chip.ngpio) {
++			u32 map = irq_find_mapping(domain, bit);
++			generic_handle_irq(map);
++			rt_gpio_w32(rg, GPIO_REG_INT, BIT(bit));
++		}
++	}
++}
++
++static void ralink_gpio_irq_unmask(struct irq_data *d)
++{
++	struct ralink_gpio_chip *rg;
++	unsigned long flags;
++	u32 rise, fall;
++
++	rg = (struct ralink_gpio_chip *) d->domain->host_data;
++	rise = rt_gpio_r32(rg, GPIO_REG_RENA);
++	fall = rt_gpio_r32(rg, GPIO_REG_FENA);
++
++	spin_lock_irqsave(&rg->lock, flags);
++	rt_gpio_w32(rg, GPIO_REG_RENA, rise | (BIT(d->hwirq) & rg->rising));
++	rt_gpio_w32(rg, GPIO_REG_FENA, fall | (BIT(d->hwirq) & rg->falling));
++	spin_unlock_irqrestore(&rg->lock, flags);
++}
++
++static void ralink_gpio_irq_mask(struct irq_data *d)
++{
++	struct ralink_gpio_chip *rg;
++	unsigned long flags;
++	u32 rise, fall;
++
++	rg = (struct ralink_gpio_chip *) d->domain->host_data;
++	rise = rt_gpio_r32(rg, GPIO_REG_RENA);
++	fall = rt_gpio_r32(rg, GPIO_REG_FENA);
++
++	spin_lock_irqsave(&rg->lock, flags);
++	rt_gpio_w32(rg, GPIO_REG_FENA, fall & ~BIT(d->hwirq));
++	rt_gpio_w32(rg, GPIO_REG_RENA, rise & ~BIT(d->hwirq));
++	spin_unlock_irqrestore(&rg->lock, flags);
++}
++
++static int ralink_gpio_irq_type(struct irq_data *d, unsigned int type)
++{
++	struct ralink_gpio_chip *rg;
++	u32 mask = BIT(d->hwirq);
++
++	rg = (struct ralink_gpio_chip *) d->domain->host_data;
++
++	if (type == IRQ_TYPE_PROBE) {
++		if ((rg->rising | rg->falling) & mask)
++			return 0;
++
++		type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
++	}
++
++	if (type & IRQ_TYPE_EDGE_RISING)
++		rg->rising |= mask;
++	else
++		rg->rising &= ~mask;
++
++	if (type & IRQ_TYPE_EDGE_FALLING)
++		rg->falling |= mask;
++	else
++		rg->falling &= ~mask;
++
++	return 0;
++}
++
++static struct irq_chip ralink_gpio_irq_chip = {
++	.name		= "GPIO",
++	.irq_unmask	= ralink_gpio_irq_unmask,
++	.irq_mask	= ralink_gpio_irq_mask,
++	.irq_mask_ack	= ralink_gpio_irq_mask,
++	.irq_set_type	= ralink_gpio_irq_type,
++};
++
++static int gpio_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
++{
++	irq_set_chip_and_handler(irq, &ralink_gpio_irq_chip, handle_level_irq);
++	irq_set_handler_data(irq, d);
++
++	return 0;
++}
++
++static const struct irq_domain_ops irq_domain_ops = {
++	.xlate = irq_domain_xlate_onecell,
++	.map = gpio_map,
++};
++
++static void ralink_gpio_irq_init(struct device_node *np,
++				 struct ralink_gpio_chip *rg)
++{
++	if (irq_map_count >= MAP_MAX)
++		return;
++
++	rg->irq = irq_of_parse_and_map(np, 0);
++	if (!rg->irq)
++		return;
++
++	rg->domain = irq_domain_add_linear(np, rg->chip.ngpio,
++					   &irq_domain_ops, rg);
++	if (!rg->domain) {
++		dev_err(rg->chip.parent, "irq_domain_add_linear failed\n");
++		return;
++	}
++
++	irq_map[irq_map_count++] = rg->domain;
++
++	rt_gpio_w32(rg, GPIO_REG_RENA, 0x0);
++	rt_gpio_w32(rg, GPIO_REG_FENA, 0x0);
++
++	if (!atomic_read(&irq_refcount))
++		irq_set_chained_handler(rg->irq, ralink_gpio_irq_handler);
++	atomic_inc(&irq_refcount);
++
++	dev_info(rg->chip.parent, "registering %d irq handlers\n", rg->chip.ngpio);
++}
++
++static int ralink_gpio_probe(struct platform_device *pdev)
++{
++	struct device_node *np = pdev->dev.of_node;
++	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	struct ralink_gpio_chip *rg;
++	const __be32 *ngpio, *gpiobase;
++
++	if (!res) {
++		dev_err(&pdev->dev, "failed to find resource\n");
++		return -ENOMEM;
++	}
++
++	rg = devm_kzalloc(&pdev->dev,
++			sizeof(struct ralink_gpio_chip), GFP_KERNEL);
++	if (!rg)
++		return -ENOMEM;
++
++	rg->membase = devm_ioremap_resource(&pdev->dev, res);
++	if (!rg->membase) {
++		dev_err(&pdev->dev, "cannot remap I/O memory region\n");
++		return -ENOMEM;
++	}
++
++	if (of_property_read_u8_array(np, "ralink,register-map",
++			rg->regs, GPIO_REG_MAX)) {
++		dev_err(&pdev->dev, "failed to read register definition\n");
++		return -EINVAL;
++	}
++
++	ngpio = of_get_property(np, "ralink,num-gpios", NULL);
++	if (!ngpio) {
++		dev_err(&pdev->dev, "failed to read number of pins\n");
++		return -EINVAL;
++	}
++
++	gpiobase = of_get_property(np, "ralink,gpio-base", NULL);
++	if (gpiobase)
++		rg->chip.base = be32_to_cpu(*gpiobase);
++	else
++		rg->chip.base = -1;
++
++	spin_lock_init(&rg->lock);
++
++	rg->chip.parent = &pdev->dev;
++	rg->chip.label = dev_name(&pdev->dev);
++	rg->chip.of_node = np;
++	rg->chip.ngpio = be32_to_cpu(*ngpio);
++	rg->chip.direction_input = ralink_gpio_direction_input;
++	rg->chip.direction_output = ralink_gpio_direction_output;
++	rg->chip.get = ralink_gpio_get;
++	rg->chip.set = ralink_gpio_set;
++	rg->chip.request = gpiochip_generic_request;
++	rg->chip.to_irq = ralink_gpio_to_irq;
++	rg->chip.free = gpiochip_generic_free;
++
++	/* set polarity to low for all lines */
++	rt_gpio_w32(rg, GPIO_REG_POL, 0);
++
++	dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio);
++
++	ralink_gpio_irq_init(np, rg);
++
++	return gpiochip_add(&rg->chip);
++}
++
++static const struct of_device_id ralink_gpio_match[] = {
++	{ .compatible = "ralink,rt2880-gpio" },
++	{},
++};
++MODULE_DEVICE_TABLE(of, ralink_gpio_match);
++
++static struct platform_driver ralink_gpio_driver = {
++	.probe = ralink_gpio_probe,
++	.driver = {
++		.name = "rt2880_gpio",
++		.owner = THIS_MODULE,
++		.of_match_table = ralink_gpio_match,
++	},
++};
++
++static int __init ralink_gpio_init(void)
++{
++	return platform_driver_register(&ralink_gpio_driver);
++}
++
++subsys_initcall(ralink_gpio_init);
diff --git a/target/linux/ramips/patches-5.10/803-gpio-ralink-Add-support-for-GPIO-as-interrupt-contro.patch b/target/linux/ramips/patches-5.10/803-gpio-ralink-Add-support-for-GPIO-as-interrupt-contro.patch
new file mode 100644
index 0000000000..8520ce32ff
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/803-gpio-ralink-Add-support-for-GPIO-as-interrupt-contro.patch
@@ -0,0 +1,44 @@
+From 57fa7f2f4ef6f78ce1d30509c0d111aa3791b524 Mon Sep 17 00:00:00 2001
+From: Daniel Santos <daniel.santos at pobox.com>
+Date: Sun, 4 Nov 2018 20:24:32 -0600
+Subject: gpio-ralink: Add support for GPIO as interrupt-controller
+
+Signed-off-by: Daniel Santos <daniel.santos at pobox.com>
+---
+ Documentation/devicetree/bindings/gpio/gpio-ralink.txt | 6 ++++++
+ drivers/gpio/gpio-ralink.c                             | 2 +-
+ 2 files changed, 7 insertions(+), 1 deletion(-)
+
+--- a/Documentation/devicetree/bindings/gpio/gpio-ralink.txt
++++ b/Documentation/devicetree/bindings/gpio/gpio-ralink.txt
+@@ -17,6 +17,9 @@ Required properties:
+ 
+ Optional properties:
+ - ralink,gpio-base : Specify the GPIO chips base number
++- interrupt-controller : marks this as an interrupt controller
++- #interrupt-cells : a standard two-cell interrupt flag, see
++  interrupt-controller/interrupts.txt
+ 
+ Example:
+ 
+@@ -28,6 +31,9 @@ Example:
+ 
+ 		reg = <0x600 0x34>;
+ 
++		interrupt-controller;
++		#interrupt-cells = <2>;
++
+ 		interrupt-parent = <&intc>;
+ 		interrupts = <6>;
+ 
+--- a/drivers/gpio/gpio-ralink.c
++++ b/drivers/gpio/gpio-ralink.c
+@@ -220,7 +220,7 @@ static int gpio_map(struct irq_domain *d
+ }
+ 
+ static const struct irq_domain_ops irq_domain_ops = {
+-	.xlate = irq_domain_xlate_onecell,
++	.xlate = irq_domain_xlate_twocell,
+ 	.map = gpio_map,
+ };
+ 
diff --git a/target/linux/ramips/patches-5.10/810-uvc-add-iPassion-iP2970-support.patch b/target/linux/ramips/patches-5.10/810-uvc-add-iPassion-iP2970-support.patch
new file mode 100644
index 0000000000..410f369f70
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/810-uvc-add-iPassion-iP2970-support.patch
@@ -0,0 +1,246 @@
+From 975e76214cd2516eb6cfff4c3eec581872645e88 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic at openwrt.org>
+Date: Thu, 19 Sep 2013 01:50:59 +0200
+Subject: [PATCH 31/53] uvc: add iPassion iP2970 support
+
+Signed-off-by: John Crispin <blogic at openwrt.org>
+---
+ drivers/media/usb/uvc/uvc_driver.c |   12 +++
+ drivers/media/usb/uvc/uvc_status.c |    2 +
+ drivers/media/usb/uvc/uvc_video.c  |  147 ++++++++++++++++++++++++++++++++++++
+ drivers/media/usb/uvc/uvcvideo.h   |    5 +-
+ 4 files changed, 165 insertions(+), 1 deletion(-)
+
+--- a/drivers/media/usb/uvc/uvc_driver.c
++++ b/drivers/media/usb/uvc/uvc_driver.c
+@@ -2969,6 +2969,18 @@ static const struct usb_device_id uvc_id
+ 	  .bInterfaceSubClass	= 1,
+ 	  .bInterfaceProtocol	= 0,
+ 	  .driver_info		= UVC_INFO_META(V4L2_META_FMT_D4XX) },
++	/* iPassion iP2970 */
++	{ .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
++				| USB_DEVICE_ID_MATCH_INT_INFO,
++	 .idVendor		= 0x1B3B,
++	 .idProduct		= 0x2970,
++	 .bInterfaceClass	= USB_CLASS_VIDEO,
++	 .bInterfaceSubClass	= 1,
++	 .bInterfaceProtocol	= 0,
++	 .driver_info		= UVC_QUIRK_PROBE_MINMAX
++				| UVC_QUIRK_STREAM_NO_FID
++				| UVC_QUIRK_MOTION
++				| UVC_QUIRK_SINGLE_ISO },
+ 	/* Generic USB Video Class */
+ 	{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_UNDEFINED) },
+ 	{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_15) },
+--- a/drivers/media/usb/uvc/uvc_status.c
++++ b/drivers/media/usb/uvc/uvc_status.c
+@@ -223,6 +223,7 @@ static void uvc_status_complete(struct u
+ 			if (uvc_event_control(urb, status, len))
+ 				/* The URB will be resubmitted in work context. */
+ 				return;
++			dev->motion = 1;
+ 			break;
+ 		}
+ 
+@@ -271,6 +272,7 @@ int uvc_status_init(struct uvc_device *d
+ 	}
+ 
+ 	pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress);
++	dev->motion = 0;
+ 
+ 	/* For high-speed interrupt endpoints, the bInterval value is used as
+ 	 * an exponent of two. Some developers forgot about it.
+--- a/drivers/media/usb/uvc/uvc_video.c
++++ b/drivers/media/usb/uvc/uvc_video.c
+@@ -16,6 +16,11 @@
+ #include <linux/wait.h>
+ #include <linux/atomic.h>
+ #include <asm/unaligned.h>
++#include <linux/skbuff.h>
++#include <linux/kobject.h>
++#include <linux/netlink.h>
++#include <linux/kobject.h>
++#include <linux/workqueue.h>
+ 
+ #include <media/v4l2-common.h>
+ 
+@@ -1156,9 +1161,149 @@ static void uvc_video_decode_data(struct
+ 	uvc_urb->async_operations++;
+ }
+ 
++struct bh_priv {
++	unsigned long	seen;
++};
++
++struct bh_event {
++	const char		*name;
++	struct sk_buff		*skb;
++	struct work_struct	work;
++};
++
++#define BH_ERR(fmt, args...) printk(KERN_ERR "%s: " fmt, "webcam", ##args )
++#define BH_DBG(fmt, args...) do {} while (0)
++#define BH_SKB_SIZE     2048
++
++extern u64 uevent_next_seqnum(void);
++static int seen = 0;
++
++static int bh_event_add_var(struct bh_event *event, int argv,
++		const char *format, ...)
++{
++	static char buf[128];
++	char *s;
++	va_list args;
++	int len;
++
++	if (argv)
++		return 0;
++
++	va_start(args, format);
++	len = vsnprintf(buf, sizeof(buf), format, args);
++	va_end(args);
++
++	if (len >= sizeof(buf)) {
++		BH_ERR("buffer size too small\n");
++		WARN_ON(1);
++		return -ENOMEM;
++	}
++
++	s = skb_put(event->skb, len + 1);
++	strcpy(s, buf);
++
++	BH_DBG("added variable '%s'\n", s);
++
++	return 0;
++}
++
++static int motion_hotplug_fill_event(struct bh_event *event)
++{
++	int s = jiffies;
++	int ret;
++
++	if (!seen)
++		seen = jiffies;
++
++	ret = bh_event_add_var(event, 0, "HOME=%s", "/");
++	if (ret)
++		return ret;
++
++	ret = bh_event_add_var(event, 0, "PATH=%s",
++		"/sbin:/bin:/usr/sbin:/usr/bin");
++	if (ret)
++		return ret;
++
++	ret = bh_event_add_var(event, 0, "SUBSYSTEM=usb");
++	if (ret)
++		return ret;
++
++	ret = bh_event_add_var(event, 0, "ACTION=motion");
++	if (ret)
++		return ret;
++
++	ret = bh_event_add_var(event, 0, "SEEN=%d", s - seen);
++	if (ret)
++		return ret;
++	seen = s;
++
++	ret = bh_event_add_var(event, 0, "SEQNUM=%llu", uevent_next_seqnum());
++
++	return ret;
++}
++
++static void motion_hotplug_work(struct work_struct *work)
++{
++	struct bh_event *event = container_of(work, struct bh_event, work);
++	int ret = 0;
++
++	event->skb = alloc_skb(BH_SKB_SIZE, GFP_KERNEL);
++	if (!event->skb)
++		goto out_free_event;
++
++	ret = bh_event_add_var(event, 0, "%s@", "add");
++	if (ret)
++		goto out_free_skb;
++
++	ret = motion_hotplug_fill_event(event);
++	if (ret)
++		goto out_free_skb;
++
++	NETLINK_CB(event->skb).dst_group = 1;
++	broadcast_uevent(event->skb, 0, 1, GFP_KERNEL);
++
++out_free_skb:
++	if (ret) {
++		BH_ERR("work error %d\n", ret);
++		kfree_skb(event->skb);
++	}
++out_free_event:
++	kfree(event);
++}
++
++static int motion_hotplug_create_event(void)
++{
++	struct bh_event *event;
++
++	event = kzalloc(sizeof(*event), GFP_KERNEL);
++	if (!event)
++		return -ENOMEM;
++
++	event->name = "motion";
++
++	INIT_WORK(&event->work, (void *)(void *)motion_hotplug_work);
++	schedule_work(&event->work);
++
++	return 0;
++}
++
++#define MOTION_FLAG_OFFSET	4
+ static void uvc_video_decode_end(struct uvc_streaming *stream,
+ 		struct uvc_buffer *buf, const u8 *data, int len)
+ {
++	if ((stream->dev->quirks & UVC_QUIRK_MOTION) &&
++			(data[len - 2] == 0xff) && (data[len - 1] == 0xd9)) {
++		u8 *mem;
++		buf->state = UVC_BUF_STATE_READY;
++		mem = (u8 *) (buf->mem + MOTION_FLAG_OFFSET);
++		if ( stream->dev->motion ) {
++			stream->dev->motion = 0;
++			motion_hotplug_create_event();
++		} else {
++			*mem &= 0x7f;
++		}
++	}
++
+ 	/* Mark the buffer as done if the EOF marker is set. */
+ 	if (data[1] & UVC_STREAM_EOF && buf->bytesused != 0) {
+ 		uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n");
+@@ -1715,6 +1860,8 @@ static int uvc_init_video_isoc(struct uv
+ 	if (npackets == 0)
+ 		return -ENOMEM;
+ 
++	if (stream->dev->quirks & UVC_QUIRK_SINGLE_ISO)
++		npackets = 1;
+ 	size = npackets * psize;
+ 
+ 	for_each_uvc_urb(uvc_urb, stream) {
+--- a/drivers/media/usb/uvc/uvcvideo.h
++++ b/drivers/media/usb/uvc/uvcvideo.h
+@@ -203,7 +203,9 @@
+ #define UVC_QUIRK_RESTORE_CTRLS_ON_INIT	0x00000400
+ #define UVC_QUIRK_FORCE_Y8		0x00000800
+ #define UVC_QUIRK_FORCE_BPP		0x00001000
+-
++#define UVC_QUIRK_MOTION		0x00001000
++#define UVC_QUIRK_SINGLE_ISO		0x00002000
++ 
+ /* Format flags */
+ #define UVC_FMT_FLAG_COMPRESSED		0x00000001
+ #define UVC_FMT_FLAG_STREAM		0x00000002
+@@ -672,6 +674,7 @@ struct uvc_device {
+ 	u8 *status;
+ 	struct input_dev *input;
+ 	char input_phys[64];
++	int motion;
+ 
+ 	struct uvc_ctrl_work {
+ 		struct work_struct work;
diff --git a/target/linux/ramips/patches-5.10/820-DT-Add-documentation-for-spi-rt2880.patch b/target/linux/ramips/patches-5.10/820-DT-Add-documentation-for-spi-rt2880.patch
new file mode 100644
index 0000000000..e2643e3f25
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/820-DT-Add-documentation-for-spi-rt2880.patch
@@ -0,0 +1,44 @@
+From da6015e7f19d749f135f7ac55c4ec47b06faa868 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic at openwrt.org>
+Date: Fri, 9 Aug 2013 20:12:59 +0200
+Subject: [PATCH 41/53] DT: Add documentation for spi-rt2880
+
+Describe the SPI master found on the MIPS based Ralink RT2880 SoC.
+
+Signed-off-by: John Crispin <blogic at openwrt.org>
+---
+ .../devicetree/bindings/spi/spi-rt2880.txt         |   28 ++++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/spi/spi-rt2880.txt
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/spi/spi-rt2880.txt
+@@ -0,0 +1,28 @@
++Ralink SoC RT2880 SPI master controller.
++
++This SPI controller is found on most wireless SoCs made by ralink.
++
++Required properties:
++- compatible : "ralink,rt2880-spi"
++- reg : The register base for the controller.
++- #address-cells : <1>, as required by generic SPI binding.
++- #size-cells : <0>, also as required by generic SPI binding.
++
++Child nodes as per the generic SPI binding.
++
++Example:
++
++	spi at b00 {
++		compatible = "ralink,rt2880-spi";
++		reg = <0xb00 0x100>;
++
++		#address-cells = <1>;
++		#size-cells = <0>;
++
++		m25p80 at 0 {
++			compatible = "m25p80";
++			reg = <0>;
++			spi-max-frequency = <10000000>;
++		};
++	};
++
diff --git a/target/linux/ramips/patches-5.10/821-SPI-ralink-add-Ralink-SoC-spi-driver.patch b/target/linux/ramips/patches-5.10/821-SPI-ralink-add-Ralink-SoC-spi-driver.patch
new file mode 100644
index 0000000000..f656c1071c
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/821-SPI-ralink-add-Ralink-SoC-spi-driver.patch
@@ -0,0 +1,574 @@
+From 683af4ebb91a1600df1946ac4769d916b8a1be65 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic at openwrt.org>
+Date: Sun, 27 Jul 2014 11:15:12 +0100
+Subject: [PATCH 42/53] SPI: ralink: add Ralink SoC spi driver
+
+Add the driver needed to make SPI work on Ralink SoC.
+
+Signed-off-by: Gabor Juhos <juhosg at openwrt.org>
+Acked-by: John Crispin <blogic at openwrt.org>
+---
+ drivers/spi/Kconfig      |    6 +
+ drivers/spi/Makefile     |    1 +
+ drivers/spi/spi-rt2880.c |  530 ++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 537 insertions(+)
+ create mode 100644 drivers/spi/spi-rt2880.c
+
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -689,6 +689,12 @@ config SPI_QCOM_GENI
+ 	  This driver can also be built as a module.  If so, the module
+ 	  will be called spi-geni-qcom.
+ 
++config SPI_RT2880
++	tristate "Ralink RT288x SPI Controller"
++	depends on RALINK
++	help
++	  This selects a driver for the Ralink RT288x/RT305x SPI Controller.
++
+ config SPI_S3C24XX
+ 	tristate "Samsung S3C24XX series SPI"
+ 	depends on ARCH_S3C24XX
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -96,6 +96,7 @@ obj-$(CONFIG_SPI_ROCKCHIP)		+= spi-rockc
+ obj-$(CONFIG_SPI_RB4XX)			+= spi-rb4xx.o
+ obj-$(CONFIG_SPI_RPCIF)			+= spi-rpc-if.o
+ obj-$(CONFIG_SPI_RSPI)			+= spi-rspi.o
++obj-$(CONFIG_SPI_RT2880)		+= spi-rt2880.o
+ obj-$(CONFIG_SPI_S3C24XX)		+= spi-s3c24xx-hw.o
+ spi-s3c24xx-hw-y			:= spi-s3c24xx.o
+ obj-$(CONFIG_SPI_S3C64XX)		+= spi-s3c64xx.o
+--- /dev/null
++++ b/drivers/spi/spi-rt2880.c
+@@ -0,0 +1,530 @@
++/*
++ * spi-rt2880.c -- Ralink RT288x/RT305x SPI controller driver
++ *
++ * Copyright (C) 2011 Sergiy <piratfm at gmail.com>
++ * Copyright (C) 2011-2013 Gabor Juhos <juhosg at openwrt.org>
++ *
++ * Some parts are based on spi-orion.c:
++ *   Author: Shadi Ammouri <shadi at marvell.com>
++ *   Copyright (C) 2007-2008 Marvell Ltd.
++ *
++ * 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/init.h>
++#include <linux/module.h>
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <linux/reset.h>
++#include <linux/spi/spi.h>
++#include <linux/platform_device.h>
++#include <linux/gpio.h>
++
++#define DRIVER_NAME			"spi-rt2880"
++
++#define RAMIPS_SPI_STAT			0x00
++#define RAMIPS_SPI_CFG			0x10
++#define RAMIPS_SPI_CTL			0x14
++#define RAMIPS_SPI_DATA			0x20
++#define RAMIPS_SPI_ADDR			0x24
++#define RAMIPS_SPI_BS			0x28
++#define RAMIPS_SPI_USER			0x2C
++#define RAMIPS_SPI_TXFIFO		0x30
++#define RAMIPS_SPI_RXFIFO		0x34
++#define RAMIPS_SPI_FIFO_STAT		0x38
++#define RAMIPS_SPI_MODE			0x3C
++#define RAMIPS_SPI_DEV_OFFSET		0x40
++#define RAMIPS_SPI_DMA			0x80
++#define RAMIPS_SPI_DMASTAT		0x84
++#define RAMIPS_SPI_ARBITER		0xF0
++
++/* SPISTAT register bit field */
++#define SPISTAT_BUSY			BIT(0)
++
++/* SPICFG register bit field */
++#define SPICFG_ADDRMODE			BIT(12)
++#define SPICFG_RXENVDIS			BIT(11)
++#define SPICFG_RXCAP			BIT(10)
++#define SPICFG_SPIENMODE		BIT(9)
++#define SPICFG_MSBFIRST			BIT(8)
++#define SPICFG_SPICLKPOL		BIT(6)
++#define SPICFG_RXCLKEDGE_FALLING	BIT(5)
++#define SPICFG_TXCLKEDGE_FALLING	BIT(4)
++#define SPICFG_HIZSPI			BIT(3)
++#define SPICFG_SPICLK_PRESCALE_MASK	0x7
++#define SPICFG_SPICLK_DIV2		0
++#define SPICFG_SPICLK_DIV4		1
++#define SPICFG_SPICLK_DIV8		2
++#define SPICFG_SPICLK_DIV16		3
++#define SPICFG_SPICLK_DIV32		4
++#define SPICFG_SPICLK_DIV64		5
++#define SPICFG_SPICLK_DIV128		6
++#define SPICFG_SPICLK_DISABLE		7
++
++/* SPICTL register bit field */
++#define SPICTL_START			BIT(4)
++#define SPICTL_HIZSDO			BIT(3)
++#define SPICTL_STARTWR			BIT(2)
++#define SPICTL_STARTRD			BIT(1)
++#define SPICTL_SPIENA			BIT(0)
++
++/* SPIUSER register bit field */
++#define SPIUSER_USERMODE		BIT(21)
++#define SPIUSER_INSTR_PHASE		BIT(20)
++#define SPIUSER_ADDR_PHASE_MASK		0x7
++#define SPIUSER_ADDR_PHASE_OFFSET	17
++#define SPIUSER_MODE_PHASE		BIT(16)
++#define SPIUSER_DUMMY_PHASE_MASK	0x3
++#define SPIUSER_DUMMY_PHASE_OFFSET	14
++#define SPIUSER_DATA_PHASE_MASK		0x3
++#define SPIUSER_DATA_PHASE_OFFSET	12
++#define SPIUSER_DATA_READ		(BIT(0) << SPIUSER_DATA_PHASE_OFFSET)
++#define SPIUSER_DATA_WRITE		(BIT(1) << SPIUSER_DATA_PHASE_OFFSET)
++#define SPIUSER_ADDR_TYPE_OFFSET	9
++#define SPIUSER_MODE_TYPE_OFFSET	6
++#define SPIUSER_DUMMY_TYPE_OFFSET	3
++#define SPIUSER_DATA_TYPE_OFFSET	0
++#define SPIUSER_TRANSFER_MASK		0x7
++#define SPIUSER_TRANSFER_SINGLE		BIT(0)
++#define SPIUSER_TRANSFER_DUAL		BIT(1)
++#define SPIUSER_TRANSFER_QUAD		BIT(2)
++
++#define SPIUSER_TRANSFER_TYPE(type) ( \
++	(type << SPIUSER_ADDR_TYPE_OFFSET) | \
++	(type << SPIUSER_MODE_TYPE_OFFSET) | \
++	(type << SPIUSER_DUMMY_TYPE_OFFSET) | \
++	(type << SPIUSER_DATA_TYPE_OFFSET) \
++)
++
++/* SPIFIFOSTAT register bit field */
++#define SPIFIFOSTAT_TXEMPTY		BIT(19)
++#define SPIFIFOSTAT_RXEMPTY		BIT(18)
++#define SPIFIFOSTAT_TXFULL		BIT(17)
++#define SPIFIFOSTAT_RXFULL		BIT(16)
++#define SPIFIFOSTAT_FIFO_MASK		0xff
++#define SPIFIFOSTAT_TX_OFFSET		8
++#define SPIFIFOSTAT_RX_OFFSET		0
++
++#define SPI_FIFO_DEPTH			16
++
++/* SPIMODE register bit field */
++#define SPIMODE_MODE_OFFSET		24
++#define SPIMODE_DUMMY_OFFSET		0
++
++/* SPIARB register bit field */
++#define SPICTL_ARB_EN			BIT(31)
++#define SPICTL_CSCTL1			BIT(16)
++#define SPI1_POR			BIT(1)
++#define SPI0_POR			BIT(0)
++
++#define RT2880_SPI_MODE_BITS	(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | \
++		SPI_CS_HIGH)
++
++static atomic_t hw_reset_count = ATOMIC_INIT(0);
++
++struct rt2880_spi {
++	struct spi_master	*master;
++	void __iomem		*base;
++	u32			speed;
++	u16			wait_loops;
++	u16			mode;
++	struct clk		*clk;
++};
++
++static inline struct rt2880_spi *spidev_to_rt2880_spi(struct spi_device *spi)
++{
++	return spi_master_get_devdata(spi->master);
++}
++
++static inline u32 rt2880_spi_read(struct rt2880_spi *rs, u32 reg)
++{
++	return ioread32(rs->base + reg);
++}
++
++static inline void rt2880_spi_write(struct rt2880_spi *rs, u32 reg,
++		const u32 val)
++{
++	iowrite32(val, rs->base + reg);
++}
++
++static inline void rt2880_spi_setbits(struct rt2880_spi *rs, u32 reg, u32 mask)
++{
++	void __iomem *addr = rs->base + reg;
++
++	iowrite32((ioread32(addr) | mask), addr);
++}
++
++static inline void rt2880_spi_clrbits(struct rt2880_spi *rs, u32 reg, u32 mask)
++{
++	void __iomem *addr = rs->base + reg;
++
++	iowrite32((ioread32(addr) & ~mask), addr);
++}
++
++static u32 rt2880_spi_baudrate_get(struct spi_device *spi, unsigned int speed)
++{
++	struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
++	u32 rate;
++	u32 prescale;
++
++	/*
++	 * the supported rates are: 2, 4, 8, ... 128
++	 * round up as we look for equal or less speed
++	 */
++	rate = DIV_ROUND_UP(clk_get_rate(rs->clk), speed);
++	rate = roundup_pow_of_two(rate);
++
++	/* Convert the rate to SPI clock divisor value.	*/
++	prescale = ilog2(rate / 2);
++
++	/* some tolerance. double and add 100 */
++	rs->wait_loops = (8 * HZ * loops_per_jiffy) /
++		(clk_get_rate(rs->clk) / rate);
++	rs->wait_loops = (rs->wait_loops << 1) + 100;
++	rs->speed = speed;
++
++	dev_dbg(&spi->dev, "speed: %lu/%u, rate: %u, prescal: %u, loops: %hu\n",
++			clk_get_rate(rs->clk) / rate, speed, rate, prescale,
++			rs->wait_loops);
++
++	return prescale;
++}
++
++static u32 get_arbiter_offset(struct spi_master *master)
++{
++	u32 offset;
++
++	offset = RAMIPS_SPI_ARBITER;
++	if (master->bus_num == 1)
++		offset -= RAMIPS_SPI_DEV_OFFSET;
++
++	return offset;
++}
++
++static void rt2880_spi_set_cs(struct spi_device *spi, bool enable)
++{
++	struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
++
++	if (enable)
++		rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
++	else
++		rt2880_spi_clrbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
++}
++
++static int rt2880_spi_wait_ready(struct rt2880_spi *rs, int len)
++{
++	int loop = rs->wait_loops * len;
++
++	while ((rt2880_spi_read(rs, RAMIPS_SPI_STAT) & SPISTAT_BUSY) && --loop)
++		cpu_relax();
++
++	if (loop)
++		return 0;
++
++	return -ETIMEDOUT;
++}
++
++static void rt2880_dump_reg(struct spi_master *master)
++{
++	struct rt2880_spi *rs = spi_master_get_devdata(master);
++
++	dev_dbg(&master->dev, "stat: %08x, cfg: %08x, ctl: %08x, " \
++			"data: %08x, arb: %08x\n",
++			rt2880_spi_read(rs, RAMIPS_SPI_STAT),
++			rt2880_spi_read(rs, RAMIPS_SPI_CFG),
++			rt2880_spi_read(rs, RAMIPS_SPI_CTL),
++			rt2880_spi_read(rs, RAMIPS_SPI_DATA),
++			rt2880_spi_read(rs, get_arbiter_offset(master)));
++}
++
++static int rt2880_spi_transfer_one(struct spi_master *master,
++		struct spi_device *spi, struct spi_transfer *xfer)
++{
++	struct rt2880_spi *rs = spi_master_get_devdata(master);
++	unsigned len;
++	const u8 *tx = xfer->tx_buf;
++	u8 *rx = xfer->rx_buf;
++	int err = 0;
++
++	/* change clock speed  */
++	if (unlikely(rs->speed != xfer->speed_hz)) {
++		u32 reg;
++		reg = rt2880_spi_read(rs, RAMIPS_SPI_CFG);
++		reg &= ~SPICFG_SPICLK_PRESCALE_MASK;
++		reg |= rt2880_spi_baudrate_get(spi, xfer->speed_hz);
++		rt2880_spi_write(rs, RAMIPS_SPI_CFG, reg);
++	}
++
++	if (tx) {
++		len = xfer->len;
++		while (len-- > 0) {
++			rt2880_spi_write(rs, RAMIPS_SPI_DATA, *tx++);
++			rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTWR);
++			err = rt2880_spi_wait_ready(rs, 1);
++			if (err) {
++				dev_err(&spi->dev, "TX failed, err=%d\n", err);
++				goto out;
++			}
++		}
++	}
++
++	if (rx) {
++		len = xfer->len;
++		while (len-- > 0) {
++			rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTRD);
++			err = rt2880_spi_wait_ready(rs, 1);
++			if (err) {
++				dev_err(&spi->dev, "RX failed, err=%d\n", err);
++				goto out;
++			}
++			*rx++ = (u8) rt2880_spi_read(rs, RAMIPS_SPI_DATA);
++		}
++	}
++
++out:
++	return err;
++}
++
++/* copy from spi.c */
++static void spi_set_cs(struct spi_device *spi, bool enable)
++{
++	if (spi->mode & SPI_CS_HIGH)
++		enable = !enable;
++
++	if (spi->cs_gpio >= 0)
++		gpio_set_value(spi->cs_gpio, !enable);
++	else if (spi->master->set_cs)
++		spi->master->set_cs(spi, !enable);
++}
++
++static int rt2880_spi_setup(struct spi_device *spi)
++{
++	struct spi_master *master = spi->master;
++	struct rt2880_spi *rs = spi_master_get_devdata(master);
++	u32 reg, old_reg, arbit_off;
++
++	if ((spi->max_speed_hz > master->max_speed_hz) ||
++			(spi->max_speed_hz < master->min_speed_hz)) {
++		dev_err(&spi->dev, "invalide requested speed %d Hz\n",
++				spi->max_speed_hz);
++		return -EINVAL;
++	}
++
++	if (!(master->bits_per_word_mask &
++				BIT(spi->bits_per_word - 1))) {
++		dev_err(&spi->dev, "invalide bits_per_word %d\n",
++				spi->bits_per_word);
++		return -EINVAL;
++	}
++
++	/* the hardware seems can't work on mode0 force it to mode3 */
++	if ((spi->mode & (SPI_CPOL | SPI_CPHA)) == SPI_MODE_0) {
++		dev_warn(&spi->dev, "force spi mode3\n");
++		spi->mode |= SPI_MODE_3;
++	}
++
++	/* chip polarity */
++	arbit_off = get_arbiter_offset(master);
++	reg = old_reg = rt2880_spi_read(rs, arbit_off);
++	if (spi->mode & SPI_CS_HIGH) {
++		switch (master->bus_num) {
++		case 1:
++			reg |= SPI1_POR;
++			break;
++		default:
++			reg |= SPI0_POR;
++			break;
++		}
++	} else {
++		switch (master->bus_num) {
++		case 1:
++			reg &= ~SPI1_POR;
++			break;
++		default:
++			reg &= ~SPI0_POR;
++			break;
++		}
++	}
++
++	/* enable spi1 */
++	if (master->bus_num == 1)
++		reg |= SPICTL_ARB_EN;
++
++	if (reg != old_reg)
++		rt2880_spi_write(rs, arbit_off, reg);
++
++	/* deselected the spi device */
++	spi_set_cs(spi, false);
++
++	rt2880_dump_reg(master);
++
++	return 0;
++}
++
++static int rt2880_spi_prepare_message(struct spi_master *master,
++		struct spi_message *msg)
++{
++	struct rt2880_spi *rs = spi_master_get_devdata(master);
++	struct spi_device *spi = msg->spi;
++	u32 reg;
++
++	if ((rs->mode == spi->mode) && (rs->speed == spi->max_speed_hz))
++		return 0;
++
++#if 0
++	/* set spido to tri-state */
++	rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_HIZSDO);
++#endif
++
++	reg = rt2880_spi_read(rs, RAMIPS_SPI_CFG);
++
++	reg &= ~(SPICFG_MSBFIRST | SPICFG_SPICLKPOL |
++			SPICFG_RXCLKEDGE_FALLING |
++			SPICFG_TXCLKEDGE_FALLING |
++			SPICFG_SPICLK_PRESCALE_MASK);
++
++	/* MSB */
++	if (!(spi->mode & SPI_LSB_FIRST))
++		reg |= SPICFG_MSBFIRST;
++
++	/* spi mode */
++	switch (spi->mode & (SPI_CPOL | SPI_CPHA)) {
++	case SPI_MODE_0:
++		reg |= SPICFG_TXCLKEDGE_FALLING;
++		break;
++	case SPI_MODE_1:
++		reg |= SPICFG_RXCLKEDGE_FALLING;
++		break;
++	case SPI_MODE_2:
++		reg |= SPICFG_SPICLKPOL | SPICFG_RXCLKEDGE_FALLING;
++		break;
++	case SPI_MODE_3:
++		reg |= SPICFG_SPICLKPOL | SPICFG_TXCLKEDGE_FALLING;
++		break;
++	}
++	rs->mode = spi->mode;
++
++#if 0
++	/* set spiclk and spiena to tri-state */
++	reg |= SPICFG_HIZSPI;
++#endif
++
++	/* clock divide */
++	reg |= rt2880_spi_baudrate_get(spi, spi->max_speed_hz);
++
++	rt2880_spi_write(rs, RAMIPS_SPI_CFG, reg);
++
++	return 0;
++}
++
++static int rt2880_spi_probe(struct platform_device *pdev)
++{
++	struct spi_master *master;
++	struct rt2880_spi *rs;
++	void __iomem *base;
++	struct resource *r;
++	struct clk *clk;
++	int ret;
++
++	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	base = devm_ioremap_resource(&pdev->dev, r);
++	if (IS_ERR(base))
++		return PTR_ERR(base);
++
++	clk = devm_clk_get(&pdev->dev, NULL);
++	if (IS_ERR(clk)) {
++		dev_err(&pdev->dev, "unable to get SYS clock\n");
++		return PTR_ERR(clk);
++	}
++
++	ret = clk_prepare_enable(clk);
++	if (ret)
++		goto err_clk;
++
++	master = spi_alloc_master(&pdev->dev, sizeof(*rs));
++	if (master == NULL) {
++		dev_dbg(&pdev->dev, "master allocation failed\n");
++		ret = -ENOMEM;
++		goto err_clk;
++	}
++
++	master->dev.of_node = pdev->dev.of_node;
++	master->mode_bits = RT2880_SPI_MODE_BITS;
++	master->bits_per_word_mask = SPI_BPW_MASK(8);
++	master->min_speed_hz = clk_get_rate(clk) / 128;
++	master->max_speed_hz = clk_get_rate(clk) / 2;
++	master->flags = SPI_MASTER_HALF_DUPLEX;
++	master->setup = rt2880_spi_setup;
++	master->prepare_message = rt2880_spi_prepare_message;
++	master->set_cs = rt2880_spi_set_cs;
++	master->transfer_one = rt2880_spi_transfer_one,
++
++	dev_set_drvdata(&pdev->dev, master);
++
++	rs = spi_master_get_devdata(master);
++	rs->master = master;
++	rs->base = base;
++	rs->clk = clk;
++
++	if (atomic_inc_return(&hw_reset_count) == 1)
++		device_reset(&pdev->dev);
++
++	ret = devm_spi_register_master(&pdev->dev, master);
++	if (ret < 0) {
++		dev_err(&pdev->dev, "devm_spi_register_master error.\n");
++		goto err_master;
++	}
++
++	return ret;
++
++err_master:
++	spi_master_put(master);
++	kfree(master);
++err_clk:
++	clk_disable_unprepare(clk);
++
++	return ret;
++}
++
++static int rt2880_spi_remove(struct platform_device *pdev)
++{
++	struct spi_master *master;
++	struct rt2880_spi *rs;
++
++	master = dev_get_drvdata(&pdev->dev);
++	rs = spi_master_get_devdata(master);
++
++	clk_disable_unprepare(rs->clk);
++	atomic_dec(&hw_reset_count);
++
++	return 0;
++}
++
++MODULE_ALIAS("platform:" DRIVER_NAME);
++
++static const struct of_device_id rt2880_spi_match[] = {
++	{ .compatible = "ralink,rt2880-spi" },
++	{},
++};
++MODULE_DEVICE_TABLE(of, rt2880_spi_match);
++
++static struct platform_driver rt2880_spi_driver = {
++	.driver = {
++		.name = DRIVER_NAME,
++		.owner = THIS_MODULE,
++		.of_match_table = rt2880_spi_match,
++	},
++	.probe = rt2880_spi_probe,
++	.remove = rt2880_spi_remove,
++};
++
++module_platform_driver(rt2880_spi_driver);
++
++MODULE_DESCRIPTION("Ralink SPI driver");
++MODULE_AUTHOR("Sergiy <piratfm at gmail.com>");
++MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
++MODULE_LICENSE("GPL");
diff --git a/target/linux/ramips/patches-5.10/825-i2c-MIPS-adds-ralink-I2C-driver.patch b/target/linux/ramips/patches-5.10/825-i2c-MIPS-adds-ralink-I2C-driver.patch
new file mode 100644
index 0000000000..7fdbceac09
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/825-i2c-MIPS-adds-ralink-I2C-driver.patch
@@ -0,0 +1,507 @@
+From 723b8beaabf3c3c4b1ce69480141f1e926f3f3b2 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic at openwrt.org>
+Date: Sun, 27 Jul 2014 09:52:56 +0100
+Subject: [PATCH 44/53] i2c: MIPS: adds ralink I2C driver
+
+Signed-off-by: John Crispin <blogic at openwrt.org>
+---
+ .../devicetree/bindings/i2c/i2c-ralink.txt         |   27 ++
+ drivers/i2c/busses/Kconfig                         |    4 +
+ drivers/i2c/busses/Makefile                        |    1 +
+ drivers/i2c/busses/i2c-ralink.c                    |  327 ++++++++++++++++++++
+ 4 files changed, 359 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/i2c/i2c-ralink.txt
+ create mode 100644 drivers/i2c/busses/i2c-ralink.c
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/i2c/i2c-ralink.txt
+@@ -0,0 +1,27 @@
++I2C for Ralink platforms
++
++Required properties :
++- compatible : Must be "link,rt3052-i2c"
++- reg: physical base address of the controller and length of memory mapped
++     region.
++- #address-cells = <1>;
++- #size-cells = <0>;
++
++Optional properties:
++- Child nodes conforming to i2c bus binding
++
++Example :
++
++palmbus at 10000000 {
++	i2c at 900 {
++		compatible = "link,rt3052-i2c";
++		reg = <0x900 0x100>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++
++		hwmon at 4b {
++			compatible = "national,lm92";
++			reg = <0x4b>;
++		};
++	};
++};
+--- a/drivers/i2c/busses/Kconfig
++++ b/drivers/i2c/busses/Kconfig
+@@ -954,6 +954,11 @@ config I2C_RK3X
+ 	  This driver can also be built as a module. If so, the module will
+ 	  be called i2c-rk3x.
+ 
++config I2C_RALINK
++	tristate "Ralink I2C Controller"
++	depends on RALINK && !SOC_MT7621
++	select OF_I2C
++
+ config HAVE_S3C2410_I2C
+ 	bool
+ 	help
+--- a/drivers/i2c/busses/Makefile
++++ b/drivers/i2c/busses/Makefile
+@@ -90,6 +90,7 @@ obj-$(CONFIG_I2C_PMCMSP)	+= i2c-pmcmsp.o
+ obj-$(CONFIG_I2C_PNX)		+= i2c-pnx.o
+ obj-$(CONFIG_I2C_PXA)		+= i2c-pxa.o
+ obj-$(CONFIG_I2C_PXA_PCI)	+= i2c-pxa-pci.o
++obj-$(CONFIG_I2C_RALINK)	+= i2c-ralink.o
+ obj-$(CONFIG_I2C_QCOM_CCI)	+= i2c-qcom-cci.o
+ obj-$(CONFIG_I2C_QCOM_GENI)	+= i2c-qcom-geni.o
+ obj-$(CONFIG_I2C_QUP)		+= i2c-qup.o
+--- /dev/null
++++ b/drivers/i2c/busses/i2c-ralink.c
+@@ -0,0 +1,435 @@
++/*
++ * drivers/i2c/busses/i2c-ralink.c
++ *
++ * Copyright (C) 2013 Steven Liu <steven_liu at mediatek.com>
++ * Copyright (C) 2016 Michael Lee <igvtee at gmail.com>
++ *
++ * Improve driver for i2cdetect from i2c-tools to detect i2c devices on the bus.
++ * (C) 2014 Sittisak <sittisaks at hotmail.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * 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/kernel.h>
++#include <linux/module.h>
++#include <linux/reset.h>
++#include <linux/delay.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/platform_device.h>
++#include <linux/of_platform.h>
++#include <linux/i2c.h>
++#include <linux/io.h>
++#include <linux/err.h>
++#include <linux/clk.h>
++
++#define REG_CONFIG_REG		0x00
++#define REG_CLKDIV_REG		0x04
++#define REG_DEVADDR_REG		0x08
++#define REG_ADDR_REG		0x0C
++#define REG_DATAOUT_REG		0x10
++#define REG_DATAIN_REG		0x14
++#define REG_STATUS_REG		0x18
++#define REG_STARTXFR_REG	0x1C
++#define REG_BYTECNT_REG		0x20
++
++/* REG_CONFIG_REG */
++#define I2C_ADDRLEN_OFFSET	5
++#define I2C_DEVADLEN_OFFSET	2
++#define I2C_ADDRLEN_MASK	0x3
++#define I2C_ADDR_DIS		BIT(1)
++#define I2C_DEVADDR_DIS		BIT(0)
++#define I2C_ADDRLEN_8		(7 << I2C_ADDRLEN_OFFSET)
++#define I2C_DEVADLEN_7		(6 << I2C_DEVADLEN_OFFSET)
++#define I2C_CONF_DEFAULT	(I2C_ADDRLEN_8 | I2C_DEVADLEN_7)
++
++/* REG_CLKDIV_REG */
++#define I2C_CLKDIV_MASK		0xffff
++
++/* REG_DEVADDR_REG */
++#define I2C_DEVADDR_MASK	0x7f
++
++/* REG_ADDR_REG */
++#define I2C_ADDR_MASK		0xff
++
++/* REG_STATUS_REG */
++#define I2C_STARTERR		BIT(4)
++#define I2C_ACKERR		BIT(3)
++#define I2C_DATARDY		BIT(2)
++#define I2C_SDOEMPTY		BIT(1)
++#define I2C_BUSY		BIT(0)
++
++/* REG_STARTXFR_REG */
++#define NOSTOP_CMD		BIT(2)
++#define NODATA_CMD		BIT(1)
++#define READ_CMD		BIT(0)
++
++/* REG_BYTECNT_REG */
++#define BYTECNT_MAX		64
++#define SET_BYTECNT(x)		(x - 1)
++
++/* timeout waiting for I2C devices to respond (clock streching) */
++#define TIMEOUT_MS              1000
++#define DELAY_INTERVAL_US       100
++
++struct rt_i2c {
++	void __iomem *base;
++	struct clk *clk;
++	struct device *dev;
++	struct i2c_adapter adap;
++	u32 cur_clk;
++	u32 clk_div;
++	u32 flags;
++};
++
++static void rt_i2c_w32(struct rt_i2c *i2c, u32 val, unsigned reg)
++{
++	iowrite32(val, i2c->base + reg);
++}
++
++static u32 rt_i2c_r32(struct rt_i2c *i2c, unsigned reg)
++{
++	return ioread32(i2c->base + reg);
++}
++
++static int poll_down_timeout(void __iomem *addr, u32 mask)
++{
++	unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS);
++
++	do {
++		if (!(readl_relaxed(addr) & mask))
++			return 0;
++
++		usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50);
++	} while (time_before(jiffies, timeout));
++
++	return (readl_relaxed(addr) & mask) ? -EAGAIN : 0;
++}
++
++static int rt_i2c_wait_idle(struct rt_i2c *i2c)
++{
++	int ret;
++
++	ret = poll_down_timeout(i2c->base + REG_STATUS_REG, I2C_BUSY);
++	if (ret < 0)
++		dev_dbg(i2c->dev, "idle err(%d)\n", ret);
++
++	return ret;
++}
++
++static int poll_up_timeout(void __iomem *addr, u32 mask)
++{
++	unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS);
++	u32 status;
++
++	do {
++		status = readl_relaxed(addr);
++
++		/* check error status */
++		if (status & I2C_STARTERR)
++			return -EAGAIN;
++		else if (status & I2C_ACKERR)
++			return -ENXIO;
++		else if (status & mask)
++			return 0;
++
++		usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50);
++	} while (time_before(jiffies, timeout));
++
++	return -ETIMEDOUT;
++}
++
++static int rt_i2c_wait_rx_done(struct rt_i2c *i2c)
++{
++	int ret;
++
++	ret = poll_up_timeout(i2c->base + REG_STATUS_REG, I2C_DATARDY);
++	if (ret < 0)
++		dev_dbg(i2c->dev, "rx err(%d)\n", ret);
++
++	return ret;
++}
++
++static int rt_i2c_wait_tx_done(struct rt_i2c *i2c)
++{
++	int ret;
++
++	ret = poll_up_timeout(i2c->base + REG_STATUS_REG, I2C_SDOEMPTY);
++	if (ret < 0)
++		dev_dbg(i2c->dev, "tx err(%d)\n", ret);
++
++	return ret;
++}
++
++static void rt_i2c_reset(struct rt_i2c *i2c)
++{
++	device_reset(i2c->adap.dev.parent);
++	barrier();
++	rt_i2c_w32(i2c, i2c->clk_div, REG_CLKDIV_REG);
++}
++
++static void rt_i2c_dump_reg(struct rt_i2c *i2c)
++{
++	dev_dbg(i2c->dev, "conf %08x, clkdiv %08x, devaddr %08x, " \
++			"addr %08x, dataout %08x, datain %08x, " \
++			"status %08x, startxfr %08x, bytecnt %08x\n",
++			rt_i2c_r32(i2c, REG_CONFIG_REG),
++			rt_i2c_r32(i2c, REG_CLKDIV_REG),
++			rt_i2c_r32(i2c, REG_DEVADDR_REG),
++			rt_i2c_r32(i2c, REG_ADDR_REG),
++			rt_i2c_r32(i2c, REG_DATAOUT_REG),
++			rt_i2c_r32(i2c, REG_DATAIN_REG),
++			rt_i2c_r32(i2c, REG_STATUS_REG),
++			rt_i2c_r32(i2c, REG_STARTXFR_REG),
++			rt_i2c_r32(i2c, REG_BYTECNT_REG));
++}
++
++static int rt_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
++		int num)
++{
++	struct rt_i2c *i2c;
++	struct i2c_msg *pmsg;
++	unsigned char addr;
++	int i, j, ret;
++	u32 cmd;
++
++	i2c = i2c_get_adapdata(adap);
++
++	for (i = 0; i < num; i++) {
++		pmsg = &msgs[i];
++		if (i == (num - 1))
++			cmd = 0;
++		else
++			cmd = NOSTOP_CMD;
++
++		dev_dbg(i2c->dev, "addr: 0x%x, len: %d, flags: 0x%x, stop: %d\n",
++				pmsg->addr, pmsg->len, pmsg->flags,
++				(cmd == 0)? 1 : 0);
++
++		/* wait hardware idle */
++		if ((ret = rt_i2c_wait_idle(i2c)))
++			goto err_timeout;
++
++		if (pmsg->flags & I2C_M_TEN) {
++			rt_i2c_w32(i2c, I2C_CONF_DEFAULT, REG_CONFIG_REG);
++			/* 10 bits address */
++			addr = 0x78 | ((pmsg->addr >> 8) & 0x03);
++			rt_i2c_w32(i2c, addr & I2C_DEVADDR_MASK,
++					REG_DEVADDR_REG);
++			rt_i2c_w32(i2c, pmsg->addr & I2C_ADDR_MASK,
++					REG_ADDR_REG);
++		} else {
++			rt_i2c_w32(i2c, I2C_CONF_DEFAULT | I2C_ADDR_DIS,
++					REG_CONFIG_REG);
++			/* 7 bits address */
++			rt_i2c_w32(i2c, pmsg->addr & I2C_DEVADDR_MASK,
++					REG_DEVADDR_REG);
++		}
++
++		/* buffer length */
++		if (pmsg->len == 0)
++			cmd |= NODATA_CMD;
++		else
++			rt_i2c_w32(i2c, SET_BYTECNT(pmsg->len),
++					REG_BYTECNT_REG);
++
++		j = 0;
++		if (pmsg->flags & I2C_M_RD) {
++			cmd |= READ_CMD;
++			/* start transfer */
++			barrier();
++			rt_i2c_w32(i2c, cmd, REG_STARTXFR_REG);
++			do {
++				/* wait */
++				if ((ret = rt_i2c_wait_rx_done(i2c)))
++					goto err_timeout;
++				/* read data */
++				if (pmsg->len)
++					pmsg->buf[j] = rt_i2c_r32(i2c,
++							REG_DATAIN_REG);
++				j++;
++			} while (j < pmsg->len);
++		} else {
++			do {
++				/* write data */
++				if (pmsg->len)
++					rt_i2c_w32(i2c, pmsg->buf[j],
++							REG_DATAOUT_REG);
++				/* start transfer */
++				if (j == 0) {
++					barrier();
++					rt_i2c_w32(i2c, cmd, REG_STARTXFR_REG);
++				}
++				/* wait */
++				if ((ret = rt_i2c_wait_tx_done(i2c)))
++					goto err_timeout;
++				j++;
++			} while (j < pmsg->len);
++		}
++	}
++	/* the return value is number of executed messages */
++	ret = i;
++
++	return ret;
++
++err_timeout:
++	rt_i2c_dump_reg(i2c);
++	rt_i2c_reset(i2c);
++	return ret;
++}
++
++static u32 rt_i2c_func(struct i2c_adapter *a)
++{
++	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
++}
++
++static const struct i2c_algorithm rt_i2c_algo = {
++	.master_xfer	= rt_i2c_master_xfer,
++	.functionality	= rt_i2c_func,
++};
++
++static const struct of_device_id i2c_rt_dt_ids[] = {
++	{ .compatible = "ralink,rt2880-i2c" },
++	{ /* sentinel */ }
++};
++
++MODULE_DEVICE_TABLE(of, i2c_rt_dt_ids);
++
++static struct i2c_adapter_quirks rt_i2c_quirks = {
++        .max_write_len = BYTECNT_MAX,
++        .max_read_len = BYTECNT_MAX,
++};
++
++static int rt_i2c_init(struct rt_i2c *i2c)
++{
++	u32 reg;
++
++	/* i2c_sclk = periph_clk / ((2 * clk_div) + 5) */
++	i2c->clk_div = (clk_get_rate(i2c->clk) - (5 * i2c->cur_clk)) /
++		(2 * i2c->cur_clk);
++	if (i2c->clk_div < 8)
++		i2c->clk_div = 8;
++	if (i2c->clk_div > I2C_CLKDIV_MASK)
++		i2c->clk_div = I2C_CLKDIV_MASK;
++
++	/* check support combinde/repeated start message */
++	rt_i2c_w32(i2c, NOSTOP_CMD, REG_STARTXFR_REG);
++	reg = rt_i2c_r32(i2c, REG_STARTXFR_REG) & NOSTOP_CMD;
++
++	rt_i2c_reset(i2c);
++
++	return reg;
++}
++
++static int rt_i2c_probe(struct platform_device *pdev)
++{
++	struct resource *res;
++	struct rt_i2c *i2c;
++	struct i2c_adapter *adap;
++	const struct of_device_id *match;
++	int ret, restart;
++
++	match = of_match_device(i2c_rt_dt_ids, &pdev->dev);
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		dev_err(&pdev->dev, "no memory resource found\n");
++		return -ENODEV;
++	}
++
++	i2c = devm_kzalloc(&pdev->dev, sizeof(struct rt_i2c), GFP_KERNEL);
++	if (!i2c) {
++		dev_err(&pdev->dev, "failed to allocate i2c_adapter\n");
++		return -ENOMEM;
++	}
++
++	i2c->base = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(i2c->base))
++		return PTR_ERR(i2c->base);
++
++	i2c->clk = devm_clk_get(&pdev->dev, NULL);
++	if (IS_ERR(i2c->clk)) {
++		dev_err(&pdev->dev, "no clock defined\n");
++		return -ENODEV;
++	}
++	clk_prepare_enable(i2c->clk);
++	i2c->dev = &pdev->dev;
++
++	if (of_property_read_u32(pdev->dev.of_node,
++				"clock-frequency", &i2c->cur_clk))
++		i2c->cur_clk = 100000;
++
++	adap = &i2c->adap;
++	adap->owner = THIS_MODULE;
++	adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
++	adap->algo = &rt_i2c_algo;
++	adap->retries = 3;
++	adap->dev.parent = &pdev->dev;
++	i2c_set_adapdata(adap, i2c);
++	adap->dev.of_node = pdev->dev.of_node;
++	strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name));
++	adap->quirks = &rt_i2c_quirks;
++
++	platform_set_drvdata(pdev, i2c);
++
++	restart = rt_i2c_init(i2c);
++
++	ret = i2c_add_adapter(adap);
++	if (ret < 0) {
++		dev_err(&pdev->dev, "failed to add adapter\n");
++		clk_disable_unprepare(i2c->clk);
++		return ret;
++	}
++
++	dev_info(&pdev->dev, "clock %uKHz, re-start %ssupport\n",
++			i2c->cur_clk/1000, restart ? "" : "not ");
++
++	return ret;
++}
++
++static int rt_i2c_remove(struct platform_device *pdev)
++{
++	struct rt_i2c *i2c = platform_get_drvdata(pdev);
++
++	i2c_del_adapter(&i2c->adap);
++	clk_disable_unprepare(i2c->clk);
++
++	return 0;
++}
++
++static struct platform_driver rt_i2c_driver = {
++	.probe		= rt_i2c_probe,
++	.remove		= rt_i2c_remove,
++	.driver		= {
++		.owner	= THIS_MODULE,
++		.name	= "i2c-ralink",
++		.of_match_table = i2c_rt_dt_ids,
++	},
++};
++
++static int __init i2c_rt_init (void)
++{
++	return platform_driver_register(&rt_i2c_driver);
++}
++subsys_initcall(i2c_rt_init);
++
++static void __exit i2c_rt_exit (void)
++{
++	platform_driver_unregister(&rt_i2c_driver);
++}
++module_exit(i2c_rt_exit);
++
++MODULE_AUTHOR("Steven Liu <steven_liu at mediatek.com>");
++MODULE_DESCRIPTION("Ralink I2c host driver");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:Ralink-I2C");
diff --git a/target/linux/ramips/patches-5.10/830-mmc-MIPS-ralink-add-sdhci-for-mt7620a-SoC.patch b/target/linux/ramips/patches-5.10/830-mmc-MIPS-ralink-add-sdhci-for-mt7620a-SoC.patch
new file mode 100644
index 0000000000..77311c36de
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/830-mmc-MIPS-ralink-add-sdhci-for-mt7620a-SoC.patch
@@ -0,0 +1,43 @@
+From 23147af14531cbdada194b94120ef8774f46292d Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic at openwrt.org>
+Date: Thu, 13 Nov 2014 19:08:40 +0100
+Subject: [PATCH 46/53] mmc: MIPS: ralink: add sdhci for mt7620a SoC
+
+Signed-off-by: John Crispin <blogic at openwrt.org>
+---
+ drivers/mmc/host/Kconfig             |    2 +
+ drivers/mmc/host/Makefile            |    1 +
+ drivers/mmc/host/mtk-mmc/Kconfig     |   16 +
+ drivers/mmc/host/mtk-mmc/Makefile    |   42 +
+ drivers/mmc/host/mtk-mmc/board.h     |  137 ++
+ drivers/mmc/host/mtk-mmc/dbg.c       |  347 ++++
+ drivers/mmc/host/mtk-mmc/dbg.h       |  156 ++
+ drivers/mmc/host/mtk-mmc/mt6575_sd.h | 1001 +++++++++++
+ drivers/mmc/host/mtk-mmc/sd.c        | 3060 ++++++++++++++++++++++++++++++++++
+ 9 files changed, 4762 insertions(+)
+ create mode 100644 drivers/mmc/host/mtk-mmc/Kconfig
+ create mode 100644 drivers/mmc/host/mtk-mmc/Makefile
+ create mode 100644 drivers/mmc/host/mtk-mmc/board.h
+ create mode 100644 drivers/mmc/host/mtk-mmc/dbg.c
+ create mode 100644 drivers/mmc/host/mtk-mmc/dbg.h
+ create mode 100644 drivers/mmc/host/mtk-mmc/mt6575_sd.h
+ create mode 100644 drivers/mmc/host/mtk-mmc/sd.c
+
+--- a/drivers/mmc/host/Kconfig
++++ b/drivers/mmc/host/Kconfig
+@@ -1101,3 +1101,5 @@ config MMC_OWL
+ 
+ config MMC_SDHCI_EXTERNAL_DMA
+ 	bool
++
++source "drivers/mmc/host/mtk-mmc/Kconfig"
+--- a/drivers/mmc/host/Makefile
++++ b/drivers/mmc/host/Makefile
+@@ -3,6 +3,7 @@
+ # Makefile for MMC/SD host controller drivers
+ #
+ 
++obj-$(CONFIG_MTK_MMC) 		+= mtk-mmc/
+ obj-$(CONFIG_MMC_ARMMMCI) += armmmci.o
+ armmmci-y := mmci.o
+ armmmci-$(CONFIG_MMC_QCOM_DML) += mmci_qcom_dml.o
diff --git a/target/linux/ramips/patches-5.10/835-asoc-add-mt7620-support.patch b/target/linux/ramips/patches-5.10/835-asoc-add-mt7620-support.patch
new file mode 100644
index 0000000000..f625d41449
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/835-asoc-add-mt7620-support.patch
@@ -0,0 +1,1046 @@
+From 7f29222b1731e8182ba94a331531dec18865a1e4 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic at openwrt.org>
+Date: Sun, 27 Jul 2014 09:31:47 +0100
+Subject: [PATCH 48/53] asoc: add mt7620 support
+
+Signed-off-by: John Crispin <blogic at openwrt.org>
+---
+ arch/mips/ralink/of.c            |    2 +
+ sound/soc/Kconfig                |    1 +
+ sound/soc/Makefile               |    1 +
+ sound/soc/ralink/Kconfig         |   15 ++
+ sound/soc/ralink/Makefile        |   11 +
+ sound/soc/ralink/mt7620-i2s.c    |  436 ++++++++++++++++++++++++++++++++++++++
+ sound/soc/ralink/mt7620-wm8960.c |  233 ++++++++++++++++++++
+ 7 files changed, 699 insertions(+)
+ create mode 100644 sound/soc/ralink/Kconfig
+ create mode 100644 sound/soc/ralink/Makefile
+ create mode 100644 sound/soc/ralink/mt7620-i2s.c
+ create mode 100644 sound/soc/ralink/mt7620-wm8960.c
+
+--- a/arch/mips/ralink/of.c
++++ b/arch/mips/ralink/of.c
+@@ -13,6 +13,7 @@
+ #include <linux/of_fdt.h>
+ #include <linux/kernel.h>
+ #include <linux/memblock.h>
++#include <linux/module.h>
+ #include <linux/of_platform.h>
+ #include <linux/of_address.h>
+ 
+@@ -24,6 +25,7 @@
+ #include "common.h"
+ 
+ __iomem void *rt_sysc_membase;
++EXPORT_SYMBOL(rt_sysc_membase);
+ __iomem void *rt_memc_membase;
+ 
+ __iomem void *plat_of_remap_node(const char *node)
+--- a/sound/soc/Kconfig
++++ b/sound/soc/Kconfig
+@@ -60,6 +60,7 @@ source "sound/soc/mxs/Kconfig"
+ source "sound/soc/pxa/Kconfig"
+ source "sound/soc/qcom/Kconfig"
+ source "sound/soc/rockchip/Kconfig"
++source "sound/soc/ralink/Kconfig"
+ source "sound/soc/samsung/Kconfig"
+ source "sound/soc/sh/Kconfig"
+ source "sound/soc/sirf/Kconfig"
+--- a/sound/soc/Makefile
++++ b/sound/soc/Makefile
+@@ -43,6 +43,7 @@ obj-$(CONFIG_SND_SOC)	+= kirkwood/
+ obj-$(CONFIG_SND_SOC)	+= pxa/
+ obj-$(CONFIG_SND_SOC)	+= qcom/
+ obj-$(CONFIG_SND_SOC)	+= rockchip/
++obj-$(CONFIG_SND_SOC)	+= ralink/
+ obj-$(CONFIG_SND_SOC)	+= samsung/
+ obj-$(CONFIG_SND_SOC)	+= sh/
+ obj-$(CONFIG_SND_SOC)	+= sirf/
+--- /dev/null
++++ b/sound/soc/ralink/Kconfig
+@@ -0,0 +1,8 @@
++config SND_RALINK_SOC_I2S
++	depends on RALINK && SND_SOC && !SOC_RT288X
++	select SND_SOC_GENERIC_DMAENGINE_PCM
++	select REGMAP_MMIO
++	tristate "SoC Audio (I2S protocol) for Ralink SoC"
++	help
++	  Say Y if you want to use I2S protocol and I2S codec on Ralink/MediaTek
++	  based boards.
+--- /dev/null
++++ b/sound/soc/ralink/Makefile
+@@ -0,0 +1,6 @@
++#
++# Ralink/MediaTek Platform Support
++#
++snd-soc-ralink-i2s-objs := ralink-i2s.o
++
++obj-$(CONFIG_SND_RALINK_SOC_I2S) += snd-soc-ralink-i2s.o
+--- /dev/null
++++ b/sound/soc/ralink/ralink-i2s.c
+@@ -0,0 +1,965 @@
++/*
++ *  Copyright (C) 2010, Lars-Peter Clausen <lars at metafoo.de>
++ *  Copyright (C) 2016 Michael Lee <igvtee at gmail.com>
++ *
++ *  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.
++ *
++ *  You should have received a copy of the GNU General Public License along
++ *  with this program; if not, write to the Free Software Foundation, Inc.,
++ *  675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/clk.h>
++#include <linux/regmap.h>
++#include <linux/reset.h>
++#include <linux/debugfs.h>
++#include <linux/of_device.h>
++#include <sound/pcm_params.h>
++#include <sound/dmaengine_pcm.h>
++
++#include <asm/mach-ralink/ralink_regs.h>
++
++#define DRV_NAME "ralink-i2s"
++
++#define I2S_REG_CFG0		0x00
++#define I2S_REG_INT_STATUS	0x04
++#define I2S_REG_INT_EN		0x08
++#define I2S_REG_FF_STATUS	0x0c
++#define I2S_REG_WREG		0x10
++#define I2S_REG_RREG		0x14
++#define I2S_REG_CFG1		0x18
++#define I2S_REG_DIVCMP		0x20
++#define I2S_REG_DIVINT		0x24
++
++/* I2S_REG_CFG0 */
++#define I2S_REG_CFG0_EN		BIT(31)
++#define I2S_REG_CFG0_DMA_EN	BIT(30)
++#define I2S_REG_CFG0_BYTE_SWAP	BIT(28)
++#define I2S_REG_CFG0_TX_EN	BIT(24)
++#define I2S_REG_CFG0_RX_EN	BIT(20)
++#define I2S_REG_CFG0_SLAVE	BIT(16)
++#define I2S_REG_CFG0_RX_THRES	12
++#define I2S_REG_CFG0_TX_THRES	4
++#define I2S_REG_CFG0_THRES_MASK	(0xf << I2S_REG_CFG0_RX_THRES) | \
++	(4 << I2S_REG_CFG0_TX_THRES)
++#define I2S_REG_CFG0_DFT_THRES	(4 << I2S_REG_CFG0_RX_THRES) | \
++	(4 << I2S_REG_CFG0_TX_THRES)
++/* RT305x */
++#define I2S_REG_CFG0_CLK_DIS	BIT(8)
++#define I2S_REG_CFG0_TXCH_SWAP	BIT(3)
++#define I2S_REG_CFG0_TXCH1_OFF	BIT(2)
++#define I2S_REG_CFG0_TXCH0_OFF	BIT(1)
++#define I2S_REG_CFG0_SLAVE_EN	BIT(0)
++/* RT3883 */
++#define I2S_REG_CFG0_RXCH_SWAP	BIT(11)
++#define I2S_REG_CFG0_RXCH1_OFF	BIT(10)
++#define I2S_REG_CFG0_RXCH0_OFF	BIT(9)
++#define I2S_REG_CFG0_WS_INV	BIT(0)
++/* MT7628 */
++#define I2S_REG_CFG0_FMT_LE	BIT(29)
++#define I2S_REG_CFG0_SYS_BE	BIT(28)
++#define I2S_REG_CFG0_NORM_24	BIT(18)
++#define I2S_REG_CFG0_DATA_24	BIT(17)
++
++/* I2S_REG_INT_STATUS */
++#define I2S_REG_INT_RX_FAULT	BIT(7)
++#define I2S_REG_INT_RX_OVRUN	BIT(6)
++#define I2S_REG_INT_RX_UNRUN	BIT(5)
++#define I2S_REG_INT_RX_THRES	BIT(4)
++#define I2S_REG_INT_TX_FAULT	BIT(3)
++#define I2S_REG_INT_TX_OVRUN	BIT(2)
++#define I2S_REG_INT_TX_UNRUN	BIT(1)
++#define I2S_REG_INT_TX_THRES	BIT(0)
++#define I2S_REG_INT_TX_MASK	0xf
++#define I2S_REG_INT_RX_MASK	0xf0
++
++/* I2S_REG_INT_STATUS */
++#define I2S_RX_AVCNT(x)		((x >> 4) & 0xf)
++#define I2S_TX_AVCNT(x)		(x & 0xf)
++/* MT7628 */
++#define MT7628_I2S_RX_AVCNT(x)	((x >> 8) & 0x1f)
++#define MT7628_I2S_TX_AVCNT(x)	(x & 0x1f)
++
++/* I2S_REG_CFG1 */
++#define I2S_REG_CFG1_LBK	BIT(31)
++#define I2S_REG_CFG1_EXTLBK	BIT(30)
++/* RT3883 */
++#define I2S_REG_CFG1_LEFT_J	BIT(0)
++#define I2S_REG_CFG1_RIGHT_J	BIT(1)
++#define I2S_REG_CFG1_FMT_MASK	0x3
++
++/* I2S_REG_DIVCMP */
++#define I2S_REG_DIVCMP_CLKEN	BIT(31)
++#define I2S_REG_DIVCMP_DIVCOMP_MASK	0x1ff
++
++/* I2S_REG_DIVINT */
++#define I2S_REG_DIVINT_MASK	0x3ff
++
++/* BCLK dividers */
++#define RALINK_I2S_DIVCMP	0
++#define RALINK_I2S_DIVINT	1
++
++/* FIFO */
++#define RALINK_I2S_FIFO_SIZE	32
++
++/* feature flags */
++#define RALINK_FLAGS_TXONLY	BIT(0)
++#define RALINK_FLAGS_LEFT_J	BIT(1)
++#define RALINK_FLAGS_RIGHT_J	BIT(2)
++#define RALINK_FLAGS_ENDIAN	BIT(3)
++#define RALINK_FLAGS_24BIT	BIT(4)
++
++#define RALINK_I2S_INT_EN	0
++
++struct ralink_i2s_stats {
++	u32 dmafault;
++	u32 overrun;
++	u32 underrun;
++	u32 belowthres;
++};
++
++struct ralink_i2s {
++	struct device *dev;
++	void __iomem *regs;
++	struct clk *clk;
++	struct regmap *regmap;
++	u32 flags;
++	unsigned int fmt;
++	u16 txdma_req;
++	u16 rxdma_req;
++
++	struct snd_dmaengine_dai_dma_data playback_dma_data;
++	struct snd_dmaengine_dai_dma_data capture_dma_data;
++
++	struct dentry *dbg_dir;
++        struct dentry *dbg_stats;
++	struct ralink_i2s_stats txstats;
++	struct ralink_i2s_stats rxstats;
++};
++
++static void ralink_i2s_dump_regs(struct ralink_i2s *i2s)
++{
++	u32 buf[10];
++	int ret;
++
++	ret = regmap_bulk_read(i2s->regmap, I2S_REG_CFG0,
++			buf, ARRAY_SIZE(buf));
++
++	dev_dbg(i2s->dev, "CFG0: %08x, INTSTAT: %08x, INTEN: %08x, " \
++			"FFSTAT: %08x, WREG: %08x, RREG: %08x, " \
++			"CFG1: %08x, DIVCMP: %08x, DIVINT: %08x\n",
++			buf[0], buf[1], buf[2], buf[3], buf[4],
++			buf[5], buf[6], buf[8], buf[9]);
++}
++
++static int ralink_i2s_set_sysclk(struct snd_soc_dai *dai,
++                              int clk_id, unsigned int freq, int dir)
++{
++	return 0;
++}
++
++static int ralink_i2s_set_sys_bclk(struct snd_soc_dai *dai, int width, int rate)
++{
++	struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai);
++	unsigned long clk = clk_get_rate(i2s->clk);
++	int div;
++	uint32_t data;
++
++	/* disable clock at slave mode */
++	if ((i2s->fmt & SND_SOC_DAIFMT_MASTER_MASK) ==
++			SND_SOC_DAIFMT_CBM_CFM) {
++		regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
++				I2S_REG_CFG0_CLK_DIS,
++				I2S_REG_CFG0_CLK_DIS);
++		return 0;
++	}
++
++	/* FREQOUT = FREQIN / (I2S_CLK_DIV + 1) */
++	div = (clk / rate ) - 1;
++
++	data = rt_sysc_r32(0x30);
++	data &= (0xff << 8);
++	data |= (0x1 << 15) | (div << 8);
++	rt_sysc_w32(data, 0x30);
++
++	/* enable clock */
++	regmap_update_bits(i2s->regmap, I2S_REG_CFG0, I2S_REG_CFG0_CLK_DIS, 0);
++
++	dev_dbg(i2s->dev, "clk: %lu, rate: %u, div: %d\n",
++			clk, rate, div);
++
++	return 0;
++}
++
++static int ralink_i2s_set_bclk(struct snd_soc_dai *dai, int width, int rate)
++{
++	struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai);
++	unsigned long clk = clk_get_rate(i2s->clk);
++	int divint, divcomp;
++
++	/* disable clock at slave mode */
++	if ((i2s->fmt & SND_SOC_DAIFMT_MASTER_MASK) ==
++			SND_SOC_DAIFMT_CBM_CFM) {
++		regmap_update_bits(i2s->regmap, I2S_REG_DIVCMP,
++				I2S_REG_DIVCMP_CLKEN, 0);
++		return 0;
++	}
++
++	/* FREQOUT = FREQIN * (1/2) * (1/(DIVINT + DIVCOMP/512)) */
++	clk = clk / (2 * 2 * width);
++	divint = clk / rate;
++	divcomp = ((clk % rate) * 512) / rate;
++
++	if ((divint > I2S_REG_DIVINT_MASK) ||
++			(divcomp > I2S_REG_DIVCMP_DIVCOMP_MASK))
++		return -EINVAL;
++
++	regmap_update_bits(i2s->regmap, I2S_REG_DIVINT,
++			I2S_REG_DIVINT_MASK, divint);
++	regmap_update_bits(i2s->regmap, I2S_REG_DIVCMP,
++			I2S_REG_DIVCMP_DIVCOMP_MASK, divcomp);
++
++	/* enable clock */
++	regmap_update_bits(i2s->regmap, I2S_REG_DIVCMP, I2S_REG_DIVCMP_CLKEN,
++			I2S_REG_DIVCMP_CLKEN);
++
++	dev_dbg(i2s->dev, "clk: %lu, rate: %u, int: %d, comp: %d\n",
++			clk_get_rate(i2s->clk), rate, divint, divcomp);
++
++	return 0;
++}
++
++static int ralink_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
++{
++	struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai);
++	unsigned int cfg0 = 0, cfg1 = 0;
++
++	/* set master/slave audio interface */
++	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
++	case SND_SOC_DAIFMT_CBM_CFM:
++		if (i2s->flags & RALINK_FLAGS_TXONLY)
++			cfg0 |= I2S_REG_CFG0_SLAVE_EN;
++		else
++			cfg0 |= I2S_REG_CFG0_SLAVE;
++		break;
++	case SND_SOC_DAIFMT_CBS_CFS:
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	/* interface format */
++	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
++	case SND_SOC_DAIFMT_I2S:
++		break;
++	case SND_SOC_DAIFMT_RIGHT_J:
++		if (i2s->flags & RALINK_FLAGS_RIGHT_J) {
++			cfg1 |= I2S_REG_CFG1_RIGHT_J;
++			break;
++		}
++		return -EINVAL;
++	case SND_SOC_DAIFMT_LEFT_J:
++		if (i2s->flags & RALINK_FLAGS_LEFT_J) {
++			cfg1 |= I2S_REG_CFG1_LEFT_J;
++			break;
++		}
++		return -EINVAL;
++	default:
++		return -EINVAL;
++	}
++
++	/* clock inversion */
++	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
++	case SND_SOC_DAIFMT_NB_NF:
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	if (i2s->flags & RALINK_FLAGS_TXONLY) {
++		regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
++				I2S_REG_CFG0_SLAVE_EN, cfg0);
++	} else {
++		regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
++				I2S_REG_CFG0_SLAVE, cfg0);
++	}
++	regmap_update_bits(i2s->regmap, I2S_REG_CFG1,
++			I2S_REG_CFG1_FMT_MASK, cfg1);
++	i2s->fmt = fmt;
++
++	return 0;
++}
++
++static int ralink_i2s_startup(struct snd_pcm_substream *substream,
++		struct snd_soc_dai *dai)
++{
++	struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai);
++
++	if (snd_soc_dai_active(dai))
++		return 0;
++
++	/* setup status interrupt */
++#if (RALINK_I2S_INT_EN)
++	regmap_write(i2s->regmap, I2S_REG_INT_EN, 0xff);
++#else
++	regmap_write(i2s->regmap, I2S_REG_INT_EN, 0x0);
++#endif
++
++	/* enable */
++	regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
++			I2S_REG_CFG0_EN | I2S_REG_CFG0_DMA_EN |
++			I2S_REG_CFG0_THRES_MASK,
++			I2S_REG_CFG0_EN | I2S_REG_CFG0_DMA_EN |
++			I2S_REG_CFG0_DFT_THRES);
++
++	return 0;
++}
++
++static void ralink_i2s_shutdown(struct snd_pcm_substream *substream,
++		struct snd_soc_dai *dai)
++{
++	struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai);
++
++	/* If both streams are stopped, disable module and clock */
++	if (snd_soc_dai_active(dai))
++		return;
++
++	/*
++	 * datasheet mention when disable all control regs are cleared
++	 * to initial values. need reinit at startup.
++	 */
++	regmap_update_bits(i2s->regmap, I2S_REG_CFG0, I2S_REG_CFG0_EN, 0);
++}
++
++static int ralink_i2s_hw_params(struct snd_pcm_substream *substream,
++		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
++{
++	struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai);
++	int width;
++	int ret;
++
++	width = params_width(params);
++	switch (width) {
++	case 16:
++		if (i2s->flags & RALINK_FLAGS_24BIT)
++			regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
++					I2S_REG_CFG0_DATA_24, 0);
++		break;
++	case 24:
++		if (i2s->flags & RALINK_FLAGS_24BIT) {
++			regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
++					I2S_REG_CFG0_DATA_24,
++					I2S_REG_CFG0_DATA_24);
++			break;
++		}
++		return -EINVAL;
++	default:
++		return -EINVAL;
++	}
++
++	switch (params_channels(params)) {
++	case 2:
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	if (i2s->flags & RALINK_FLAGS_ENDIAN) {
++		/* system endian */
++#ifdef SNDRV_LITTLE_ENDIAN
++		regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
++				I2S_REG_CFG0_SYS_BE, 0);
++#else
++		regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
++				I2S_REG_CFG0_SYS_BE,
++				I2S_REG_CFG0_SYS_BE);
++#endif
++
++		/* data endian */
++		switch (params_format(params)) {
++		case SNDRV_PCM_FORMAT_S16_LE:
++		case SNDRV_PCM_FORMAT_S24_LE:
++			regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
++					I2S_REG_CFG0_FMT_LE,
++					I2S_REG_CFG0_FMT_LE);
++			break;
++		case SNDRV_PCM_FORMAT_S16_BE:
++		case SNDRV_PCM_FORMAT_S24_BE:
++			regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
++					I2S_REG_CFG0_FMT_LE, 0);
++			break;
++		default:
++			return -EINVAL;
++		}
++	}
++
++	/* setup bclk rate */
++	if (i2s->flags & RALINK_FLAGS_TXONLY)
++		ret = ralink_i2s_set_sys_bclk(dai, width, params_rate(params));
++	else
++		ret = ralink_i2s_set_bclk(dai, width, params_rate(params));
++
++	return ret;
++}
++
++static int ralink_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
++		struct snd_soc_dai *dai)
++{
++	struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai);
++	unsigned int mask, val;
++
++	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
++		mask = I2S_REG_CFG0_TX_EN;
++	else
++		mask = I2S_REG_CFG0_RX_EN;
++
++	switch (cmd) {
++	case SNDRV_PCM_TRIGGER_START:
++	case SNDRV_PCM_TRIGGER_RESUME:
++	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
++		val = mask;
++		break;
++	case SNDRV_PCM_TRIGGER_STOP:
++	case SNDRV_PCM_TRIGGER_SUSPEND:
++	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
++		val = 0;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	regmap_update_bits(i2s->regmap, I2S_REG_CFG0, mask, val);
++
++	return 0;
++}
++
++static void ralink_i2s_init_dma_data(struct ralink_i2s *i2s,
++		struct resource *res)
++{
++	struct snd_dmaengine_dai_dma_data *dma_data;
++
++	/* Playback */
++	dma_data = &i2s->playback_dma_data;
++	dma_data->addr = res->start + I2S_REG_WREG;
++	dma_data->addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++	dma_data->maxburst = 1;
++	dma_data->slave_id = i2s->txdma_req;
++
++	if (i2s->flags & RALINK_FLAGS_TXONLY)
++		return;
++
++	/* Capture */
++	dma_data = &i2s->capture_dma_data;
++	dma_data->addr = res->start + I2S_REG_RREG;
++	dma_data->addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++	dma_data->maxburst = 1;
++	dma_data->slave_id = i2s->rxdma_req;
++}
++
++static int ralink_i2s_dai_probe(struct snd_soc_dai *dai)
++{
++	struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai);
++
++	snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data,
++			&i2s->capture_dma_data);
++
++	return 0;
++}
++
++static int ralink_i2s_dai_remove(struct snd_soc_dai *dai)
++{
++	return 0;
++}
++
++static const struct snd_soc_dai_ops ralink_i2s_dai_ops = {
++	.set_sysclk = ralink_i2s_set_sysclk,
++	.set_fmt = ralink_i2s_set_fmt,
++	.startup = ralink_i2s_startup,
++	.shutdown = ralink_i2s_shutdown,
++	.hw_params = ralink_i2s_hw_params,
++	.trigger = ralink_i2s_trigger,
++};
++
++static struct snd_soc_dai_driver ralink_i2s_dai = {
++	.name = DRV_NAME,
++	.probe = ralink_i2s_dai_probe,
++	.remove = ralink_i2s_dai_remove,
++	.ops = &ralink_i2s_dai_ops,
++	.capture = {
++		.stream_name = "I2S Capture",
++		.channels_min = 2,
++		.channels_max = 2,
++		.rate_min = 5512,
++		.rate_max = 192000,
++		.rates = SNDRV_PCM_RATE_CONTINUOUS,
++		.formats = SNDRV_PCM_FMTBIT_S16_LE,
++	},
++	.playback = {
++		.stream_name = "I2S Playback",
++		.channels_min = 2,
++		.channels_max = 2,
++		.rate_min = 5512,
++		.rate_max = 192000,
++		.rates = SNDRV_PCM_RATE_CONTINUOUS,
++		.formats = SNDRV_PCM_FMTBIT_S16_LE,
++	},
++	.symmetric_rates = 1,
++};
++
++static struct snd_pcm_hardware ralink_pcm_hardware = {
++	.info = SNDRV_PCM_INFO_MMAP |
++		SNDRV_PCM_INFO_MMAP_VALID |
++		SNDRV_PCM_INFO_INTERLEAVED |
++		SNDRV_PCM_INFO_BLOCK_TRANSFER,
++	.formats = SNDRV_PCM_FMTBIT_S16_LE,
++	.channels_min		= 2,
++	.channels_max		= 2,
++	.period_bytes_min	= PAGE_SIZE,
++	.period_bytes_max	= PAGE_SIZE * 2,
++	.periods_min		= 2,
++	.periods_max		= 128,
++	.buffer_bytes_max	= 128 * 1024,
++	.fifo_size		= RALINK_I2S_FIFO_SIZE,
++};
++
++static const struct snd_dmaengine_pcm_config ralink_dmaengine_pcm_config = {
++	.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
++	.pcm_hardware = &ralink_pcm_hardware,
++	.prealloc_buffer_size = 256 * PAGE_SIZE,
++};
++
++static const struct snd_soc_component_driver ralink_i2s_component = {
++	.name = DRV_NAME,
++};
++
++static bool ralink_i2s_readable_reg(struct device *dev, unsigned int reg)
++{
++	return true;
++}
++
++static bool ralink_i2s_volatile_reg(struct device *dev, unsigned int reg)
++{
++	switch (reg) {
++	case I2S_REG_INT_STATUS:
++	case I2S_REG_FF_STATUS:
++		return true;
++	}
++	return false;
++}
++
++static bool ralink_i2s_writeable_reg(struct device *dev, unsigned int reg)
++{
++	switch (reg) {
++	case I2S_REG_FF_STATUS:
++	case I2S_REG_RREG:
++		return false;
++	}
++	return true;
++}
++
++static const struct regmap_config ralink_i2s_regmap_config = {
++	.reg_bits = 32,
++	.reg_stride = 4,
++	.val_bits = 32,
++	.writeable_reg = ralink_i2s_writeable_reg,
++	.readable_reg = ralink_i2s_readable_reg,
++	.volatile_reg = ralink_i2s_volatile_reg,
++	.max_register = I2S_REG_DIVINT,
++};
++
++#if (RALINK_I2S_INT_EN)
++static irqreturn_t ralink_i2s_irq(int irq, void *devid)
++{
++	struct ralink_i2s *i2s = devid;
++	u32 status;
++
++	regmap_read(i2s->regmap, I2S_REG_INT_STATUS, &status);
++	if (unlikely(!status))
++		return IRQ_NONE;
++
++	/* tx stats */
++	if (status & I2S_REG_INT_TX_MASK) {
++		if (status & I2S_REG_INT_TX_THRES)
++			i2s->txstats.belowthres++;
++		if (status & I2S_REG_INT_TX_UNRUN)
++			i2s->txstats.underrun++;
++		if (status & I2S_REG_INT_TX_OVRUN)
++			i2s->txstats.overrun++;
++		if (status & I2S_REG_INT_TX_FAULT)
++			i2s->txstats.dmafault++;
++	}
++
++	/* rx stats */
++	if (status & I2S_REG_INT_RX_MASK) {
++		if (status & I2S_REG_INT_RX_THRES)
++			i2s->rxstats.belowthres++;
++		if (status & I2S_REG_INT_RX_UNRUN)
++			i2s->rxstats.underrun++;
++		if (status & I2S_REG_INT_RX_OVRUN)
++			i2s->rxstats.overrun++;
++		if (status & I2S_REG_INT_RX_FAULT)
++			i2s->rxstats.dmafault++;
++	}
++
++	/* clean status bits */
++	regmap_write(i2s->regmap, I2S_REG_INT_STATUS, status);
++
++	return IRQ_HANDLED;
++}
++#endif
++
++#if IS_ENABLED(CONFIG_DEBUG_FS)
++static int ralink_i2s_stats_show(struct seq_file *s, void *unused)
++{
++        struct ralink_i2s *i2s = s->private;
++
++	seq_printf(s, "tx stats\n");
++	seq_printf(s, "\tbelow threshold\t%u\n", i2s->txstats.belowthres);
++	seq_printf(s, "\tunder run\t%u\n", i2s->txstats.underrun);
++	seq_printf(s, "\tover run\t%u\n", i2s->txstats.overrun);
++	seq_printf(s, "\tdma fault\t%u\n", i2s->txstats.dmafault);
++
++	seq_printf(s, "rx stats\n");
++	seq_printf(s, "\tbelow threshold\t%u\n", i2s->rxstats.belowthres);
++	seq_printf(s, "\tunder run\t%u\n", i2s->rxstats.underrun);
++	seq_printf(s, "\tover run\t%u\n", i2s->rxstats.overrun);
++	seq_printf(s, "\tdma fault\t%u\n", i2s->rxstats.dmafault);
++
++	ralink_i2s_dump_regs(i2s);
++
++	return 0;
++}
++
++static int ralink_i2s_stats_open(struct inode *inode, struct file *file)
++{
++        return single_open(file, ralink_i2s_stats_show, inode->i_private);
++}
++
++static const struct file_operations ralink_i2s_stats_ops = {
++        .open = ralink_i2s_stats_open,
++        .read = seq_read,
++        .llseek = seq_lseek,
++        .release = single_release,
++};
++
++static inline int ralink_i2s_debugfs_create(struct ralink_i2s *i2s)
++{
++        i2s->dbg_dir = debugfs_create_dir(dev_name(i2s->dev), NULL);
++        if (!i2s->dbg_dir)
++                return -ENOMEM;
++
++        i2s->dbg_stats = debugfs_create_file("stats", S_IRUGO,
++                        i2s->dbg_dir, i2s, &ralink_i2s_stats_ops);
++        if (!i2s->dbg_stats) {
++                debugfs_remove(i2s->dbg_dir);
++                return -ENOMEM;
++        }
++
++        return 0;
++}
++
++static inline void ralink_i2s_debugfs_remove(struct ralink_i2s *i2s)
++{
++	debugfs_remove(i2s->dbg_stats);
++	debugfs_remove(i2s->dbg_dir);
++}
++#else
++static inline int ralink_i2s_debugfs_create(struct ralink_i2s *i2s)
++{
++	return 0;
++}
++
++static inline void ralink_i2s_debugfs_remove(struct fsl_ssi_dbg *ssi_dbg)
++{
++}
++#endif
++
++/*
++ * TODO: these refclk setup functions should use
++ * clock framework instead. hardcode it now.
++ */
++static void rt3350_refclk_setup(void)
++{
++	uint32_t data;
++
++	/* set refclk output 12Mhz clock */
++	data = rt_sysc_r32(0x2c);
++	data |= (0x1 << 8);
++	rt_sysc_w32(data, 0x2c);
++}
++
++static void rt3883_refclk_setup(void)
++{
++	uint32_t data;
++
++	/* set refclk output 12Mhz clock */
++	data = rt_sysc_r32(0x2c);
++	data &= ~(0x3 << 13);
++	data |= (0x1 << 13);
++	rt_sysc_w32(data, 0x2c);
++}
++
++static void rt3552_refclk_setup(void)
++{
++	uint32_t data;
++
++	/* set refclk output 12Mhz clock */
++	data = rt_sysc_r32(0x2c);
++	data &= ~(0xf << 8);
++	data |= (0x3 << 8);
++	rt_sysc_w32(data, 0x2c);
++}
++
++static void mt7620_refclk_setup(void)
++{
++	uint32_t data;
++
++	/* set refclk output 12Mhz clock */
++	data = rt_sysc_r32(0x2c);
++	data &= ~(0x7 << 9);
++	data |= 0x1 << 9;
++	rt_sysc_w32(data, 0x2c);
++}
++
++static void mt7621_refclk_setup(void)
++{
++	uint32_t data;
++
++	/* set refclk output 12Mhz clock */
++	data = rt_sysc_r32(0x2c);
++	data &= ~(0x1f << 18);
++	data |= (0x19 << 18);
++	data &= ~(0x1f << 12);
++	data |= (0x1 << 12);
++	data &= ~(0x7 << 9);
++	data |= (0x5 << 9);
++	rt_sysc_w32(data, 0x2c);
++}
++
++static void mt7628_refclk_setup(void)
++{
++	uint32_t data;
++
++	/* set i2s and refclk digital pad */
++	data = rt_sysc_r32(0x3c);
++	data |= 0x1f;
++	rt_sysc_w32(data, 0x3c);
++
++	/* Adjust REFCLK0's driving strength */
++	data = rt_sysc_r32(0x1354);
++	data &= ~(0x1 << 5);
++	rt_sysc_w32(data, 0x1354);
++	data = rt_sysc_r32(0x1364);
++	data |= ~(0x1 << 5);
++	rt_sysc_w32(data, 0x1364);
++
++	/* set refclk output 12Mhz clock */
++	data = rt_sysc_r32(0x2c);
++	data &= ~(0x7 << 9);
++	data |= 0x1 << 9;
++	rt_sysc_w32(data, 0x2c);
++}
++
++struct rt_i2s_data {
++	u32 flags;
++	void (*refclk_setup)(void);
++};
++
++struct rt_i2s_data rt3050_i2s_data = { .flags = RALINK_FLAGS_TXONLY };
++struct rt_i2s_data rt3350_i2s_data = { .flags = RALINK_FLAGS_TXONLY,
++	.refclk_setup = rt3350_refclk_setup };
++struct rt_i2s_data rt3883_i2s_data = {
++	.flags = (RALINK_FLAGS_LEFT_J | RALINK_FLAGS_RIGHT_J),
++	.refclk_setup = rt3883_refclk_setup };
++struct rt_i2s_data rt3352_i2s_data = { .refclk_setup = rt3552_refclk_setup};
++struct rt_i2s_data mt7620_i2s_data = { .refclk_setup = mt7620_refclk_setup};
++struct rt_i2s_data mt7621_i2s_data = { .refclk_setup = mt7621_refclk_setup};
++struct rt_i2s_data mt7628_i2s_data = {
++	.flags = (RALINK_FLAGS_ENDIAN | RALINK_FLAGS_24BIT |
++			RALINK_FLAGS_LEFT_J),
++	.refclk_setup = mt7628_refclk_setup};
++
++static const struct of_device_id ralink_i2s_match_table[] = {
++	{ .compatible = "ralink,rt3050-i2s",
++		.data = (void *)&rt3050_i2s_data },
++	{ .compatible = "ralink,rt3350-i2s",
++		.data = (void *)&rt3350_i2s_data },
++	{ .compatible = "ralink,rt3883-i2s",
++		.data = (void *)&rt3883_i2s_data },
++	{ .compatible = "ralink,rt3352-i2s",
++		.data = (void *)&rt3352_i2s_data },
++	{ .compatible = "mediatek,mt7620-i2s",
++		.data = (void *)&mt7620_i2s_data },
++	{ .compatible = "mediatek,mt7621-i2s",
++		.data = (void *)&mt7621_i2s_data },
++	{ .compatible = "mediatek,mt7628-i2s",
++		.data = (void *)&mt7628_i2s_data },
++};
++MODULE_DEVICE_TABLE(of, ralink_i2s_match_table);
++
++static int ralink_i2s_probe(struct platform_device *pdev)
++{
++	const struct of_device_id *match;
++	struct device_node *np = pdev->dev.of_node;
++	struct ralink_i2s *i2s;
++	struct resource *res;
++	int irq, ret;
++	u32 dma_req;
++	struct rt_i2s_data *data;
++
++	i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
++	if (!i2s)
++		return -ENOMEM;
++
++	platform_set_drvdata(pdev, i2s);
++	i2s->dev = &pdev->dev;
++
++	match = of_match_device(ralink_i2s_match_table, &pdev->dev);
++	if (!match)
++		return -EINVAL;
++	data = (struct rt_i2s_data *)match->data;
++	i2s->flags = data->flags;
++	/* setup out 12Mhz refclk to codec as mclk */
++	if (data->refclk_setup)
++		data->refclk_setup();
++
++	if (of_property_read_u32(np, "txdma-req", &dma_req)) {
++		dev_err(&pdev->dev, "no txdma-req define\n");
++		return -EINVAL;
++	}
++	i2s->txdma_req = (u16)dma_req;
++	if (!(i2s->flags & RALINK_FLAGS_TXONLY)) {
++		if (of_property_read_u32(np, "rxdma-req", &dma_req)) {
++			dev_err(&pdev->dev, "no rxdma-req define\n");
++			return -EINVAL;
++		}
++		i2s->rxdma_req = (u16)dma_req;
++	}
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	i2s->regs = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(i2s->regs))
++		return PTR_ERR(i2s->regs);
++
++	i2s->regmap = devm_regmap_init_mmio(&pdev->dev, i2s->regs,
++			&ralink_i2s_regmap_config);
++	if (IS_ERR(i2s->regmap)) {
++		dev_err(&pdev->dev, "regmap init failed\n");
++		return PTR_ERR(i2s->regmap);
++	}
++
++        irq = platform_get_irq(pdev, 0);
++        if (irq < 0) {
++                dev_err(&pdev->dev, "failed to get irq\n");
++                return -EINVAL;
++        }
++
++#if (RALINK_I2S_INT_EN)
++	ret = devm_request_irq(&pdev->dev, irq, ralink_i2s_irq,
++			0, dev_name(&pdev->dev), i2s);
++	if (ret) {
++		dev_err(&pdev->dev, "failed to request irq\n");
++		return ret;
++	}
++#endif
++
++	i2s->clk = devm_clk_get(&pdev->dev, NULL);
++	if (IS_ERR(i2s->clk)) {
++		dev_err(&pdev->dev, "no clock defined\n");
++		return PTR_ERR(i2s->clk);
++	}
++
++	ret = clk_prepare_enable(i2s->clk);
++	if (ret)
++		return ret;
++
++	ralink_i2s_init_dma_data(i2s, res);
++
++	device_reset(&pdev->dev);
++
++	ret = ralink_i2s_debugfs_create(i2s);
++	if (ret) {
++		dev_err(&pdev->dev, "create debugfs failed\n");
++		goto err_clk_disable;
++	}
++
++	/* enable 24bits support */
++	if (i2s->flags & RALINK_FLAGS_24BIT) {
++		ralink_i2s_dai.capture.formats |= SNDRV_PCM_FMTBIT_S24_LE;
++		ralink_i2s_dai.playback.formats |= SNDRV_PCM_FMTBIT_S24_LE;
++	}
++
++	/* enable big endian support */
++	if (i2s->flags & RALINK_FLAGS_ENDIAN) {
++		ralink_i2s_dai.capture.formats |= SNDRV_PCM_FMTBIT_S16_BE;
++		ralink_i2s_dai.playback.formats |= SNDRV_PCM_FMTBIT_S16_BE;
++		ralink_pcm_hardware.formats |= SNDRV_PCM_FMTBIT_S16_BE;
++		if (i2s->flags & RALINK_FLAGS_24BIT) {
++			ralink_i2s_dai.capture.formats |=
++				SNDRV_PCM_FMTBIT_S24_BE;
++			ralink_i2s_dai.playback.formats |=
++				SNDRV_PCM_FMTBIT_S24_BE;
++			ralink_pcm_hardware.formats |=
++				SNDRV_PCM_FMTBIT_S24_BE;
++		}
++	}
++
++	/* disable capture support */
++	if (i2s->flags & RALINK_FLAGS_TXONLY)
++		memset(&ralink_i2s_dai.capture, sizeof(ralink_i2s_dai.capture),
++				0);
++
++	ret = devm_snd_soc_register_component(&pdev->dev, &ralink_i2s_component,
++			&ralink_i2s_dai, 1);
++	if (ret)
++		goto err_debugfs;
++
++	ret = devm_snd_dmaengine_pcm_register(&pdev->dev,
++			&ralink_dmaengine_pcm_config,
++			SND_DMAENGINE_PCM_FLAG_COMPAT);
++	if (ret)
++		goto err_debugfs;
++
++	dev_info(i2s->dev, "mclk %luMHz\n", clk_get_rate(i2s->clk) / 1000000);
++
++	return 0;
++
++err_debugfs:
++	ralink_i2s_debugfs_remove(i2s);
++
++err_clk_disable:
++	clk_disable_unprepare(i2s->clk);
++
++	return ret;
++}
++
++static int ralink_i2s_remove(struct platform_device *pdev)
++{
++	struct ralink_i2s *i2s = platform_get_drvdata(pdev);
++
++	ralink_i2s_debugfs_remove(i2s);
++	clk_disable_unprepare(i2s->clk);
++
++	return 0;
++}
++
++static struct platform_driver ralink_i2s_driver = {
++	.probe = ralink_i2s_probe,
++	.remove = ralink_i2s_remove,
++	.driver = {
++		.name = DRV_NAME,
++		.of_match_table = ralink_i2s_match_table,
++	},
++};
++module_platform_driver(ralink_i2s_driver);
++
++MODULE_AUTHOR("Lars-Peter Clausen, <lars at metafoo.de>");
++MODULE_DESCRIPTION("Ralink/MediaTek I2S driver");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/target/linux/ramips/patches-5.10/840-serial-add-ugly-custom-baud-rate-hack.patch b/target/linux/ramips/patches-5.10/840-serial-add-ugly-custom-baud-rate-hack.patch
new file mode 100644
index 0000000000..634033d18d
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/840-serial-add-ugly-custom-baud-rate-hack.patch
@@ -0,0 +1,22 @@
+From a7eb46e0ea4a11e4dfb56ab129bf816d1059a6c5 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic at openwrt.org>
+Date: Mon, 7 Dec 2015 17:31:08 +0100
+Subject: [PATCH 51/53] serial: add ugly custom baud rate hack
+
+Signed-off-by: John Crispin <blogic at openwrt.org>
+---
+ drivers/tty/serial/serial_core.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/tty/serial/serial_core.c
++++ b/drivers/tty/serial/serial_core.c
+@@ -418,6 +418,9 @@ uart_get_baud_rate(struct uart_port *por
+ 		break;
+ 	}
+ 
++	if (tty_termios_baud_rate(termios) == 2500000)
++		return 250000;
++
+ 	for (try = 0; try < 2; try++) {
+ 		baud = tty_termios_baud_rate(termios);
+ 
diff --git a/target/linux/ramips/patches-5.10/845-pwm-add-mediatek-support.patch b/target/linux/ramips/patches-5.10/845-pwm-add-mediatek-support.patch
new file mode 100644
index 0000000000..794e3360fb
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/845-pwm-add-mediatek-support.patch
@@ -0,0 +1,217 @@
+From fc8f96309c21c1bc3276427309cd7d361347d66e Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic at openwrt.org>
+Date: Mon, 7 Dec 2015 17:16:50 +0100
+Subject: [PATCH 52/53] pwm: add mediatek support
+
+Signed-off-by: John Crispin <blogic at openwrt.org>
+---
+ drivers/pwm/Kconfig        |    9 +++
+ drivers/pwm/Makefile       |    1 +
+ drivers/pwm/pwm-mediatek.c |  173 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 183 insertions(+)
+ create mode 100644 drivers/pwm/pwm-mediatek.c
+
+--- a/drivers/pwm/Kconfig
++++ b/drivers/pwm/Kconfig
+@@ -339,6 +339,15 @@ config PWM_MEDIATEK
+ 	  To compile this driver as a module, choose M here: the module
+ 	  will be called pwm-mediatek.
+ 
++config PWM_MEDIATEK_RAMIPS
++	tristate "Mediatek PWM support"
++	depends on RALINK && OF
++	help
++	  Generic PWM framework driver for Mediatek ARM SoC.
++
++	  To compile this driver as a module, choose M here: the module
++	  will be called pwm-mxs.
++
+ config PWM_MXS
+ 	tristate "Freescale MXS PWM support"
+ 	depends on OF
+--- a/drivers/pwm/Makefile
++++ b/drivers/pwm/Makefile
+@@ -30,6 +30,7 @@ obj-$(CONFIG_PWM_LPSS_PCI)	+= pwm-lpss-p
+ obj-$(CONFIG_PWM_LPSS_PLATFORM)	+= pwm-lpss-platform.o
+ obj-$(CONFIG_PWM_MESON)		+= pwm-meson.o
+ obj-$(CONFIG_PWM_MEDIATEK)	+= pwm-mediatek.o
++obj-$(CONFIG_PWM_MEDIATEK_RAMIPS)	+= pwm-mediatek-ramips.o
+ obj-$(CONFIG_PWM_MTK_DISP)	+= pwm-mtk-disp.o
+ obj-$(CONFIG_PWM_MXS)		+= pwm-mxs.o
+ obj-$(CONFIG_PWM_OMAP_DMTIMER)	+= pwm-omap-dmtimer.o
+--- /dev/null
++++ b/drivers/pwm/pwm-mediatek-ramips.c
+@@ -0,0 +1,173 @@
++/*
++ * Mediatek Pulse Width Modulator driver
++ *
++ * Copyright (C) 2015 John Crispin <blogic at openwrt.org>
++ *
++ * This file is licensed under the terms of the GNU General Public
++ * License version 2. This program is licensed "as is" without any
++ * warranty of any kind, whether express or implied.
++ */
++
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/pwm.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++
++#define NUM_PWM		4
++
++/* PWM registers and bits definitions */
++#define PWMCON			0x00
++#define PWMHDUR			0x04
++#define PWMLDUR			0x08
++#define PWMGDUR			0x0c
++#define PWMWAVENUM		0x28
++#define PWMDWIDTH		0x2c
++#define PWMTHRES		0x30
++
++/**
++ * struct mtk_pwm_chip - struct representing pwm chip
++ *
++ * @mmio_base: base address of pwm chip
++ * @chip: linux pwm chip representation
++ */
++struct mtk_pwm_chip {
++	void __iomem *mmio_base;
++	struct pwm_chip chip;
++};
++
++static inline struct mtk_pwm_chip *to_mtk_pwm_chip(struct pwm_chip *chip)
++{
++	return container_of(chip, struct mtk_pwm_chip, chip);
++}
++
++static inline u32 mtk_pwm_readl(struct mtk_pwm_chip *chip, unsigned int num,
++				  unsigned long offset)
++{
++	return ioread32(chip->mmio_base + 0x10 + (num * 0x40) + offset);
++}
++
++static inline void mtk_pwm_writel(struct mtk_pwm_chip *chip,
++				    unsigned int num, unsigned long offset,
++				    unsigned long val)
++{
++	iowrite32(val, chip->mmio_base + 0x10 + (num * 0x40) + offset);
++}
++
++static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
++			    int duty_ns, int period_ns)
++{
++	struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
++	u32 resolution = 100 / 4;
++	u32 clkdiv = 0;
++
++	while (period_ns / resolution  > 8191) {
++		clkdiv++;
++		resolution *= 2;
++	}
++
++	if (clkdiv > 7)
++		return -1;
++
++	mtk_pwm_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | BIT(3) | clkdiv);
++	mtk_pwm_writel(pc, pwm->hwpwm, PWMDWIDTH, period_ns / resolution);
++	mtk_pwm_writel(pc, pwm->hwpwm, PWMTHRES, duty_ns / resolution);
++	return 0;
++}
++
++static int mtk_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++	struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
++	u32 val;
++
++	val = ioread32(pc->mmio_base);
++	val |= BIT(pwm->hwpwm);
++	iowrite32(val, pc->mmio_base);
++
++	return 0;
++}
++
++static void mtk_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++	struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
++	u32 val;
++
++	val = ioread32(pc->mmio_base);
++	val &= ~BIT(pwm->hwpwm);
++	iowrite32(val, pc->mmio_base);
++}
++
++static const struct pwm_ops mtk_pwm_ops = {
++	.config = mtk_pwm_config,
++	.enable = mtk_pwm_enable,
++	.disable = mtk_pwm_disable,
++	.owner = THIS_MODULE,
++};
++
++static int mtk_pwm_probe(struct platform_device *pdev)
++{
++	struct mtk_pwm_chip *pc;
++	struct resource *r;
++	int ret;
++
++	pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
++	if (!pc)
++		return -ENOMEM;
++
++	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	pc->mmio_base = devm_ioremap_resource(&pdev->dev, r);
++	if (IS_ERR(pc->mmio_base))
++		return PTR_ERR(pc->mmio_base);
++
++	platform_set_drvdata(pdev, pc);
++
++	pc->chip.dev = &pdev->dev;
++	pc->chip.ops = &mtk_pwm_ops;
++	pc->chip.base = -1;
++	pc->chip.npwm = NUM_PWM;
++
++	ret = pwmchip_add(&pc->chip);
++	if (ret < 0)
++		dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
++
++	return ret;
++}
++
++static int mtk_pwm_remove(struct platform_device *pdev)
++{
++	struct mtk_pwm_chip *pc = platform_get_drvdata(pdev);
++	int i;
++
++	for (i = 0; i < NUM_PWM; i++)
++		pwm_disable(&pc->chip.pwms[i]);
++
++	return pwmchip_remove(&pc->chip);
++}
++
++static const struct of_device_id mtk_pwm_of_match[] = {
++	{ .compatible = "mediatek,mt7628-pwm" },
++	{ }
++};
++
++MODULE_DEVICE_TABLE(of, mtk_pwm_of_match);
++
++static struct platform_driver mtk_pwm_driver = {
++	.driver = {
++		.name = "mtk-pwm",
++		.owner = THIS_MODULE,
++		.of_match_table = mtk_pwm_of_match,
++	},
++	.probe = mtk_pwm_probe,
++	.remove = mtk_pwm_remove,
++};
++
++module_platform_driver(mtk_pwm_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("John Crispin <blogic at openwrt.org>");
++MODULE_ALIAS("platform:mtk-pwm");
diff --git a/target/linux/ramips/patches-5.10/850-awake-rt305x-dwc2-controller.patch b/target/linux/ramips/patches-5.10/850-awake-rt305x-dwc2-controller.patch
new file mode 100644
index 0000000000..19c8ec877e
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/850-awake-rt305x-dwc2-controller.patch
@@ -0,0 +1,15 @@
+--- a/drivers/usb/dwc2/platform.c
++++ b/drivers/usb/dwc2/platform.c
+@@ -477,6 +477,12 @@ static int dwc2_driver_probe(struct plat
+ 	if (retval)
+ 		return retval;
+ 
++	/* Enable USB port before any regs access */
++	if (readl(hsotg->regs + PCGCTL) & 0x0f) {
++		writel(0x00, hsotg->regs + PCGCTL);
++		/* TODO: mdelay(25) here? vendor driver don't use it */
++	}
++
+ 	hsotg->needs_byte_swap = dwc2_check_core_endianness(hsotg);
+ 
+ 	retval = dwc2_get_dr_mode(hsotg);
diff --git a/target/linux/ramips/patches-5.10/855-linkit_bootstrap.patch b/target/linux/ramips/patches-5.10/855-linkit_bootstrap.patch
new file mode 100644
index 0000000000..379aa28ae2
--- /dev/null
+++ b/target/linux/ramips/patches-5.10/855-linkit_bootstrap.patch
@@ -0,0 +1,97 @@
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -50,6 +50,7 @@ obj-$(CONFIG_GENWQE)		+= genwqe/
+ obj-$(CONFIG_ECHO)		+= echo/
+ obj-$(CONFIG_CXL_BASE)		+= cxl/
+ obj-$(CONFIG_PCI_ENDPOINT_TEST)	+= pci_endpoint_test.o
++obj-$(CONFIG_SOC_MT7620)	+= linkit.o
+ obj-$(CONFIG_OCXL)		+= ocxl/
+ obj-y				+= cardreader/
+ obj-$(CONFIG_PVPANIC)   	+= pvpanic.o
+--- /dev/null
++++ b/drivers/misc/linkit.c
+@@ -0,0 +1,84 @@
++/*
++ *  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
++ *  publishhed by the Free Software Foundation.
++ *
++ *  Copyright (C) 2015 John Crispin <blogic at openwrt.org>
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/of.h>
++#include <linux/mtd/mtd.h>
++#include <linux/gpio.h>
++
++#define LINKIT_LATCH_GPIO	11
++
++struct linkit_hw_data {
++	char board[16];
++	char rev[16];
++};
++
++static void sanify_string(char *s)
++{
++	int i;
++
++	for (i = 0; i < 15; i++)
++		if (s[i] <= 0x20)
++			s[i] = '\0';
++	s[15] = '\0';
++}
++
++static int linkit_probe(struct platform_device *pdev)
++{
++	struct linkit_hw_data hw;
++	struct mtd_info *mtd;
++	size_t retlen;
++	int ret;
++
++	mtd = get_mtd_device_nm("factory");
++	if (IS_ERR(mtd))
++		return PTR_ERR(mtd);
++
++	ret = mtd_read(mtd, 0x400, sizeof(hw), &retlen, (u_char *) &hw);
++	put_mtd_device(mtd);
++
++	sanify_string(hw.board);
++	sanify_string(hw.rev);
++
++	dev_info(&pdev->dev, "Version  : %s\n", hw.board);
++	dev_info(&pdev->dev, "Revision : %s\n", hw.rev);
++
++	if (!strcmp(hw.board, "LINKITS7688")) {
++		dev_info(&pdev->dev, "setting up bootstrap latch\n");
++
++		if (devm_gpio_request(&pdev->dev, LINKIT_LATCH_GPIO, "bootstrap")) {
++			dev_err(&pdev->dev, "failed to setup bootstrap gpio\n");
++			return -1;
++		}
++		gpio_direction_output(LINKIT_LATCH_GPIO, 0);
++	}
++
++	return 0;
++}
++
++static const struct of_device_id linkit_match[] = {
++	{ .compatible = "mediatek,linkit" },
++	{},
++};
++MODULE_DEVICE_TABLE(of, linkit_match);
++
++static struct platform_driver linkit_driver = {
++	.probe = linkit_probe,
++	.driver = {
++		.name = "mtk-linkit",
++		.owner = THIS_MODULE,
++		.of_match_table = linkit_match,
++	},
++};
++
++int __init linkit_init(void)
++{
++	return platform_driver_register(&linkit_driver);
++}
++late_initcall_sync(linkit_init);
diff --git a/target/linux/ramips/rt288x/config-5.10 b/target/linux/ramips/rt288x/config-5.10
new file mode 100644
index 0000000000..2fbab0baf0
--- /dev/null
+++ b/target/linux/ramips/rt288x/config-5.10
@@ -0,0 +1,177 @@
+CONFIG_ARCH_32BIT_OFF_T=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_MMAP_RND_BITS_MAX=15
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_BLK_MQ_PCI=y
+CONFIG_CEVT_R4K=y
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
+CONFIG_CMDLINE_BOOL=y
+# CONFIG_CMDLINE_OVERRIDE is not set
+CONFIG_COMPAT_32BIT_TIME=y
+CONFIG_CPU_GENERIC_DUMP_TLB=y
+CONFIG_CPU_HAS_DIEI=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_CPU_HAS_RIXI=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_CPU_MIPS32=y
+# CONFIG_CPU_MIPS32_R1 is not set
+CONFIG_CPU_MIPS32_R2=y
+CONFIG_CPU_MIPSR2=y
+CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
+CONFIG_CPU_R4K_CACHE_TLB=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_CPU_SUPPORTS_MSA=y
+CONFIG_CRYPTO_LIB_POLY1305_RSIZE=2
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CSRC_R4K=y
+CONFIG_DMA_NONCOHERENT=y
+# CONFIG_DTB_RT2880_EVAL is not set
+CONFIG_DTB_RT_NONE=y
+CONFIG_DTC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_FIXED_PHY=y
+CONFIG_FW_LOADER_PAGED_BUF=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_GENERIC_ATOMIC64=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_CPU_AUTOPROBE=y
+CONFIG_GENERIC_GETTIMEOFDAY=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_GENERIC_IRQ_CHIP=y
+CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_LIB_ASHLDI3=y
+CONFIG_GENERIC_LIB_ASHRDI3=y
+CONFIG_GENERIC_LIB_CMPDI2=y
+CONFIG_GENERIC_LIB_LSHRDI3=y
+CONFIG_GENERIC_LIB_UCMPDI2=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_RALINK=y
+CONFIG_HANDLE_DOMAIN_IRQ=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HZ=250
+CONFIG_HZ_250=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_IP17XX_PHY=y
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_INTC=y
+CONFIG_IRQ_MIPS_CPU=y
+CONFIG_IRQ_WORK=y
+# CONFIG_KERNEL_ZSTD is not set
+CONFIG_LIBFDT=y
+CONFIG_LLD_VERSION=0
+CONFIG_LOCK_DEBUGGING_SUPPORT=y
+CONFIG_MDIO_BUS=y
+CONFIG_MDIO_DEVICE=y
+CONFIG_MEMFD_CREATE=y
+CONFIG_MIGRATION=y
+CONFIG_MIPS=y
+CONFIG_MIPS_ASID_BITS=8
+CONFIG_MIPS_ASID_SHIFT=0
+CONFIG_MIPS_CBPF_JIT=y
+CONFIG_MIPS_CLOCK_VSYSCALL=y
+# CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND is not set
+# CONFIG_MIPS_CMDLINE_DTB_EXTEND is not set
+# CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER is not set
+CONFIG_MIPS_CMDLINE_FROM_DTB=y
+# CONFIG_MIPS_ELF_APPENDED_DTB is not set
+CONFIG_MIPS_L1_CACHE_SHIFT=4
+CONFIG_MIPS_L1_CACHE_SHIFT_4=y
+CONFIG_MIPS_LD_CAN_LINK_VDSO=y
+# CONFIG_MIPS_NO_APPENDED_DTB is not set
+CONFIG_MIPS_RAW_APPENDED_DTB=y
+CONFIG_MIPS_SPRAM=y
+CONFIG_MODULES_USE_ELF_REL=y
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_SPLIT_LZMA_FW=y
+CONFIG_MTD_SPLIT_UIMAGE_FW=y
+CONFIG_MTD_SPLIT_WRGG_FW=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_PER_CPU_KM=y
+CONFIG_NET_RALINK_MDIO=y
+CONFIG_NET_RALINK_MDIO_RT2880=y
+CONFIG_NET_RALINK_RT2880=y
+CONFIG_NET_RALINK_SOC=y
+CONFIG_NET_VENDOR_RALINK=y
+CONFIG_NLS=m
+CONFIG_NO_GENERIC_PCI_IOPORT_MAP=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_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_DRIVERS_LEGACY=y
+# CONFIG_PCI_MT7621 is not set
+# CONFIG_PCI_MT7621_PHY is not set
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYLIB=y
+# CONFIG_PHY_RALINK_USB is not set
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_RT2880=y
+# CONFIG_PINCTRL_SINGLE is not set
+CONFIG_RALINK=y
+CONFIG_RALINK_WDT=y
+CONFIG_RESET_CONTROLLER=y
+CONFIG_SERIAL_8250_RT288X=y
+CONFIG_SERIAL_MCTRL_GPIO=y
+CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_SOC_MT7620 is not set
+# CONFIG_SOC_MT7621 is not set
+CONFIG_SOC_RT288X=y
+# CONFIG_SOC_RT305X is not set
+# CONFIG_SOC_RT3883 is not set
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_MEM=y
+# CONFIG_SPI_MT7621 is not set
+CONFIG_SPI_RT2880=y
+CONFIG_SRCU=y
+CONFIG_SWCONFIG=y
+CONFIG_SWPHY=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_SYS_HAS_CPU_MIPS32_R2=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_MIPS16=y
+CONFIG_SYS_SUPPORTS_ZBOOT=y
+CONFIG_TARGET_ISA_REV=2
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TINY_SRCU=y
+CONFIG_USB=m
+CONFIG_USB_COMMON=m
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB_EHCI_HCD_PLATFORM=m
+CONFIG_USB_OHCI_HCD=m
+CONFIG_USB_OHCI_HCD_PLATFORM=m
+CONFIG_USB_SUPPORT=y
+CONFIG_USE_OF=y
+CONFIG_WATCHDOG_CORE=y
diff --git a/target/linux/ramips/rt305x/config-5.10 b/target/linux/ramips/rt305x/config-5.10
new file mode 100644
index 0000000000..94ba19efbe
--- /dev/null
+++ b/target/linux/ramips/rt305x/config-5.10
@@ -0,0 +1,176 @@
+CONFIG_ARCH_32BIT_OFF_T=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_MMAP_RND_BITS_MAX=15
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_CEVT_R4K=y
+CONFIG_CEVT_SYSTICK_QUIRK=y
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLKEVT_RT3352=y
+CONFIG_CLKSRC_MMIO=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
+CONFIG_CMDLINE_BOOL=y
+# CONFIG_CMDLINE_OVERRIDE is not set
+CONFIG_COMPAT_32BIT_TIME=y
+CONFIG_CPU_GENERIC_DUMP_TLB=y
+CONFIG_CPU_HAS_DIEI=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_CPU_HAS_RIXI=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_CPU_MIPS32=y
+# CONFIG_CPU_MIPS32_R1 is not set
+CONFIG_CPU_MIPS32_R2=y
+CONFIG_CPU_MIPSR2=y
+CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
+CONFIG_CPU_R4K_CACHE_TLB=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_CPU_SUPPORTS_MSA=y
+CONFIG_CRYPTO_LIB_POLY1305_RSIZE=2
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CSRC_R4K=y
+CONFIG_DEBUG_PINCTRL=y
+CONFIG_DMA_NONCOHERENT=y
+# CONFIG_DTB_RT305X_EVAL is not set
+CONFIG_DTB_RT_NONE=y
+CONFIG_DTC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_FIXED_PHY=y
+CONFIG_FW_LOADER_PAGED_BUF=y
+CONFIG_GENERIC_ATOMIC64=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_CPU_AUTOPROBE=y
+CONFIG_GENERIC_GETTIMEOFDAY=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_GENERIC_IRQ_CHIP=y
+CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_LIB_ASHLDI3=y
+CONFIG_GENERIC_LIB_ASHRDI3=y
+CONFIG_GENERIC_LIB_CMPDI2=y
+CONFIG_GENERIC_LIB_LSHRDI3=y
+CONFIG_GENERIC_LIB_UCMPDI2=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_PHY=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_RALINK=y
+CONFIG_HANDLE_DOMAIN_IRQ=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HZ=250
+CONFIG_HZ_250=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_INTC=y
+CONFIG_IRQ_MIPS_CPU=y
+CONFIG_IRQ_WORK=y
+# CONFIG_KERNEL_ZSTD is not set
+CONFIG_LIBFDT=y
+CONFIG_LLD_VERSION=0
+CONFIG_LOCK_DEBUGGING_SUPPORT=y
+CONFIG_MDIO_BUS=y
+CONFIG_MDIO_DEVICE=y
+CONFIG_MEMFD_CREATE=y
+CONFIG_MFD_SYSCON=y
+CONFIG_MIGRATION=y
+CONFIG_MIPS=y
+CONFIG_MIPS_ASID_BITS=8
+CONFIG_MIPS_ASID_SHIFT=0
+CONFIG_MIPS_CBPF_JIT=y
+CONFIG_MIPS_CLOCK_VSYSCALL=y
+# CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND is not set
+# CONFIG_MIPS_CMDLINE_DTB_EXTEND is not set
+# CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER is not set
+CONFIG_MIPS_CMDLINE_FROM_DTB=y
+# CONFIG_MIPS_ELF_APPENDED_DTB is not set
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+CONFIG_MIPS_LD_CAN_LINK_VDSO=y
+# CONFIG_MIPS_NO_APPENDED_DTB is not set
+CONFIG_MIPS_RAW_APPENDED_DTB=y
+CONFIG_MIPS_SPRAM=y
+CONFIG_MODULES_USE_ELF_REL=y
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y
+CONFIG_MTD_SPI_NOR_USE_4K_SECTORS_LIMIT=16384
+CONFIG_MTD_SPLIT_JIMAGE_FW=y
+CONFIG_MTD_SPLIT_SEAMA_FW=y
+CONFIG_MTD_SPLIT_UIMAGE_FW=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_PER_CPU_KM=y
+CONFIG_NET_RALINK_ESW_RT3050=y
+CONFIG_NET_RALINK_RT3050=y
+CONFIG_NET_RALINK_SOC=y
+CONFIG_NET_VENDOR_RALINK=y
+CONFIG_NO_GENERIC_PCI_IOPORT_MAP=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_PCI_DRIVERS_LEGACY=y
+# CONFIG_PCI_MT7621 is not set
+# CONFIG_PCI_MT7621_PHY is not set
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYLIB=y
+CONFIG_PHY_RALINK_USB=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_RT2880=y
+# CONFIG_PINCTRL_SINGLE is not set
+CONFIG_RALINK=y
+# CONFIG_RALINK_ILL_ACC is not set
+CONFIG_RALINK_WDT=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_RESET_CONTROLLER=y
+CONFIG_SERIAL_8250_RT288X=y
+CONFIG_SERIAL_MCTRL_GPIO=y
+CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_SOC_MT7620 is not set
+# CONFIG_SOC_MT7621 is not set
+# CONFIG_SOC_RT288X is not set
+CONFIG_SOC_RT305X=y
+# CONFIG_SOC_RT3883 is not set
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_MEM=y
+# CONFIG_SPI_MT7621 is not set
+CONFIG_SPI_RT2880=y
+CONFIG_SRCU=y
+CONFIG_SWCONFIG=y
+CONFIG_SWPHY=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_SYS_HAS_CPU_MIPS32_R2=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_MIPS16=y
+CONFIG_SYS_SUPPORTS_ZBOOT=y
+CONFIG_TARGET_ISA_REV=2
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TIMER_OF=y
+CONFIG_TIMER_PROBE=y
+CONFIG_TINY_SRCU=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USE_OF=y
+CONFIG_WATCHDOG_CORE=y
diff --git a/target/linux/ramips/rt3883/config-5.10 b/target/linux/ramips/rt3883/config-5.10
new file mode 100644
index 0000000000..65b7be7ea4
--- /dev/null
+++ b/target/linux/ramips/rt3883/config-5.10
@@ -0,0 +1,177 @@
+CONFIG_AR8216_PHY=y
+CONFIG_ARCH_32BIT_OFF_T=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_MMAP_RND_BITS_MAX=15
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_BLK_MQ_PCI=y
+CONFIG_CEVT_R4K=y
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
+CONFIG_CMDLINE_BOOL=y
+# CONFIG_CMDLINE_OVERRIDE is not set
+CONFIG_COMPAT_32BIT_TIME=y
+CONFIG_CPU_GENERIC_DUMP_TLB=y
+CONFIG_CPU_HAS_DIEI=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_CPU_HAS_RIXI=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_CPU_MIPS32=y
+# CONFIG_CPU_MIPS32_R1 is not set
+CONFIG_CPU_MIPS32_R2=y
+CONFIG_CPU_MIPSR2=y
+CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
+CONFIG_CPU_R4K_CACHE_TLB=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_CPU_SUPPORTS_MSA=y
+CONFIG_CRYPTO_LIB_POLY1305_RSIZE=2
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CSRC_R4K=y
+CONFIG_DEBUG_PINCTRL=y
+CONFIG_DMA_NONCOHERENT=y
+# CONFIG_DTB_RT3883_EVAL is not set
+CONFIG_DTB_RT_NONE=y
+CONFIG_DTC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_FIXED_PHY=y
+CONFIG_FW_LOADER_PAGED_BUF=y
+CONFIG_GENERIC_ATOMIC64=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_CPU_AUTOPROBE=y
+CONFIG_GENERIC_GETTIMEOFDAY=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_GENERIC_IRQ_CHIP=y
+CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_LIB_ASHLDI3=y
+CONFIG_GENERIC_LIB_ASHRDI3=y
+CONFIG_GENERIC_LIB_CMPDI2=y
+CONFIG_GENERIC_LIB_LSHRDI3=y
+CONFIG_GENERIC_LIB_UCMPDI2=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_PHY=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_RALINK=y
+CONFIG_HANDLE_DOMAIN_IRQ=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HZ=250
+CONFIG_HZ_250=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_INTC=y
+CONFIG_IRQ_MIPS_CPU=y
+CONFIG_IRQ_WORK=y
+# CONFIG_KERNEL_ZSTD is not set
+CONFIG_LIBFDT=y
+CONFIG_LLD_VERSION=0
+CONFIG_LOCK_DEBUGGING_SUPPORT=y
+CONFIG_MDIO_BUS=y
+CONFIG_MDIO_DEVICE=y
+CONFIG_MEMFD_CREATE=y
+CONFIG_MFD_SYSCON=y
+CONFIG_MIGRATION=y
+CONFIG_MIPS=y
+CONFIG_MIPS_ASID_BITS=8
+CONFIG_MIPS_ASID_SHIFT=0
+CONFIG_MIPS_CBPF_JIT=y
+CONFIG_MIPS_CLOCK_VSYSCALL=y
+# CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND is not set
+# CONFIG_MIPS_CMDLINE_DTB_EXTEND is not set
+# CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER is not set
+CONFIG_MIPS_CMDLINE_FROM_DTB=y
+# CONFIG_MIPS_ELF_APPENDED_DTB is not set
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+CONFIG_MIPS_LD_CAN_LINK_VDSO=y
+# CONFIG_MIPS_NO_APPENDED_DTB is not set
+CONFIG_MIPS_RAW_APPENDED_DTB=y
+CONFIG_MIPS_SPRAM=y
+CONFIG_MODULES_USE_ELF_REL=y
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y
+CONFIG_MTD_SPI_NOR_USE_4K_SECTORS_LIMIT=16384
+CONFIG_MTD_SPLIT_SEAMA_FW=y
+CONFIG_MTD_SPLIT_UIMAGE_FW=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_PER_CPU_KM=y
+CONFIG_NET_RALINK_MDIO=y
+CONFIG_NET_RALINK_MDIO_RT2880=y
+CONFIG_NET_RALINK_RT3883=y
+CONFIG_NET_RALINK_SOC=y
+CONFIG_NET_VENDOR_RALINK=y
+CONFIG_NO_GENERIC_PCI_IOPORT_MAP=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_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_DRIVERS_LEGACY=y
+# CONFIG_PCI_MT7621 is not set
+# CONFIG_PCI_MT7621_PHY is not set
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYLIB=y
+CONFIG_PHY_RALINK_USB=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_RT2880=y
+# CONFIG_PINCTRL_SINGLE is not set
+CONFIG_RALINK=y
+CONFIG_RALINK_WDT=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_RESET_CONTROLLER=y
+CONFIG_RTL8366_SMI=y
+CONFIG_RTL8367B_PHY=y
+CONFIG_RTL8367_PHY=y
+CONFIG_SERIAL_8250_RT288X=y
+CONFIG_SERIAL_MCTRL_GPIO=y
+CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_SOC_MT7620 is not set
+# CONFIG_SOC_MT7621 is not set
+# CONFIG_SOC_RT288X is not set
+# CONFIG_SOC_RT305X is not set
+CONFIG_SOC_RT3883=y
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_MEM=y
+# CONFIG_SPI_MT7621 is not set
+CONFIG_SPI_RT2880=y
+CONFIG_SRCU=y
+CONFIG_SWCONFIG=y
+CONFIG_SWPHY=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_SYS_HAS_CPU_MIPS32_R2=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_MIPS16=y
+CONFIG_SYS_SUPPORTS_ZBOOT=y
+CONFIG_TARGET_ISA_REV=2
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TINY_SRCU=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USE_OF=y
+CONFIG_WATCHDOG_CORE=y



More information about the lede-commits mailing list