ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/package/kernel/mac80211/patches/rt2x00/002-rt2x00-define-RF5592-in-init_eeprom-routine.patch b/package/kernel/mac80211/patches/rt2x00/002-rt2x00-define-RF5592-in-init_eeprom-routine.patch
new file mode 100644
index 0000000..13298d3
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/002-rt2x00-define-RF5592-in-init_eeprom-routine.patch
@@ -0,0 +1,51 @@
+From patchwork Thu Dec 27 14:05:26 2018
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 8bit
+X-Patchwork-Submitter: Tom Psyborg <pozega.tomislav@gmail.com>
+X-Patchwork-Id: 10743707
+X-Patchwork-Delegate: kvalo@adurom.com
+From: =?utf-8?q?Tomislav_Po=C5=BEega?= <pozega.tomislav@gmail.com>
+To: linux-wireless@vger.kernel.org
+Cc: kvalo@codeaurora.org, hauke@hauke-m.de, nbd@nbd.name,
+        john@phrozen.org, sgruszka@redhat.com, daniel@makrotopia.org
+Subject: [PATCH 2/2] rt2x00: define RF5592 in init_eeprom routine
+Date: Thu, 27 Dec 2018 15:05:26 +0100
+Message-Id: <1545919526-4074-2-git-send-email-pozega.tomislav@gmail.com>
+X-Mailer: git-send-email 1.7.0.4
+In-Reply-To: <1545919526-4074-1-git-send-email-pozega.tomislav@gmail.com>
+References: <1545919526-4074-1-git-send-email-pozega.tomislav@gmail.com>
+MIME-Version: 1.0
+Sender: linux-wireless-owner@vger.kernel.org
+Precedence: bulk
+List-ID: <linux-wireless.vger.kernel.org>
+X-Mailing-List: linux-wireless@vger.kernel.org
+X-Virus-Scanned: ClamAV using ClamSMTP
+
+This patch fixes following crash on Linksys EA2750 during 5GHz wifi
+init:
+
+[    7.955153] rt2800pci 0000:01:00.0: card - bus=0x1, slot = 0x0 irq=4
+[    7.962259] rt2800pci 0000:01:00.0: loaded eeprom from mtd device "Factory"
+[    7.969435] ieee80211 phy0: rt2x00_set_rt: Info - RT chipset 5592, rev 0222 detected
+[    7.977348] ieee80211 phy0: rt2800_init_eeprom: Error - Invalid RF chipset 0x0000 detected
+[    7.985793] ieee80211 phy0: rt2x00lib_probe_dev: Error - Failed to allocate device
+[    7.993569] CPU 0 Unable to handle kernel paging request at virtual address 00000024, epc == 800c8f54, ra == 80249ff8
+[    8.004408] Oops[#1]:
+
+Signed-off-by: Tomislav Požega <pozega.tomislav@gmail.com>
+---
+ drivers/net/wireless/ralink/rt2x00/rt2800lib.c |    2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+@@ -9442,6 +9442,8 @@ static int rt2800_init_eeprom(struct rt2
+ 		rf = RF3853;
+ 	else if (rt2x00_rt(rt2x00dev, RT5350))
+ 		rf = RF5350;
++	else if (rt2x00_rt(rt2x00dev, RT5592))
++		rf = RF5592;
+ 	else
+ 		rf = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RF_TYPE);
+ 
diff --git a/package/kernel/mac80211/patches/rt2x00/100-rt2x00_options.patch b/package/kernel/mac80211/patches/rt2x00/100-rt2x00_options.patch
new file mode 100644
index 0000000..295904c
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/100-rt2x00_options.patch
@@ -0,0 +1,47 @@
+--- a/drivers/net/wireless/ralink/rt2x00/Kconfig
++++ b/drivers/net/wireless/ralink/rt2x00/Kconfig
+@@ -226,36 +226,37 @@ config RT2800SOC
+ 
+ 
+ config RT2800_LIB
+-	tristate
++	tristate "RT2800 USB/PCI support"
+ 	depends on m
+ 
+ config RT2800_LIB_MMIO
+-	tristate
++	tristate "RT2800 MMIO support"
+ 	depends on m
+ 	select RT2X00_LIB_MMIO
+ 	select RT2800_LIB
+ 
+ config RT2X00_LIB_MMIO
+-	tristate
++	tristate "RT2x00 MMIO support"
+ 	depends on m
+ 
+ config RT2X00_LIB_PCI
+-	tristate
++	tristate "RT2x00 PCI support"
+ 	depends on m
+ 	select RT2X00_LIB
+ 
+ config RT2X00_LIB_SOC
+-	tristate
++	tristate "RT2x00 SoC support"
++	depends on SOC_RT288X || SOC_RT305X || SOC_MT7620
+ 	depends on m
+ 	select RT2X00_LIB
+ 
+ config RT2X00_LIB_USB
+-	tristate
++	tristate "RT2x00 USB support"
+ 	depends on m
+ 	select RT2X00_LIB
+ 
+ config RT2X00_LIB
+-	tristate
++	tristate "RT2x00 support"
+ 	depends on m
+ 
+ config RT2X00_LIB_FIRMWARE
diff --git a/package/kernel/mac80211/patches/rt2x00/501-rt2x00-allow-to-build-rt2800soc-module-for-RT3883.patch b/package/kernel/mac80211/patches/rt2x00/501-rt2x00-allow-to-build-rt2800soc-module-for-RT3883.patch
new file mode 100644
index 0000000..b4106b0
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/501-rt2x00-allow-to-build-rt2800soc-module-for-RT3883.patch
@@ -0,0 +1,30 @@
+From 91094ed065f7794886b4a5490fd6de942f036bb4 Mon Sep 17 00:00:00 2001
+From: Gabor Juhos <juhosg@openwrt.org>
+Date: Sun, 24 Mar 2013 19:26:26 +0100
+Subject: [PATCH] rt2x00: allow to build rt2800soc module for RT3883
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ drivers/net/wireless/ralink/rt2x00/Kconfig |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/ralink/rt2x00/Kconfig
++++ b/drivers/net/wireless/ralink/rt2x00/Kconfig
+@@ -211,7 +211,7 @@ endif
+ config RT2800SOC
+ 	tristate "Ralink WiSoC support"
+ 	depends on m
+-	depends on SOC_RT288X || SOC_RT305X || SOC_MT7620
++	depends on SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620
+ 	select RT2X00_LIB_SOC
+ 	select RT2X00_LIB_MMIO
+ 	select RT2X00_LIB_CRYPTO
+@@ -246,7 +246,7 @@ config RT2X00_LIB_PCI
+ 
+ config RT2X00_LIB_SOC
+ 	tristate "RT2x00 SoC support"
+-	depends on SOC_RT288X || SOC_RT305X || SOC_MT7620
++	depends on SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620
+ 	depends on m
+ 	select RT2X00_LIB
+ 
diff --git a/package/kernel/mac80211/patches/rt2x00/601-rt2x00-introduce-rt2x00_platform_h.patch b/package/kernel/mac80211/patches/rt2x00/601-rt2x00-introduce-rt2x00_platform_h.patch
new file mode 100644
index 0000000..1e6211a
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/601-rt2x00-introduce-rt2x00_platform_h.patch
@@ -0,0 +1,32 @@
+--- /dev/null
++++ b/include/linux/rt2x00_platform.h
+@@ -0,0 +1,19 @@
++/*
++ * Platform data definition for the rt2x00 driver
++ *
++ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ */
++
++#ifndef _RT2X00_PLATFORM_H
++#define _RT2X00_PLATFORM_H
++
++struct rt2x00_platform_data {
++	char *eeprom_file_name;
++};
++
++#endif /* _RT2X00_PLATFORM_H */
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+@@ -28,6 +28,7 @@
+ #include <linux/average.h>
+ #include <linux/usb.h>
+ #include <linux/clk.h>
++#include <linux/rt2x00_platform.h>
+ 
+ #include <net/mac80211.h>
+ 
diff --git a/package/kernel/mac80211/patches/rt2x00/602-rt2x00-introduce-rt2x00eeprom.patch b/package/kernel/mac80211/patches/rt2x00/602-rt2x00-introduce-rt2x00eeprom.patch
new file mode 100644
index 0000000..e74d9a9
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/602-rt2x00-introduce-rt2x00eeprom.patch
@@ -0,0 +1,296 @@
+--- a/local-symbols
++++ b/local-symbols
+@@ -332,6 +332,7 @@ RT2X00_LIB_FIRMWARE=
+ RT2X00_LIB_CRYPTO=
+ RT2X00_LIB_LEDS=
+ RT2X00_LIB_DEBUGFS=
++RT2X00_LIB_EEPROM=
+ RT2X00_DEBUG=
+ WLAN_VENDOR_REALTEK=
+ RTL8180=
+--- a/drivers/net/wireless/ralink/rt2x00/Kconfig
++++ b/drivers/net/wireless/ralink/rt2x00/Kconfig
+@@ -70,6 +70,7 @@ config RT2800PCI
+ 	select RT2X00_LIB_MMIO
+ 	select RT2X00_LIB_PCI
+ 	select RT2X00_LIB_FIRMWARE
++	select RT2X00_LIB_EEPROM
+ 	select RT2X00_LIB_CRYPTO
+ 	depends on CRC_CCITT
+ 	depends on EEPROM_93CX6
+@@ -216,6 +217,7 @@ config RT2800SOC
+ 	select RT2X00_LIB_MMIO
+ 	select RT2X00_LIB_CRYPTO
+ 	select RT2X00_LIB_FIRMWARE
++	select RT2X00_LIB_EEPROM
+ 	select RT2800_LIB
+ 	select RT2800_LIB_MMIO
+ 	help
+@@ -266,6 +268,9 @@ config RT2X00_LIB_FIRMWARE
+ config RT2X00_LIB_CRYPTO
+ 	bool
+ 
++config RT2X00_LIB_EEPROM
++	bool
++
+ config RT2X00_LIB_LEDS
+ 	bool
+ 	default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n)
+--- a/drivers/net/wireless/ralink/rt2x00/Makefile
++++ b/drivers/net/wireless/ralink/rt2x00/Makefile
+@@ -8,6 +8,7 @@ rt2x00lib-$(CPTCFG_RT2X00_LIB_DEBUGFS)	+
+ rt2x00lib-$(CPTCFG_RT2X00_LIB_CRYPTO)	+= rt2x00crypto.o
+ rt2x00lib-$(CPTCFG_RT2X00_LIB_FIRMWARE)	+= rt2x00firmware.o
+ rt2x00lib-$(CPTCFG_RT2X00_LIB_LEDS)	+= rt2x00leds.o
++rt2x00lib-$(CPTCFG_RT2X00_LIB_EEPROM)	+= rt2x00eeprom.o
+ 
+ obj-$(CPTCFG_RT2X00_LIB)		+= rt2x00lib.o
+ obj-$(CPTCFG_RT2X00_LIB_MMIO)		+= rt2x00mmio.o
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+@@ -37,6 +37,8 @@ struct rt2800_drv_data {
+ 	struct ieee80211_sta *wcid_to_sta[STA_IDS_SIZE];
+ };
+ 
++#include "rt2800.h"
++
+ struct rt2800_ops {
+ 	u32 (*register_read)(struct rt2x00_dev *rt2x00dev,
+ 			      const unsigned int offset);
+@@ -135,6 +137,15 @@ static inline int rt2800_read_eeprom(str
+ {
+ 	const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
+ 
++	if (rt2x00dev->eeprom_file) {
++		memcpy(rt2x00dev->eeprom, rt2x00dev->eeprom_file->data,
++		       EEPROM_SIZE);
++		return 0;
++	}
++
++	if (!rt2800ops->read_eeprom)
++		return -EINVAL;
++
+ 	return rt2800ops->read_eeprom(rt2x00dev);
+ }
+ 
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+@@ -90,19 +90,6 @@ static int rt2800soc_set_device_state(st
+ 	return retval;
+ }
+ 
+-static int rt2800soc_read_eeprom(struct rt2x00_dev *rt2x00dev)
+-{
+-	void __iomem *base_addr = ioremap(0x1F040000, EEPROM_SIZE);
+-
+-	if (!base_addr)
+-		return -ENOMEM;
+-
+-	memcpy_fromio(rt2x00dev->eeprom, base_addr, EEPROM_SIZE);
+-
+-	iounmap(base_addr);
+-	return 0;
+-}
+-
+ /* Firmware functions */
+ static char *rt2800soc_get_firmware_name(struct rt2x00_dev *rt2x00dev)
+ {
+@@ -167,7 +154,6 @@ static const struct rt2800_ops rt2800soc
+ 	.register_multiread	= rt2x00mmio_register_multiread,
+ 	.register_multiwrite	= rt2x00mmio_register_multiwrite,
+ 	.regbusy_read		= rt2x00mmio_regbusy_read,
+-	.read_eeprom		= rt2800soc_read_eeprom,
+ 	.hwcrypt_disabled	= rt2800soc_hwcrypt_disabled,
+ 	.drv_write_firmware	= rt2800soc_write_firmware,
+ 	.drv_init_registers	= rt2800mmio_init_registers,
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+@@ -694,6 +694,7 @@ enum rt2x00_capability_flags {
+ 	REQUIRE_HT_TX_DESC,
+ 	REQUIRE_PS_AUTOWAKE,
+ 	REQUIRE_DELAYED_RFKILL,
++	REQUIRE_EEPROM_FILE,
+ 
+ 	/*
+ 	 * Capabilities
+@@ -970,6 +971,11 @@ struct rt2x00_dev {
+ 	const struct firmware *fw;
+ 
+ 	/*
++	 * EEPROM image.
++	 */
++	const struct firmware *eeprom_file;
++
++	/*
+ 	 * FIFO for storing tx status reports between isr and tasklet.
+ 	 */
+ 	DECLARE_KFIFO_PTR(txstatus_fifo, u32);
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+@@ -1406,6 +1406,10 @@ int rt2x00lib_probe_dev(struct rt2x00_de
+ 	INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup);
+ 	INIT_WORK(&rt2x00dev->sleep_work, rt2x00lib_sleep);
+ 
++	retval = rt2x00lib_load_eeprom_file(rt2x00dev);
++	if (retval)
++		goto exit;
++
+ 	/*
+ 	 * Let the driver probe the device to detect the capabilities.
+ 	 */
+@@ -1549,6 +1553,11 @@ void rt2x00lib_remove_dev(struct rt2x00_
+ 	 * Free the driver data.
+ 	 */
+ 	kfree(rt2x00dev->drv_data);
++
++	/*
++	 * Free EEPROM image.
++	 */
++	rt2x00lib_free_eeprom_file(rt2x00dev);
+ }
+ EXPORT_SYMBOL_GPL(rt2x00lib_remove_dev);
+ 
+--- /dev/null
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c
+@@ -0,0 +1,106 @@
++/*
++	Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
++	Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com>
++	<http://rt2x00.serialmonkey.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.
++
++	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.
++
++	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.,
++	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ */
++
++/*
++	Module: rt2x00lib
++	Abstract: rt2x00 eeprom file loading routines.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++
++#include "rt2x00.h"
++#include "rt2x00lib.h"
++
++static const char *
++rt2x00lib_get_eeprom_file_name(struct rt2x00_dev *rt2x00dev)
++{
++	struct rt2x00_platform_data *pdata = rt2x00dev->dev->platform_data;
++
++	if (pdata && pdata->eeprom_file_name)
++		return pdata->eeprom_file_name;
++
++	return NULL
++}
++
++static int rt2x00lib_request_eeprom_file(struct rt2x00_dev *rt2x00dev)
++{
++	const struct firmware *ee;
++	const char *ee_name;
++	int retval;
++
++	ee_name = rt2x00lib_get_eeprom_file_name(rt2x00dev);
++	if (!ee_name && test_bit(REQUIRE_EEPROM_FILE, &rt2x00dev->cap_flags)) {
++		rt2x00_err(rt2x00dev, "Required EEPROM name is missing.");
++		return -EINVAL;
++	}
++
++	if (!ee_name)
++		return 0;
++
++	rt2x00_info(rt2x00dev, "Loading EEPROM data from '%s'.\n", ee_name);
++
++	retval = request_firmware(&ee, ee_name, rt2x00dev->dev);
++	if (retval) {
++		rt2x00_err(rt2x00dev, "Failed to request EEPROM.\n");
++		return retval;
++	}
++
++	if (!ee || !ee->size || !ee->data) {
++		rt2x00_err(rt2x00dev, "Failed to read EEPROM file.\n");
++		retval = -ENOENT;
++		goto err_exit;
++	}
++
++	if (ee->size != rt2x00dev->ops->eeprom_size) {
++		rt2x00_err(rt2x00dev,
++			   "EEPROM file size is invalid, it should be %d bytes\n",
++			   rt2x00dev->ops->eeprom_size);
++		retval = -EINVAL;
++		goto err_release_ee;
++	}
++
++	rt2x00dev->eeprom_file = ee;
++	return 0;
++
++err_release_ee:
++	release_firmware(ee);
++err_exit:
++	return retval;
++}
++
++int rt2x00lib_load_eeprom_file(struct rt2x00_dev *rt2x00dev)
++{
++	int retval;
++
++	retval = rt2x00lib_request_eeprom_file(rt2x00dev);
++	if (retval)
++		return retval;
++
++	return 0;
++}
++
++void rt2x00lib_free_eeprom_file(struct rt2x00_dev *rt2x00dev)
++{
++	if (rt2x00dev->eeprom_file && rt2x00dev->eeprom_file->size)
++		release_firmware(rt2x00dev->eeprom_file);
++	rt2x00dev->eeprom_file = NULL;
++}
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00lib.h
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00lib.h
+@@ -286,6 +286,22 @@ static inline void rt2x00lib_free_firmwa
+ #endif /* CPTCFG_RT2X00_LIB_FIRMWARE */
+ 
+ /*
++ * EEPROM file handlers.
++ */
++#ifdef CPTCFG_RT2X00_LIB_EEPROM
++int rt2x00lib_load_eeprom_file(struct rt2x00_dev *rt2x00dev);
++void rt2x00lib_free_eeprom_file(struct rt2x00_dev *rt2x00dev);
++#else
++static inline int rt2x00lib_load_eeprom_file(struct rt2x00_dev *rt2x00dev)
++{
++	return 0;
++}
++static inline void rt2x00lib_free_eeprom_file(struct rt2x00_dev *rt2x00dev)
++{
++}
++#endif /* CPTCFG_RT2X00_LIB_EEPROM */
++
++/*
+  * Debugfs handlers.
+  */
+ #ifdef CPTCFG_RT2X00_LIB_DEBUGFS
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c
+@@ -86,6 +86,7 @@ int rt2x00soc_probe(struct platform_devi
+ 	if (IS_ERR(rt2x00dev->clk))
+ 		rt2x00dev->clk = NULL;
+ 
++	set_bit(REQUIRE_EEPROM_FILE, &rt2x00dev->cap_flags);
+ 	rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC);
+ 
+ 	retval = rt2x00soc_alloc_reg(rt2x00dev);
diff --git a/package/kernel/mac80211/patches/rt2x00/603-rt2x00-of_load_eeprom_filename.patch b/package/kernel/mac80211/patches/rt2x00/603-rt2x00-of_load_eeprom_filename.patch
new file mode 100644
index 0000000..9dffef1
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/603-rt2x00-of_load_eeprom_filename.patch
@@ -0,0 +1,33 @@
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c
+@@ -26,6 +26,7 @@
+ 
+ #include <linux/kernel.h>
+ #include <linux/module.h>
++#include <linux/of.h>
+ 
+ #include "rt2x00.h"
+ #include "rt2x00lib.h"
+@@ -34,11 +35,21 @@ static const char *
+ rt2x00lib_get_eeprom_file_name(struct rt2x00_dev *rt2x00dev)
+ {
+ 	struct rt2x00_platform_data *pdata = rt2x00dev->dev->platform_data;
++#ifdef CONFIG_OF
++	struct device_node *np;
++	const char *eep;
++#endif
+ 
+ 	if (pdata && pdata->eeprom_file_name)
+ 		return pdata->eeprom_file_name;
+ 
+-	return NULL
++#ifdef CONFIG_OF
++	np = rt2x00dev->dev->of_node;
++	if (np && of_property_read_string(np, "ralink,eeprom", &eep) == 0)
++	    return eep;
++#endif
++
++	return NULL;
+ }
+ 
+ static int rt2x00lib_request_eeprom_file(struct rt2x00_dev *rt2x00dev)
diff --git a/package/kernel/mac80211/patches/rt2x00/604-rt2x00-load-eeprom-on-SoC-from-a-mtd-device-defines-.patch b/package/kernel/mac80211/patches/rt2x00/604-rt2x00-load-eeprom-on-SoC-from-a-mtd-device-defines-.patch
new file mode 100644
index 0000000..7338eb1
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/604-rt2x00-load-eeprom-on-SoC-from-a-mtd-device-defines-.patch
@@ -0,0 +1,113 @@
+From 339fe73f340161a624cc08e738d2244814852c3e Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 17 Mar 2013 00:55:04 +0100
+Subject: [PATCH] rt2x00: load eeprom on SoC from a mtd device defines inside
+ OF
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/net/wireless/ralink/rt2x00/Kconfig        |  1 +
+ drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c | 65 +++++++++++++++++++++++
+ 2 files changed, 66 insertions(+)
+
+--- a/drivers/net/wireless/ralink/rt2x00/Kconfig
++++ b/drivers/net/wireless/ralink/rt2x00/Kconfig
+@@ -220,6 +220,7 @@ config RT2800SOC
+ 	select RT2X00_LIB_EEPROM
+ 	select RT2800_LIB
+ 	select RT2800_LIB_MMIO
++	select MTD if SOC_RT288X || SOC_RT305X
+ 	help
+ 	  This adds support for Ralink WiSoC devices.
+ 	  Supported chips: RT2880, RT3050, RT3052, RT3350, RT3352.
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c
+@@ -26,11 +26,76 @@
+ 
+ #include <linux/kernel.h>
+ #include <linux/module.h>
++#if IS_ENABLED(CONFIG_MTD)
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#endif
+ #include <linux/of.h>
+ 
+ #include "rt2x00.h"
+ #include "rt2x00lib.h"
+ 
++#if IS_ENABLED(CONFIG_MTD)
++static int rt2800lib_read_eeprom_mtd(struct rt2x00_dev *rt2x00dev)
++{
++	int ret = -EINVAL;
++#ifdef CONFIG_OF
++	static struct firmware mtd_fw;
++	struct device_node *np = rt2x00dev->dev->of_node, *mtd_np = NULL;
++	size_t retlen, len = rt2x00dev->ops->eeprom_size;
++	int i, size, offset = 0;
++	struct mtd_info *mtd;
++	const char *part;
++	const __be32 *list;
++	phandle phandle;
++
++	list = of_get_property(np, "ralink,mtd-eeprom", &size);
++	if (!list)
++		return -ENOENT;
++
++	phandle = be32_to_cpup(list++);
++	if (phandle)
++		mtd_np = of_find_node_by_phandle(phandle);
++	if (!mtd_np) {
++		dev_err(rt2x00dev->dev, "failed to load mtd phandle\n");
++		return -EINVAL;
++	}
++
++	part = of_get_property(mtd_np, "label", NULL);
++	if (!part)
++		part = mtd_np->name;
++
++	mtd = get_mtd_device_nm(part);
++	if (IS_ERR(mtd)) {
++		dev_err(rt2x00dev->dev, "failed to get mtd device \"%s\"\n", part);
++		return PTR_ERR(mtd);
++	}
++
++	if (size > sizeof(*list))
++		offset = be32_to_cpup(list);
++
++	ret = mtd_read(mtd, offset, len, &retlen, (u_char *) rt2x00dev->eeprom);
++	put_mtd_device(mtd);
++
++	if ((retlen != rt2x00dev->ops->eeprom_size) || ret) {
++		dev_err(rt2x00dev->dev, "failed to load eeprom from device \"%s\"\n", part);
++		return ret;
++	}
++
++	if (of_find_property(np, "ralink,mtd-eeprom-swap", NULL))
++		for (i = 0; i < len/sizeof(u16); i++)
++			rt2x00dev->eeprom[i] = swab16(rt2x00dev->eeprom[i]);
++
++	rt2x00dev->eeprom_file = &mtd_fw;
++	mtd_fw.data = (const u8 *) rt2x00dev->eeprom;
++
++	dev_info(rt2x00dev->dev, "loaded eeprom from mtd device \"%s\"\n", part);
++#endif
++
++	return ret;
++}
++#endif
++
+ static const char *
+ rt2x00lib_get_eeprom_file_name(struct rt2x00_dev *rt2x00dev)
+ {
+@@ -58,6 +123,11 @@ static int rt2x00lib_request_eeprom_file
+ 	const char *ee_name;
+ 	int retval;
+ 
++#if IS_ENABLED(CONFIG_MTD)
++	if (!rt2800lib_read_eeprom_mtd(rt2x00dev))
++		return 0;
++#endif
++
+ 	ee_name = rt2x00lib_get_eeprom_file_name(rt2x00dev);
+ 	if (!ee_name && test_bit(REQUIRE_EEPROM_FILE, &rt2x00dev->cap_flags)) {
+ 		rt2x00_err(rt2x00dev, "Required EEPROM name is missing.");
diff --git a/package/kernel/mac80211/patches/rt2x00/606-rt2x00-allow_disabling_bands_through_platform_data.patch b/package/kernel/mac80211/patches/rt2x00/606-rt2x00-allow_disabling_bands_through_platform_data.patch
new file mode 100644
index 0000000..6a8e594
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/606-rt2x00-allow_disabling_bands_through_platform_data.patch
@@ -0,0 +1,47 @@
+--- a/include/linux/rt2x00_platform.h
++++ b/include/linux/rt2x00_platform.h
+@@ -14,6 +14,9 @@
+ 
+ struct rt2x00_platform_data {
+ 	char *eeprom_file_name;
++
++	int disable_2ghz;
++	int disable_5ghz;
+ };
+ 
+ #endif /* _RT2X00_PLATFORM_H */
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+@@ -1012,6 +1012,22 @@ static int rt2x00lib_probe_hw_modes(stru
+ 	unsigned int num_rates;
+ 	unsigned int i;
+ 
++	if (rt2x00dev->dev->platform_data) {
++		struct rt2x00_platform_data *pdata;
++
++		pdata = rt2x00dev->dev->platform_data;
++		if (pdata->disable_2ghz)
++			spec->supported_bands &= ~SUPPORT_BAND_2GHZ;
++		if (pdata->disable_5ghz)
++			spec->supported_bands &= ~SUPPORT_BAND_5GHZ;
++	}
++
++	if ((spec->supported_bands & SUPPORT_BAND_BOTH) == 0) {
++		rt2x00_err(rt2x00dev, "No supported bands\n");
++		return -EINVAL;
++	}
++
++
+ 	num_rates = 0;
+ 	if (spec->supported_rates & SUPPORT_RATE_CCK)
+ 		num_rates += 4;
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+@@ -399,6 +399,7 @@ struct hw_mode_spec {
+ 	unsigned int supported_bands;
+ #define SUPPORT_BAND_2GHZ	0x00000001
+ #define SUPPORT_BAND_5GHZ	0x00000002
++#define SUPPORT_BAND_BOTH	(SUPPORT_BAND_2GHZ | SUPPORT_BAND_5GHZ)
+ 
+ 	unsigned int supported_rates;
+ #define SUPPORT_RATE_CCK	0x00000001
diff --git a/package/kernel/mac80211/patches/rt2x00/607-rt2x00-add_platform_data_mac_addr.patch b/package/kernel/mac80211/patches/rt2x00/607-rt2x00-add_platform_data_mac_addr.patch
new file mode 100644
index 0000000..b5b2c61
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/607-rt2x00-add_platform_data_mac_addr.patch
@@ -0,0 +1,26 @@
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+@@ -990,8 +990,13 @@ static void rt2x00lib_rate(struct ieee80
+ 
+ void rt2x00lib_set_mac_address(struct rt2x00_dev *rt2x00dev, u8 *eeprom_mac_addr)
+ {
++	struct rt2x00_platform_data *pdata;
+ 	const char *mac_addr;
+ 
++	pdata = rt2x00dev->dev->platform_data;
++	if (pdata && pdata->mac_address)
++		ether_addr_copy(eeprom_mac_addr, pdata->mac_address);
++
+ 	mac_addr = of_get_mac_address(rt2x00dev->dev->of_node);
+ 	if (!IS_ERR(mac_addr))
+ 		ether_addr_copy(eeprom_mac_addr, mac_addr);
+--- a/include/linux/rt2x00_platform.h
++++ b/include/linux/rt2x00_platform.h
+@@ -14,6 +14,7 @@
+ 
+ struct rt2x00_platform_data {
+ 	char *eeprom_file_name;
++	const u8 *mac_address;
+ 
+ 	int disable_2ghz;
+ 	int disable_5ghz;
diff --git a/package/kernel/mac80211/patches/rt2x00/608-rt2x00-allow_disabling_bands_through_dts.patch b/package/kernel/mac80211/patches/rt2x00/608-rt2x00-allow_disabling_bands_through_dts.patch
new file mode 100644
index 0000000..ff8b2c9
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/608-rt2x00-allow_disabling_bands_through_dts.patch
@@ -0,0 +1,19 @@
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+@@ -1016,6 +1016,16 @@ static int rt2x00lib_probe_hw_modes(stru
+ 	struct ieee80211_rate *rates;
+ 	unsigned int num_rates;
+ 	unsigned int i;
++#ifdef CONFIG_OF
++	struct device_node *np = rt2x00dev->dev->of_node;
++	unsigned int enabled;
++	if (!of_property_read_u32(np, "ralink,2ghz",
++                                          &enabled) && !enabled)
++		spec->supported_bands &= ~SUPPORT_BAND_2GHZ;
++	if (!of_property_read_u32(np, "ralink,5ghz",
++                                          &enabled) && !enabled)
++		spec->supported_bands &= ~SUPPORT_BAND_5GHZ;
++#endif /* CONFIG_OF */
+ 
+ 	if (rt2x00dev->dev->platform_data) {
+ 		struct rt2x00_platform_data *pdata;
diff --git a/package/kernel/mac80211/patches/rt2x00/609-rt2x00-make-wmac-loadable-via-OF-on-rt288x-305x-SoC.patch b/package/kernel/mac80211/patches/rt2x00/609-rt2x00-make-wmac-loadable-via-OF-on-rt288x-305x-SoC.patch
new file mode 100644
index 0000000..38f8b77
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/609-rt2x00-make-wmac-loadable-via-OF-on-rt288x-305x-SoC.patch
@@ -0,0 +1,33 @@
+From 04dbd87265f6ba4a373b211ba324b437d224fb2d Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 17 Mar 2013 00:03:31 +0100
+Subject: [PATCH 21/38] rt2x00: make wmac loadable via OF on rt288x/305x SoC
+
+This patch ads the match table to allow loading the wmac support from a
+devicetree.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/net/wireless/ralink/rt2x00/rt2800pci.c |    7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+@@ -224,10 +224,17 @@ static int rt2800soc_probe(struct platfo
+ 	return rt2x00soc_probe(pdev, &rt2800soc_ops);
+ }
+ 
++static const struct of_device_id rt2880_wmac_match[] = {
++	{ .compatible = "ralink,rt2880-wmac" },
++	{},
++};
++MODULE_DEVICE_TABLE(of, rt2880_wmac_match);
++
+ static struct platform_driver rt2800soc_driver = {
+ 	.driver		= {
+ 		.name		= "rt2800_wmac",
+ 		.mod_name	= KBUILD_MODNAME,
++		.of_match_table	= rt2880_wmac_match,
+ 	},
+ 	.probe		= rt2800soc_probe,
+ 	.remove		= rt2x00soc_remove,
diff --git a/package/kernel/mac80211/patches/rt2x00/610-rt2x00-change-led-polarity-from-OF.patch b/package/kernel/mac80211/patches/rt2x00/610-rt2x00-change-led-polarity-from-OF.patch
new file mode 100644
index 0000000..87f1ab4
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/610-rt2x00-change-led-polarity-from-OF.patch
@@ -0,0 +1,40 @@
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+@@ -25,6 +25,7 @@
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/slab.h>
++#include <linux/of.h>
+ 
+ #include "rt2x00.h"
+ #include "rt2800lib.h"
+@@ -9556,6 +9557,17 @@ static int rt2800_init_eeprom(struct rt2
+ 	rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC);
+ 	rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY);
+ 
++	{
++		struct device_node *np = rt2x00dev->dev->of_node;
++		unsigned int led_polarity;
++
++		/* Allow overriding polarity from OF */
++		if (!of_property_read_u32(np, "ralink,led-polarity",
++					  &led_polarity))
++			rt2x00_set_field16(&eeprom, EEPROM_FREQ_LED_POLARITY,
++					   led_polarity);
++	}
++
+ 	rt2x00dev->led_mcu_reg = eeprom;
+ #endif /* CPTCFG_RT2X00_LIB_LEDS */
+ 
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00leds.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00leds.c
+@@ -98,6 +98,9 @@ static int rt2x00leds_register_led(struc
+ 	led->led_dev.name = name;
+ 	led->led_dev.brightness = LED_OFF;
+ 
++	if (rt2x00_is_soc(rt2x00dev))
++		led->led_dev.brightness_set(&led->led_dev, LED_OFF);
++
+ 	retval = led_classdev_register(device, &led->led_dev);
+ 	if (retval) {
+ 		rt2x00_err(rt2x00dev, "Failed to register led handler\n");
diff --git a/package/kernel/mac80211/patches/rt2x00/611-rt2x00-add-AP+STA-support.patch b/package/kernel/mac80211/patches/rt2x00/611-rt2x00-add-AP+STA-support.patch
new file mode 100644
index 0000000..88d6dd5
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/611-rt2x00-add-AP+STA-support.patch
@@ -0,0 +1,11 @@
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+@@ -1344,7 +1344,7 @@ static inline void rt2x00lib_set_if_comb
+ 	 */
+ 	if_limit = &rt2x00dev->if_limits_ap;
+ 	if_limit->max = rt2x00dev->ops->max_ap_intf;
+-	if_limit->types = BIT(NL80211_IFTYPE_AP);
++	if_limit->types = BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION);
+ #ifdef CPTCFG_MAC80211_MESH
+ 	if_limit->types |= BIT(NL80211_IFTYPE_MESH_POINT);
+ #endif
diff --git a/package/kernel/mac80211/patches/rt2x00/612-rt2x00-led-tpt-trigger-support.patch b/package/kernel/mac80211/patches/rt2x00/612-rt2x00-led-tpt-trigger-support.patch
new file mode 100644
index 0000000..fca1fb2
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/612-rt2x00-led-tpt-trigger-support.patch
@@ -0,0 +1,44 @@
+From: David Bauer <mail@david-bauer.net>
+Date: Mon, 16 Dec 2019 20:47:06 +0100
+Subject: [PATCH] rt2x00: add throughput LED trigger
+
+This adds a (currently missing) throughput LED trigger for the rt2x00
+driver. Previously, LED triggers had to be assigned to the netdev, which
+was limited to a single VAP.
+
+Signed-off-by: David Bauer <mail@david-bauer.net>
+Tested-by: Christoph Krapp <achterin@googlemail.com>
+
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+@@ -1129,6 +1129,19 @@ static void rt2x00lib_remove_hw(struct r
+ 	kfree(rt2x00dev->spec.channels_info);
+ }
+ 
++static const struct ieee80211_tpt_blink rt2x00_tpt_blink[] = {
++	{ .throughput = 0 * 1024, .blink_time = 334 },
++	{ .throughput = 1 * 1024, .blink_time = 260 },
++	{ .throughput = 2 * 1024, .blink_time = 220 },
++	{ .throughput = 5 * 1024, .blink_time = 190 },
++	{ .throughput = 10 * 1024, .blink_time = 170 },
++	{ .throughput = 25 * 1024, .blink_time = 150 },
++	{ .throughput = 54 * 1024, .blink_time = 130 },
++	{ .throughput = 120 * 1024, .blink_time = 110 },
++	{ .throughput = 265 * 1024, .blink_time = 80 },
++	{ .throughput = 586 * 1024, .blink_time = 50 },
++};
++
+ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
+ {
+ 	struct hw_mode_spec *spec = &rt2x00dev->spec;
+@@ -1210,6 +1223,10 @@ static int rt2x00lib_probe_hw(struct rt2
+ 
+ #undef RT2X00_TASKLET_INIT
+ 
++	ieee80211_create_tpt_led_trigger(rt2x00dev->hw,
++		IEEE80211_TPT_LEDTRIG_FL_RADIO, rt2x00_tpt_blink,
++		ARRAY_SIZE(rt2x00_tpt_blink));
++
+ 	/*
+ 	 * Register HW.
+ 	 */
diff --git a/package/kernel/mac80211/patches/rt2x00/650-rt2x00-add-support-for-external-PA-on-MT7620.patch b/package/kernel/mac80211/patches/rt2x00/650-rt2x00-add-support-for-external-PA-on-MT7620.patch
new file mode 100644
index 0000000..3de562d
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/650-rt2x00-add-support-for-external-PA-on-MT7620.patch
@@ -0,0 +1,107 @@
+From 9782a7f7488443568fa4d6088b73c9aff7eb8510 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Wed, 19 Apr 2017 16:14:53 +0200
+Subject: [PATCH] rt2x00: add support for external PA on MT7620
+To: Stanislaw Gruszka <sgruszka@redhat.com>
+Cc: Helmut Schaa <helmut.schaa@googlemail.com>,
+    linux-wireless@vger.kernel.org,
+    Kalle Valo <kvalo@codeaurora.org>
+Content-Type: text/plain; charset="UTF-8"
+Content-Transfer-Encoding: quoted-printable
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: Tomislav Po=C5=BEega <pozega.tomislav@gmail.com>
+[pozega.tomislav@gmail.com: use chanreg and dccal helpers.]
+
+---
+ drivers/net/wireless/ralink/rt2x00/rt2800.h    |  1 +
+ drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 70 +++++++++++++++++++++++++-
+ 2 files changed, 70 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800.h
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800.h
+@@ -2739,6 +2739,7 @@ enum rt2800_eeprom_word {
+ #define EEPROM_NIC_CONF2_RX_STREAM	FIELD16(0x000f)
+ #define EEPROM_NIC_CONF2_TX_STREAM	FIELD16(0x00f0)
+ #define EEPROM_NIC_CONF2_CRYSTAL	FIELD16(0x0600)
++#define EEPROM_NIC_CONF2_EXTERNAL_PA	FIELD16(0xc000)
+ 
+ /*
+  * EEPROM LNA
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+@@ -4360,6 +4360,45 @@ static void rt2800_config_channel(struct
+ 			rt2800_iq_calibrate(rt2x00dev, rf->channel);
+ 	}
+ 
++	if (rt2x00_rt(rt2x00dev, RT6352)) {
++		if (test_bit(CAPABILITY_EXTERNAL_PA_TX0,
++			     &rt2x00dev->cap_flags)) {
++			rt2x00_warn(rt2x00dev, "Using incomplete support for " \
++					       "external PA\n");
++			reg = rt2800_register_read(rt2x00dev, RF_CONTROL3);
++			reg |= 0x00000101;
++			rt2800_register_write(rt2x00dev, RF_CONTROL3, reg);
++
++			reg = rt2800_register_read(rt2x00dev, RF_BYPASS3);
++			reg |= 0x00000101;
++			rt2800_register_write(rt2x00dev, RF_BYPASS3, reg);
++
++			rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0x73);
++			rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0x73);
++			rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0x73);
++			rt2800_rfcsr_write_chanreg(rt2x00dev, 46, 0x27);
++			rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0xC8);
++			rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xA4);
++			rt2800_rfcsr_write_chanreg(rt2x00dev, 49, 0x05);
++			rt2800_rfcsr_write_chanreg(rt2x00dev, 54, 0x27);
++			rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0xC8);
++			rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xA4);
++			rt2800_rfcsr_write_chanreg(rt2x00dev, 57, 0x05);
++			rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x27);
++			rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0xC8);
++			rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xA4);
++			rt2800_rfcsr_write_chanreg(rt2x00dev, 61, 0x05);
++			rt2800_rfcsr_write_dccal(rt2x00dev, 05, 0x00);
++
++			rt2800_register_write(rt2x00dev, TX0_RF_GAIN_CORRECT,
++					      0x36303636);
++			rt2800_register_write(rt2x00dev, TX0_RF_GAIN_ATTEN,
++					      0x6C6C6B6C);
++			rt2800_register_write(rt2x00dev, TX1_RF_GAIN_ATTEN,
++					      0x6C6C6B6C);
++		}
++	}
++
+ 	bbp = rt2800_bbp_read(rt2x00dev, 4);
+ 	rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf));
+ 	rt2800_bbp_write(rt2x00dev, 4, bbp);
+@@ -9585,7 +9624,8 @@ static int rt2800_init_eeprom(struct rt2
+ 	 */
+ 	eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1);
+ 
+-	if (rt2x00_rt(rt2x00dev, RT3352)) {
++	if (rt2x00_rt(rt2x00dev, RT3352) ||
++	    rt2x00_rt(rt2x00dev, RT6352)) {
+ 		if (rt2x00_get_field16(eeprom,
+ 		    EEPROM_NIC_CONF1_EXTERNAL_TX0_PA_3352))
+ 		    __set_bit(CAPABILITY_EXTERNAL_PA_TX0,
+@@ -9596,6 +9636,18 @@ static int rt2800_init_eeprom(struct rt2
+ 			      &rt2x00dev->cap_flags);
+ 	}
+ 
++	eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF2);
++
++	if (rt2x00_rt(rt2x00dev, RT6352) && eeprom != 0 && eeprom != 0xffff) {
++		if (rt2x00_get_field16(eeprom,
++		    EEPROM_NIC_CONF2_EXTERNAL_PA)) {
++		    __set_bit(CAPABILITY_EXTERNAL_PA_TX0,
++			      &rt2x00dev->cap_flags);
++		    __set_bit(CAPABILITY_EXTERNAL_PA_TX1,
++			      &rt2x00dev->cap_flags);
++		}
++	}
++
+ 	return 0;
+ }
+ 
diff --git a/package/kernel/mac80211/patches/rt2x00/982-rt2x00-add-rf-self-txdc-calibration.patch b/package/kernel/mac80211/patches/rt2x00/982-rt2x00-add-rf-self-txdc-calibration.patch
new file mode 100644
index 0000000..8064c4f
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/982-rt2x00-add-rf-self-txdc-calibration.patch
@@ -0,0 +1,67 @@
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+@@ -8445,6 +8445,56 @@ static void rt2800_init_rfcsr_5592(struc
+ 	rt2800_led_open_drain_enable(rt2x00dev);
+ }
+ 
++static void rt2800_rf_self_txdc_cal(struct rt2x00_dev *rt2x00dev)
++{
++	u8 rfb5r1_org, rfb7r1_org, rfvalue;
++	u32 mac0518, mac051c, mac0528, mac052c;
++	u8 i;
++
++	rt2x00_info(rt2x00dev, "RF Tx self calibration start\n");
++	mac0518 = rt2800_register_read(rt2x00dev, RF_CONTROL0);
++	mac051c = rt2800_register_read(rt2x00dev, RF_BYPASS0);
++	mac0528 = rt2800_register_read(rt2x00dev, RF_CONTROL2);
++	mac052c = rt2800_register_read(rt2x00dev, RF_BYPASS2);
++
++	rt2800_register_write(rt2x00dev, RF_BYPASS0, 0x0);
++	rt2800_register_write(rt2x00dev, RF_BYPASS2, 0x0);
++
++	rt2800_register_write(rt2x00dev, RF_CONTROL0, 0xC);
++	rt2800_register_write(rt2x00dev, RF_BYPASS0, 0x3306);
++	rt2800_register_write(rt2x00dev, RF_CONTROL2, 0x3330);
++	rt2800_register_write(rt2x00dev, RF_BYPASS2, 0xfffff);
++	rfb5r1_org = rt2800_rfcsr_read_bank(rt2x00dev, 5, 1);
++	rfb7r1_org = rt2800_rfcsr_read_bank(rt2x00dev, 7, 1);
++
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 1, 0x4);
++	for (i = 0; i < 100; i = i + 1) {
++		udelay(50);
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 5, 1);
++		if((rfvalue & 0x04) != 0x4)
++			break;
++	}
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 1, rfb5r1_org);
++
++	rt2800_rfcsr_write_bank(rt2x00dev, 7, 1, 0x4);
++	for (i = 0; i < 100; i = i + 1) {
++		udelay(50);
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 7, 1);
++		if((rfvalue & 0x04) != 0x4)
++			break;
++	}
++	rt2800_rfcsr_write_bank(rt2x00dev, 7, 1, rfb7r1_org);
++
++	rt2800_register_write(rt2x00dev, RF_BYPASS0, 0x0);
++	rt2800_register_write(rt2x00dev, RF_BYPASS2, 0x0);
++	rt2800_register_write(rt2x00dev, RF_CONTROL0, mac0518);
++	rt2800_register_write(rt2x00dev, RF_BYPASS0, mac051c);
++	rt2800_register_write(rt2x00dev, RF_CONTROL2, mac0528);
++	rt2800_register_write(rt2x00dev, RF_BYPASS2, mac052c);
++
++	rt2x00_info(rt2x00dev, "RF Tx self calibration end\n");
++}
++
+ static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev,
+ 				       bool set_bw, bool is_ht40)
+ {
+@@ -9052,6 +9102,7 @@ static void rt2800_init_rfcsr_6352(struc
+ 	rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00);
+ 	rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C);
+ 
++	rt2800_rf_self_txdc_cal(rt2x00dev);
+ 	rt2800_bw_filter_calibration(rt2x00dev, true);
+ 	rt2800_bw_filter_calibration(rt2x00dev, false);
+ }
diff --git a/package/kernel/mac80211/patches/rt2x00/983-rt2x00-add-r-calibration.patch b/package/kernel/mac80211/patches/rt2x00/983-rt2x00-add-r-calibration.patch
new file mode 100644
index 0000000..539a1b5
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/983-rt2x00-add-r-calibration.patch
@@ -0,0 +1,166 @@
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+@@ -8495,6 +8495,155 @@ static void rt2800_rf_self_txdc_cal(stru
+ 	rt2x00_info(rt2x00dev, "RF Tx self calibration end\n");
+ }
+ 
++static int rt2800_calcrcalibrationcode(struct rt2x00_dev *rt2x00dev, int d1, int d2)
++{
++	int calcode;
++	calcode = ((d2 - d1) * 1000) / 43;
++	if ((calcode%10) >= 5)
++		calcode += 10;
++	calcode = (calcode / 10);
++
++	return calcode;
++}
++
++static void rt2800_r_calibration(struct rt2x00_dev *rt2x00dev)
++{
++	u32 savemacsysctrl;
++	u8 saverfb0r1, saverfb0r34, saverfb0r35;
++	u8 saverfb5r4, saverfb5r17, saverfb5r18;
++	u8 saverfb5r19, saverfb5r20;
++	u8 savebbpr22, savebbpr47, savebbpr49;
++	u8 bytevalue = 0;
++	int rcalcode;
++	u8 r_cal_code = 0;
++	char d1 = 0, d2 = 0;
++	u8 rfvalue;
++	u32 MAC_RF_BYPASS0, MAC_RF_CONTROL0, MAC_PWR_PIN_CFG;
++	u32 maccfg, macstatus;
++	int i;
++
++	saverfb0r1 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 1);
++	saverfb0r34 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 34);
++	saverfb0r35 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 35);
++	saverfb5r4 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 4);
++	saverfb5r17 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 17);
++	saverfb5r18 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 18);
++	saverfb5r19 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 19);
++	saverfb5r20 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 20);
++
++	savebbpr22 = rt2800_bbp_read(rt2x00dev, 22);
++	savebbpr47 = rt2800_bbp_read(rt2x00dev, 47);
++	savebbpr49 = rt2800_bbp_read(rt2x00dev, 49);
++
++	savemacsysctrl = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
++	MAC_RF_BYPASS0 = rt2800_register_read(rt2x00dev, RF_BYPASS0);
++	MAC_RF_CONTROL0 = rt2800_register_read(rt2x00dev, RF_CONTROL0);
++	MAC_PWR_PIN_CFG = rt2800_register_read(rt2x00dev, PWR_PIN_CFG);
++
++	maccfg = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
++	maccfg &= (~0x04);
++	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, maccfg);
++
++	for (i = 0; i < 10000; i++) {
++		macstatus = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG);
++		if (macstatus & 0x1)
++			udelay(50);
++		else
++			break;
++	}
++
++	if (i == 10000)
++		rt2x00_warn(rt2x00dev, "Wait MAC Tx Status to MAX !!!\n");
++
++	maccfg = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
++	maccfg &= (~0x04);
++	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, maccfg);
++
++	for (i = 0; i < 10000; i++) {
++		macstatus = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG);
++		if (macstatus & 0x2)
++			udelay(50);
++		else
++			break;
++		}
++
++	if (i == 10000)
++		rt2x00_warn(rt2x00dev, "Wait MAC Rx Status to MAX !!!\n");
++
++	rfvalue = (MAC_RF_BYPASS0 | 0x3004);
++	rt2800_register_write(rt2x00dev, RF_BYPASS0, rfvalue);
++	rfvalue = (MAC_RF_CONTROL0 | (~0x3002));
++	rt2800_register_write(rt2x00dev, RF_CONTROL0, rfvalue);
++
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 4, 0x27);
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 17, 0x80);
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 18, 0x83);
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 19, 0x00);
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 20, 0x20);
++
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 1, 0x00);
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 34, 0x13);
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 35, 0x00);
++
++	rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x1);
++
++	rt2800_bbp_write(rt2x00dev, 47, 0x04);
++	rt2800_bbp_write(rt2x00dev, 22, 0x80);
++	udelay(100);
++	bytevalue = rt2800_bbp_read(rt2x00dev, 49);
++	if (bytevalue > 128)
++		d1 = bytevalue - 256;
++	else
++		d1 = (char)bytevalue;
++	rt2800_bbp_write(rt2x00dev, 22, 0x0);
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 35, 0x01);
++
++	rt2800_bbp_write(rt2x00dev, 22, 0x80);
++	udelay(100);
++	bytevalue = rt2800_bbp_read(rt2x00dev, 49);
++	if (bytevalue > 128)
++		d2 = bytevalue - 256;
++	else
++		d2 = (char)bytevalue;
++	rt2800_bbp_write(rt2x00dev, 22, 0x0);
++
++	rcalcode = rt2800_calcrcalibrationcode(rt2x00dev, d1, d2);
++	if (rcalcode < 0)
++		r_cal_code = 256 + rcalcode;
++	else
++		r_cal_code = (u8)rcalcode;
++
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 7, r_cal_code);
++
++	rt2800_bbp_write(rt2x00dev, 22, 0x0);
++
++	bytevalue = rt2800_bbp_read(rt2x00dev, 21);
++	bytevalue |= 0x1;
++	rt2800_bbp_write(rt2x00dev, 21, bytevalue);
++	bytevalue = rt2800_bbp_read(rt2x00dev, 21);
++	bytevalue &= (~0x1);
++	rt2800_bbp_write(rt2x00dev, 21, bytevalue);
++
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 1, saverfb0r1);
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 34, saverfb0r34);
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 35, saverfb0r35);
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 4, saverfb5r4);
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 17, saverfb5r17);
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 18, saverfb5r18);
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 19, saverfb5r19);
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 20, saverfb5r20);
++
++	rt2800_bbp_write(rt2x00dev, 22, savebbpr22);
++	rt2800_bbp_write(rt2x00dev, 47, savebbpr47);
++	rt2800_bbp_write(rt2x00dev, 49, savebbpr49);
++
++	rt2800_register_write(rt2x00dev, RF_BYPASS0, MAC_RF_BYPASS0);
++	rt2800_register_write(rt2x00dev, RF_CONTROL0, MAC_RF_CONTROL0);
++
++	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, savemacsysctrl);
++	rt2800_register_write(rt2x00dev, PWR_PIN_CFG, MAC_PWR_PIN_CFG);
++}
++
+ static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev,
+ 				       bool set_bw, bool is_ht40)
+ {
+@@ -9102,6 +9251,7 @@ static void rt2800_init_rfcsr_6352(struc
+ 	rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00);
+ 	rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C);
+ 
++	rt2800_r_calibration(rt2x00dev);
+ 	rt2800_rf_self_txdc_cal(rt2x00dev);
+ 	rt2800_bw_filter_calibration(rt2x00dev, true);
+ 	rt2800_bw_filter_calibration(rt2x00dev, false);
diff --git a/package/kernel/mac80211/patches/rt2x00/984-rt2x00-add-rxdcoc-calibration.patch b/package/kernel/mac80211/patches/rt2x00/984-rt2x00-add-rxdcoc-calibration.patch
new file mode 100644
index 0000000..a45e7ae
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/984-rt2x00-add-rxdcoc-calibration.patch
@@ -0,0 +1,81 @@
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+@@ -8644,6 +8644,70 @@ static void rt2800_r_calibration(struct
+ 	rt2800_register_write(rt2x00dev, PWR_PIN_CFG, MAC_PWR_PIN_CFG);
+ }
+ 
++static void rt2800_rxdcoc_calibration(struct rt2x00_dev *rt2x00dev)
++{
++	u8 bbpreg = 0;
++	u32 macvalue = 0, macvalue1 = 0;
++	u8 saverfb0r2, saverfb5r4, saverfb7r4, rfvalue;
++	int i;
++
++	saverfb0r2 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 2);
++	rfvalue = saverfb0r2;
++	rfvalue |= 0x03;
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 2, rfvalue);
++
++	rt2800_bbp_write(rt2x00dev, 158, 141);
++	bbpreg = rt2800_bbp_read(rt2x00dev, 159);
++	bbpreg |= 0x10;
++	rt2800_bbp_write(rt2x00dev, 159, bbpreg);
++
++	macvalue = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
++	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x8);
++
++	for (i = 0; i < 10000; i++) {
++		macvalue1 = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG);
++		if (macvalue1 & 0x1)
++			udelay(50);
++		else
++			break;
++	}
++
++	saverfb5r4 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 0);
++	saverfb7r4 = rt2800_rfcsr_read_bank(rt2x00dev, 7, 4);
++	saverfb5r4 = saverfb5r4 & (~0x40);
++	saverfb7r4 = saverfb7r4 & (~0x40);
++	rt2800_rfcsr_write_dccal(rt2x00dev, 4, 0x64);
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 4, saverfb5r4);
++	rt2800_rfcsr_write_bank(rt2x00dev, 7, 4, saverfb7r4);
++
++	rt2800_bbp_write(rt2x00dev, 158, 141);
++	bbpreg = rt2800_bbp_read(rt2x00dev, 159);
++	bbpreg = bbpreg & (~0x40);
++	rt2800_bbp_write(rt2x00dev, 159, bbpreg);
++	bbpreg |= 0x48;
++	rt2800_bbp_write(rt2x00dev, 159, bbpreg);
++
++	for (i = 0; i < 10000; i++) {
++		bbpreg = rt2800_bbp_read(rt2x00dev, 159);
++		if ((bbpreg & 0x40)==0)
++			break;
++		udelay(50);
++	}
++
++	bbpreg = rt2800_bbp_read(rt2x00dev, 159);
++	bbpreg = bbpreg & (~0x40);
++	rt2800_bbp_write(rt2x00dev, 159, bbpreg);
++
++	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, macvalue);
++
++	rt2800_bbp_write(rt2x00dev, 158, 141);
++	bbpreg = rt2800_bbp_read(rt2x00dev, 159);
++	bbpreg &= (~0x10);
++	rt2800_bbp_write(rt2x00dev, 159, bbpreg);
++
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 2, saverfb0r2);
++}
++
+ static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev,
+ 				       bool set_bw, bool is_ht40)
+ {
+@@ -9253,6 +9317,7 @@ static void rt2800_init_rfcsr_6352(struc
+ 
+ 	rt2800_r_calibration(rt2x00dev);
+ 	rt2800_rf_self_txdc_cal(rt2x00dev);
++	rt2800_rxdcoc_calibration(rt2x00dev);
+ 	rt2800_bw_filter_calibration(rt2x00dev, true);
+ 	rt2800_bw_filter_calibration(rt2x00dev, false);
+ }
diff --git a/package/kernel/mac80211/patches/rt2x00/985-rt2x00-add-rxiq-calibration.patch b/package/kernel/mac80211/patches/rt2x00/985-rt2x00-add-rxiq-calibration.patch
new file mode 100644
index 0000000..bc03d72
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/985-rt2x00-add-rxiq-calibration.patch
@@ -0,0 +1,395 @@
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+@@ -8708,6 +8708,384 @@ static void rt2800_rxdcoc_calibration(st
+ 	rt2800_rfcsr_write_bank(rt2x00dev, 0, 2, saverfb0r2);
+ }
+ 
++static u32 rt2800_do_sqrt_accumulation(u32 si) {
++	u32 root, root_pre, bit;
++	char i;
++	bit = 1 << 15;
++	root = 0;
++	for (i = 15; i >= 0; i = i - 1) {
++		root_pre = root + bit;
++		if ((root_pre*root_pre) <= si)
++			root = root_pre;
++		bit = bit >> 1;
++	}
++
++	return root;
++}
++
++static void rt2800_rxiq_calibration(struct rt2x00_dev *rt2x00dev) {
++	u8 rfb0r1, rfb0r2, rfb0r42;
++	u8 rfb4r0, rfb4r19;
++	u8 rfb5r3, rfb5r4, rfb5r17, rfb5r18, rfb5r19, rfb5r20;
++	u8 rfb6r0, rfb6r19;
++	u8 rfb7r3, rfb7r4, rfb7r17, rfb7r18, rfb7r19, rfb7r20;
++
++	u8 bbp1, bbp4;
++	u8 bbpr241, bbpr242;
++	u32 i;
++	u8 ch_idx;
++	u8 bbpval;
++	u8 rfval, vga_idx = 0;
++	int mi = 0, mq = 0, si = 0, sq = 0, riq = 0;
++	int sigma_i, sigma_q, r_iq, g_rx;
++	int g_imb;
++	int ph_rx;
++	u32 savemacsysctrl = 0;
++	u32 orig_RF_CONTROL0 = 0;
++	u32 orig_RF_BYPASS0 = 0;
++	u32 orig_RF_CONTROL1 = 0;
++	u32 orig_RF_BYPASS1 = 0;
++	u32 orig_RF_CONTROL3 = 0;
++	u32 orig_RF_BYPASS3 = 0;
++	u32 macstatus, bbpval1 = 0;
++	u8 rf_vga_table[] = {0x20, 0x21, 0x22, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f};
++
++	savemacsysctrl = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
++	orig_RF_CONTROL0 = rt2800_register_read(rt2x00dev, RF_CONTROL0);
++	orig_RF_BYPASS0 = rt2800_register_read(rt2x00dev, RF_BYPASS0);
++	orig_RF_CONTROL1 = rt2800_register_read(rt2x00dev, RF_CONTROL1);
++	orig_RF_BYPASS1 = rt2800_register_read(rt2x00dev, RF_BYPASS1);
++	orig_RF_CONTROL3 = rt2800_register_read(rt2x00dev, RF_CONTROL3);
++	orig_RF_BYPASS3 = rt2800_register_read(rt2x00dev, RF_BYPASS3);
++
++	bbp1 = rt2800_bbp_read(rt2x00dev, 1);
++	bbp4 = rt2800_bbp_read(rt2x00dev, 4);
++
++	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x0);
++
++	for (i = 0; i < 10000; i++) {
++		macstatus = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG);
++		if (macstatus & 0x3)
++			udelay(50);
++		else
++			break;
++	}
++
++	if (i == 10000)
++		rt2x00_warn(rt2x00dev, "Wait MAC Status to MAX !!!\n");
++
++	bbpval = bbp4 & (~0x18);
++	bbpval = bbp4 | 0x00;
++	rt2800_bbp_write(rt2x00dev, 4, bbpval);
++
++	bbpval = rt2800_bbp_read(rt2x00dev, 21);
++	bbpval = bbpval | 1;
++	rt2800_bbp_write(rt2x00dev, 21, bbpval);
++	bbpval = bbpval & 0xfe;
++	rt2800_bbp_write(rt2x00dev, 21, bbpval);
++
++	rt2800_register_write(rt2x00dev, RF_CONTROL1, 0x00000202);
++	rt2800_register_write(rt2x00dev, RF_BYPASS1, 0x00000303);
++	if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags))
++		rt2800_register_write(rt2x00dev, RF_CONTROL3, 0x0101);
++	else
++		rt2800_register_write(rt2x00dev, RF_CONTROL3, 0x0000);
++
++	rt2800_register_write(rt2x00dev, RF_BYPASS3, 0xf1f1);
++
++	rfb0r1 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 1);
++	rfb0r2 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 2);
++	rfb0r42 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 42);
++	rfb4r0 = rt2800_rfcsr_read_bank(rt2x00dev, 4, 0);
++	rfb4r19 = rt2800_rfcsr_read_bank(rt2x00dev, 4, 19);
++	rfb5r3 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 3);
++	rfb5r4 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 4);
++	rfb5r17 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 17);
++	rfb5r18 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 18);
++	rfb5r19 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 19);
++	rfb5r20 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 20);
++
++	rfb6r0 = rt2800_rfcsr_read_bank(rt2x00dev, 6, 0);
++	rfb6r19 = rt2800_rfcsr_read_bank(rt2x00dev, 6, 19);
++	rfb7r3 = rt2800_rfcsr_read_bank(rt2x00dev, 7, 3);
++	rfb7r4 = rt2800_rfcsr_read_bank(rt2x00dev, 7, 4);
++	rfb7r17 = rt2800_rfcsr_read_bank(rt2x00dev, 7, 17);
++	rfb7r18 = rt2800_rfcsr_read_bank(rt2x00dev, 7, 18);
++	rfb7r19 = rt2800_rfcsr_read_bank(rt2x00dev, 7, 19);
++	rfb7r20 = rt2800_rfcsr_read_bank(rt2x00dev, 7, 20);
++
++	rt2800_rfcsr_write_chanreg(rt2x00dev, 0, 0x87);
++	rt2800_rfcsr_write_chanreg(rt2x00dev, 19, 0x27);
++	rt2800_rfcsr_write_dccal(rt2x00dev, 3, 0x38);
++	rt2800_rfcsr_write_dccal(rt2x00dev, 4, 0x38);
++	rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x80);
++	rt2800_rfcsr_write_dccal(rt2x00dev, 18, 0xC1);
++	rt2800_rfcsr_write_dccal(rt2x00dev, 19, 0x60);
++	rt2800_rfcsr_write_dccal(rt2x00dev, 20, 0x00);
++
++	rt2800_bbp_write(rt2x00dev, 23, 0x0);
++	rt2800_bbp_write(rt2x00dev, 24, 0x0);
++
++	rt2800_bbp_dcoc_write(rt2x00dev, 5, 0x0);
++
++	bbpr241 = rt2800_bbp_read(rt2x00dev, 241);
++	bbpr242 = rt2800_bbp_read(rt2x00dev, 242);
++
++	rt2800_bbp_write(rt2x00dev, 241, 0x10);
++	rt2800_bbp_write(rt2x00dev, 242, 0x84);
++	rt2800_bbp_write(rt2x00dev, 244, 0x31);
++
++	bbpval = rt2800_bbp_dcoc_read(rt2x00dev, 3);
++	bbpval = bbpval & (~0x7);
++	rt2800_bbp_dcoc_write(rt2x00dev, 3, bbpval);
++
++	rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00000004);
++	udelay(1);
++	rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00000006);
++	usleep_range(1, 200);
++	rt2800_register_write(rt2x00dev, RF_BYPASS0, 0x00003376);
++	rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00001006);
++	udelay(1);
++	if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) {
++		rt2800_bbp_write(rt2x00dev, 23, 0x06);
++		rt2800_bbp_write(rt2x00dev, 24, 0x06);
++	} else {
++		rt2800_bbp_write(rt2x00dev, 23, 0x02);
++		rt2800_bbp_write(rt2x00dev, 24, 0x02);
++	}
++
++	for (ch_idx = 0; ch_idx < 2; ch_idx = ch_idx + 1) {
++		if (ch_idx == 0) {
++			rfval = rfb0r1 & (~0x3);
++			rfval = rfb0r1 | 0x1;
++			rt2800_rfcsr_write_bank(rt2x00dev, 0, 1, rfval);
++			rfval = rfb0r2 & (~0x33);
++			rfval = rfb0r2 | 0x11;
++			rt2800_rfcsr_write_bank(rt2x00dev, 0, 2, rfval);
++			rfval = rfb0r42 & (~0x50);
++			rfval = rfb0r42 | 0x10;
++			rt2800_rfcsr_write_bank(rt2x00dev, 0, 42, rfval);
++
++			rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00001006);
++			udelay(1);
++
++			bbpval = bbp1 & (~ 0x18);
++			bbpval = bbpval | 0x00;
++			rt2800_bbp_write(rt2x00dev, 1, bbpval);
++
++			rt2800_bbp_dcoc_write(rt2x00dev, 1, 0x00);
++		} else {
++			rfval = rfb0r1 & (~0x3);
++			rfval = rfb0r1 | 0x2;
++			rt2800_rfcsr_write_bank(rt2x00dev, 0, 1, rfval);
++			rfval = rfb0r2 & (~0x33);
++			rfval = rfb0r2 | 0x22;
++			rt2800_rfcsr_write_bank(rt2x00dev, 0, 2, rfval);
++			rfval = rfb0r42 & (~0x50);
++			rfval = rfb0r42 | 0x40;
++			rt2800_rfcsr_write_bank(rt2x00dev, 0, 42, rfval);
++
++			rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00002006);
++			udelay(1);
++
++			bbpval = bbp1 & (~ 0x18);
++			bbpval = bbpval | 0x08;
++			rt2800_bbp_write(rt2x00dev, 1, bbpval);
++
++			rt2800_bbp_dcoc_write(rt2x00dev, 1, 0x01);
++		}
++		udelay(500);
++
++		vga_idx = 0;
++			while (vga_idx < 11) {
++				rt2800_rfcsr_write_dccal(rt2x00dev, 3, rf_vga_table[vga_idx]);
++				rt2800_rfcsr_write_dccal(rt2x00dev, 4, rf_vga_table[vga_idx]);
++
++				rt2800_bbp_dcoc_write(rt2x00dev, 0, 0x93);
++
++				for (i = 0; i < 10000; i++) {
++					bbpval = rt2800_bbp_read(rt2x00dev, 159);
++					if ((bbpval & 0xff) == 0x93)
++						udelay(50);
++					else
++						break;
++					}
++
++				if ((bbpval & 0xff) == 0x93) {
++					rt2x00_warn(rt2x00dev, "Fatal Error: Calibration doesn't finish");
++					goto restore_value;
++				}
++
++				for (i = 0; i < 5; i++) {
++					u32 bbptemp = 0;
++					u8 value = 0;
++					int result = 0;
++
++					rt2800_bbp_write(rt2x00dev, 158, 0x1e);
++					rt2800_bbp_write(rt2x00dev, 159, i);
++					rt2800_bbp_write(rt2x00dev, 158, 0x22);
++					value = rt2800_bbp_read(rt2x00dev, 159);
++					bbptemp = bbptemp + (value << 24);
++					rt2800_bbp_write(rt2x00dev, 158, 0x21);
++					value = rt2800_bbp_read(rt2x00dev, 159);
++					bbptemp = bbptemp + (value << 16);
++					rt2800_bbp_write(rt2x00dev, 158, 0x20);
++					value = rt2800_bbp_read(rt2x00dev, 159);
++					bbptemp = bbptemp + (value << 8);
++					rt2800_bbp_write(rt2x00dev, 158, 0x1f);
++					value = rt2800_bbp_read(rt2x00dev, 159);
++					bbptemp = bbptemp + value;
++
++					if ((i < 2) && (bbptemp & 0x800000))
++						result = (bbptemp & 0xffffff) - 0x1000000;
++					else if (i == 4)
++						result = bbptemp;
++					else
++						result = bbptemp;
++
++					if (i == 0)
++						mi = result/4096;
++					else if (i == 1)
++						mq = result/4096;
++					else if (i == 2)
++						si = bbptemp/4096;
++					else if (i == 3)
++						sq = bbptemp/4096;
++					else
++						riq = result/4096;
++				}
++
++				bbpval1 = si - mi*mi;
++				rt2x00_dbg(rt2x00dev, "RXIQ si=%d, sq=%d, riq=%d, bbpval %d, vga_idx %d", si, sq, riq, bbpval1, vga_idx);
++
++				if (bbpval1 >= (100*100))
++					break;
++
++				if (bbpval1 <= 100)
++					vga_idx = vga_idx + 9;
++				else if (bbpval1 <= 158)
++					vga_idx = vga_idx + 8;
++				else if (bbpval1 <= 251)
++					vga_idx = vga_idx + 7;
++				else if (bbpval1 <= 398)
++					vga_idx = vga_idx + 6;
++				else if (bbpval1 <= 630)
++					vga_idx = vga_idx + 5;
++				else if (bbpval1 <= 1000)
++					vga_idx = vga_idx + 4;
++				else if (bbpval1 <= 1584)
++					vga_idx = vga_idx + 3;
++				else if (bbpval1 <= 2511)
++					vga_idx = vga_idx + 2;
++				else
++					vga_idx = vga_idx + 1;
++			}
++
++		sigma_i = rt2800_do_sqrt_accumulation(100*(si - mi*mi));
++		sigma_q = rt2800_do_sqrt_accumulation(100*(sq - mq*mq));
++		r_iq = 10*(riq-(mi*mq));
++
++		rt2x00_dbg(rt2x00dev, "Sigma_i=%d, Sigma_q=%d, R_iq=%d", sigma_i, sigma_q, r_iq);
++
++		if (((sigma_i <= 1400 ) && (sigma_i >= 1000))
++			&& ((sigma_i - sigma_q) <= 112)
++			&& ((sigma_i - sigma_q) >= -112)
++			&& ((mi <= 32) && (mi >= -32))
++			&& ((mq <= 32) && (mq >= -32))) {
++				r_iq = 10*(riq-(mi*mq));
++				rt2x00_dbg(rt2x00dev, "RXIQ Sigma_i=%d, Sigma_q=%d, R_iq=%d\n", sigma_i, sigma_q, r_iq);
++
++				g_rx = (1000 * sigma_q) / sigma_i;
++				g_imb = ((-2) * 128 * (1000 - g_rx)) / (1000 + g_rx);
++				ph_rx = (r_iq * 2292) / (sigma_i * sigma_q);
++				rt2x00_info(rt2x00dev, "RXIQ G_imb=%d, Ph_rx=%d\n", g_imb, ph_rx);
++
++				if ((ph_rx > 20) || (ph_rx < -20)) {
++					ph_rx = 0;
++					rt2x00_warn(rt2x00dev, "RXIQ calibration FAIL");
++				}
++
++				if ((g_imb > 12) || (g_imb < -12)) {
++					g_imb = 0;
++					rt2x00_warn(rt2x00dev, "RXIQ calibration FAIL");
++				}
++			}
++		else {
++			g_imb = 0;
++			ph_rx = 0;
++			rt2x00_dbg(rt2x00dev, "RXIQ Sigma_i=%d, Sigma_q=%d, R_iq=%d\n", sigma_i, sigma_q, r_iq);
++			rt2x00_warn(rt2x00dev, "RXIQ calibration FAIL");
++		}
++
++		if (ch_idx == 0) {
++			rt2800_bbp_write(rt2x00dev, 158, 0x37);
++			rt2800_bbp_write(rt2x00dev, 159, g_imb & 0x3f);
++			rt2800_bbp_write(rt2x00dev, 158, 0x35);
++			rt2800_bbp_write(rt2x00dev, 159, ph_rx & 0x3f);
++		} else {
++			rt2800_bbp_write(rt2x00dev, 158, 0x55);
++			rt2800_bbp_write(rt2x00dev, 159, g_imb & 0x3f);
++			rt2800_bbp_write(rt2x00dev, 158, 0x53);
++			rt2800_bbp_write(rt2x00dev, 159, ph_rx & 0x3f);
++		}
++	}
++
++restore_value:
++	rt2800_bbp_write(rt2x00dev, 158, 0x3);
++	bbpval = rt2800_bbp_read(rt2x00dev, 159);
++	rt2800_bbp_write(rt2x00dev, 159, (bbpval | 0x07));
++
++	rt2800_bbp_write(rt2x00dev, 158, 0x00);
++	rt2800_bbp_write(rt2x00dev, 159, 0x00);
++	rt2800_bbp_write(rt2x00dev, 1, bbp1);
++	rt2800_bbp_write(rt2x00dev, 4, bbp4);
++	rt2800_bbp_write(rt2x00dev, 241, bbpr241);
++	rt2800_bbp_write(rt2x00dev, 242, bbpr242);
++
++	rt2800_bbp_write(rt2x00dev, 244, 0x00);
++	bbpval = rt2800_bbp_read(rt2x00dev, 21);
++	bbpval |= 0x1;
++	rt2800_bbp_write(rt2x00dev, 21, bbpval);
++	usleep_range(10, 200);
++	bbpval &= 0xfe;
++	rt2800_bbp_write(rt2x00dev, 21, bbpval);
++
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 1, rfb0r1);
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 2, rfb0r2);
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 42, rfb0r42);
++
++	rt2800_rfcsr_write_bank(rt2x00dev, 4, 0, rfb4r0);
++	rt2800_rfcsr_write_bank(rt2x00dev, 4, 19, rfb4r19);
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 3, rfb5r3);
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 4, rfb5r4);
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 17, rfb5r17);
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 18, rfb5r18);
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 19, rfb5r19);
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 20, rfb5r20);
++
++	rt2800_rfcsr_write_bank(rt2x00dev, 6, 0, rfb6r0);
++	rt2800_rfcsr_write_bank(rt2x00dev, 6, 19, rfb6r19);
++	rt2800_rfcsr_write_bank(rt2x00dev, 7, 3, rfb7r3);
++	rt2800_rfcsr_write_bank(rt2x00dev, 7, 4, rfb7r4);
++	rt2800_rfcsr_write_bank(rt2x00dev, 7, 17, rfb7r17);
++	rt2800_rfcsr_write_bank(rt2x00dev, 7, 18, rfb7r18);
++	rt2800_rfcsr_write_bank(rt2x00dev, 7, 19, rfb7r19);
++	rt2800_rfcsr_write_bank(rt2x00dev, 7, 20, rfb7r20);
++
++	rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00000006);
++	udelay(1);
++	rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00000004);
++	udelay(1);
++	rt2800_register_write(rt2x00dev, RF_CONTROL0, orig_RF_CONTROL0);
++	udelay(1);
++	rt2800_register_write(rt2x00dev, RF_BYPASS0, orig_RF_BYPASS0);
++	rt2800_register_write(rt2x00dev, RF_CONTROL1, orig_RF_CONTROL1);
++	rt2800_register_write(rt2x00dev, RF_BYPASS1, orig_RF_BYPASS1);
++	rt2800_register_write(rt2x00dev, RF_CONTROL3, orig_RF_CONTROL3);
++	rt2800_register_write(rt2x00dev, RF_BYPASS3, orig_RF_BYPASS3);
++	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, savemacsysctrl);
++}
++
+ static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev,
+ 				       bool set_bw, bool is_ht40)
+ {
+@@ -9320,6 +9698,7 @@ static void rt2800_init_rfcsr_6352(struc
+ 	rt2800_rxdcoc_calibration(rt2x00dev);
+ 	rt2800_bw_filter_calibration(rt2x00dev, true);
+ 	rt2800_bw_filter_calibration(rt2x00dev, false);
++	rt2800_rxiq_calibration(rt2x00dev);
+ }
+ 
+ static void rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
diff --git a/package/kernel/mac80211/patches/rt2x00/986-rt2x00-add-TX-LOFT-calibration.patch b/package/kernel/mac80211/patches/rt2x00/986-rt2x00-add-TX-LOFT-calibration.patch
new file mode 100644
index 0000000..bd664d0
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/986-rt2x00-add-TX-LOFT-calibration.patch
@@ -0,0 +1,973 @@
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+@@ -9086,6 +9086,943 @@ restore_value:
+ 	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, savemacsysctrl);
+ }
+ 
++static void rt2800_rf_configstore(struct rt2x00_dev *rt2x00dev, rf_reg_pair rf_reg_record[][13], u8 chain)
++{
++	u8 rfvalue = 0;
++
++	if (chain == CHAIN_0) {
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 0, 1);
++		rf_reg_record[CHAIN_0][0].bank = 0;
++		rf_reg_record[CHAIN_0][0].reg = 1;
++		rf_reg_record[CHAIN_0][0].value = rfvalue;
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 0, 2);
++		rf_reg_record[CHAIN_0][1].bank = 0;
++		rf_reg_record[CHAIN_0][1].reg = 2;
++		rf_reg_record[CHAIN_0][1].value = rfvalue;
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 0, 35);
++		rf_reg_record[CHAIN_0][2].bank = 0;
++		rf_reg_record[CHAIN_0][2].reg = 35;
++		rf_reg_record[CHAIN_0][2].value = rfvalue;
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 0, 42);
++		rf_reg_record[CHAIN_0][3].bank = 0;
++		rf_reg_record[CHAIN_0][3].reg = 42;
++		rf_reg_record[CHAIN_0][3].value = rfvalue;
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 4, 0);
++		rf_reg_record[CHAIN_0][4].bank = 4;
++		rf_reg_record[CHAIN_0][4].reg = 0;
++		rf_reg_record[CHAIN_0][4].value = rfvalue;
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 4, 2);
++		rf_reg_record[CHAIN_0][5].bank = 4;
++		rf_reg_record[CHAIN_0][5].reg = 2;
++		rf_reg_record[CHAIN_0][5].value = rfvalue;
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 4, 34);
++		rf_reg_record[CHAIN_0][6].bank = 4;
++		rf_reg_record[CHAIN_0][6].reg = 34;
++		rf_reg_record[CHAIN_0][6].value = rfvalue;
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 5, 3);
++		rf_reg_record[CHAIN_0][7].bank = 5;
++		rf_reg_record[CHAIN_0][7].reg = 3;
++		rf_reg_record[CHAIN_0][7].value = rfvalue;
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 5, 4);
++		rf_reg_record[CHAIN_0][8].bank = 5;
++		rf_reg_record[CHAIN_0][8].reg = 4;
++		rf_reg_record[CHAIN_0][8].value = rfvalue;
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 5, 17);
++		rf_reg_record[CHAIN_0][9].bank = 5;
++		rf_reg_record[CHAIN_0][9].reg = 17;
++		rf_reg_record[CHAIN_0][9].value = rfvalue;
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 5, 18);
++		rf_reg_record[CHAIN_0][10].bank = 5;
++		rf_reg_record[CHAIN_0][10].reg = 18;
++		rf_reg_record[CHAIN_0][10].value = rfvalue;
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 5, 19);
++		rf_reg_record[CHAIN_0][11].bank = 5;
++		rf_reg_record[CHAIN_0][11].reg = 19;
++		rf_reg_record[CHAIN_0][11].value = rfvalue;
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 5, 20);
++		rf_reg_record[CHAIN_0][12].bank = 5;
++		rf_reg_record[CHAIN_0][12].reg = 20;
++		rf_reg_record[CHAIN_0][12].value = rfvalue;
++	} else if (chain == CHAIN_1) {
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 0, 1);
++		rf_reg_record[CHAIN_1][0].bank = 0;
++		rf_reg_record[CHAIN_1][0].reg = 1;
++		rf_reg_record[CHAIN_1][0].value = rfvalue;
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 0, 2);
++		rf_reg_record[CHAIN_1][1].bank = 0;
++		rf_reg_record[CHAIN_1][1].reg = 2;
++		rf_reg_record[CHAIN_1][1].value = rfvalue;
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 0, 35);
++		rf_reg_record[CHAIN_1][2].bank = 0;
++		rf_reg_record[CHAIN_1][2].reg = 35;
++		rf_reg_record[CHAIN_1][2].value = rfvalue;
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 0, 42);
++		rf_reg_record[CHAIN_1][3].bank = 0;
++		rf_reg_record[CHAIN_1][3].reg = 42;
++		rf_reg_record[CHAIN_1][3].value = rfvalue;
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 6, 0);
++		rf_reg_record[CHAIN_1][4].bank = 6;
++		rf_reg_record[CHAIN_1][4].reg = 0;
++		rf_reg_record[CHAIN_1][4].value = rfvalue;
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 6, 2);
++		rf_reg_record[CHAIN_1][5].bank = 6;
++		rf_reg_record[CHAIN_1][5].reg = 2;
++		rf_reg_record[CHAIN_1][5].value = rfvalue;
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 6, 34);
++		rf_reg_record[CHAIN_1][6].bank = 6;
++		rf_reg_record[CHAIN_1][6].reg = 34;
++		rf_reg_record[CHAIN_1][6].value = rfvalue;
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 7, 3);
++		rf_reg_record[CHAIN_1][7].bank = 7;
++		rf_reg_record[CHAIN_1][7].reg = 3;
++		rf_reg_record[CHAIN_1][7].value = rfvalue;
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 7, 4);
++		rf_reg_record[CHAIN_1][8].bank = 7;
++		rf_reg_record[CHAIN_1][8].reg = 4;
++		rf_reg_record[CHAIN_1][8].value = rfvalue;
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 7, 17);
++		rf_reg_record[CHAIN_1][9].bank = 7;
++		rf_reg_record[CHAIN_1][9].reg = 17;
++		rf_reg_record[CHAIN_1][9].value = rfvalue;
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 7, 18);
++		rf_reg_record[CHAIN_1][10].bank = 7;
++		rf_reg_record[CHAIN_1][10].reg = 18;
++		rf_reg_record[CHAIN_1][10].value = rfvalue;
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 7, 19);
++		rf_reg_record[CHAIN_1][11].bank = 7;
++		rf_reg_record[CHAIN_1][11].reg = 19;
++		rf_reg_record[CHAIN_1][11].value = rfvalue;
++		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 7, 20);
++		rf_reg_record[CHAIN_1][12].bank = 7;
++		rf_reg_record[CHAIN_1][12].reg = 20;
++		rf_reg_record[CHAIN_1][12].value = rfvalue;
++	} else {
++		rt2x00_warn(rt2x00dev, "Unknown chain = %u\n", chain);
++		return;
++	}
++
++	return;
++}
++
++static void rt2800_rf_configrecover(struct rt2x00_dev *rt2x00dev, rf_reg_pair rf_record[][13])
++{
++	u8 chain_index = 0, record_index = 0;
++	u8 bank = 0, rf_register = 0, value = 0;
++
++	for (chain_index = 0; chain_index < 2; chain_index++) {
++		for (record_index = 0; record_index < 13; record_index++) {
++			bank = rf_record[chain_index][record_index].bank;
++			rf_register = rf_record[chain_index][record_index].reg;
++			value = rf_record[chain_index][record_index].value;
++			rt2800_rfcsr_write_bank(rt2x00dev, bank, rf_register, value);
++			rt2x00_dbg(rt2x00dev, "bank: %d, rf_register: %d, value: %x\n", bank, rf_register, value);
++		}
++	}
++
++	return;
++}
++
++static void rt2800_setbbptonegenerator(struct rt2x00_dev *rt2x00dev)
++{
++	rt2800_bbp_write(rt2x00dev, 158, 0xAA);
++	rt2800_bbp_write(rt2x00dev, 159, 0x00);
++
++	rt2800_bbp_write(rt2x00dev, 158, 0xAB);
++	rt2800_bbp_write(rt2x00dev, 159, 0x0A);
++
++	rt2800_bbp_write(rt2x00dev, 158, 0xAC);
++	rt2800_bbp_write(rt2x00dev, 159, 0x3F);
++
++	rt2800_bbp_write(rt2x00dev, 158, 0xAD);
++	rt2800_bbp_write(rt2x00dev, 159, 0x3F);
++
++	rt2800_bbp_write(rt2x00dev, 244, 0x40);
++
++	return;
++}
++
++static u32 rt2800_do_fft_accumulation(struct rt2x00_dev *rt2x00dev, u8 tidx, u8 read_neg)
++{
++	u32 macvalue = 0;
++	int fftout_i = 0, fftout_q = 0;
++	u32 ptmp=0, pint = 0;
++	u8 bbp = 0;
++	u8 tidxi;
++
++	rt2800_bbp_write(rt2x00dev, 158, 0x00);
++	rt2800_bbp_write(rt2x00dev, 159, 0x9b);
++
++	bbp = 0x9b;
++
++	while (bbp == 0x9b) {
++		udelay(10);
++		bbp = rt2800_bbp_read(rt2x00dev, 159);
++		bbp = bbp & 0xff;
++	}
++
++	rt2800_bbp_write(rt2x00dev, 158, 0xba);
++	rt2800_bbp_write(rt2x00dev, 159, tidx);
++	rt2800_bbp_write(rt2x00dev, 159, tidx);
++	rt2800_bbp_write(rt2x00dev, 159, tidx);
++
++	macvalue = rt2800_register_read(rt2x00dev, 0x057C);
++
++	fftout_i = (macvalue >> 16);
++	fftout_i = (fftout_i & 0x8000) ? (fftout_i - 0x10000) : fftout_i;
++	fftout_q = (macvalue & 0xffff);
++	fftout_q = (fftout_q & 0x8000) ? (fftout_q - 0x10000) : fftout_q;
++	ptmp = (fftout_i * fftout_i);
++	ptmp = ptmp + (fftout_q * fftout_q);
++	pint = ptmp;
++	rt2x00_dbg(rt2x00dev, "I = %d,  Q = %d, power = %x\n", fftout_i, fftout_q, pint);
++	if (read_neg) {
++		pint = pint >> 1;
++		tidxi = 0x40 - tidx;
++		tidxi = tidxi & 0x3f;
++
++		rt2800_bbp_write(rt2x00dev, 158, 0xba);
++		rt2800_bbp_write(rt2x00dev, 159, tidxi);
++		rt2800_bbp_write(rt2x00dev, 159, tidxi);
++		rt2800_bbp_write(rt2x00dev, 159, tidxi);
++
++		macvalue = rt2800_register_read(rt2x00dev, 0x057C);
++
++		fftout_i = (macvalue >> 16);
++		fftout_i = (fftout_i & 0x8000) ? (fftout_i - 0x10000) : fftout_i;
++		fftout_q = (macvalue & 0xffff);
++		fftout_q = (fftout_q & 0x8000) ? (fftout_q - 0x10000) : fftout_q;
++		ptmp = (fftout_i * fftout_i);
++		ptmp = ptmp + (fftout_q * fftout_q);
++		ptmp = ptmp >> 1;
++		pint = pint + ptmp;
++	}
++
++	return pint;
++}
++
++static u32 rt2800_read_fft_accumulation(struct rt2x00_dev *rt2x00dev, u8 tidx) {
++	u32 macvalue = 0;
++	int fftout_i = 0, fftout_q = 0;
++	u32 ptmp=0, pint = 0;
++
++	rt2800_bbp_write(rt2x00dev, 158, 0xBA);
++	rt2800_bbp_write(rt2x00dev, 159, tidx);
++	rt2800_bbp_write(rt2x00dev, 159, tidx);
++	rt2800_bbp_write(rt2x00dev, 159, tidx);
++
++	macvalue = rt2800_register_read(rt2x00dev, 0x057C);
++
++	fftout_i = (macvalue >> 16);
++	fftout_i = (fftout_i & 0x8000) ? (fftout_i - 0x10000) : fftout_i;
++	fftout_q = (macvalue & 0xffff);
++	fftout_q = (fftout_q & 0x8000) ? (fftout_q - 0x10000) : fftout_q;
++	ptmp = (fftout_i * fftout_i);
++	ptmp = ptmp + (fftout_q * fftout_q);
++	pint = ptmp;
++	rt2x00_info(rt2x00dev, "I = %d,  Q = %d, power = %x\n", fftout_i, fftout_q, pint);
++
++	return pint;
++}
++
++static void rt2800_write_dc(struct rt2x00_dev *rt2x00dev, u8 ch_idx, u8 alc, u8 iorq, u8 dc)
++{
++	u8 bbp = 0;
++
++	rt2800_bbp_write(rt2x00dev, 158, 0xb0);
++	bbp = alc | 0x80;
++	rt2800_bbp_write(rt2x00dev, 159, bbp);
++
++	if (ch_idx == 0)
++		bbp = (iorq == 0) ? 0xb1: 0xb2;
++	else
++		bbp = (iorq == 0) ? 0xb8: 0xb9;
++
++	rt2800_bbp_write(rt2x00dev, 158, bbp);
++	bbp = dc;
++	rt2800_bbp_write(rt2x00dev, 159, bbp);
++
++	return;
++}
++
++static void rt2800_loft_search(struct rt2x00_dev *rt2x00dev, u8 ch_idx, u8 alc_idx, u8 dc_result[][RF_ALC_NUM][2])
++{
++	u32 p0 = 0, p1 = 0, pf = 0;
++	char idx0 = 0, idx1 = 0;
++	u8 idxf[] = {0x00, 0x00};
++	u8 ibit = 0x20;
++	u8 iorq;
++	char bidx;
++
++	rt2800_bbp_write(rt2x00dev, 158, 0xb0);
++	rt2800_bbp_write(rt2x00dev, 159, 0x80);
++
++	for (bidx = 5; bidx >= 0; bidx--) {
++		for (iorq = 0; iorq <= 1; iorq++) {
++			rt2x00_dbg(rt2x00dev, "\n========================================================\n");
++
++			if (idxf[iorq] == 0x20) {
++				idx0 = 0x20;
++				p0 = pf;
++			} else {
++				idx0 = idxf[iorq] - ibit;
++				idx0 = idx0 & 0x3F;
++				rt2800_write_dc(rt2x00dev, ch_idx, 0, iorq, idx0);
++				p0 = rt2800_do_fft_accumulation(rt2x00dev, 0x0A, 0);
++			}
++
++			idx1 = idxf[iorq] + ((bidx == 5) ? 0 : ibit);
++			idx1 = idx1 & 0x3F;
++			rt2800_write_dc(rt2x00dev, ch_idx, 0, iorq, idx1);
++			p1 = rt2800_do_fft_accumulation(rt2x00dev, 0x0A, 0);
++
++			rt2x00_dbg(rt2x00dev, "alc=%u, IorQ=%u, idx_final=%2x\n", alc_idx, iorq, idxf[iorq]);
++			rt2x00_dbg(rt2x00dev, "p0=%x, p1=%x, pf=%x, idx_0=%x, idx_1=%x, ibit=%x !\n", p0, p1, pf, idx0, idx1, ibit);
++
++			if ((bidx != 5) && (pf <= p0) && (pf < p1)) {
++				pf = pf;
++				idxf[iorq] = idxf[iorq];
++			} else if (p0 < p1) {
++				pf = p0;
++				idxf[iorq] = idx0 & 0x3F;
++			} else {
++				pf = p1;
++				idxf[iorq] = idx1 & 0x3F;
++			}
++			rt2x00_dbg(rt2x00dev, "IorQ=%u, idx_final[%u]:%x, pf:%8x\n", iorq, iorq, idxf[iorq], pf);
++
++			rt2800_write_dc(rt2x00dev, ch_idx, 0, iorq, idxf[iorq]);
++
++		}
++		ibit = ibit >> 1;
++	}
++	dc_result[ch_idx][alc_idx][0] = idxf[0];
++	dc_result[ch_idx][alc_idx][1] = idxf[1];
++
++	return;
++}
++
++static void rt2800_iq_search(struct rt2x00_dev *rt2x00dev, u8 ch_idx, u8 *ges, u8 *pes)
++{
++	u32 p0 = 0, p1 = 0, pf = 0;
++	char perr = 0, gerr = 0, iq_err = 0;
++	char pef = 0, gef = 0;
++	char psta, pend;
++	char gsta, gend;
++
++	u8 ibit = 0x20;
++	u8 first_search = 0x00, touch_neg_max = 0x00;
++	char idx0 = 0, idx1 = 0;
++	u8 gop;
++	u8 bbp = 0;
++	char bidx;
++
++	rt2x00_info(rt2x00dev, "IQCalibration Start!\n");
++	for (bidx = 5; bidx >= 1; bidx--) {
++		for (gop = 0; gop < 2; gop++) {
++			rt2x00_dbg(rt2x00dev, "\n========================================================\n");
++
++			if ((gop == 1) || (bidx < 4)) {
++				if (gop == 0)
++					iq_err = gerr;
++				else
++					iq_err = perr;
++
++				first_search = (gop == 0) ? (bidx == 3) : (bidx == 5);
++				touch_neg_max = (gop) ? ((iq_err & 0x0F) == 0x08) : ((iq_err & 0x3F) == 0x20);
++
++				if (touch_neg_max) {
++					p0 = pf;
++					idx0 = iq_err;
++				} else {
++					idx0 = iq_err - ibit;
++					bbp = (ch_idx == 0) ? ((gop == 0) ? 0x28 : 0x29): ((gop == 0) ? 0x46 : 0x47);
++
++					rt2800_bbp_write(rt2x00dev, 158, bbp);
++					rt2800_bbp_write(rt2x00dev, 159, idx0);
++
++					p0 = rt2800_do_fft_accumulation(rt2x00dev, 0x14, 1);
++				}
++
++				idx1 = iq_err + (first_search ? 0 : ibit);
++				idx1 = (gop == 0) ? (idx1 & 0x0F) : (idx1 & 0x3F);
++
++				bbp = (ch_idx == 0) ? (gop == 0) ? 0x28 : 0x29 : (gop == 0) ? 0x46 : 0x47;
++
++				rt2800_bbp_write(rt2x00dev, 158, bbp);
++				rt2800_bbp_write(rt2x00dev, 159, idx1);
++
++				p1 = rt2800_do_fft_accumulation(rt2x00dev, 0x14, 1);
++
++				rt2x00_dbg(rt2x00dev, "p0=%x, p1=%x, pwer_final=%x, idx0=%x, idx1=%x, iq_err=%x, gop=%d, ibit=%x !\n", p0, p1, pf, idx0, idx1, iq_err, gop, ibit);
++
++				if ((!first_search) && (pf <= p0) && (pf < p1)) {
++					pf = pf;
++				} else if (p0 < p1) {
++					pf = p0;
++					iq_err = idx0;
++				} else {
++					pf = p1;
++					iq_err = idx1;
++				}
++
++				bbp = (ch_idx == 0) ? (gop == 0) ? 0x28 : 0x29 : (gop == 0) ? 0x46 : 0x47;
++
++				rt2800_bbp_write(rt2x00dev, 158, bbp);
++				rt2800_bbp_write(rt2x00dev, 159, iq_err);
++
++				if (gop == 0)
++					gerr = iq_err;
++				else
++					perr = iq_err;
++
++				rt2x00_dbg(rt2x00dev, "IQCalibration pf=%8x (%2x, %2x) !\n", pf, gerr & 0x0F, perr & 0x3F);
++
++			}
++		}
++
++		if (bidx > 0)
++			ibit = (ibit >> 1);
++	}
++	gerr = (gerr & 0x08) ? (gerr & 0x0F) - 0x10 : (gerr & 0x0F);
++	perr = (perr & 0x20) ? (perr & 0x3F) - 0x40 : (perr & 0x3F);
++
++	gerr = (gerr < -0x07) ? -0x07 : (gerr > 0x05) ? 0x05 : gerr;
++	gsta = gerr - 1;
++	gend = gerr + 2;
++
++	perr = (perr < -0x1f) ? -0x1f : (perr > 0x1d) ? 0x1d : perr;
++	psta = perr - 1;
++	pend = perr + 2;
++
++	for (gef = gsta; gef <= gend; gef = gef + 1)
++		for (pef = psta; pef <= pend; pef = pef + 1) {
++			bbp = (ch_idx == 0) ? 0x28 : 0x46;
++			rt2800_bbp_write(rt2x00dev, 158, bbp);
++			rt2800_bbp_write(rt2x00dev, 159, gef & 0x0F);
++
++			bbp = (ch_idx == 0) ? 0x29 : 0x47;
++			rt2800_bbp_write(rt2x00dev, 158, bbp);
++			rt2800_bbp_write(rt2x00dev, 159, pef & 0x3F);
++
++			p1 = rt2800_do_fft_accumulation(rt2x00dev, 0x14, 1);
++			if ((gef == gsta) && (pef == psta)) {
++				pf = p1;
++				gerr = gef;
++				perr = pef;
++			}
++			else if (pf > p1){
++				pf = p1;
++				gerr = gef;
++				perr = pef;
++			}
++			rt2x00_dbg(rt2x00dev, "Fine IQCalibration p1=%8x pf=%8x (%2x, %2x) !\n", p1, pf, gef & 0x0F, pef & 0x3F);
++		}
++
++	ges[ch_idx] = gerr & 0x0F;
++	pes[ch_idx] = perr & 0x3F;
++
++	rt2x00_info(rt2x00dev, "IQCalibration Done! CH = %u, (gain=%2x, phase=%2x)\n", ch_idx, gerr & 0x0F, perr & 0x3F);
++
++	return;
++}
++
++static void rt2800_rf_aux_tx0_loopback(struct rt2x00_dev *rt2x00dev)
++{
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 1, 0x21);
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 2, 0x10);
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 35, 0x00);
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 42, 0x1b);
++	rt2800_rfcsr_write_bank(rt2x00dev, 4, 0, 0x81);
++	rt2800_rfcsr_write_bank(rt2x00dev, 4, 2, 0x81);
++	rt2800_rfcsr_write_bank(rt2x00dev, 4, 34, 0xee);
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 3, 0x2d);
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 4, 0x2d);
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 17, 0x80);
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 18, 0xd7);
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 19, 0xa2);
++	rt2800_rfcsr_write_bank(rt2x00dev, 5, 20, 0x20);
++}
++
++static void rt2800_rf_aux_tx1_loopback(struct rt2x00_dev *rt2x00dev)
++{
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 1, 0x22);
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 2, 0x20);
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 35, 0x00);
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 42, 0x4b);
++	rt2800_rfcsr_write_bank(rt2x00dev, 6, 0, 0x81);
++	rt2800_rfcsr_write_bank(rt2x00dev, 6, 2, 0x81);
++	rt2800_rfcsr_write_bank(rt2x00dev, 6, 34, 0xee);
++	rt2800_rfcsr_write_bank(rt2x00dev, 7, 3, 0x2d);
++	rt2800_rfcsr_write_bank(rt2x00dev, 7, 4, 0x2d);
++	rt2800_rfcsr_write_bank(rt2x00dev, 7, 17, 0x80);
++	rt2800_rfcsr_write_bank(rt2x00dev, 7, 18, 0xd7);
++	rt2800_rfcsr_write_bank(rt2x00dev, 7, 19, 0xa2);
++	rt2800_rfcsr_write_bank(rt2x00dev, 7, 20, 0x20);
++}
++
++void rt2800_loft_iq_calibration(struct rt2x00_dev *rt2x00dev)
++{
++	rf_reg_pair rf_store[CHAIN_NUM][13];
++	u32 macorg1 = 0;
++	u32 macorg2 = 0;
++	u32 macorg3 = 0;
++	u32 macorg4 = 0;
++	u32 macorg5 = 0;
++	u32 orig528 = 0;
++	u32 orig52c = 0;
++
++	u32 savemacsysctrl = 0, mtxcycle = 0;
++	u32 macvalue = 0;
++	u32 mac13b8 = 0;
++	u32 p0 = 0, p1 = 0;
++	u32 p0_idx10 = 0, p1_idx10 = 0;
++
++	u8 rfvalue;
++	u8 loft_dc_search_result[CHAIN_NUM][RF_ALC_NUM][2];
++	u8 ger[CHAIN_NUM], per[CHAIN_NUM];
++	u8 rf_gain[] = {0x00, 0x01, 0x02, 0x04, 0x08, 0x0c};
++	u8 rfvga_gain_table[] = {0x24, 0x25, 0x26, 0x27, 0x28, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3F};
++
++	u8 vga_gain[] = {14, 14};
++	u8 bbp_2324gain[] = {0x16, 0x14, 0x12, 0x10, 0x0c, 0x08};
++	u8 bbp = 0, ch_idx = 0, rf_alc_idx = 0, idx = 0;
++	u8 bbpr30, rfb0r39, rfb0r42;
++	u8 bbpr1;
++	u8 bbpr4;
++	u8 bbpr241, bbpr242;
++	u8 count_step;
++
++	savemacsysctrl = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
++	macorg1 = rt2800_register_read(rt2x00dev, TX_PIN_CFG);
++	macorg2 = rt2800_register_read(rt2x00dev, RF_CONTROL0);
++	macorg3 = rt2800_register_read(rt2x00dev, RF_BYPASS0);
++	macorg4 = rt2800_register_read(rt2x00dev, RF_CONTROL3);
++	macorg5 = rt2800_register_read(rt2x00dev, RF_BYPASS3);
++	mac13b8 = rt2800_register_read(rt2x00dev, 0x13b8);
++	orig528 = rt2800_register_read(rt2x00dev, RF_CONTROL2);
++	orig52c = rt2800_register_read(rt2x00dev, RF_BYPASS2);
++
++	macvalue = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
++	macvalue &= (~0x04);
++	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, macvalue);
++
++	for (mtxcycle = 0; mtxcycle < 10000; mtxcycle++) {
++		macvalue = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG);
++		if (macvalue & 0x01)
++			udelay(50);
++		else
++			break;
++	}
++
++	macvalue = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
++	macvalue &= (~0x08);
++	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, macvalue);
++
++	for (mtxcycle = 0; mtxcycle < 10000; mtxcycle++) {
++		macvalue = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG);
++		if (macvalue & 0x02)
++			udelay(50);
++		else
++			break;
++	}
++
++	for (ch_idx = 0; ch_idx < 2; ch_idx++) {
++		rt2800_rf_configstore(rt2x00dev, rf_store, ch_idx);
++	}
++
++	bbpr30 = rt2800_bbp_read(rt2x00dev, 30);
++	rfb0r39 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 39);
++	rfb0r42 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 42);
++
++	rt2800_bbp_write(rt2x00dev, 30, 0x1F);
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 39, 0x80);
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 42, 0x5B);
++
++	rt2800_bbp_write(rt2x00dev, 23, 0x00);
++	rt2800_bbp_write(rt2x00dev, 24, 0x00);
++
++	rt2800_setbbptonegenerator(rt2x00dev);
++
++	for (ch_idx = 0; ch_idx < 2; ch_idx ++) {
++		rt2800_bbp_write(rt2x00dev, 23, 0x00);
++		rt2800_bbp_write(rt2x00dev, 24, 0x00);
++		rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00);
++		rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0x0000000F);
++		rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00000004);
++		rt2800_register_write(rt2x00dev, RF_BYPASS0, 0x00003306);
++		rt2800_register_write(rt2x00dev, 0x13b8, 0x10);
++		udelay(1);
++
++		if (ch_idx == 0) {
++			rt2800_rf_aux_tx0_loopback(rt2x00dev);
++		} else {
++			rt2800_rf_aux_tx1_loopback(rt2x00dev);
++		}
++		udelay(1);
++
++		if (ch_idx == 0) {
++			rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00001004);
++		} else {
++			rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00002004);
++		}
++
++		rt2800_bbp_write(rt2x00dev, 158, 0x05);
++		rt2800_bbp_write(rt2x00dev, 159, 0x00);
++
++		rt2800_bbp_write(rt2x00dev, 158, 0x01);
++		if (ch_idx == 0)
++			rt2800_bbp_write(rt2x00dev, 159, 0x00);
++		else
++			rt2800_bbp_write(rt2x00dev, 159, 0x01);
++
++		vga_gain[ch_idx] = 18;
++		for (rf_alc_idx = 0; rf_alc_idx < 3; rf_alc_idx++) {
++			rt2800_bbp_write(rt2x00dev, 23, bbp_2324gain[rf_alc_idx]);
++			rt2800_bbp_write(rt2x00dev, 24, bbp_2324gain[rf_alc_idx]);
++
++			macvalue = rt2800_register_read(rt2x00dev, RF_CONTROL3);
++			macvalue &= (~0x0000F1F1);
++			macvalue |= (rf_gain[rf_alc_idx] << 4);
++			macvalue |= (rf_gain[rf_alc_idx] << 12);
++			rt2800_register_write(rt2x00dev, RF_CONTROL3, macvalue);
++			macvalue = (0x0000F1F1);
++			rt2800_register_write(rt2x00dev, RF_BYPASS3, macvalue);
++
++			if (rf_alc_idx == 0) {
++				rt2800_write_dc(rt2x00dev, ch_idx, 0, 1, 0x21);
++				for (;vga_gain[ch_idx] > 0;vga_gain[ch_idx] = vga_gain[ch_idx] - 2) {
++					rfvalue = rfvga_gain_table[vga_gain[ch_idx]];
++					rt2800_rfcsr_write_dccal(rt2x00dev, 3, rfvalue);
++					rt2800_rfcsr_write_dccal(rt2x00dev, 4, rfvalue);
++					rt2800_write_dc(rt2x00dev, ch_idx, 0, 1, 0x00);
++					rt2800_write_dc(rt2x00dev, ch_idx, 0, 0, 0x00);
++					p0 = rt2800_do_fft_accumulation(rt2x00dev, 0x0A, 0);
++					rt2800_write_dc(rt2x00dev, ch_idx, 0, 0, 0x21);
++					p1 = rt2800_do_fft_accumulation(rt2x00dev, 0x0A, 0);
++					rt2x00_dbg(rt2x00dev, "LOFT AGC %d %d\n", p0, p1);
++					if ((p0 < 7000*7000) && (p1 < (7000*7000))) {
++						break;
++					}
++				}
++
++				rt2800_write_dc(rt2x00dev, ch_idx, 0, 0, 0x00);
++				rt2800_write_dc(rt2x00dev, ch_idx, 0, 1, 0x00);
++
++				rt2x00_dbg(rt2x00dev, "Used VGA %d %x\n",vga_gain[ch_idx], rfvga_gain_table[vga_gain[ch_idx]]);
++
++				if (vga_gain[ch_idx] < 0)
++					vga_gain[ch_idx] = 0;
++		 	}
++
++			rfvalue = rfvga_gain_table[vga_gain[ch_idx]];
++
++			rt2800_rfcsr_write_dccal(rt2x00dev, 3, rfvalue);
++			rt2800_rfcsr_write_dccal(rt2x00dev, 4, rfvalue);
++
++			rt2800_loft_search(rt2x00dev, ch_idx, rf_alc_idx, loft_dc_search_result);
++		}
++	}
++
++	for (rf_alc_idx = 0; rf_alc_idx < 3; rf_alc_idx++) {
++		for (idx = 0; idx < 4; idx++) {
++			rt2800_bbp_write(rt2x00dev, 158, 0xB0);
++			bbp = (idx<<2) + rf_alc_idx;
++			rt2800_bbp_write(rt2x00dev, 159, bbp);
++			rt2x00_dbg(rt2x00dev, " ALC %2x,", bbp);
++
++			rt2800_bbp_write(rt2x00dev, 158, 0xb1);
++			bbp = loft_dc_search_result[CHAIN_0][rf_alc_idx][0x00];
++			bbp = bbp & 0x3F;
++			rt2800_bbp_write(rt2x00dev, 159, bbp);
++			rt2x00_dbg(rt2x00dev, " I0 %2x,", bbp);
++
++			rt2800_bbp_write(rt2x00dev, 158, 0xb2);
++			bbp = loft_dc_search_result[CHAIN_0][rf_alc_idx][0x01];
++			bbp = bbp & 0x3F;
++			rt2800_bbp_write(rt2x00dev, 159, bbp);
++			rt2x00_dbg(rt2x00dev, " Q0 %2x,", bbp);
++
++			rt2800_bbp_write(rt2x00dev, 158, 0xb8);
++			bbp = loft_dc_search_result[CHAIN_1][rf_alc_idx][0x00];
++			bbp = bbp & 0x3F;
++			rt2800_bbp_write(rt2x00dev, 159, bbp);
++			rt2x00_dbg(rt2x00dev, " I1 %2x,", bbp);
++
++			rt2800_bbp_write(rt2x00dev, 158, 0xb9);
++			bbp = loft_dc_search_result[CHAIN_1][rf_alc_idx][0x01];
++			bbp = bbp & 0x3F;
++			rt2800_bbp_write(rt2x00dev, 159, bbp);
++			rt2x00_dbg(rt2x00dev, " Q1 %2x\n", bbp);
++		}
++	}
++
++	rt2800_bbp_write(rt2x00dev, 23, 0x00);
++	rt2800_bbp_write(rt2x00dev, 24, 0x00);
++
++	rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x04);
++
++	rt2800_bbp_write(rt2x00dev, 158, 0x00);
++	rt2800_bbp_write(rt2x00dev, 159, 0x00);
++
++	bbp = 0x00;
++	rt2800_bbp_write(rt2x00dev, 244, 0x00);
++
++	rt2800_bbp_write(rt2x00dev, 21, 0x01);
++	udelay(1);
++	rt2800_bbp_write(rt2x00dev, 21, 0x00);
++
++	rt2800_rf_configrecover(rt2x00dev, rf_store);
++
++	rt2800_register_write(rt2x00dev, TX_PIN_CFG, macorg1);
++	rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x04);
++	rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00);
++	rt2800_register_write(rt2x00dev, RF_BYPASS0, 0x00);
++	rt2800_register_write(rt2x00dev, RF_CONTROL0, macorg2);
++	udelay(1);
++	rt2800_register_write(rt2x00dev, RF_BYPASS0, macorg3);
++	rt2800_register_write(rt2x00dev, RF_CONTROL3, macorg4);
++	rt2800_register_write(rt2x00dev, RF_BYPASS3, macorg5);
++	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, savemacsysctrl);
++	rt2800_register_write(rt2x00dev, RF_CONTROL2, orig528);
++	rt2800_register_write(rt2x00dev, RF_BYPASS2, orig52c);
++	rt2800_register_write(rt2x00dev, 0x13b8, mac13b8);
++
++	rt2x00_info(rt2x00dev, "LOFT Calibration Done!\n");
++
++	savemacsysctrl = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
++	macorg1 = rt2800_register_read(rt2x00dev, TX_PIN_CFG);
++	macorg2 = rt2800_register_read(rt2x00dev, RF_CONTROL0);
++	macorg3 = rt2800_register_read(rt2x00dev, RF_BYPASS0);
++	macorg4 = rt2800_register_read(rt2x00dev, RF_CONTROL3);
++	macorg5 = rt2800_register_read(rt2x00dev, RF_BYPASS3);
++
++	bbpr1 = rt2800_bbp_read(rt2x00dev, 1);
++	bbpr4 = rt2800_bbp_read(rt2x00dev, 4);
++	bbpr241 = rt2800_bbp_read(rt2x00dev, 241);
++	bbpr242 = rt2800_bbp_read(rt2x00dev, 242);
++	mac13b8 = rt2800_register_read(rt2x00dev, 0x13b8);
++
++	macvalue = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
++	macvalue &= (~0x04);
++	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, macvalue);
++	for (mtxcycle = 0; mtxcycle < 10000; mtxcycle++) {
++		macvalue = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG);
++		if (macvalue & 0x01)
++			udelay(50);
++		else
++			break;
++	}
++
++	macvalue = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
++	macvalue &= (~0x08);
++	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, macvalue);
++	for (mtxcycle = 0; mtxcycle < 10000; mtxcycle++) {
++		macvalue = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG);
++		if (macvalue & 0x02)
++			udelay(50);
++		else
++			break;
++	}
++
++	if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) {
++		rt2800_register_write(rt2x00dev, RF_CONTROL3, 0x00000101);
++		rt2800_register_write(rt2x00dev, RF_BYPASS3, 0x0000F1F1);
++	}
++
++	rt2800_bbp_write(rt2x00dev, 23, 0x00);
++	rt2800_bbp_write(rt2x00dev, 24, 0x00);
++
++	if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) {
++		rt2800_bbp_write(rt2x00dev, 4, bbpr4 & (~0x18));
++		rt2800_bbp_write(rt2x00dev, 21, 0x01);
++		udelay(1);
++		rt2800_bbp_write(rt2x00dev, 21, 0x00);
++
++		rt2800_bbp_write(rt2x00dev, 241, 0x14);
++		rt2800_bbp_write(rt2x00dev, 242, 0x80);
++		rt2800_bbp_write(rt2x00dev, 244, 0x31);
++	} else {
++		rt2800_setbbptonegenerator(rt2x00dev);
++	}
++
++	rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00000004);
++	rt2800_register_write(rt2x00dev, RF_BYPASS0, 0x00003306);
++	udelay(1);
++
++	rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0x0000000F);
++
++	if (!test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) {
++		rt2800_register_write(rt2x00dev, RF_CONTROL3, 0x00000000);
++		rt2800_register_write(rt2x00dev, RF_BYPASS3, 0x0000F1F1);
++	}
++
++	rt2800_register_write(rt2x00dev, 0x13b8, 0x00000010);
++
++	for (ch_idx = 0; ch_idx < 2; ch_idx++) {
++		rt2800_rf_configstore(rt2x00dev, rf_store, ch_idx);
++	}
++
++	rt2800_rfcsr_write_dccal(rt2x00dev, 3, 0x3B);
++	rt2800_rfcsr_write_dccal(rt2x00dev, 4, 0x3B);
++
++	rt2800_bbp_write(rt2x00dev, 158, 0x03);
++	rt2800_bbp_write(rt2x00dev, 159, 0x60);
++	rt2800_bbp_write(rt2x00dev, 158, 0xB0);
++	rt2800_bbp_write(rt2x00dev, 159, 0x80);
++
++	for (ch_idx = 0; ch_idx < 2; ch_idx ++) {
++		rt2800_bbp_write(rt2x00dev, 23, 0x00);
++		rt2800_bbp_write(rt2x00dev, 24, 0x00);
++
++		if (ch_idx == 0) {
++			rt2800_bbp_write(rt2x00dev, 158, 0x01);
++			rt2800_bbp_write(rt2x00dev, 159, 0x00);
++			if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) {
++				bbp = bbpr1 & (~0x18);
++				bbp = bbp | 0x00;
++				rt2800_bbp_write(rt2x00dev, 1, bbp);
++			}
++			rt2800_rf_aux_tx0_loopback(rt2x00dev);
++			rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00001004);
++		} else {
++			rt2800_bbp_write(rt2x00dev, 158, 0x01);
++			rt2800_bbp_write(rt2x00dev, 159, 0x01);
++			if (test_bit(CAPABILITY_EXTERNAL_PA_TX1, &rt2x00dev->cap_flags)) {
++				bbp = bbpr1 & (~0x18);
++				bbp = bbp | 0x08;
++				rt2800_bbp_write(rt2x00dev, 1, bbp);
++			}
++			rt2800_rf_aux_tx1_loopback(rt2x00dev);
++			rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00002004);
++		}
++
++		rt2800_bbp_write(rt2x00dev, 158, 0x05);
++		rt2800_bbp_write(rt2x00dev, 159, 0x04);
++
++		bbp = (ch_idx == 0) ? 0x28 : 0x46;
++		rt2800_bbp_write(rt2x00dev, 158, bbp);
++		rt2800_bbp_write(rt2x00dev, 159, 0x00);
++
++		if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) {
++			rt2800_bbp_write(rt2x00dev, 23, 0x06);
++			rt2800_bbp_write(rt2x00dev, 24, 0x06);
++			count_step = 1;
++		} else {
++			rt2800_bbp_write(rt2x00dev, 23, 0x1F);
++			rt2800_bbp_write(rt2x00dev, 24, 0x1F);
++			count_step = 2;
++		}
++
++		for (;vga_gain[ch_idx] < 19; vga_gain[ch_idx]=(vga_gain[ch_idx] + count_step)) {
++			rfvalue = rfvga_gain_table[vga_gain[ch_idx]];
++			rt2800_rfcsr_write_dccal(rt2x00dev, 3, rfvalue);
++			rt2800_rfcsr_write_dccal(rt2x00dev, 4, rfvalue);
++
++			bbp = (ch_idx == 0) ? 0x29 : 0x47;
++			rt2800_bbp_write(rt2x00dev, 158, bbp);
++			rt2800_bbp_write(rt2x00dev, 159, 0x00);
++			p0 = rt2800_do_fft_accumulation(rt2x00dev, 0x14, 0);
++			if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) {
++				p0_idx10 = rt2800_read_fft_accumulation(rt2x00dev, 0x0A);
++			}
++
++			bbp = (ch_idx == 0) ? 0x29 : 0x47;
++			rt2800_bbp_write(rt2x00dev, 158, bbp);
++			rt2800_bbp_write(rt2x00dev, 159, 0x21);
++			p1 = rt2800_do_fft_accumulation(rt2x00dev, 0x14, 0);
++			if (test_bit(CAPABILITY_EXTERNAL_PA_TX1, &rt2x00dev->cap_flags)) {
++				p1_idx10 = rt2800_read_fft_accumulation(rt2x00dev, 0x0A);
++			}
++
++			rt2x00_dbg(rt2x00dev, "IQ AGC %d %d\n", p0, p1);
++
++			if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) {
++				rt2x00_dbg(rt2x00dev, "IQ AGC IDX 10 %d %d\n", p0_idx10, p1_idx10);
++				if ((p0_idx10 > 7000*7000) || (p1_idx10 > 7000*7000)) {
++					if (vga_gain[ch_idx]!=0)
++						vga_gain[ch_idx] = vga_gain[ch_idx]-1;
++					break;
++				}
++			}
++
++			if ((p0 > 2500*2500) || (p1 > 2500*2500)) {
++				break;
++			}
++		}
++
++		if (vga_gain[ch_idx] > 18)
++			vga_gain[ch_idx] = 18;
++		rt2x00_dbg(rt2x00dev, "Used VGA %d %x\n",vga_gain[ch_idx], rfvga_gain_table[vga_gain[ch_idx]]);
++
++		bbp = (ch_idx == 0) ? 0x29 : 0x47;
++		rt2800_bbp_write(rt2x00dev, 158, bbp);
++		rt2800_bbp_write(rt2x00dev, 159, 0x00);
++
++		rt2800_iq_search(rt2x00dev, ch_idx, ger, per);
++	}
++
++	rt2800_bbp_write(rt2x00dev, 23, 0x00);
++	rt2800_bbp_write(rt2x00dev, 24, 0x00);
++	rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x04);
++
++	rt2800_bbp_write(rt2x00dev, 158, 0x28);
++	bbp = ger[CHAIN_0] & 0x0F;
++	rt2800_bbp_write(rt2x00dev, 159, bbp);
++
++	rt2800_bbp_write(rt2x00dev, 158, 0x29);
++	bbp = per[CHAIN_0] & 0x3F;
++	rt2800_bbp_write(rt2x00dev, 159, bbp);
++
++	rt2800_bbp_write(rt2x00dev, 158, 0x46);
++	bbp = ger[CHAIN_1] & 0x0F;
++	rt2800_bbp_write(rt2x00dev, 159, bbp);
++
++	rt2800_bbp_write(rt2x00dev, 158, 0x47);
++	bbp = per[CHAIN_1] & 0x3F;
++	rt2800_bbp_write(rt2x00dev, 159, bbp);
++
++	if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) {
++		rt2800_bbp_write(rt2x00dev, 1, bbpr1);
++		rt2800_bbp_write(rt2x00dev, 241, bbpr241);
++		rt2800_bbp_write(rt2x00dev, 242, bbpr242);
++	}
++	rt2800_bbp_write(rt2x00dev, 244, 0x00);
++
++	rt2800_bbp_write(rt2x00dev, 158, 0x00);
++	rt2800_bbp_write(rt2x00dev, 159, 0x00);
++	rt2800_bbp_write(rt2x00dev, 158, 0xB0);
++	rt2800_bbp_write(rt2x00dev, 159, 0x00);
++
++	rt2800_bbp_write(rt2x00dev, 30, bbpr30);
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 39, rfb0r39);
++	rt2800_rfcsr_write_bank(rt2x00dev, 0, 42, rfb0r42);
++
++	if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) {
++		rt2800_bbp_write(rt2x00dev, 4, bbpr4);
++	}
++
++	rt2800_bbp_write(rt2x00dev, 21, 0x01);
++	udelay(1);
++	rt2800_bbp_write(rt2x00dev, 21, 0x00);
++
++	rt2800_rf_configrecover(rt2x00dev, rf_store);
++
++	rt2800_register_write(rt2x00dev, TX_PIN_CFG, macorg1);
++	rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00);
++	rt2800_register_write(rt2x00dev, RF_BYPASS0, 0x00);
++	rt2800_register_write(rt2x00dev, RF_CONTROL0, macorg2);
++	udelay(1);
++	rt2800_register_write(rt2x00dev, RF_BYPASS0, macorg3);
++	rt2800_register_write(rt2x00dev, RF_CONTROL3, macorg4);
++	rt2800_register_write(rt2x00dev, RF_BYPASS3, macorg5);
++	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, savemacsysctrl);
++	rt2800_register_write(rt2x00dev, 0x13b8, mac13b8);
++
++	rt2x00_info(rt2x00dev, "TX IQ Calibration Done!\n");
++
++	return;
++}
++
+ static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev,
+ 				       bool set_bw, bool is_ht40)
+ {
+@@ -9698,6 +10635,7 @@ static void rt2800_init_rfcsr_6352(struc
+ 	rt2800_rxdcoc_calibration(rt2x00dev);
+ 	rt2800_bw_filter_calibration(rt2x00dev, true);
+ 	rt2800_bw_filter_calibration(rt2x00dev, false);
++	rt2800_loft_iq_calibration(rt2x00dev);
+ 	rt2800_rxiq_calibration(rt2x00dev);
+ }
+ 
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+@@ -17,6 +17,16 @@
+ #define WCID_START	33
+ #define WCID_END	222
+ #define STA_IDS_SIZE	(WCID_END - WCID_START + 2)
++#define CHAIN_0		0x0
++#define CHAIN_1		0x1
++#define RF_ALC_NUM	6
++#define CHAIN_NUM	2
++
++typedef struct rf_reg_pair {
++	u8 bank;
++	u8 reg;
++	u8 value;
++} rf_reg_pair;
+ 
+ /* RT2800 driver data structure */
+ struct rt2800_drv_data {
diff --git a/package/kernel/mac80211/patches/rt2x00/990-rt2x00-mt7620-introduce-accessors-for-CHIP_VER-register.patch b/package/kernel/mac80211/patches/rt2x00/990-rt2x00-mt7620-introduce-accessors-for-CHIP_VER-register.patch
new file mode 100644
index 0000000..76114fe
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/990-rt2x00-mt7620-introduce-accessors-for-CHIP_VER-register.patch
@@ -0,0 +1,139 @@
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+@@ -78,6 +78,9 @@ struct rt2800_ops {
+ 	int (*drv_init_registers)(struct rt2x00_dev *rt2x00dev);
+ 	__le32 *(*drv_get_txwi)(struct queue_entry *entry);
+ 	unsigned int (*drv_get_dma_done)(struct data_queue *queue);
++	int (*hw_get_chippkg)(void);
++	int (*hw_get_chipver)(void);
++	int (*hw_get_chipeco)(void);
+ };
+ 
+ static inline u32 rt2800_register_read(struct rt2x00_dev *rt2x00dev,
+@@ -195,6 +198,27 @@ static inline unsigned int rt2800_drv_ge
+ 	return rt2800ops->drv_get_dma_done(queue);
+ }
+ 
++static inline int rt2800_hw_get_chippkg(struct rt2x00_dev *rt2x00dev)
++{
++	const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
++
++	return rt2800ops->hw_get_chippkg();
++}
++
++static inline int rt2800_hw_get_chipver(struct rt2x00_dev *rt2x00dev)
++{
++	const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
++
++	return rt2800ops->hw_get_chipver();
++}
++
++static inline int rt2800_hw_get_chipeco(struct rt2x00_dev *rt2x00dev)
++{
++	const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
++
++	return rt2800ops->hw_get_chipeco();
++}
++
+ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
+ 			const u8 command, const u8 token,
+ 			const u8 arg0, const u8 arg1);
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
+@@ -286,6 +286,10 @@ static int rt2800pci_read_eeprom(struct
+ 	return retval;
+ }
+ 
++static int rt2800pci_get_chippkg(void) { return 0; }
++static int rt2800pci_get_chipver(void) { return 0; }
++static int rt2800pci_get_chipeco(void) { return 0; }
++
+ static const struct ieee80211_ops rt2800pci_mac80211_ops = {
+ 	.tx			= rt2x00mac_tx,
+ 	.start			= rt2x00mac_start,
+@@ -328,6 +332,9 @@ static const struct rt2800_ops rt2800pci
+ 	.drv_init_registers	= rt2800mmio_init_registers,
+ 	.drv_get_txwi		= rt2800mmio_get_txwi,
+ 	.drv_get_dma_done	= rt2800mmio_get_dma_done,
++	.hw_get_chippkg		= rt2800pci_get_chippkg,
++	.hw_get_chipver		= rt2800pci_get_chipver,
++	.hw_get_chipeco		= rt2800pci_get_chipeco,
+ };
+ 
+ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+@@ -27,6 +27,12 @@
+ #include "rt2800lib.h"
+ #include "rt2800mmio.h"
+ 
++/* Needed to probe CHIP_VER register on MT7620 */
++#ifdef CONFIG_SOC_MT7620
++#include <asm/mach-ralink/ralink_regs.h>
++#include <asm/mach-ralink/mt7620.h>
++#endif
++
+ /* Allow hardware encryption to be disabled. */
+ static bool modparam_nohwcrypt;
+ module_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444);
+@@ -118,6 +124,27 @@ static int rt2800soc_write_firmware(stru
+ 	return 0;
+ }
+ 
++#ifdef CONFIG_SOC_MT7620
++static int rt2800soc_get_chippkg(void)
++{
++	return mt7620_get_pkg();
++}
++
++static int rt2800soc_get_chipver(void)
++{
++	return mt7620_get_chipver();
++}
++
++static int rt2800soc_get_chipeco(void)
++{
++	return mt7620_get_eco();
++}
++#else
++static int rt2800soc_get_chippkg(void) { return 0; }
++static int rt2800soc_get_chipver(void) { return 0; }
++static int rt2800soc_get_chipeco(void) { return 0; }
++#endif
++
+ static const struct ieee80211_ops rt2800soc_mac80211_ops = {
+ 	.tx			= rt2x00mac_tx,
+ 	.start			= rt2x00mac_start,
+@@ -159,6 +186,9 @@ static const struct rt2800_ops rt2800soc
+ 	.drv_init_registers	= rt2800mmio_init_registers,
+ 	.drv_get_txwi		= rt2800mmio_get_txwi,
+ 	.drv_get_dma_done	= rt2800mmio_get_dma_done,
++	.hw_get_chippkg		= rt2800soc_get_chippkg,
++	.hw_get_chipver		= rt2800soc_get_chipver,
++	.hw_get_chipeco		= rt2800soc_get_chipeco,
+ };
+ 
+ static const struct rt2x00lib_ops rt2800soc_rt2x00_ops = {
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
+@@ -628,6 +628,10 @@ static int rt2800usb_probe_hw(struct rt2
+ 	return 0;
+ }
+ 
++static int rt2800usb_get_chippkg(void) { return 0; }
++static int rt2800usb_get_chipver(void) { return 0; }
++static int rt2800usb_get_chipeco(void) { return 0; }
++
+ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
+ 	.tx			= rt2x00mac_tx,
+ 	.start			= rt2x00mac_start,
+@@ -671,6 +675,9 @@ static const struct rt2800_ops rt2800usb
+ 	.drv_init_registers	= rt2800usb_init_registers,
+ 	.drv_get_txwi		= rt2800usb_get_txwi,
+ 	.drv_get_dma_done	= rt2800usb_get_dma_done,
++	.hw_get_chippkg		= rt2800usb_get_chippkg,
++	.hw_get_chipver		= rt2800usb_get_chipver,
++	.hw_get_chipeco		= rt2800usb_get_chipeco,
+ };
+ 
+ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
diff --git a/package/kernel/mac80211/patches/rt2x00/991-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch b/package/kernel/mac80211/patches/rt2x00/991-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch
new file mode 100644
index 0000000..a724232
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/991-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch
@@ -0,0 +1,408 @@
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800.h
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800.h
+@@ -1042,6 +1042,11 @@
+ #define MIMO_PS_CFG_RX_STBY_POL		FIELD32(0x00000010)
+ #define MIMO_PS_CFG_RX_RX_STBY0		FIELD32(0x00000020)
+ 
++#define BB_PA_MODE_CFG0			0x1214
++#define BB_PA_MODE_CFG1			0x1218
++#define RF_PA_MODE_CFG0			0x121C
++#define RF_PA_MODE_CFG1			0x1220
++
+ /*
+  * EDCA_AC0_CFG:
+  */
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+@@ -3685,14 +3685,16 @@ static void rt2800_config_channel_rf7620
+ 	rt2x00_set_field8(&rfcsr, RFCSR19_K, rf->rf4);
+ 	rt2800_rfcsr_write(rt2x00dev, 19, rfcsr);
+ 
+-	/* Default: XO=20MHz , SDM mode */
+-	rfcsr = rt2800_rfcsr_read(rt2x00dev, 16);
+-	rt2x00_set_field8(&rfcsr, RFCSR16_SDM_MODE_MT7620, 0x80);
+-	rt2800_rfcsr_write(rt2x00dev, 16, rfcsr);
+-
+-	rfcsr = rt2800_rfcsr_read(rt2x00dev, 21);
+-	rt2x00_set_field8(&rfcsr, RFCSR21_BIT8, 1);
+-	rt2800_rfcsr_write(rt2x00dev, 21, rfcsr);
++	if (rt2800_hw_get_chipver(rt2x00dev) > 1) {
++		/* Default: XO=20MHz , SDM mode */
++		rfcsr = rt2800_rfcsr_read(rt2x00dev, 16);
++		rt2x00_set_field8(&rfcsr, RFCSR16_SDM_MODE_MT7620, 0x80);
++		rt2800_rfcsr_write(rt2x00dev, 16, rfcsr);
++
++		rfcsr = rt2800_rfcsr_read(rt2x00dev, 21);
++		rt2x00_set_field8(&rfcsr, RFCSR21_BIT8, 1);
++		rt2800_rfcsr_write(rt2x00dev, 21, rfcsr);
++	}
+ 
+ 	rfcsr = rt2800_rfcsr_read(rt2x00dev, 1);
+ 	rt2x00_set_field8(&rfcsr, RFCSR1_TX2_EN_MT7620,
+@@ -3726,18 +3728,23 @@ static void rt2800_config_channel_rf7620
+ 		rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x20);
+ 	}
+ 
+-	if (conf_is_ht40(conf)) {
+-		rt2800_rfcsr_write_dccal(rt2x00dev, 58, 0x08);
+-		rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x08);
+-	} else {
+-		rt2800_rfcsr_write_dccal(rt2x00dev, 58, 0x28);
+-		rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x28);
++	if (rt2800_hw_get_chipver(rt2x00dev) > 1) {
++		if (conf_is_ht40(conf)) {
++			rt2800_rfcsr_write_dccal(rt2x00dev, 58, 0x08);
++			rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x08);
++		} else {
++			rt2800_rfcsr_write_dccal(rt2x00dev, 58, 0x28);
++			rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x28);
++		}
+ 	}
+ 
+-	rfcsr = rt2800_rfcsr_read(rt2x00dev, 28);
+-	rt2x00_set_field8(&rfcsr, RFCSR28_CH11_HT40,
+-			  conf_is_ht40(conf) && (rf->channel == 11));
+-	rt2800_rfcsr_write(rt2x00dev, 28, rfcsr);
++	if (rt2800_hw_get_chipver(rt2x00dev) > 1 &&
++	    rt2800_hw_get_chipeco(rt2x00dev) == 2) {
++		rfcsr = rt2800_rfcsr_read(rt2x00dev, 28);
++		rt2x00_set_field8(&rfcsr, RFCSR28_CH11_HT40,
++				  conf_is_ht40(conf) && (rf->channel == 11));
++		rt2800_rfcsr_write(rt2x00dev, 28, rfcsr);
++	}
+ 
+ 	if (!test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags)) {
+ 		if (conf_is_ht40(conf)) {
+@@ -3837,25 +3844,29 @@ static void rt2800_config_alc(struct rt2
+ 	if (i == 10000)
+ 		rt2x00_warn(rt2x00dev, "Wait MAC Status to MAX !!!\n");
+ 
+-	if (chan->center_freq > 2457) {
+-		bbp = rt2800_bbp_read(rt2x00dev, 30);
+-		bbp = 0x40;
+-		rt2800_bbp_write(rt2x00dev, 30, bbp);
+-		rt2800_rfcsr_write(rt2x00dev, 39, 0);
+-		if (rt2x00_has_cap_external_lna_bg(rt2x00dev))
+-			rt2800_rfcsr_write(rt2x00dev, 42, 0xfb);
+-		else
+-			rt2800_rfcsr_write(rt2x00dev, 42, 0x7b);
+-	} else {
+-		bbp = rt2800_bbp_read(rt2x00dev, 30);
+-		bbp = 0x1f;
+-		rt2800_bbp_write(rt2x00dev, 30, bbp);
+-		rt2800_rfcsr_write(rt2x00dev, 39, 0x80);
+-		if (rt2x00_has_cap_external_lna_bg(rt2x00dev))
+-			rt2800_rfcsr_write(rt2x00dev, 42, 0xdb);
+-		else
+-			rt2800_rfcsr_write(rt2x00dev, 42, 0x5b);
++	if (rt2800_hw_get_chipver(rt2x00dev) > 1 &&
++	    rt2800_hw_get_chipeco(rt2x00dev) >= 2) {
++		if (chan->center_freq > 2457) {
++			bbp = rt2800_bbp_read(rt2x00dev, 30);
++			bbp = 0x40;
++			rt2800_bbp_write(rt2x00dev, 30, bbp);
++			rt2800_rfcsr_write(rt2x00dev, 39, 0);
++			if (rt2x00_has_cap_external_lna_bg(rt2x00dev))
++				rt2800_rfcsr_write(rt2x00dev, 42, 0xfb);
++			else
++				rt2800_rfcsr_write(rt2x00dev, 42, 0x7b);
++		} else {
++			bbp = rt2800_bbp_read(rt2x00dev, 30);
++			bbp = 0x1f;
++			rt2800_bbp_write(rt2x00dev, 30, bbp);
++			rt2800_rfcsr_write(rt2x00dev, 39, 0x80);
++			if (rt2x00_has_cap_external_lna_bg(rt2x00dev))
++				rt2800_rfcsr_write(rt2x00dev, 42, 0xdb);
++			else
++				rt2800_rfcsr_write(rt2x00dev, 42, 0x5b);
++		}
+ 	}
++
+ 	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, mac_sys_ctrl);
+ 
+ 	rt2800_vco_calibration(rt2x00dev);
+@@ -5892,18 +5903,33 @@ static int rt2800_init_registers(struct
+ 	} else if (rt2x00_rt(rt2x00dev, RT5350)) {
+ 		rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404);
+ 	} else if (rt2x00_rt(rt2x00dev, RT6352)) {
+-		rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000401);
+-		rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x000C0001);
+-		rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
+-		rt2800_register_write(rt2x00dev, TX_ALC_VGA3, 0x00000000);
+-		rt2800_register_write(rt2x00dev, TX0_BB_GAIN_ATTEN, 0x0);
+-		rt2800_register_write(rt2x00dev, TX1_BB_GAIN_ATTEN, 0x0);
+-		rt2800_register_write(rt2x00dev, TX0_RF_GAIN_ATTEN, 0x6C6C666C);
+-		rt2800_register_write(rt2x00dev, TX1_RF_GAIN_ATTEN, 0x6C6C666C);
+-		rt2800_register_write(rt2x00dev, TX0_RF_GAIN_CORRECT,
+-				      0x3630363A);
+-		rt2800_register_write(rt2x00dev, TX1_RF_GAIN_CORRECT,
+-				      0x3630363A);
++		if (rt2800_hw_get_chipver(rt2x00dev) <= 1) {
++			rt2800_register_write(rt2x00dev, TX_ALC_VGA3,
++					      0x00000000);
++			rt2800_register_write(rt2x00dev, BB_PA_MODE_CFG0,
++					      0x000055FF);
++			rt2800_register_write(rt2x00dev, BB_PA_MODE_CFG1,
++					      0x00550055);
++			rt2800_register_write(rt2x00dev, RF_PA_MODE_CFG0,
++					      0x000055FF);
++			rt2800_register_write(rt2x00dev, RF_PA_MODE_CFG1,
++					      0x00550055);
++		} else {
++			rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000401);
++			rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x000C0001);
++			rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
++			rt2800_register_write(rt2x00dev, TX_ALC_VGA3, 0x00000000);
++			rt2800_register_write(rt2x00dev, TX0_BB_GAIN_ATTEN, 0x0);
++			rt2800_register_write(rt2x00dev, TX1_BB_GAIN_ATTEN, 0x0);
++			rt2800_register_write(rt2x00dev, TX0_RF_GAIN_ATTEN,
++					      0x6C6C666C);
++			rt2800_register_write(rt2x00dev, TX1_RF_GAIN_ATTEN,
++					      0x6C6C666C);
++			rt2800_register_write(rt2x00dev, TX0_RF_GAIN_CORRECT,
++					      0x3630363A);
++			rt2800_register_write(rt2x00dev, TX1_RF_GAIN_CORRECT,
++					      0x3630363A);
++		}
+ 		reg = rt2800_register_read(rt2x00dev, TX_ALC_CFG_1);
+ 		rt2x00_set_field32(&reg, TX_ALC_CFG_1_ROS_BUSY_EN, 0);
+ 		rt2800_register_write(rt2x00dev, TX_ALC_CFG_1, reg);
+@@ -7068,14 +7094,16 @@ static void rt2800_init_bbp_6352(struct
+ 	rt2800_bbp_write(rt2x00dev, 188, 0x00);
+ 	rt2800_bbp_write(rt2x00dev, 189, 0x00);
+ 
+-	rt2800_bbp_write(rt2x00dev, 91, 0x06);
+-	rt2800_bbp_write(rt2x00dev, 92, 0x04);
+-	rt2800_bbp_write(rt2x00dev, 93, 0x54);
+-	rt2800_bbp_write(rt2x00dev, 99, 0x50);
+-	rt2800_bbp_write(rt2x00dev, 148, 0x84);
+-	rt2800_bbp_write(rt2x00dev, 167, 0x80);
+-	rt2800_bbp_write(rt2x00dev, 178, 0xFF);
+-	rt2800_bbp_write(rt2x00dev, 106, 0x13);
++	if (rt2800_hw_get_chipver(rt2x00dev) > 1) {
++		rt2800_bbp_write(rt2x00dev, 91, 0x06);
++		rt2800_bbp_write(rt2x00dev, 92, 0x04);
++		rt2800_bbp_write(rt2x00dev, 93, 0x54);
++		rt2800_bbp_write(rt2x00dev, 99, 0x50);
++		rt2800_bbp_write(rt2x00dev, 148, 0x84);
++		rt2800_bbp_write(rt2x00dev, 167, 0x80);
++		rt2800_bbp_write(rt2x00dev, 178, 0xFF);
++		rt2800_bbp_write(rt2x00dev, 106, 0x13);
++	}
+ 
+ 	/* BBP for G band GLRT function (BBP_128 ~ BBP_221) */
+ 	rt2800_bbp_glrt_write(rt2x00dev, 0, 0x00);
+@@ -10414,31 +10442,36 @@ static void rt2800_init_rfcsr_6352(struc
+ 	rt2800_rfcsr_write(rt2x00dev, 42, 0x5B);
+ 	rt2800_rfcsr_write(rt2x00dev, 43, 0x00);
+ 
+-	rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
+-	if (rt2800_clk_is_20mhz(rt2x00dev))
+-		rt2800_rfcsr_write(rt2x00dev, 13, 0x03);
+-	else
+-		rt2800_rfcsr_write(rt2x00dev, 13, 0x00);
+-	rt2800_rfcsr_write(rt2x00dev, 14, 0x7C);
+-	rt2800_rfcsr_write(rt2x00dev, 16, 0x80);
+-	rt2800_rfcsr_write(rt2x00dev, 17, 0x99);
+-	rt2800_rfcsr_write(rt2x00dev, 18, 0x99);
+-	rt2800_rfcsr_write(rt2x00dev, 19, 0x09);
+-	rt2800_rfcsr_write(rt2x00dev, 20, 0x50);
+-	rt2800_rfcsr_write(rt2x00dev, 21, 0xB0);
+-	rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
+-	rt2800_rfcsr_write(rt2x00dev, 23, 0x06);
+-	rt2800_rfcsr_write(rt2x00dev, 24, 0x00);
+-	rt2800_rfcsr_write(rt2x00dev, 25, 0x00);
+-	rt2800_rfcsr_write(rt2x00dev, 26, 0x5D);
+-	rt2800_rfcsr_write(rt2x00dev, 27, 0x00);
+-	rt2800_rfcsr_write(rt2x00dev, 28, 0x61);
+-	rt2800_rfcsr_write(rt2x00dev, 29, 0xB5);
+-	rt2800_rfcsr_write(rt2x00dev, 43, 0x02);
+-
+-	rt2800_rfcsr_write(rt2x00dev, 28, 0x62);
+-	rt2800_rfcsr_write(rt2x00dev, 29, 0xAD);
+-	rt2800_rfcsr_write(rt2x00dev, 39, 0x80);
++	if (rt2800_hw_get_chipver(rt2x00dev) > 1) {
++		rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
++		if (rt2800_clk_is_20mhz(rt2x00dev))
++			rt2800_rfcsr_write(rt2x00dev, 13, 0x03);
++		else
++			rt2800_rfcsr_write(rt2x00dev, 13, 0x00);
++		rt2800_rfcsr_write(rt2x00dev, 14, 0x7C);
++		rt2800_rfcsr_write(rt2x00dev, 16, 0x80);
++		rt2800_rfcsr_write(rt2x00dev, 17, 0x99);
++		rt2800_rfcsr_write(rt2x00dev, 18, 0x99);
++		rt2800_rfcsr_write(rt2x00dev, 19, 0x09);
++		rt2800_rfcsr_write(rt2x00dev, 20, 0x50);
++		rt2800_rfcsr_write(rt2x00dev, 21, 0xB0);
++		rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
++		rt2800_rfcsr_write(rt2x00dev, 23, 0x06);
++		rt2800_rfcsr_write(rt2x00dev, 24, 0x00);
++		rt2800_rfcsr_write(rt2x00dev, 25, 0x00);
++		rt2800_rfcsr_write(rt2x00dev, 26, 0x5D);
++		rt2800_rfcsr_write(rt2x00dev, 27, 0x00);
++		rt2800_rfcsr_write(rt2x00dev, 28, 0x61);
++		rt2800_rfcsr_write(rt2x00dev, 29, 0xB5);
++		rt2800_rfcsr_write(rt2x00dev, 43, 0x02);
++	}
++
++	if (rt2800_hw_get_chipver(rt2x00dev) > 1 &&
++	    rt2800_hw_get_chipeco(rt2x00dev) >= 2) {
++		rt2800_rfcsr_write(rt2x00dev, 28, 0x62);
++		rt2800_rfcsr_write(rt2x00dev, 29, 0xAD);
++		rt2800_rfcsr_write(rt2x00dev, 39, 0x80);
++	}
+ 
+ 	/* Initialize RF channel register to default value */
+ 	rt2800_rfcsr_write_chanreg(rt2x00dev, 0, 0x03);
+@@ -10504,63 +10537,71 @@ static void rt2800_init_rfcsr_6352(struc
+ 
+ 	rt2800_rfcsr_write_bank(rt2x00dev, 6, 45, 0xC5);
+ 
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 9, 0x47);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 10, 0x71);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 11, 0x33);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x0E);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 17, 0x23);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 19, 0xA4);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 20, 0x02);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 21, 0x12);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 28, 0x1C);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 29, 0xEB);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 32, 0x7D);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 34, 0xD6);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 36, 0x08);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 38, 0xB4);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0xD3);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0xB3);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0xD5);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 46, 0x27);
+-	rt2800_rfcsr_write_bank(rt2x00dev, 4, 47, 0x67);
+-	rt2800_rfcsr_write_bank(rt2x00dev, 6, 47, 0x69);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xFF);
+-	rt2800_rfcsr_write_bank(rt2x00dev, 4, 54, 0x27);
+-	rt2800_rfcsr_write_bank(rt2x00dev, 6, 54, 0x20);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x66);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xFF);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 57, 0x1C);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x20);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0x6B);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xF7);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 61, 0x09);
+-
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 10, 0x51);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x06);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 19, 0xA7);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 28, 0x2C);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x64);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 8, 0x51);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 9, 0x36);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 11, 0x53);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x16);
+-
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0x6C);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xFC);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 49, 0x1F);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 54, 0x27);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x66);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0x6B);
+-
+-	/* Initialize RF channel register for DRQFN */
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0xD3);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0xE3);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0xE5);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0x28);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x68);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xF7);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x02);
+-	rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xC7);
++	if (rt2800_hw_get_chipver(rt2x00dev) > 1) {
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 9, 0x47);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 10, 0x71);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 11, 0x33);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x0E);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 17, 0x23);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 19, 0xA4);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 20, 0x02);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 21, 0x12);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 28, 0x1C);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 29, 0xEB);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 32, 0x7D);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 34, 0xD6);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 36, 0x08);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 38, 0xB4);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0xD3);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0xB3);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0xD5);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 46, 0x27);
++		rt2800_rfcsr_write_bank(rt2x00dev, 4, 47, 0x67);
++		rt2800_rfcsr_write_bank(rt2x00dev, 6, 47, 0x69);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xFF);
++		rt2800_rfcsr_write_bank(rt2x00dev, 4, 54, 0x27);
++		rt2800_rfcsr_write_bank(rt2x00dev, 6, 54, 0x20);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x66);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xFF);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 57, 0x1C);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x20);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0x6B);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xF7);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 61, 0x09);
++	}
++
++	if (rt2800_hw_get_chipver(rt2x00dev) > 1 &&
++	    rt2800_hw_get_chipeco(rt2x00dev) >= 2) {
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 10, 0x51);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x06);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 19, 0xA7);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 28, 0x2C);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x64);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 8, 0x51);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 9, 0x36);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 11, 0x53);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x16);
++
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0x6C);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xFC);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 49, 0x1F);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 54, 0x27);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x66);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0x6B);
++	}
++
++	if (rt2800_hw_get_chippkg(rt2x00dev) == 0 &&
++	    rt2800_hw_get_chipver(rt2x00dev) == 1) {
++		/* Initialize RF channel register for DRQFN */
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0xD3);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0xE3);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0xE5);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0x28);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x68);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xF7);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x02);
++		rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xC7);
++	}
+ 
+ 	/* Initialize RF DC calibration register to default value */
+ 	rt2800_rfcsr_write_dccal(rt2x00dev, 0, 0x47);
+@@ -10623,12 +10664,17 @@ static void rt2800_init_rfcsr_6352(struc
+ 	rt2800_rfcsr_write_dccal(rt2x00dev, 62, 0x00);
+ 	rt2800_rfcsr_write_dccal(rt2x00dev, 63, 0x00);
+ 
+-	rt2800_rfcsr_write_dccal(rt2x00dev, 3, 0x08);
+-	rt2800_rfcsr_write_dccal(rt2x00dev, 4, 0x04);
+-	rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x20);
++	if (rt2800_hw_get_chipver(rt2x00dev) > 1) {
++		rt2800_rfcsr_write_dccal(rt2x00dev, 3, 0x08);
++		rt2800_rfcsr_write_dccal(rt2x00dev, 4, 0x04);
++		rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x20);
++	}
+ 
+-	rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00);
+-	rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C);
++	if (rt2800_hw_get_chipver(rt2x00dev) > 1 &&
++	    rt2800_hw_get_chipeco(rt2x00dev) >= 2) {
++		rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00);
++		rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C);
++	}
+ 
+ 	rt2800_r_calibration(rt2x00dev);
+ 	rt2800_rf_self_txdc_cal(rt2x00dev);
diff --git a/package/kernel/mac80211/patches/rt2x00/992-rt2x00-save-survey-for-every-channel-visited.patch b/package/kernel/mac80211/patches/rt2x00/992-rt2x00-save-survey-for-every-channel-visited.patch
new file mode 100644
index 0000000..b73af6e
--- /dev/null
+++ b/package/kernel/mac80211/patches/rt2x00/992-rt2x00-save-survey-for-every-channel-visited.patch
@@ -0,0 +1,183 @@
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+@@ -1238,6 +1238,8 @@ void rt2800_watchdog(struct rt2x00_dev *
+ 	if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
+ 		return;
+ 
++	rt2800_update_survey(rt2x00dev);
++
+ 	queue_for_each(rt2x00dev, queue) {
+ 		switch (queue->qid) {
+ 		case QID_AC_VO:
+@@ -1274,6 +1276,18 @@ void rt2800_watchdog(struct rt2x00_dev *
+ }
+ EXPORT_SYMBOL_GPL(rt2800_watchdog);
+ 
++void rt2800_update_survey(struct rt2x00_dev *rt2x00dev)
++{
++	struct ieee80211_channel *chan = rt2x00dev->hw->conf.chandef.chan;
++	struct rt2x00_chan_survey *chan_survey =
++		   &rt2x00dev->chan_survey[chan->hw_value];
++
++	chan_survey->time_idle += rt2800_register_read(rt2x00dev, CH_IDLE_STA);
++	chan_survey->time_busy += rt2800_register_read(rt2x00dev, CH_BUSY_STA);
++	chan_survey->time_ext_busy += rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC);
++}
++EXPORT_SYMBOL_GPL(rt2800_update_survey);
++
+ static unsigned int rt2800_hw_beacon_base(struct rt2x00_dev *rt2x00dev,
+ 					  unsigned int index)
+ {
+@@ -12225,26 +12239,30 @@ int rt2800_get_survey(struct ieee80211_h
+ {
+ 	struct rt2x00_dev *rt2x00dev = hw->priv;
+ 	struct ieee80211_conf *conf = &hw->conf;
+-	u32 idle, busy, busy_ext;
++	struct rt2x00_chan_survey *chan_survey =
++		   &rt2x00dev->chan_survey[idx];
++	enum nl80211_band band = NL80211_BAND_2GHZ;
+ 
+-	if (idx != 0)
++	if (idx >= rt2x00dev->bands[band].n_channels) {
++		idx -= rt2x00dev->bands[band].n_channels;
++		band = NL80211_BAND_5GHZ;
++	}
++
++	if (idx >= rt2x00dev->bands[band].n_channels)
+ 		return -ENOENT;
+ 
+-	survey->channel = conf->chandef.chan;
++	if (idx == 0)
++		rt2800_update_survey(rt2x00dev);
+ 
+-	idle = rt2800_register_read(rt2x00dev, CH_IDLE_STA);
+-	busy = rt2800_register_read(rt2x00dev, CH_BUSY_STA);
+-	busy_ext = rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC);
+-
+-	if (idle || busy) {
+-		survey->filled = SURVEY_INFO_TIME |
+-				 SURVEY_INFO_TIME_BUSY |
+-				 SURVEY_INFO_TIME_EXT_BUSY;
+-
+-		survey->time = (idle + busy) / 1000;
+-		survey->time_busy = busy / 1000;
+-		survey->time_ext_busy = busy_ext / 1000;
+-	}
++	survey->channel = &rt2x00dev->bands[band].channels[idx];
++
++	survey->filled = SURVEY_INFO_TIME |
++			 SURVEY_INFO_TIME_BUSY |
++			 SURVEY_INFO_TIME_EXT_BUSY;
++
++	survey->time = div_u64(chan_survey->time_idle + chan_survey->time_busy, 1000);
++	survey->time_busy = div_u64(chan_survey->time_busy, 1000);
++	survey->time_ext_busy = div_u64(chan_survey->time_ext_busy, 1000);
+ 
+ 	if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
+ 		survey->filled |= SURVEY_INFO_IN_USE;
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+@@ -243,6 +243,7 @@ bool rt2800_txstatus_timeout(struct rt2x
+ bool rt2800_txstatus_pending(struct rt2x00_dev *rt2x00dev);
+ 
+ void rt2800_watchdog(struct rt2x00_dev *rt2x00dev);
++void rt2800_update_survey(struct rt2x00_dev *rt2x00dev);
+ 
+ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
+ void rt2800_clear_beacon(struct queue_entry *entry);
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
+@@ -360,6 +360,7 @@ static const struct rt2x00lib_ops rt2800
+ 	.gain_calibration	= rt2800_gain_calibration,
+ 	.vco_calibration	= rt2800_vco_calibration,
+ 	.watchdog		= rt2800_watchdog,
++	.update_survey		= rt2800_update_survey,
+ 	.start_queue		= rt2800mmio_start_queue,
+ 	.kick_queue		= rt2800mmio_kick_queue,
+ 	.stop_queue		= rt2800mmio_stop_queue,
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+@@ -214,6 +214,7 @@ static const struct rt2x00lib_ops rt2800
+ 	.gain_calibration	= rt2800_gain_calibration,
+ 	.vco_calibration	= rt2800_vco_calibration,
+ 	.watchdog		= rt2800_watchdog,
++	.update_survey		= rt2800_update_survey,
+ 	.start_queue		= rt2800mmio_start_queue,
+ 	.kick_queue		= rt2800mmio_kick_queue,
+ 	.stop_queue		= rt2800mmio_stop_queue,
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+@@ -183,6 +183,15 @@ struct rf_channel {
+ };
+ 
+ /*
++ * Information structure for channel survey.
++ */
++struct rt2x00_chan_survey {
++	u64 time_idle;
++	u64 time_busy;
++	u64 time_ext_busy;
++};
++
++/*
+  * Channel information structure
+  */
+ struct channel_info {
+@@ -567,6 +576,7 @@ struct rt2x00lib_ops {
+ 	 * Data queue handlers.
+ 	 */
+ 	void (*watchdog) (struct rt2x00_dev *rt2x00dev);
++	void (*update_survey) (struct rt2x00_dev *rt2x00dev);
+ 	void (*start_queue) (struct data_queue *queue);
+ 	void (*kick_queue) (struct data_queue *queue);
+ 	void (*stop_queue) (struct data_queue *queue);
+@@ -755,6 +765,7 @@ struct rt2x00_dev {
+ 	 */
+ 	struct ieee80211_hw *hw;
+ 	struct ieee80211_supported_band bands[NUM_NL80211_BANDS];
++	struct rt2x00_chan_survey *chan_survey;
+ 	enum nl80211_band curr_band;
+ 	int curr_freq;
+ 
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+@@ -1057,6 +1057,12 @@ static int rt2x00lib_probe_hw_modes(stru
+ 	if (!rates)
+ 		goto exit_free_channels;
+ 
++	rt2x00dev->chan_survey =
++		kcalloc(spec->num_channels, sizeof(struct rt2x00_chan_survey),
++			GFP_KERNEL);
++	if (!rt2x00dev->chan_survey)
++		goto exit_free_rates;
++
+ 	/*
+ 	 * Initialize Rate list.
+ 	 */
+@@ -1108,6 +1114,8 @@ static int rt2x00lib_probe_hw_modes(stru
+ 
+ 	return 0;
+ 
++ exit_free_rates:
++	kfree(rates);
+  exit_free_channels:
+ 	kfree(channels);
+ 	rt2x00_err(rt2x00dev, "Allocation ieee80211 modes failed\n");
+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
+@@ -317,6 +317,15 @@ int rt2x00mac_config(struct ieee80211_hw
+ 		return 0;
+ 
+ 	/*
++	 * To provide correct survey data for survey-based ACS algorithm
++	 * we have to save survey data for current channel before switching.
++	 */
++	if (rt2x00dev->ops->lib->update_survey &&
++	    (changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
++		rt2x00dev->ops->lib->update_survey(rt2x00dev);
++	}
++
++	/*
+ 	 * Some configuration parameters (e.g. channel and antenna values) can
+ 	 * only be set when the radio is enabled, but do require the RX to
+ 	 * be off. During this period we should keep link tuning enabled,