[][MAC80211][misc][update autobuild folder for WiFi7]
[Description]
Refactor autobuild folder for external build PASS.
Update MT7996 mp2.0 FW to 20230608.
[Release-log]
N/A
Change-Id: Idf22eb7dd01a777657f90ff0ce170f31abb106f7
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7633627
diff --git a/autobuild_mac80211_release/feeds.conf.default b/autobuild_mac80211_release/feeds.conf.default
new file mode 100644
index 0000000..4eef7a8
--- /dev/null
+++ b/autobuild_mac80211_release/feeds.conf.default
@@ -0,0 +1,4 @@
+src-git packages https://git.openwrt.org/feed/packages.git
+src-git luci https://git.openwrt.org/project/luci.git
+src-git routing https://git.openwrt.org/feed/routing.git
+src-git mtk_openwrt_feed https://git01.mediatek.com/openwrt/feeds/mtk-openwrt-feeds
diff --git a/autobuild_mac80211_release/feeds.conf.default-21.02 b/autobuild_mac80211_release/feeds.conf.default-21.02
new file mode 100644
index 0000000..1f1c65f
--- /dev/null
+++ b/autobuild_mac80211_release/feeds.conf.default-21.02
@@ -0,0 +1,4 @@
+src-git packages https://git.openwrt.org/feed/packages.git;openwrt-21.02
+src-git luci https://git.openwrt.org/project/luci.git;openwrt-21.02
+src-git routing https://git.openwrt.org/feed/routing.git;openwrt-21.02.
+src-git mtk_openwrt_feed https://git01.mediatek.com/openwrt/feeds/mtk-openwrt-feeds;openwrt-21.02
diff --git a/autobuild_mac80211_release/mt7988_mt7996_mac80211/target/linux/mediatek/patches-5.4/999-3021-mtk-wed-add-wed3-support.patch b/autobuild_mac80211_release/mt7988_mt7996_mac80211/target/linux/mediatek/patches-5.4/999-3021-mtk-wed-add-wed3-support.patch
new file mode 100644
index 0000000..8c5f048
--- /dev/null
+++ b/autobuild_mac80211_release/mt7988_mt7996_mac80211/target/linux/mediatek/patches-5.4/999-3021-mtk-wed-add-wed3-support.patch
@@ -0,0 +1,3720 @@
+From 400f8349a31ffc48538aa7df64a88111de9a738b Mon Sep 17 00:00:00 2001
+From: Sujuan Chen <sujuan.chen@mediatek.com>
+Date: Thu, 13 Apr 2023 15:51:08 +0800
+Subject: [PATCH] mtk:wed:add wed3 support
+
+Signed-off-by: sujuan.chen <sujuan.chen@mediatek.com>
+---
+ arch/arm64/boot/dts/mediatek/mt7988.dtsi | 152 ++-
+ .../dts/mediatek/mt7988a-dsa-10g-spim-nor.dts | 16 +-
+ .../dts/mediatek/mt7988d-dsa-10g-spim-nor.dts | 16 +-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 +-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 5 +-
+ drivers/net/ethernet/mediatek/mtk_ppe.c | 17 +-
+ drivers/net/ethernet/mediatek/mtk_ppe.h | 2 +-
+ .../net/ethernet/mediatek/mtk_ppe_offload.c | 13 +-
+ drivers/net/ethernet/mediatek/mtk_wed.c | 1164 +++++++++++++----
+ drivers/net/ethernet/mediatek/mtk_wed.h | 25 +-
+ .../net/ethernet/mediatek/mtk_wed_debugfs.c | 584 ++++++++-
+ drivers/net/ethernet/mediatek/mtk_wed_mcu.c | 13 +-
+ drivers/net/ethernet/mediatek/mtk_wed_mcu.h | 5 +-
+ drivers/net/ethernet/mediatek/mtk_wed_regs.h | 338 ++++-
+ include/linux/netdevice.h | 7 +
+ include/linux/soc/mediatek/mtk_wed.h | 81 +-
+ 16 files changed, 1446 insertions(+), 333 deletions(-)
+ mode change 100755 => 100644 drivers/net/ethernet/mediatek/mtk_ppe.c
+
+diff --git a/arch/arm64/boot/dts/mediatek/mt7988.dtsi b/arch/arm64/boot/dts/mediatek/mt7988.dtsi
+index 364deef..f9a0120 100644
+--- a/arch/arm64/boot/dts/mediatek/mt7988.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7988.dtsi
+@@ -191,44 +191,49 @@
+ status = "disabled";
+ };
+
+- wed: wed@15010000 {
+- compatible = "mediatek,wed";
+- wed_num = <3>;
+- /* add this property for wed get the pci slot number. */
+- pci_slot_map = <0>, <1>, <2>;
+- reg = <0 0x15010000 0 0x2000>,
+- <0 0x15012000 0 0x2000>,
+- <0 0x15014000 0 0x2000>;
++ wed0: wed@15010000 {
++ compatible = "mediatek,mt7988-wed",
++ "syscon";
++ reg = <0 0x15010000 0 0x2000>;
+ interrupt-parent = <&gic>;
+- interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>;
+- };
+-
+- wed2: wed2@15012000 {
+- compatible = "mediatek,wed2";
+- wed_num = <3>;
+- /* add this property for wed get the pci slot number. */
+- reg = <0 0x15010000 0 0x2000>,
+- <0 0x15012000 0 0x2000>,
+- <0 0x15014000 0 0x2000>;
++ interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
++ mediatek,wed_pcie = <&wed_pcie>;
++ mediatek,ap2woccif = <&ap2woccif0>;
++ mediatek,wocpu_ilm = <&wocpu0_ilm>;
++ mediatek,wocpu_dlm = <&wocpu0_dlm>;
++ mediatek,wocpu_boot = <&cpu0_boot>;
++ mediatek,wocpu_emi = <&wocpu0_emi>;
++ mediatek,wocpu_data = <&wocpu_data>;
++ };
++
++ wed1: wed@15012000 {
++ compatible = "mediatek,mt7988-wed",
++ "syscon";
++ reg = <0 0x15012000 0 0x2000>;
+ interrupt-parent = <&gic>;
+- interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>;
+- };
+-
+- wed3: wed3@15014000 {
+- compatible = "mediatek,wed3";
+- wed_num = <3>;
+- /* add this property for wed get the pci slot number. */
+- reg = <0 0x15010000 0 0x2000>,
+- <0 0x15012000 0 0x2000>,
+- <0 0x15014000 0 0x2000>;
++ interrupts = <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
++ mediatek,wed_pcie = <&wed_pcie>;
++ mediatek,ap2woccif = <&ap2woccif1>;
++ mediatek,wocpu_ilm = <&wocpu1_ilm>;
++ mediatek,wocpu_dlm = <&wocpu1_dlm>;
++ mediatek,wocpu_boot = <&cpu1_boot>;
++ mediatek,wocpu_emi = <&wocpu1_emi>;
++ mediatek,wocpu_data = <&wocpu_data>;
++ };
++
++ wed2: wed@15014000 {
++ compatible = "mediatek,mt7988-wed",
++ "syscon";
++ reg = <0 0x15014000 0 0x2000>;
+ interrupt-parent = <&gic>;
+- interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>;
++ interrupts = <GIC_SPI 207 IRQ_TYPE_LEVEL_HIGH>;
++ mediatek,wed_pcie = <&wed_pcie>;
++ mediatek,ap2woccif = <&ap2woccif2>;
++ mediatek,wocpu_ilm = <&wocpu2_ilm>;
++ mediatek,wocpu_dlm = <&wocpu2_dlm>;
++ mediatek,wocpu_boot = <&cpu2_boot>;
++ mediatek,wocpu_emi = <&wocpu2_emi>;
++ mediatek,wocpu_data = <&wocpu_data>;
+ };
+
+ wdma: wdma@15104800 {
+@@ -238,15 +243,25 @@
+ <0 0x15105000 0 0x400>;
+ };
+
+- ap2woccif: ap2woccif@151A5000 {
+- compatible = "mediatek,ap2woccif";
+- reg = <0 0x151A5000 0 0x1000>,
+- <0 0x152A5000 0 0x1000>,
+- <0 0x153A5000 0 0x1000>;
++ ap2woccif0: ap2woccif@151A5000 {
++ compatible = "mediatek,ap2woccif", "syscon";
++ reg = <0 0x151A5000 0 0x1000>;
++ interrupt-parent = <&gic>;
++ interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>;
++ };
++
++ ap2woccif1: ap2woccif@152A5000 {
++ compatible = "mediatek,ap2woccif", "syscon";
++ reg = <0 0x152A5000 0 0x1000>;
+ interrupt-parent = <&gic>;
+- interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>;
++ interrupts = <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>;
++ };
++
++ ap2woccif2: ap2woccif@153A5000 {
++ compatible = "mediatek,ap2woccif", "syscon";
++ reg = <0 0x153A5000 0 0x1000>;
++ interrupt-parent = <&gic>;
++ interrupts = <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ wocpu0_ilm: wocpu0_ilm@151E0000 {
+@@ -254,31 +269,53 @@
+ reg = <0 0x151E0000 0 0x8000>;
+ };
+
+- wocpu1_ilm: wocpu1_ilm@152E0000 {
+- compatible = "mediatek,wocpu1_ilm";
++ wocpu1_ilm: wocpu_ilm@152E0000 {
++ compatible = "mediatek,wocpu_ilm";
+ reg = <0 0x152E0000 0 0x8000>;
+ };
+
+- wocpu2_ilm: wocpu2_ilm@153E0000 {
+- compatible = "mediatek,wocpu2_ilm";
+- reg = <0 0x153E0000 0 0x8000>;
++ wocpu2_ilm: wocpu_ilm@153E0000 {
++ compatible = "mediatek,wocpu_ilm";
++ reg = <0 0x153E0000 0 0x8000>;
++ };
++
++ wocpu0_dlm: wocpu_dlm@151E8000 {
++ compatible = "mediatek,wocpu_dlm";
++ reg = <0 0x151E8000 0 0x2000>;
++
++ resets = <ðsysrst 0>;
++ reset-names = "wocpu_rst";
++ };
++
++ wocpu1_dlm: wocpu_dlm@0x152E8000 {
++ compatible = "mediatek,wocpu_dlm";
++ reg = <0 0x152E8000 0 0x2000>;
++
++ resets = <ðsysrst 0>;
++ reset-names = "wocpu_rst";
+ };
+
+- wocpu_dlm: wocpu_dlm@151E8000 {
++ wocpu2_dlm: wocpu_dlm@0x153E8000 {
+ compatible = "mediatek,wocpu_dlm";
+- reg = <0 0x151E8000 0 0x2000>,
+- <0 0x152E8000 0 0x2000>,
+- <0 0x153E8000 0 0x2000>;
++ reg = <0 0x153E8000 0 0x2000>;
+
+ resets = <ðsysrst 0>;
+ reset-names = "wocpu_rst";
+ };
+
+- cpu_boot: wocpu_boot@15194000 {
+- compatible = "mediatek,wocpu_boot";
+- reg = <0 0x15194000 0 0x1000>,
+- <0 0x15294000 0 0x1000>,
+- <0 0x15394000 0 0x1000>;
++ cpu0_boot: wocpu_boot@15194000 {
++ compatible = "mediatek,wocpu0_boot";
++ reg = <0 0x15194000 0 0x1000>;
++ };
++
++ cpu1_boot: wocpu_boot@15294000 {
++ compatible = "mediatek,wocpu1_boot";
++ reg = <0 0x15294000 0 0x1000>;
++ };
++
++ cpu2_boot: wocpu_boot@15394000 {
++ compatible = "mediatek,wocpu2_boot";
++ reg = <0 0x15394000 0 0x1000>;
+ };
+
+ reserved-memory {
+@@ -827,6 +864,7 @@
+ <&topckgen CK_TOP_CB_SGM_325M>;
+ mediatek,ethsys = <ðsys>;
+ mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
++ mediatek,wed = <&wed0>, <&wed1>, <&wed2>;
+ mediatek,usxgmiisys = <&usxgmiisys0>, <&usxgmiisys1>;
+ mediatek,xfi_pextp = <&xfi_pextp0>, <&xfi_pextp1>;
+ mediatek,xfi_pll = <&xfi_pll>;
+diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts b/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts
+index 7db5164..0a6db8b 100644
+--- a/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts
+@@ -341,9 +341,23 @@
+ status = "okay";
+ };
+
+-&wed {
++&wed0 {
+ dy_txbm_enable = "true";
+ dy_txbm_budge = <8>;
+ txbm_init_sz = <10>;
+ status = "okay";
+ };
++
++&wed1 {
++ dy_txbm_enable = "true";
++ dy_txbm_budge = <8>;
++ txbm_init_sz = <10>;
++ status = "okay";
++};
++
++&wed2 {
++ dy_txbm_enable = "true";
++ dy_txbm_budge = <8>;
++ txbm_init_sz = <10>;
++ status = "okay";
++};
+\ No newline at end of file
+diff --git a/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts b/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts
+index 67c6508..c407b33 100644
+--- a/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts
+@@ -325,9 +325,23 @@
+ status = "okay";
+ };
+
+-&wed {
++&wed0 {
+ dy_txbm_enable = "true";
+ dy_txbm_budge = <8>;
+ txbm_init_sz = <10>;
+ status = "okay";
+ };
++
++&wed1 {
++ dy_txbm_enable = "true";
++ dy_txbm_budge = <8>;
++ txbm_init_sz = <10>;
++ status = "okay";
++};
++
++&wed2 {
++ dy_txbm_enable = "true";
++ dy_txbm_budge = <8>;
++ txbm_init_sz = <10>;
++ status = "okay";
++};
+\ No newline at end of file
+diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+index 388982c..d59c29f 100644
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -4709,7 +4709,8 @@ static int mtk_probe(struct platform_device *pdev)
+ "mediatek,wed", i);
+ static const u32 wdma_regs[] = {
+ MTK_WDMA0_BASE,
+- MTK_WDMA1_BASE
++ MTK_WDMA1_BASE,
++ MTK_WDMA2_BASE
+ };
+ void __iomem *wdma;
+ u32 wdma_phy;
+diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+index a9feaed..70e8377 100644
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -605,9 +605,12 @@
+ #define RX_DMA_SPORT_MASK 0x7
+ #define RX_DMA_SPORT_MASK_V2 0xf
+
+-#if defined(CONFIG_MEDIATEK_NETSYS_V2)
++#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
+ #define MTK_WDMA0_BASE 0x4800
+ #define MTK_WDMA1_BASE 0x4c00
++#if defined(CONFIG_MEDIATEK_NETSYS_V3)
++#define MTK_WDMA2_BASE 0x5000
++#endif
+ #else
+ #define MTK_WDMA0_BASE 0x2800
+ #define MTK_WDMA1_BASE 0x2c00
+diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
+old mode 100755
+new mode 100644
+index bc13a9b..3910163
+--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
+@@ -9,6 +9,7 @@
+ #include <linux/if_ether.h>
+ #include <linux/if_vlan.h>
+ #include <net/dsa.h>
++#include <net/route.h>
+ #include "mtk_eth_soc.h"
+ #include "mtk_ppe.h"
+ #include "mtk_ppe_regs.h"
+@@ -396,7 +397,7 @@ int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid)
+ }
+
+ int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
+- int bss, int wcid)
++ int bss, int wcid, bool amsdu_en)
+ {
+ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry);
+ u32 *ib2 = mtk_foe_entry_ib2(entry);
+@@ -408,6 +409,9 @@ int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
+
+ l2->winfo = FIELD_PREP(MTK_FOE_WINFO_WCID, wcid) |
+ FIELD_PREP(MTK_FOE_WINFO_BSS, bss);
++#if defined(CONFIG_MEDIATEK_NETSYS_V3)
++ l2->winfo_pao = FIELD_PREP(MTK_FOE_WINFO_PAO_AMSDU_EN, amsdu_en);
++#endif
+ #else
+ if (wdma_idx)
+ *ib2 |= MTK_FOE_IB2_WDMA_DEVIDX;
+@@ -443,6 +447,17 @@ int mtk_foe_entry_set_dscp(struct mtk_foe_entry *entry, int dscp)
+ *ib2 &= ~MTK_FOE_IB2_DSCP;
+ *ib2 |= FIELD_PREP(MTK_FOE_IB2_DSCP, dscp);
+
++#if defined(CONFIG_MEDIATEK_NETSYS_V3)
++ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry);
++
++ if (*ib2 & MTK_FOE_IB2_WDMA_WINFO &&
++ l2->winfo_pao & MTK_FOE_WINFO_PAO_AMSDU_EN) {
++ u8 tid = rt_tos2priority(dscp) & 0xf;
++
++ l2->winfo_pao |= FIELD_PREP(MTK_FOE_WINFO_PAO_TID, tid);
++ }
++#endif
++
+ return 0;
+ }
+
+diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
+index df10040..9e7d5aa 100644
+--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
+@@ -428,7 +428,7 @@ int mtk_foe_entry_set_dsa(struct mtk_foe_entry *entry, int port);
+ int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid);
+ int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid);
+ int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
+- int bss, int wcid);
++ int bss, int wcid, bool amsdu_en);
+ int mtk_foe_entry_set_qid(struct mtk_foe_entry *entry, int qid);
+ int mtk_foe_entry_set_dscp(struct mtk_foe_entry *entry, int dscp);
+ int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
+diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+index 9bc0857..86fc9a1 100644
+--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+@@ -112,6 +112,7 @@ mtk_flow_get_wdma_info(struct net_device *dev, const u8 *addr, struct mtk_wdma_i
+ info->queue = path.mtk_wdma.queue;
+ info->bss = path.mtk_wdma.bss;
+ info->wcid = path.mtk_wdma.wcid;
++ info->amsdu_en = path.mtk_wdma.amsdu_en;
+
+ return 0;
+ }
+@@ -193,13 +194,15 @@ mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe,
+
+ if (mtk_flow_get_wdma_info(dev, dest_mac, &info) == 0) {
+ mtk_foe_entry_set_wdma(foe, info.wdma_idx, info.queue, info.bss,
+- info.wcid);
++ info.wcid, info.amsdu_en);
+ pse_port = PSE_PPE0_PORT;
+ #if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
+ if (info.wdma_idx == 0)
+ pse_port = PSE_WDMA0_PORT;
+ else if (info.wdma_idx == 1)
+ pse_port = PSE_WDMA1_PORT;
++ else if (info.wdma_idx == 2)
++ pse_port = PSE_WDMA2_PORT;
+ else
+ return -EOPNOTSUPP;
+ #endif
+@@ -458,8 +461,8 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+ if (err)
+ return err;
+
+- if (wed_index >= 0 && (err = mtk_wed_flow_add(wed_index)) < 0)
+- return err;
++ /*if (wed_index >= 0 && (err = mtk_wed_flow_add(wed_index)) < 0)
++ return err;*/
+
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+@@ -499,8 +502,8 @@ clear:
+ mtk_foe_entry_clear(eth->ppe[i], entry);
+ free:
+ kfree(entry);
+- if (wed_index >= 0)
+- mtk_wed_flow_remove(wed_index);
++ /*if (wed_index >= 0)
++ mtk_wed_flow_remove(wed_index);*/
+ return err;
+ }
+
+diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
+index 37a86c3..e3809db 100644
+--- a/drivers/net/ethernet/mediatek/mtk_wed.c
++++ b/drivers/net/ethernet/mediatek/mtk_wed.c
+@@ -28,7 +28,7 @@ struct wo_cmd_ring {
+ u32 cnt;
+ u32 unit;
+ };
+-static struct mtk_wed_hw *hw_list[2];
++static struct mtk_wed_hw *hw_list[3];
+ static DEFINE_MUTEX(hw_lock);
+
+ static void
+@@ -73,6 +73,26 @@ mtk_wdma_read_reset(struct mtk_wed_device *dev)
+ return wdma_r32(dev, MTK_WDMA_GLO_CFG);
+ }
+
++static u32
++mtk_wed_check_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
++{
++ if (wed_r32(dev, reg) & mask)
++ return true;
++
++ return false;
++}
++
++static int
++mtk_wed_poll_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
++{
++ int sleep = 1000;
++ int timeout = 100 * sleep;
++ u32 val;
++
++ return read_poll_timeout(mtk_wed_check_busy, val, !val, sleep,
++ timeout, false, dev, reg, mask);
++}
++
+ static int
+ mtk_wdma_rx_reset(struct mtk_wed_device *dev)
+ {
+@@ -235,6 +255,8 @@ mtk_wed_assign(struct mtk_wed_device *dev)
+ continue;
+
+ hw->wed_dev = dev;
++ hw->pci_base = MTK_WED_PCIE_BASE;
++
+ return hw;
+ }
+
+@@ -242,23 +264,84 @@ mtk_wed_assign(struct mtk_wed_device *dev)
+ }
+
+ static int
+-mtk_wed_buffer_alloc(struct mtk_wed_device *dev)
++mtk_wed_pao_buffer_alloc(struct mtk_wed_device *dev)
++{
++ struct mtk_wed_pao *pao;
++ int i, j;
++
++ pao = kzalloc(sizeof(struct mtk_wed_pao), GFP_KERNEL);
++ if (!pao)
++ return -ENOMEM;
++
++ dev->hw->wed_pao = pao;
++
++ for (i = 0; i < 32; i++) {
++ /* each segment is 64K*/
++ pao->hif_txd[i] = (char *)__get_free_pages(GFP_ATOMIC |
++ GFP_DMA32 |
++ __GFP_ZERO, 4);
++ if (!pao->hif_txd[i])
++ goto err;
++
++ pao->hif_txd_phys[i] = dma_map_single(dev->hw->dev,
++ pao->hif_txd[i],
++ 16 * PAGE_SIZE,
++ DMA_TO_DEVICE);
++ if (unlikely(dma_mapping_error(dev->hw->dev,
++ pao->hif_txd_phys[i])))
++ goto err;
++ }
++
++ return 0;
++
++err:
++ for (j = 0; j < i; j++)
++ dma_unmap_single(dev->hw->dev, pao->hif_txd_phys[j],
++ 16 * PAGE_SIZE, DMA_TO_DEVICE);
++
++ return -ENOMEM;
++}
++
++static int
++mtk_wed_pao_free_buffer(struct mtk_wed_device *dev)
++{
++ struct mtk_wed_pao *pao = dev->hw->wed_pao;
++ int i;
++
++ for (i = 0; i < 32; i++) {
++ dma_unmap_single(dev->hw->dev, pao->hif_txd_phys[i],
++ 16 * PAGE_SIZE, DMA_TO_DEVICE);
++ free_pages((unsigned long)pao->hif_txd[i], 4);
++ }
++
++ return 0;
++}
++
++static int
++mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev)
+ {
+ struct mtk_wdma_desc *desc;
++ void *desc_ptr;
+ dma_addr_t desc_phys;
+- void **page_list;
++ struct dma_page_info *page_list;
+ u32 last_seg = MTK_WDMA_DESC_CTRL_LAST_SEG1;
+ int token = dev->wlan.token_start;
+- int ring_size, n_pages, page_idx;
+- int i;
+-
++ int ring_size, pkt_nums, n_pages, page_idx;
++ int i, ret = 0;
+
+ if (dev->ver == MTK_WED_V1) {
+ ring_size = dev->wlan.nbuf & ~(MTK_WED_BUF_PER_PAGE - 1);
+- } else {
++ pkt_nums = ring_size;
++ dev->tx_buf_ring.desc_size = sizeof(struct mtk_wdma_desc);
++ } else if (dev->hw->version == 2) {
+ ring_size = MTK_WED_VLD_GROUP_SIZE * MTK_WED_PER_GROUP_PKT +
+ MTK_WED_WDMA_RING_SIZE * 2;
+ last_seg = MTK_WDMA_DESC_CTRL_LAST_SEG0;
++ dev->tx_buf_ring.desc_size = sizeof(struct mtk_wdma_desc);
++ } else if (dev->hw->version == 3) {
++ ring_size = MTK_WED_TX_BM_DMA_SIZE;
++ pkt_nums = MTK_WED_TX_BM_PKT_CNT;
++ dev->tx_buf_ring.desc_size = sizeof(struct mtk_rxbm_desc);
+ }
+
+ n_pages = ring_size / MTK_WED_BUF_PER_PAGE;
+@@ -267,18 +350,20 @@ mtk_wed_buffer_alloc(struct mtk_wed_device *dev)
+ if (!page_list)
+ return -ENOMEM;
+
+- dev->buf_ring.size = dev->wlan.nbuf & ~(MTK_WED_BUF_PER_PAGE - 1);
+- dev->buf_ring.pages = page_list;
++ dev->tx_buf_ring.size = ring_size;
++ dev->tx_buf_ring.pages = page_list;
++ dev->tx_buf_ring.pkt_nums = pkt_nums;
+
+- desc = dma_alloc_coherent(dev->hw->dev, ring_size * sizeof(*desc),
+- &desc_phys, GFP_KERNEL);
+- if (!desc)
++ desc_ptr = dma_alloc_coherent(dev->hw->dev,
++ ring_size * dev->tx_buf_ring.desc_size,
++ &desc_phys, GFP_KERNEL);
++ if (!desc_ptr)
+ return -ENOMEM;
+
+- dev->buf_ring.desc = desc;
+- dev->buf_ring.desc_phys = desc_phys;
++ dev->tx_buf_ring.desc = desc_ptr;
++ dev->tx_buf_ring.desc_phys = desc_phys;
+
+- for (i = 0, page_idx = 0; i < ring_size; i += MTK_WED_BUF_PER_PAGE) {
++ for (i = 0, page_idx = 0; i < pkt_nums; i += MTK_WED_BUF_PER_PAGE) {
+ dma_addr_t page_phys, buf_phys;
+ struct page *page;
+ void *buf;
+@@ -295,7 +380,10 @@ mtk_wed_buffer_alloc(struct mtk_wed_device *dev)
+ return -ENOMEM;
+ }
+
+- page_list[page_idx++] = page;
++ page_list[page_idx].addr = page;
++ page_list[page_idx].addr_phys = page_phys;
++ page_idx++;
++
+ dma_sync_single_for_cpu(dev->hw->dev, page_phys, PAGE_SIZE,
+ DMA_BIDIRECTIONAL);
+
+@@ -303,19 +391,23 @@ mtk_wed_buffer_alloc(struct mtk_wed_device *dev)
+ buf_phys = page_phys;
+
+ for (s = 0; s < MTK_WED_BUF_PER_PAGE; s++) {
+- u32 txd_size;
+-
+- txd_size = dev->wlan.init_buf(buf, buf_phys, token++);
+-
++ desc = desc_ptr;
+ desc->buf0 = buf_phys;
+- desc->buf1 = buf_phys + txd_size;
+- desc->ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0,
+- txd_size) |
+- FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1,
+- MTK_WED_BUF_SIZE - txd_size) |
+- last_seg;
+- desc->info = 0;
+- desc++;
++ if (dev->hw->version < 3) {
++ u32 txd_size;
++
++ txd_size = dev->wlan.init_buf(buf, buf_phys, token++);
++ desc->buf1 = buf_phys + txd_size;
++ desc->ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0,
++ txd_size) |
++ FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1,
++ MTK_WED_BUF_SIZE - txd_size) |
++ last_seg;
++ desc->info = 0;
++ } else {
++ desc->ctrl = token << 16;
++ }
++ desc_ptr += dev->tx_buf_ring.desc_size;
+
+ buf += MTK_WED_BUF_SIZE;
+ buf_phys += MTK_WED_BUF_SIZE;
+@@ -325,15 +417,18 @@ mtk_wed_buffer_alloc(struct mtk_wed_device *dev)
+ DMA_BIDIRECTIONAL);
+ }
+
+- return 0;
++ if (dev->hw->version == 3)
++ ret = mtk_wed_pao_buffer_alloc(dev);
++
++ return ret;
+ }
+
+ static void
+-mtk_wed_free_buffer(struct mtk_wed_device *dev)
++mtk_wed_free_tx_buffer(struct mtk_wed_device *dev)
+ {
+- struct mtk_wdma_desc *desc = dev->buf_ring.desc;
+- void **page_list = dev->buf_ring.pages;
+- int ring_size, page_idx;
++ struct mtk_rxbm_desc *desc = dev->tx_buf_ring.desc;
++ struct dma_page_info *page_list = dev->tx_buf_ring.pages;
++ int ring_size, page_idx, pkt_nums;
+ int i;
+
+ if (!page_list)
+@@ -342,33 +437,33 @@ mtk_wed_free_buffer(struct mtk_wed_device *dev)
+ if (!desc)
+ goto free_pagelist;
+
+- if (dev->ver == MTK_WED_V1) {
+- ring_size = dev->wlan.nbuf & ~(MTK_WED_BUF_PER_PAGE - 1);
+- } else {
+- ring_size = MTK_WED_VLD_GROUP_SIZE * MTK_WED_PER_GROUP_PKT +
+- MTK_WED_WDMA_RING_SIZE * 2;
++ pkt_nums = ring_size = dev->tx_buf_ring.size;
++ if (dev->hw->version == 3) {
++ mtk_wed_pao_free_buffer(dev);
++ pkt_nums = dev->tx_buf_ring.pkt_nums;
+ }
+
+- for (i = 0, page_idx = 0; i < ring_size; i += MTK_WED_BUF_PER_PAGE) {
+- void *page = page_list[page_idx++];
++ for (i = 0, page_idx = 0; i < pkt_nums; i += MTK_WED_BUF_PER_PAGE) {
++ void *page = page_list[page_idx].addr;
+
+ if (!page)
+ break;
+
+- dma_unmap_page(dev->hw->dev, desc[i].buf0,
++ dma_unmap_page(dev->hw->dev, page_list[page_idx].addr_phys,
+ PAGE_SIZE, DMA_BIDIRECTIONAL);
+ __free_page(page);
++ page_idx++;
+ }
+
+- dma_free_coherent(dev->hw->dev, ring_size * sizeof(*desc),
+- desc, dev->buf_ring.desc_phys);
++ dma_free_coherent(dev->hw->dev, ring_size * dev->tx_buf_ring.desc_size,
++ dev->tx_buf_ring.desc, dev->tx_buf_ring.desc_phys);
+
+ free_pagelist:
+ kfree(page_list);
+ }
+
+ static int
+-mtk_wed_rx_bm_alloc(struct mtk_wed_device *dev)
++mtk_wed_rx_buffer_alloc(struct mtk_wed_device *dev)
+ {
+ struct mtk_rxbm_desc *desc;
+ dma_addr_t desc_phys;
+@@ -389,7 +484,7 @@ mtk_wed_rx_bm_alloc(struct mtk_wed_device *dev)
+ }
+
+ static void
+-mtk_wed_free_rx_bm(struct mtk_wed_device *dev)
++mtk_wed_free_rx_buffer(struct mtk_wed_device *dev)
+ {
+ struct mtk_rxbm_desc *desc = dev->rx_buf_ring.desc;
+ int ring_size = dev->rx_buf_ring.size;
+@@ -403,6 +498,113 @@ mtk_wed_free_rx_bm(struct mtk_wed_device *dev)
+ desc, dev->rx_buf_ring.desc_phys);
+ }
+
++/* TODO */
++static int
++mtk_wed_rx_page_buffer_alloc(struct mtk_wed_device *dev)
++{
++ int ring_size = dev->wlan.rx_nbuf, buf_num = MTK_WED_RX_PG_BM_CNT;
++ struct mtk_rxbm_desc *desc;
++ dma_addr_t desc_phys;
++ struct dma_page_info *page_list;
++ int n_pages, page_idx;
++ int i;
++
++ n_pages = buf_num / MTK_WED_RX_PAGE_BUF_PER_PAGE;
++
++ page_list = kcalloc(n_pages, sizeof(*page_list), GFP_KERNEL);
++ if (!page_list)
++ return -ENOMEM;
++
++ dev->rx_page_buf_ring.size = ring_size & ~(MTK_WED_BUF_PER_PAGE - 1);
++ dev->rx_page_buf_ring.pages = page_list;
++ dev->rx_page_buf_ring.pkt_nums = buf_num;
++
++ desc = dma_alloc_coherent(dev->hw->dev, ring_size * sizeof(*desc),
++ &desc_phys, GFP_KERNEL);
++ if (!desc)
++ return -ENOMEM;
++
++ dev->rx_page_buf_ring.desc = desc;
++ dev->rx_page_buf_ring.desc_phys = desc_phys;
++
++ for (i = 0, page_idx = 0; i < buf_num; i += MTK_WED_RX_PAGE_BUF_PER_PAGE) {
++ dma_addr_t page_phys, buf_phys;
++ struct page *page;
++ void *buf;
++ int s;
++
++ page = __dev_alloc_pages(GFP_KERNEL, 0);
++ if (!page)
++ return -ENOMEM;
++
++ page_phys = dma_map_page(dev->hw->dev, page, 0, PAGE_SIZE,
++ DMA_BIDIRECTIONAL);
++ if (dma_mapping_error(dev->hw->dev, page_phys)) {
++ __free_page(page);
++ return -ENOMEM;
++ }
++
++ page_list[page_idx].addr= page;
++ page_list[page_idx].addr_phys= page_phys;
++ page_idx++;
++
++ dma_sync_single_for_cpu(dev->hw->dev, page_phys, PAGE_SIZE,
++ DMA_BIDIRECTIONAL);
++
++ buf = page_to_virt(page);
++ buf_phys = page_phys;
++
++ for (s = 0; s < MTK_WED_RX_PAGE_BUF_PER_PAGE; s++) {
++
++ desc->buf0 = cpu_to_le32(buf_phys);
++ desc++;
++
++ buf += MTK_WED_PAGE_BUF_SIZE;
++ buf_phys += MTK_WED_PAGE_BUF_SIZE;
++ }
++
++ dma_sync_single_for_device(dev->hw->dev, page_phys, PAGE_SIZE,
++ DMA_BIDIRECTIONAL);
++ }
++
++ return 0;
++}
++
++static void
++mtk_wed_rx_page_free_buffer(struct mtk_wed_device *dev)
++{
++ struct mtk_rxbm_desc *desc = dev->rx_page_buf_ring.desc;
++ struct dma_page_info *page_list = dev->rx_page_buf_ring.pages;
++ int ring_size, page_idx;
++ int i;
++
++ if (!page_list)
++ return;
++
++ if (!desc)
++ goto free_pagelist;
++
++ ring_size = dev->rx_page_buf_ring.pkt_nums;
++
++ for (i = 0, page_idx = 0; i < ring_size; i += MTK_WED_RX_PAGE_BUF_PER_PAGE) {
++ void *page = page_list[page_idx].addr;
++
++ if (!page)
++ break;
++
++ dma_unmap_page(dev->hw->dev, page_list[page_idx].addr_phys,
++ PAGE_SIZE, DMA_BIDIRECTIONAL);
++ __free_page(page);
++ page_idx++;
++ }
++
++ dma_free_coherent(dev->hw->dev, ring_size * sizeof(*desc),
++ desc, dev->rx_page_buf_ring.desc_phys);
++
++free_pagelist:
++ kfree(page_list);
++}
++
+ static void
+ mtk_wed_free_ring(struct mtk_wed_device *dev, struct mtk_wed_ring *ring, int scale)
+ {
+@@ -416,19 +618,25 @@ mtk_wed_free_ring(struct mtk_wed_device *dev, struct mtk_wed_ring *ring, int sca
+ static void
+ mtk_wed_free_tx_rings(struct mtk_wed_device *dev)
+ {
+- int i;
++ int i, scale = dev->hw->version > 1 ? 2 : 1;
+
+ for (i = 0; i < ARRAY_SIZE(dev->tx_ring); i++)
+- mtk_wed_free_ring(dev, &dev->tx_ring[i], 1);
++ if (!(dev->rx_ring[i].flags & MTK_WED_RING_CONFIGURED))
++ mtk_wed_free_ring(dev, &dev->tx_ring[i], 1);
++
+ for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
+- mtk_wed_free_ring(dev, &dev->tx_wdma[i], dev->ver);
++ if ((dev->rx_ring[i].flags & MTK_WED_RING_CONFIGURED))
++ mtk_wed_free_ring(dev, &dev->tx_wdma[i], scale);
+ }
+
+ static void
+ mtk_wed_free_rx_rings(struct mtk_wed_device *dev)
+ {
+- mtk_wed_free_rx_bm(dev);
++ mtk_wed_free_rx_buffer(dev);
+ mtk_wed_free_ring(dev, &dev->rro.rro_ring, 1);
++
++ if (dev->wlan.hwrro)
++ mtk_wed_rx_page_free_buffer(dev);
+ }
+
+ static void
+@@ -437,7 +645,7 @@ mtk_wed_set_int(struct mtk_wed_device *dev, u32 irq_mask)
+ u32 wdma_mask;
+
+ wdma_mask = FIELD_PREP(MTK_WDMA_INT_MASK_RX_DONE, GENMASK(1, 0));
+- if (dev->ver > MTK_WED_V1)
++ if (mtk_wed_get_rx_capa(dev))
+ wdma_mask |= FIELD_PREP(MTK_WDMA_INT_MASK_TX_DONE,
+ GENMASK(1, 0));
+ /* wed control cr set */
+@@ -447,7 +655,7 @@ mtk_wed_set_int(struct mtk_wed_device *dev, u32 irq_mask)
+ MTK_WED_CTRL_WED_TX_BM_EN |
+ MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
+
+- if (dev->ver == MTK_WED_V1) {
++ if (dev->hw->version == 1) {
+ wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER,
+ MTK_WED_PCIE_INT_TRIGGER_STATUS);
+
+@@ -458,6 +666,8 @@ mtk_wed_set_int(struct mtk_wed_device *dev, u32 irq_mask)
+ wed_set(dev, MTK_WED_WPDMA_INT_CTRL,
+ MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV);
+ } else {
++ if (dev->hw->version == 3)
++ wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_TKID_ALI_EN);
+
+ wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX,
+ MTK_WED_WPDMA_INT_CTRL_TX0_DONE_EN |
+@@ -475,18 +685,20 @@ mtk_wed_set_int(struct mtk_wed_device *dev, u32 irq_mask)
+ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_TRIG,
+ dev->wlan.txfree_tbit));
+
+- wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_RX,
+- MTK_WED_WPDMA_INT_CTRL_RX0_EN |
+- MTK_WED_WPDMA_INT_CTRL_RX0_CLR |
+- MTK_WED_WPDMA_INT_CTRL_RX1_EN |
+- MTK_WED_WPDMA_INT_CTRL_RX1_CLR |
+- FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RX0_DONE_TRIG,
+- dev->wlan.rx_tbit[0]) |
+- FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RX1_DONE_TRIG,
+- dev->wlan.rx_tbit[1]));
++ if (mtk_wed_get_rx_capa(dev))
++ wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_RX,
++ MTK_WED_WPDMA_INT_CTRL_RX0_EN |
++ MTK_WED_WPDMA_INT_CTRL_RX0_CLR |
++ MTK_WED_WPDMA_INT_CTRL_RX1_EN |
++ MTK_WED_WPDMA_INT_CTRL_RX1_CLR |
++ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RX0_DONE_TRIG,
++ dev->wlan.rx_tbit[0]) |
++ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RX1_DONE_TRIG,
++ dev->wlan.rx_tbit[1]));
+ }
++
+ wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, wdma_mask);
+- if (dev->ver == MTK_WED_V1) {
++ if (dev->hw->version == 1) {
+ wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask);
+ } else {
+ wed_w32(dev, MTK_WED_WDMA_INT_CLR, wdma_mask);
+@@ -506,6 +718,21 @@ mtk_wed_set_ext_int(struct mtk_wed_device *dev, bool en)
+ {
+ u32 mask = MTK_WED_EXT_INT_STATUS_ERROR_MASK;
+
++ switch (dev->hw->version) {
++ case 1:
++ mask |= MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR;
++ break;
++ case 2 :
++ mask |= MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH2 |
++ MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH2 |
++ MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT |
++ MTK_WED_EXT_INT_STATUS_TX_DMA_W_RESP_ERR;
++ break;
++ case 3:
++ mask = MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT;
++ break;
++ }
++
+ if (!dev->hw->num_flows)
+ mask &= ~MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD;
+
+@@ -514,31 +741,86 @@ mtk_wed_set_ext_int(struct mtk_wed_device *dev, bool en)
+ }
+
+ static void
+-mtk_wed_set_512_support(struct mtk_wed_device *dev, bool en)
++mtk_wed_pao_init(struct mtk_wed_device *dev)
+ {
+- if (en) {
+- wed_w32(dev, MTK_WED_TXDP_CTRL, MTK_WED_TXDP_DW9_OVERWR);
+- wed_w32(dev, MTK_WED_TXP_DW1,
+- FIELD_PREP(MTK_WED_WPDMA_WRITE_TXP, 0x0103));
+- } else {
+- wed_w32(dev, MTK_WED_TXP_DW1,
+- FIELD_PREP(MTK_WED_WPDMA_WRITE_TXP, 0x0100));
+- wed_clr(dev, MTK_WED_TXDP_CTRL, MTK_WED_TXDP_DW9_OVERWR);
++ struct mtk_wed_pao *pao = dev->hw->wed_pao;
++ int i;
++
++ for (i = 0; i < 32; i++)
++ wed_w32(dev, MTK_WED_PAO_HIFTXD_BASE_L(i),
++ pao->hif_txd_phys[i]);
++
++ /* init all sta parameter */
++ wed_w32(dev, MTK_WED_PAO_STA_INFO_INIT, MTK_WED_PAO_STA_RMVL |
++ MTK_WED_PAO_STA_WTBL_HDRT_MODE |
++ FIELD_PREP(MTK_WED_PAO_STA_MAX_AMSDU_LEN,
++ dev->wlan.max_amsdu_len >> 8) |
++ FIELD_PREP(MTK_WED_PAO_STA_MAX_AMSDU_NUM,
++ dev->wlan.max_amsdu_nums));
++
++ wed_w32(dev, MTK_WED_PAO_STA_INFO, MTK_WED_PAO_STA_INFO_DO_INIT);
++
++ if (mtk_wed_poll_busy(dev, MTK_WED_PAO_STA_INFO,
++ MTK_WED_PAO_STA_INFO_DO_INIT)) {
++ dev_err(dev->hw->dev, "mtk_wed%d: pao init failed!\n",
++ dev->hw->index);
++ return;
+ }
++
++ /* init pao txd src */
++ wed_set(dev, MTK_WED_PAO_HIFTXD_CFG,
++ FIELD_PREP(MTK_WED_PAO_HIFTXD_SRC, dev->hw->index));
++
++ /* init qmem */
++ wed_set(dev, MTK_WED_PAO_PSE, MTK_WED_PAO_PSE_RESET);
++ if (mtk_wed_poll_busy(dev, MTK_WED_PAO_MON_QMEM_STS1, BIT(29))) {
++ pr_info("%s: init pao qmem fail\n", __func__);
++ return;
++ }
++
++ /* eagle E1 PCIE1 tx ring 22 flow control issue */
++ if (dev->wlan.chip_id == 0x7991) {
++ wed_clr(dev, MTK_WED_PAO_AMSDU_FIFO,
++ MTK_WED_PAO_AMSDU_IS_PRIOR0_RING);
++ }
++
++ wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_PAO_EN);
++
++ return;
+ }
+
+-static void
+-mtk_wed_check_wfdma_rx_fill(struct mtk_wed_device *dev, int idx)
++static int
++mtk_wed_hwrro_init(struct mtk_wed_device *dev)
+ {
+-#define MTK_WFMDA_RX_DMA_EN BIT(2)
++ if (!mtk_wed_get_rx_capa(dev))
++ return 0;
++
++ wed_set(dev, MTK_WED_RRO_PG_BM_RX_DMAM,
++ FIELD_PREP(MTK_WED_RRO_PG_BM_RX_SDL0, 128));
++
++ wed_w32(dev, MTK_WED_RRO_PG_BM_BASE,
++ dev->rx_page_buf_ring.desc_phys);
++
++ wed_w32(dev, MTK_WED_RRO_PG_BM_INIT_PTR,
++ MTK_WED_RRO_PG_BM_INIT_SW_TAIL_IDX |
++ FIELD_PREP(MTK_WED_RRO_PG_BM_SW_TAIL_IDX,
++ MTK_WED_RX_PG_BM_CNT));
++
++ /* enable rx_page_bm to fetch dmad */
++ wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_PG_BM_EN);
++
++ return 0;
++}
+
++static int
++mtk_wed_check_wfdma_rx_fill(struct mtk_wed_device *dev,
++ struct mtk_wed_ring *ring)
++{
+ int timeout = 3;
+- u32 cur_idx, regs;
++ u32 cur_idx;
+
+ do {
+- regs = MTK_WED_WPDMA_RING_RX_DATA(idx) +
+- MTK_WED_RING_OFS_CPU_IDX;
+- cur_idx = wed_r32(dev, regs);
++ cur_idx = readl(ring->wpdma + MTK_WED_RING_OFS_CPU_IDX);
+ if (cur_idx == MTK_WED_RX_RING_SIZE - 1)
+ break;
+
+@@ -546,70 +828,133 @@ mtk_wed_check_wfdma_rx_fill(struct mtk_wed_device *dev, int idx)
+ timeout--;
+ } while (timeout > 0);
+
+- if (timeout) {
+- unsigned int val;
++ return timeout;
++}
+
+- val = wifi_r32(dev, dev->wlan.wpdma_rx_glo -
+- dev->wlan.phy_base);
+- val |= MTK_WFMDA_RX_DMA_EN;
+
+- wifi_w32(dev, dev->wlan.wpdma_rx_glo -
+- dev->wlan.phy_base, val);
++static void
++mtk_wed_set_512_support(struct mtk_wed_device *dev, bool en)
++{
++ if (en) {
++ wed_w32(dev, MTK_WED_TXDP_CTRL, MTK_WED_TXDP_DW9_OVERWR);
++ wed_w32(dev, MTK_WED_TXP_DW1,
++ FIELD_PREP(MTK_WED_WPDMA_WRITE_TXP, 0x0103));
+ } else {
+- dev_err(dev->hw->dev, "mtk_wed%d: rx(%d) dma enable failed!\n",
+- dev->hw->index, idx);
++ wed_w32(dev, MTK_WED_TXP_DW1,
++ FIELD_PREP(MTK_WED_WPDMA_WRITE_TXP, 0x0100));
++ wed_clr(dev, MTK_WED_TXDP_CTRL, MTK_WED_TXDP_DW9_OVERWR);
+ }
+ }
+
+ static void
+ mtk_wed_dma_enable(struct mtk_wed_device *dev)
+ {
+- wed_set(dev, MTK_WED_WPDMA_INT_CTRL,
+- MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV);
++#define MTK_WFMDA_RX_DMA_EN BIT(2)
++
++ if (dev->hw->version == 1)
++ wed_set(dev, MTK_WED_WPDMA_INT_CTRL,
++ MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV);
+
+ wed_set(dev, MTK_WED_GLO_CFG,
+ MTK_WED_GLO_CFG_TX_DMA_EN |
+ MTK_WED_GLO_CFG_RX_DMA_EN);
++
++ wed_set(dev, MTK_WED_WDMA_RX_PREF_CFG,
++ FIELD_PREP(MTK_WED_WDMA_RX_PREF_BURST_SIZE, 0x10) |
++ FIELD_PREP(MTK_WED_WDMA_RX_PREF_LOW_THRES, 0x8));
++ wed_clr(dev, MTK_WED_WDMA_RX_PREF_CFG,
++ MTK_WED_WDMA_RX_PREF_DDONE2_EN);
++
++ wed_set(dev, MTK_WED_WDMA_RX_PREF_CFG, MTK_WED_WDMA_RX_PREF_EN);
++
+ wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
+ MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN |
+- MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN);
++ MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN |
++ MTK_WED_WPDMA_GLO_CFG_RX_DDONE2_WR);
+ wed_set(dev, MTK_WED_WDMA_GLO_CFG,
+ MTK_WED_WDMA_GLO_CFG_RX_DRV_EN);
+
+ wdma_set(dev, MTK_WDMA_GLO_CFG,
+- MTK_WDMA_GLO_CFG_TX_DMA_EN |
++ MTK_WDMA_GLO_CFG_TX_DMA_EN /*|
+ MTK_WDMA_GLO_CFG_RX_INFO1_PRERES |
+- MTK_WDMA_GLO_CFG_RX_INFO2_PRERES);
++ MTK_WDMA_GLO_CFG_RX_INFO2_PRERES*/);
+
+- if (dev->ver == MTK_WED_V1) {
++ if (dev->hw->version == 1) {
+ wdma_set(dev, MTK_WDMA_GLO_CFG,
+ MTK_WDMA_GLO_CFG_RX_INFO3_PRERES);
+ } else {
+ int idx = 0;
+
+- wed_set(dev, MTK_WED_WPDMA_CTRL,
+- MTK_WED_WPDMA_CTRL_SDL1_FIXED);
+-
+- wed_set(dev, MTK_WED_WDMA_GLO_CFG,
+- MTK_WED_WDMA_GLO_CFG_TX_DRV_EN |
+- MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK);
++ if (mtk_wed_get_rx_capa(dev))
++ wed_set(dev, MTK_WED_WDMA_GLO_CFG,
++ MTK_WED_WDMA_GLO_CFG_TX_DRV_EN |
++ MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK);
+
+ wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
+ MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC |
+ MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC);
+
++ if (dev->hw->version == 3) {
++ wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
++ MTK_WED_WPDMA_GLO_CFG_TX_DDONE_CHK_LAST);
++ wed_set(dev, MTK_WED_WPDMA_GLO_CFG,
++ MTK_WED_WPDMA_GLO_CFG_TX_DDONE_CHK |
++ MTK_WED_WPDMA_GLO_CFG_RX_DRV_EVENT_PKT_FMT_CHK |
++ MTK_WED_WPDMA_GLO_CFG_RX_DRV_UNS_VER_FORCE_4);
++
++ wdma_set(dev, MTK_WDMA_PREF_RX_CFG, MTK_WDMA_PREF_RX_CFG_PREF_EN);
++ //wdma_w32(dev, MTK_WDMA_WRBK_RX_CFG, MTK_WDMA_WRBK_RX_CFG_WRBK_EN);
++ if (mtk_wed_get_rx_capa(dev)) {
++ wed_set(dev, MTK_WED_WPDMA_RX_D_PREF_CFG,
++ MTK_WED_WPDMA_RX_D_PREF_EN |
++ FIELD_PREP(MTK_WED_WPDMA_RX_D_PREF_BURST_SIZE, 0x10) |
++ FIELD_PREP(MTK_WED_WPDMA_RX_D_PREF_LOW_THRES, 0x8));
++
++ wed_set(dev, MTK_WED_RRO_RX_D_CFG(2), MTK_WED_RRO_RX_D_DRV_EN);
++
++ wdma_set(dev, MTK_WDMA_PREF_TX_CFG, MTK_WDMA_PREF_TX_CFG_PREF_EN);
++
++ wdma_set(dev, MTK_WDMA_WRBK_TX_CFG, MTK_WDMA_WRBK_TX_CFG_WRBK_EN);
++ }
++ }
++
+ wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
+ MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP |
+ MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV);
+
++ if (!mtk_wed_get_rx_capa(dev))
++ return;
++
++ wed_clr(dev, MTK_WED_WPDMA_RX_D_GLO_CFG, MTK_WED_WPDMA_RX_D_RXD_READ_LEN);
+ wed_set(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
+ MTK_WED_WPDMA_RX_D_RX_DRV_EN |
+ FIELD_PREP(MTK_WED_WPDMA_RX_D_RXD_READ_LEN, 0x18) |
+ FIELD_PREP(MTK_WED_WPDMA_RX_D_INIT_PHASE_RXEN_SEL,
+ 0x2));
+
+- for (idx = 0; idx < dev->hw->ring_num; idx++)
+- mtk_wed_check_wfdma_rx_fill(dev, idx);
++ for (idx = 0; idx < dev->hw->ring_num; idx++) {
++ struct mtk_wed_ring *ring = &dev->rx_ring[idx];
++
++ if(!(ring->flags & MTK_WED_RING_CONFIGURED))
++ continue;
++
++ if(mtk_wed_check_wfdma_rx_fill(dev, ring)) {
++ unsigned int val;
++
++ val = wifi_r32(dev, dev->wlan.wpdma_rx_glo -
++ dev->wlan.phy_base);
++ val |= MTK_WFMDA_RX_DMA_EN;
++
++ wifi_w32(dev, dev->wlan.wpdma_rx_glo -
++ dev->wlan.phy_base, val);
++
++ dev_err(dev->hw->dev, "mtk_wed%d: rx(%d) dma enable successful!\n",
++ dev->hw->index, idx);
++ } else {
++ dev_err(dev->hw->dev, "mtk_wed%d: rx(%d) dma enable failed!\n",
++ dev->hw->index, idx);
++ }
++ }
+ }
+ }
+
+@@ -644,15 +989,20 @@ mtk_wed_dma_disable(struct mtk_wed_device *dev)
+ MTK_WED_WPDMA_RX_D_RX_DRV_EN);
+ wed_clr(dev, MTK_WED_WDMA_GLO_CFG,
+ MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK);
+- }
+
+- mtk_wed_set_512_support(dev, false);
++ if (dev->hw->version == 3 && mtk_wed_get_rx_capa(dev)) {
++ wdma_clr(dev, MTK_WDMA_PREF_TX_CFG,
++ MTK_WDMA_PREF_TX_CFG_PREF_EN);
++ wdma_clr(dev, MTK_WDMA_PREF_RX_CFG,
++ MTK_WDMA_PREF_RX_CFG_PREF_EN);
++ }
++ }
+ }
+
+ static void
+ mtk_wed_stop(struct mtk_wed_device *dev)
+ {
+- if (dev->ver > MTK_WED_V1) {
++ if (mtk_wed_get_rx_capa(dev)) {
+ wed_w32(dev, MTK_WED_EXT_INT_MASK1, 0);
+ wed_w32(dev, MTK_WED_EXT_INT_MASK2, 0);
+ }
+@@ -677,13 +1027,21 @@ mtk_wed_deinit(struct mtk_wed_device *dev)
+ MTK_WED_CTRL_WED_TX_BM_EN |
+ MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
+
+- if (dev->hw->ver == 1)
++ if (dev->hw->version == 1)
+ return;
+
+ wed_clr(dev, MTK_WED_CTRL,
+ MTK_WED_CTRL_RX_ROUTE_QM_EN |
+ MTK_WED_CTRL_WED_RX_BM_EN |
+ MTK_WED_CTRL_RX_RRO_QM_EN);
++
++ if (dev->hw->version == 3) {
++ wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_PAO_EN);
++ wed_clr(dev, MTK_WED_RESET, MTK_WED_RESET_TX_PAO);
++ wed_clr(dev, MTK_WED_PCIE_INT_CTRL,
++ MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA |
++ MTK_WED_PCIE_INT_CTRL_MSK_IRQ_FILTER);
++ }
+ }
+
+ static void
+@@ -702,9 +1060,9 @@ mtk_wed_detach(struct mtk_wed_device *dev)
+
+ mtk_wdma_tx_reset(dev);
+
+- mtk_wed_free_buffer(dev);
++ mtk_wed_free_tx_buffer(dev);
+ mtk_wed_free_tx_rings(dev);
+- if (dev->ver > MTK_WED_V1) {
++ if (mtk_wed_get_rx_capa(dev)) {
+ mtk_wed_wo_reset(dev);
+ mtk_wed_free_rx_rings(dev);
+ mtk_wed_wo_exit(hw);
+@@ -728,73 +1086,97 @@ mtk_wed_detach(struct mtk_wed_device *dev)
+ mutex_unlock(&hw_lock);
+ }
+
++#define IRQ_MASK_APMCU 0x1000301c
+ static void
+ mtk_wed_bus_init(struct mtk_wed_device *dev)
+ {
+-#define PCIE_BASE_ADDR0 0x11280000
++ switch (dev->wlan.bus_type) {
++ case MTK_WED_BUS_PCIE: {
++ struct device_node *np = dev->hw->eth->dev->of_node;
++ struct regmap *regs;
++ unsigned long addr;
++ u32 value;
+
+- if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) {
+- struct device_node *node;
+- void __iomem * base_addr;
+- u32 value = 0;
++ if (dev->hw->version == 2) {
++ regs = syscon_regmap_lookup_by_phandle(np,
++ "mediatek,wed-pcie");
++ if (IS_ERR(regs))
++ break;
+
+- node = of_parse_phandle(dev->hw->node, "mediatek,wed_pcie", 0);
+- if (!node) {
+- pr_err("%s: no wed_pcie node\n", __func__);
+- return;
++ regmap_update_bits(regs, 0, BIT(0), BIT(0));
+ }
+
+- base_addr = of_iomap(node, 0);
+-
+- value = readl(base_addr);
+- value |= BIT(0);
+- writel(value, base_addr);
++ if (dev->wlan.msi) {
++ wed_w32(dev, MTK_WED_PCIE_CFG_INTM, dev->hw->pci_base| 0xc08);
++ wed_w32(dev, MTK_WED_PCIE_CFG_BASE, dev->hw->pci_base | 0xc04);
++ wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(8));
++ } else {
++ wed_w32(dev, MTK_WED_PCIE_CFG_INTM, dev->hw->pci_base | 0x180);
++ wed_w32(dev, MTK_WED_PCIE_CFG_BASE, dev->hw->pci_base | 0x184);
++ wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(24));
++ }
+
+- wed_w32(dev, MTK_WED_PCIE_INT_CTRL,
+- FIELD_PREP(MTK_WED_PCIE_INT_CTRL_POLL_EN, 2));
++ if (dev->hw->version < 3 || dev->hw->index) {
++ wed_w32(dev, MTK_WED_PCIE_INT_CTRL,
++ FIELD_PREP(MTK_WED_PCIE_INT_CTRL_POLL_EN, 2));
++ } else {
++ /* set mask apmcu */
++ addr = (unsigned long)ioremap(IRQ_MASK_APMCU, 4);
++ value = readl((void *)addr);
++ value |= 0x7;
++ writel(value, (void *)addr);
++ iounmap((void *)addr);
++ }
+
+ /* pcie interrupt control: pola/source selection */
+ wed_set(dev, MTK_WED_PCIE_INT_CTRL,
+ MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA |
+- FIELD_PREP(MTK_WED_PCIE_INT_CTRL_SRC_SEL, 1));
+- wed_r32(dev, MTK_WED_PCIE_INT_CTRL);
++ MTK_WED_PCIE_INT_CTRL_MSK_IRQ_FILTER |
++ FIELD_PREP(MTK_WED_PCIE_INT_CTRL_SRC_SEL, dev->hw->index));
+
+- value = wed_r32(dev, MTK_WED_PCIE_CFG_INTM);
+- value = wed_r32(dev, MTK_WED_PCIE_CFG_BASE);
+- wed_w32(dev, MTK_WED_PCIE_CFG_INTM, PCIE_BASE_ADDR0 | 0x180);
+- wed_w32(dev, MTK_WED_PCIE_CFG_BASE, PCIE_BASE_ADDR0 | 0x184);
+-
+- value = wed_r32(dev, MTK_WED_PCIE_CFG_INTM);
+- value = wed_r32(dev, MTK_WED_PCIE_CFG_BASE);
+-
+- wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(24));
+- wed_r32(dev, MTK_WED_PCIE_INT_TRIGGER);
+-
+- /* pola setting */
+- value = wed_r32(dev, MTK_WED_PCIE_INT_CTRL);
+- wed_set(dev, MTK_WED_PCIE_INT_CTRL,
+- MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA);
+- } else if (dev->wlan.bus_type == MTK_WED_BUS_AXI) {
++ break;
++ }
++ case MTK_WED_BUS_AXI:
+ wed_set(dev, MTK_WED_WPDMA_INT_CTRL,
+ MTK_WED_WPDMA_INT_CTRL_SIG_SRC |
+ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_SRC_SEL, 0));
++ break;
++ default:
++ break;
+ }
++
+ return;
+ }
+
+ static void
+ mtk_wed_set_wpdma(struct mtk_wed_device *dev)
+ {
+- if (dev->ver > MTK_WED_V1) {
++ if (dev->hw->version == 1) {
++ wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_phys);
++ } else {
++ mtk_wed_bus_init(dev);
++
+ wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_int);
+ wed_w32(dev, MTK_WED_WPDMA_CFG_INT_MASK, dev->wlan.wpdma_mask);
+- wed_w32(dev, MTK_WED_WPDMA_CFG_TX, dev->wlan.wpdma_tx);
++ wed_w32(dev, MTK_WED_WPDMA_CFG_TX, dev->wlan.wpdma_tx);
+ wed_w32(dev, MTK_WED_WPDMA_CFG_TX_FREE, dev->wlan.wpdma_txfree);
+
+- wed_w32(dev, MTK_WED_WPDMA_RX_GLO_CFG, dev->wlan.wpdma_rx_glo);
+- wed_w32(dev, MTK_WED_WPDMA_RX_RING, dev->wlan.wpdma_rx);
+- } else {
+- wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_phys);
++ if (mtk_wed_get_rx_capa(dev)) {
++ int i;
++
++ wed_w32(dev, MTK_WED_WPDMA_RX_GLO_CFG, dev->wlan.wpdma_rx_glo);
++ wed_w32(dev, MTK_WED_WPDMA_RX_RING0, dev->wlan.wpdma_rx);
++ wed_w32(dev, MTK_WED_WPDMA_RX_RING1, dev->wlan.wpdma_rx + 0x10);
++
++ if (dev->wlan.hwrro) {
++ wed_w32(dev, MTK_WED_RRO_RX_D_CFG(0), dev->wlan.wpdma_rx_rro[0]);
++ wed_w32(dev, MTK_WED_RRO_RX_D_CFG(1), dev->wlan.wpdma_rx_rro[1]);
++ for (i = 0; i < MTK_WED_RX_PAGE_QUEUES; i++) {
++ wed_w32(dev, MTK_WED_RRO_MSDU_PG_RING_CFG(i),
++ dev->wlan.wpdma_rx_pg + i * 0x10);
++ }
++ }
++ }
+ }
+ }
+
+@@ -806,21 +1188,25 @@ mtk_wed_hw_init_early(struct mtk_wed_device *dev)
+ mtk_wed_deinit(dev);
+ mtk_wed_reset(dev, MTK_WED_RESET_WED);
+
+- if (dev->ver > MTK_WED_V1)
+- mtk_wed_bus_init(dev);
+-
+ mtk_wed_set_wpdma(dev);
+
+- mask = MTK_WED_WDMA_GLO_CFG_BT_SIZE |
+- MTK_WED_WDMA_GLO_CFG_DYNAMIC_DMAD_RECYCLE |
+- MTK_WED_WDMA_GLO_CFG_RX_DIS_FSM_AUTO_IDLE;
+- set = FIELD_PREP(MTK_WED_WDMA_GLO_CFG_BT_SIZE, 2) |
+- MTK_WED_WDMA_GLO_CFG_DYNAMIC_SKIP_DMAD_PREP |
+- MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY;
++ if (dev->hw->version == 3) {
++ mask = MTK_WED_WDMA_GLO_CFG_BT_SIZE;
++ set = FIELD_PREP(MTK_WED_WDMA_GLO_CFG_BT_SIZE, 2);
++ } else {
++ mask = MTK_WED_WDMA_GLO_CFG_BT_SIZE |
++ MTK_WED_WDMA_GLO_CFG_DYNAMIC_DMAD_RECYCLE |
++ MTK_WED_WDMA_GLO_CFG_RX_DIS_FSM_AUTO_IDLE;
++ set = FIELD_PREP(MTK_WED_WDMA_GLO_CFG_BT_SIZE, 2) |
++ MTK_WED_WDMA_GLO_CFG_DYNAMIC_SKIP_DMAD_PREP |
++ MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY;
++ }
++
+ wed_m32(dev, MTK_WED_WDMA_GLO_CFG, mask, set);
+
+- if (dev->ver == MTK_WED_V1) {
++ if (dev->hw->version == 1) {
+ u32 offset;
++
+ offset = dev->hw->index ? 0x04000400 : 0;
+ wed_w32(dev, MTK_WED_WDMA_OFFSET0, 0x2a042a20 + offset);
+ wed_w32(dev, MTK_WED_WDMA_OFFSET1, 0x29002800 + offset);
+@@ -907,11 +1293,16 @@ mtk_wed_route_qm_hw_init(struct mtk_wed_device *dev)
+ } while (1);
+
+ /* configure RX_ROUTE_QM */
+- wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_Q_RST);
+- wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_TXDMAD_FPORT);
+- wed_set(dev, MTK_WED_RTQM_GLO_CFG,
+- FIELD_PREP(MTK_WED_RTQM_TXDMAD_FPORT, 0x3 + dev->hw->index));
+- wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_Q_RST);
++ if (dev->hw->version == 2) {
++ wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_Q_RST);
++ wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_TXDMAD_FPORT);
++ wed_set(dev, MTK_WED_RTQM_GLO_CFG,
++ FIELD_PREP(MTK_WED_RTQM_TXDMAD_FPORT, 0x3 + dev->hw->index));
++ wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_Q_RST);
++ } else {
++ wed_set(dev, MTK_WED_RTQM_ENQ_CFG0,
++ FIELD_PREP(MTK_WED_RTQM_ENQ_CFG_TXDMAD_FPORT, 0x3 + dev->hw->index));
++ }
+
+ /* enable RX_ROUTE_QM */
+ wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_ROUTE_QM_EN);
+@@ -920,23 +1311,45 @@ mtk_wed_route_qm_hw_init(struct mtk_wed_device *dev)
+ static void
+ mtk_wed_tx_hw_init(struct mtk_wed_device *dev)
+ {
+- int size = dev->buf_ring.size;
++ int size = dev->wlan.nbuf;
+ int rev_size = MTK_WED_TX_RING_SIZE / 2;
+- int thr = 1;
++ int thr_lo = 1, thr_hi = 1;
+
+- if (dev->ver > MTK_WED_V1) {
++ if (dev->hw->version == 1) {
++ wed_w32(dev, MTK_WED_TX_BM_CTRL,
++ MTK_WED_TX_BM_CTRL_PAUSE |
++ FIELD_PREP(MTK_WED_TX_BM_CTRL_VLD_GRP_NUM, size / 128) |
++ FIELD_PREP(MTK_WED_TX_BM_CTRL_RSV_GRP_NUM, rev_size / 128));
++ } else {
+ size = MTK_WED_WDMA_RING_SIZE * ARRAY_SIZE(dev->tx_wdma) +
+- dev->buf_ring.size;
++ dev->tx_buf_ring.size;
+ rev_size = size;
+- thr = 0;
++ thr_lo = 0;
++ thr_hi = MTK_WED_TX_BM_DYN_THR_HI;
++
++ wed_w32(dev, MTK_WED_TX_TKID_CTRL,
++ MTK_WED_TX_TKID_CTRL_PAUSE |
++ FIELD_PREP(MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM,
++ size / 128) |
++ FIELD_PREP(MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM,
++ size / 128));
++
++ /* return SKBID + SDP back to bm */
++ if (dev->ver == 3) {
++ wed_set(dev, MTK_WED_TX_TKID_CTRL,
++ MTK_WED_TX_TKID_CTRL_FREE_FORMAT);
++ size = dev->wlan.nbuf;
++ rev_size = size;
++ } else {
++ wed_w32(dev, MTK_WED_TX_TKID_DYN_THR,
++ FIELD_PREP(MTK_WED_TX_TKID_DYN_THR_LO, 0) |
++ MTK_WED_TX_TKID_DYN_THR_HI);
++ }
+ }
+
+- wed_w32(dev, MTK_WED_TX_BM_CTRL,
+- MTK_WED_TX_BM_CTRL_PAUSE |
+- FIELD_PREP(MTK_WED_TX_BM_CTRL_VLD_GRP_NUM, size / 128) |
+- FIELD_PREP(MTK_WED_TX_BM_CTRL_RSV_GRP_NUM, rev_size / 128));
++ mtk_wed_reset(dev, MTK_WED_RESET_TX_BM);
+
+- wed_w32(dev, MTK_WED_TX_BM_BASE, dev->buf_ring.desc_phys);
++ wed_w32(dev, MTK_WED_TX_BM_BASE, dev->tx_buf_ring.desc_phys);
+
+ wed_w32(dev, MTK_WED_TX_BM_TKID,
+ FIELD_PREP(MTK_WED_TX_BM_TKID_START,
+@@ -946,25 +1359,44 @@ mtk_wed_tx_hw_init(struct mtk_wed_device *dev)
+
+ wed_w32(dev, MTK_WED_TX_BM_BUF_LEN, MTK_WED_PKT_SIZE);
+
+- wed_w32(dev, MTK_WED_TX_BM_DYN_THR,
+- FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO, thr) |
+- MTK_WED_TX_BM_DYN_THR_HI);
++ if (dev->hw->version < 3)
++ wed_w32(dev, MTK_WED_TX_BM_DYN_THR,
++ FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO, thr_lo) |
++ FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO, thr_hi));
++ else {
++ /* change to new bm */
++ wed_w32(dev, MTK_WED_TX_BM_INIT_PTR, dev->tx_buf_ring.pkt_nums |
++ MTK_WED_TX_BM_INIT_SW_TAIL_IDX);
++ wed_clr(dev, MTK_WED_TX_BM_CTRL, MTK_WED_TX_BM_CTRL_LEGACY_EN);
++ }
+
+- if (dev->ver > MTK_WED_V1) {
++ if (dev->hw->version != 1) {
+ wed_w32(dev, MTK_WED_TX_TKID_CTRL,
+ MTK_WED_TX_TKID_CTRL_PAUSE |
+ FIELD_PREP(MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM,
+- dev->buf_ring.size / 128) |
++ size / 128) |
+ FIELD_PREP(MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM,
+- dev->buf_ring.size / 128));
+- wed_w32(dev, MTK_WED_TX_TKID_DYN_THR,
+- FIELD_PREP(MTK_WED_TX_TKID_DYN_THR_LO, 0) |
+- MTK_WED_TX_TKID_DYN_THR_HI);
++ size / 128));
++
++ /* return SKBID + SDP back to bm */
++ if (dev->ver == 3)
++ wed_set(dev, MTK_WED_TX_TKID_CTRL,
++ MTK_WED_TX_TKID_CTRL_FREE_FORMAT);
++ else
++ wed_w32(dev, MTK_WED_TX_TKID_DYN_THR,
++ FIELD_PREP(MTK_WED_TX_TKID_DYN_THR_LO, 0) |
++ MTK_WED_TX_TKID_DYN_THR_HI);
+ }
+- mtk_wed_reset(dev, MTK_WED_RESET_TX_BM);
++ wed_w32(dev, MTK_WED_TX_BM_TKID,
++ FIELD_PREP(MTK_WED_TX_BM_TKID_START,
++ dev->wlan.token_start) |
++ FIELD_PREP(MTK_WED_TX_BM_TKID_END,
++ dev->wlan.token_start + dev->wlan.nbuf - 1));
+
++ wed_w32(dev, MTK_WED_TX_BM_INIT_PTR, dev->tx_buf_ring.pkt_nums |
++ MTK_WED_TX_BM_INIT_SW_TAIL_IDX);
+ wed_clr(dev, MTK_WED_TX_BM_CTRL, MTK_WED_TX_BM_CTRL_PAUSE);
+- if (dev->ver > MTK_WED_V1)
++ if (dev->hw->version != 1)
+ wed_clr(dev, MTK_WED_TX_TKID_CTRL, MTK_WED_TX_TKID_CTRL_PAUSE);
+ }
+
+@@ -977,7 +1409,26 @@ mtk_wed_rx_hw_init(struct mtk_wed_device *dev)
+
+ wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX, 0);
+
++ /* reset prefetch index of ring */
++ wed_set(dev, MTK_WED_WPDMA_RX_D_PREF_RX0_SIDX,
++ MTK_WED_WPDMA_RX_D_PREF_SIDX_IDX_CLR);
++ wed_clr(dev, MTK_WED_WPDMA_RX_D_PREF_RX0_SIDX,
++ MTK_WED_WPDMA_RX_D_PREF_SIDX_IDX_CLR);
++
++ wed_set(dev, MTK_WED_WPDMA_RX_D_PREF_RX1_SIDX,
++ MTK_WED_WPDMA_RX_D_PREF_SIDX_IDX_CLR);
++ wed_clr(dev, MTK_WED_WPDMA_RX_D_PREF_RX1_SIDX,
++ MTK_WED_WPDMA_RX_D_PREF_SIDX_IDX_CLR);
++
++ /* reset prefetch FIFO of ring */
++ wed_set(dev, MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG,
++ MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG_R0_CLR |
++ MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG_R1_CLR);
++ wed_w32(dev, MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG, 0);
++
+ mtk_wed_rx_bm_hw_init(dev);
++ if (dev->wlan.hwrro)
++ mtk_wed_hwrro_init(dev);
+ mtk_wed_rro_hw_init(dev);
+ mtk_wed_route_qm_hw_init(dev);
+ }
+@@ -991,7 +1442,7 @@ mtk_wed_hw_init(struct mtk_wed_device *dev)
+ dev->init_done = true;
+ mtk_wed_set_ext_int(dev, false);
+ mtk_wed_tx_hw_init(dev);
+- if (dev->ver > MTK_WED_V1)
++ if (mtk_wed_get_rx_capa(dev))
+ mtk_wed_rx_hw_init(dev);
+ }
+
+@@ -1015,26 +1466,6 @@ mtk_wed_ring_reset(struct mtk_wdma_desc *desc, int size, int scale, bool tx)
+ }
+ }
+
+-static u32
+-mtk_wed_check_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
+-{
+- if (wed_r32(dev, reg) & mask)
+- return true;
+-
+- return false;
+-}
+-
+-static int
+-mtk_wed_poll_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
+-{
+- int sleep = 1000;
+- int timeout = 100 * sleep;
+- u32 val;
+-
+- return read_poll_timeout(mtk_wed_check_busy, val, !val, sleep,
+- timeout, false, dev, reg, mask);
+-}
+-
+ static void
+ mtk_wed_rx_reset(struct mtk_wed_device *dev)
+ {
+@@ -1133,7 +1564,7 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
+ mtk_wed_ring_reset(desc, MTK_WED_RX_RING_SIZE, 1, false);
+ }
+
+- mtk_wed_free_rx_bm(dev);
++ mtk_wed_free_rx_buffer(dev);
+ }
+
+
+@@ -1271,12 +1702,15 @@ mtk_wed_wdma_rx_ring_setup(struct mtk_wed_device *dev,
+ int idx, int size, bool reset)
+ {
+ struct mtk_wed_ring *wdma = &dev->tx_wdma[idx];
++ int scale = dev->hw->version > 1 ? 2 : 1;
+
+ if(!reset)
+ if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE,
+- dev->ver, true))
++ scale, true))
+ return -ENOMEM;
+
++ wdma->flags |= MTK_WED_RING_CONFIGURED;
++
+ wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_BASE,
+ wdma->desc_phys);
+ wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_COUNT,
+@@ -1296,12 +1730,31 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev,
+ int idx, int size, bool reset)
+ {
+ struct mtk_wed_ring *wdma = &dev->rx_wdma[idx];
++ int scale = dev->hw->version > 1 ? 2 : 1;
+
+ if (!reset)
+ if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE,
+- dev->ver, true))
++ scale, true))
+ return -ENOMEM;
+
++ if (dev->hw->version == 3) {
++ struct mtk_wdma_desc *desc = wdma->desc;
++ int i;
++
++ for (i = 0; i < MTK_WED_WDMA_RING_SIZE; i++) {
++ desc->buf0 = 0;
++ desc->ctrl = MTK_WDMA_DESC_CTRL_DMA_DONE;
++ desc->buf1 = 0;
++ desc->info = MTK_WDMA_TXD0_DESC_INFO_DMA_DONE;
++ desc++;
++ desc->buf0 = 0;
++ desc->ctrl = MTK_WDMA_DESC_CTRL_DMA_DONE;
++ desc->buf1 = 0;
++ desc->info = MTK_WDMA_TXD1_DESC_INFO_DMA_DONE;
++ desc++;
++ }
++ }
++
+ wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_BASE,
+ wdma->desc_phys);
+ wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_COUNT,
+@@ -1312,7 +1765,7 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev,
+ MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_DMA_IDX, 0);
+ if (reset)
+ mtk_wed_ring_reset(wdma->desc, MTK_WED_WDMA_RING_SIZE,
+- dev->ver, true);
++ scale, true);
+ if (idx == 0) {
+ wed_w32(dev, MTK_WED_WDMA_RING_TX
+ + MTK_WED_RING_OFS_BASE, wdma->desc_phys);
+@@ -1395,7 +1848,7 @@ mtk_wed_send_msg(struct mtk_wed_device *dev, int cmd_id, void *data, int len)
+ {
+ struct mtk_wed_wo *wo = dev->hw->wed_wo;
+
+- if (dev->ver == MTK_WED_V1)
++ if (!mtk_wed_get_rx_capa(dev))
+ return 0;
+
+ return mtk_wed_mcu_send_msg(wo, MODULE_ID_WO, cmd_id, data, len, true);
+@@ -1420,13 +1873,87 @@ mtk_wed_ppe_check(struct mtk_wed_device *dev, struct sk_buff *skb,
+ }
+ }
+
++static void
++mtk_wed_start_hwrro(struct mtk_wed_device *dev, u32 irq_mask)
++{
++ int idx, ret;
++
++ wed_w32(dev, MTK_WED_WPDMA_INT_MASK, irq_mask);
++ wed_w32(dev, MTK_WED_INT_MASK, irq_mask);
++
++ if (!mtk_wed_get_rx_capa(dev) || !dev->wlan.hwrro)
++ return;
++
++ wed_set(dev, MTK_WED_RRO_RX_D_CFG(2), MTK_WED_RRO_MSDU_PG_DRV_CLR);
++ wed_w32(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG, MTK_WED_RRO_MSDU_PG_DRV_CLR);
++
++ wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_RRO_RX,
++ MTK_WED_WPDMA_INT_CTRL_RRO_RX0_EN |
++ MTK_WED_WPDMA_INT_CTRL_RRO_RX0_CLR |
++ MTK_WED_WPDMA_INT_CTRL_RRO_RX1_EN |
++ MTK_WED_WPDMA_INT_CTRL_RRO_RX1_CLR |
++ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RRO_RX0_DONE_TRIG,
++ dev->wlan.rro_rx_tbit[0]) |
++ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RRO_RX1_DONE_TRIG,
++ dev->wlan.rro_rx_tbit[1]));
++
++ wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_RRO_MSDU_PG,
++ MTK_WED_WPDMA_INT_CTRL_RRO_PG0_EN |
++ MTK_WED_WPDMA_INT_CTRL_RRO_PG0_CLR |
++ MTK_WED_WPDMA_INT_CTRL_RRO_PG1_EN |
++ MTK_WED_WPDMA_INT_CTRL_RRO_PG1_CLR |
++ MTK_WED_WPDMA_INT_CTRL_RRO_PG2_EN |
++ MTK_WED_WPDMA_INT_CTRL_RRO_PG2_CLR |
++ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RRO_PG0_DONE_TRIG,
++ dev->wlan.rx_pg_tbit[0]) |
++ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RRO_PG1_DONE_TRIG,
++ dev->wlan.rx_pg_tbit[1])|
++ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RRO_PG2_DONE_TRIG,
++ dev->wlan.rx_pg_tbit[2]));
++
++ /*
++ * RRO_MSDU_PG_RING2_CFG1_FLD_DRV_EN should be enabled after
++ * WM FWDL completed, otherwise RRO_MSDU_PG ring may broken
++ */
++ wed_set(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG, MTK_WED_RRO_MSDU_PG_DRV_EN);
++
++ for (idx = 0; idx < MTK_WED_RX_QUEUES; idx++) {
++ struct mtk_wed_ring *ring = &dev->rx_rro_ring[idx];
++
++ if(!(ring->flags & MTK_WED_RING_CONFIGURED))
++ continue;
++
++ ret = mtk_wed_check_wfdma_rx_fill(dev, ring);
++ if (!ret)
++ dev_err(dev->hw->dev, "mtk_wed%d: rx_rro_ring(%d) init failed!\n",
++ dev->hw->index, idx);
++ }
++
++ for (idx = 0; idx < MTK_WED_RX_PAGE_QUEUES; idx++){
++ struct mtk_wed_ring *ring = &dev->rx_page_ring[idx];
++ if(!(ring->flags & MTK_WED_RING_CONFIGURED))
++ continue;
++
++ ret = mtk_wed_check_wfdma_rx_fill(dev, ring);
++ if (!ret)
++ dev_err(dev->hw->dev, "mtk_wed%d: rx_page_ring(%d) init failed!\n",
++ dev->hw->index, idx);
++ }
++}
++
+ static void
+ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
+ {
+ int i, ret;
+
+- if (dev->ver > MTK_WED_V1)
+- ret = mtk_wed_rx_bm_alloc(dev);
++ if (mtk_wed_get_rx_capa(dev)) {
++ ret = mtk_wed_rx_buffer_alloc(dev);
++ if (ret)
++ return;
++
++ if (dev->wlan.hwrro)
++ mtk_wed_rx_page_buffer_alloc(dev);
++ }
+
+ for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
+ if (!dev->tx_wdma[i].desc)
+@@ -1437,7 +1964,7 @@ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
+ mtk_wed_set_int(dev, irq_mask);
+ mtk_wed_set_ext_int(dev, true);
+
+- if (dev->ver == MTK_WED_V1) {
++ if (dev->hw->version == 1) {
+ u32 val;
+
+ val = dev->wlan.wpdma_phys |
+@@ -1448,33 +1975,52 @@ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
+ val |= BIT(1);
+ val |= BIT(0);
+ regmap_write(dev->hw->mirror, dev->hw->index * 4, val);
+- } else {
++ } else if (mtk_wed_get_rx_capa(dev)) {
+ /* driver set mid ready and only once */
+ wed_w32(dev, MTK_WED_EXT_INT_MASK1,
+ MTK_WED_EXT_INT_STATUS_WPDMA_MID_RDY);
+ wed_w32(dev, MTK_WED_EXT_INT_MASK2,
+ MTK_WED_EXT_INT_STATUS_WPDMA_MID_RDY);
++ if (dev->hw->version == 3)
++ wed_w32(dev, MTK_WED_EXT_INT_MASK3,
++ MTK_WED_EXT_INT_STATUS_WPDMA_MID_RDY);
+
+ wed_r32(dev, MTK_WED_EXT_INT_MASK1);
+ wed_r32(dev, MTK_WED_EXT_INT_MASK2);
++ if (dev->hw->version == 3)
++ wed_r32(dev, MTK_WED_EXT_INT_MASK3);
+
+ ret = mtk_wed_rro_cfg(dev);
+ if (ret)
+ return;
+ }
+- mtk_wed_set_512_support(dev, dev->wlan.wcid_512);
++
++ if (dev->hw->version == 2)
++ mtk_wed_set_512_support(dev, dev->wlan.wcid_512);
++ else if (dev->hw->version == 3)
++ mtk_wed_pao_init(dev);
+
+ mtk_wed_dma_enable(dev);
+ dev->running = true;
+ }
+
++static int
++mtk_wed_get_pci_base(struct mtk_wed_device *dev)
++{
++ if (dev->hw->index == 0)
++ return MTK_WED_PCIE_BASE0;
++ else if (dev->hw->index == 1)
++ return MTK_WED_PCIE_BASE1;
++ else
++ return MTK_WED_PCIE_BASE2;
++}
++
+ static int
+ mtk_wed_attach(struct mtk_wed_device *dev)
+ __releases(RCU)
+ {
+ struct mtk_wed_hw *hw;
+ struct device *device;
+- u16 ver;
+ int ret = 0;
+
+ RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
+@@ -1494,34 +2040,30 @@ mtk_wed_attach(struct mtk_wed_device *dev)
+ goto out;
+ }
+
+- device = dev->wlan.bus_type == MTK_WED_BUS_PCIE
+- ? &dev->wlan.pci_dev->dev
+- : &dev->wlan.platform_dev->dev;
++ device = dev->wlan.bus_type == MTK_WED_BUS_PCIE ?
++ &dev->wlan.pci_dev->dev
++ : &dev->wlan.platform_dev->dev;
+ dev_info(device, "attaching wed device %d version %d\n",
+- hw->index, hw->ver);
++ hw->index, hw->version);
+
+ dev->hw = hw;
+ dev->dev = hw->dev;
+ dev->irq = hw->irq;
+ dev->wdma_idx = hw->index;
++ dev->ver = hw->version;
++
++ if (dev->hw->version == 3)
++ dev->hw->pci_base = mtk_wed_get_pci_base(dev);
+
+ if (hw->eth->dma_dev == hw->eth->dev &&
+ of_dma_is_coherent(hw->eth->dev->of_node))
+ mtk_eth_set_dma_device(hw->eth, hw->dev);
+
+- dev->ver = FIELD_GET(MTK_WED_REV_ID_MAJOR,
+- wed_r32(dev, MTK_WED_REV_ID));
+- if (dev->ver > MTK_WED_V1)
+- ver = FIELD_GET(MTK_WED_REV_ID_MINOR,
+- wed_r32(dev, MTK_WED_REV_ID));
+-
+- dev->rev_id = ((dev->ver << 28) | ver << 16);
+-
+- ret = mtk_wed_buffer_alloc(dev);
++ ret = mtk_wed_tx_buffer_alloc(dev);
+ if (ret)
+ goto error;
+
+- if (dev->ver > MTK_WED_V1) {
++ if (mtk_wed_get_rx_capa(dev)) {
+ ret = mtk_wed_rro_alloc(dev);
+ if (ret)
+ goto error;
+@@ -1533,15 +2075,20 @@ mtk_wed_attach(struct mtk_wed_device *dev)
+ init_completion(&dev->wlan_reset_done);
+ atomic_set(&dev->fe_reset, 0);
+
+- if (dev->ver == MTK_WED_V1)
++ if (dev->hw->version != 1)
++ dev->rev_id = wed_r32(dev, MTK_WED_REV_ID);
++ else
+ regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP,
+ BIT(hw->index), 0);
+- else
++
++ if (mtk_wed_get_rx_capa(dev))
+ ret = mtk_wed_wo_init(hw);
+
+ error:
+- if (ret)
++ if (ret) {
++ pr_info("%s: detach wed\n", __func__);
+ mtk_wed_detach(dev);
++ }
+ out:
+ mutex_unlock(&hw_lock);
+
+@@ -1576,8 +2123,26 @@ mtk_wed_tx_ring_setup(struct mtk_wed_device *dev, int idx,
+ if (mtk_wed_wdma_rx_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE, reset))
+ return -ENOMEM;
+
++ if (dev->hw->version == 3 && idx == 1) {
++ /* reset prefetch index */
++ wed_set(dev, MTK_WED_WDMA_RX_PREF_CFG,
++ MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR |
++ MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR);
++
++ wed_clr(dev, MTK_WED_WDMA_RX_PREF_CFG,
++ MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR |
++ MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR);
++
++ /* reset prefetch FIFO */
++ wed_w32(dev, MTK_WED_WDMA_RX_PREF_FIFO_CFG,
++ MTK_WED_WDMA_RX_PREF_FIFO_RX0_CLR |
++ MTK_WED_WDMA_RX_PREF_FIFO_RX1_CLR);
++ wed_w32(dev, MTK_WED_WDMA_RX_PREF_FIFO_CFG, 0);
++ }
++
+ ring->reg_base = MTK_WED_RING_TX(idx);
+ ring->wpdma = regs;
++ ring->flags |= MTK_WED_RING_CONFIGURED;
+
+ /* WED -> WPDMA */
+ wpdma_tx_w32(dev, idx, MTK_WED_RING_OFS_BASE, ring->desc_phys);
+@@ -1599,7 +2164,7 @@ mtk_wed_txfree_ring_setup(struct mtk_wed_device *dev, void __iomem *regs)
+ struct mtk_wed_ring *ring = &dev->txfree_ring;
+ int i, idx = 1;
+
+- if(dev->ver > MTK_WED_V1)
++ if(dev->hw->version > 1)
+ idx = 0;
+
+ /*
+@@ -1652,6 +2217,129 @@ mtk_wed_rx_ring_setup(struct mtk_wed_device *dev,
+ return 0;
+ }
+
++static int
++mtk_wed_rro_rx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs)
++{
++ struct mtk_wed_ring *ring = &dev->rx_rro_ring[idx];
++
++ ring->wpdma = regs;
++
++ wed_w32(dev, MTK_WED_RRO_RX_D_RX(idx) + MTK_WED_RING_OFS_BASE,
++ readl(regs));
++ wed_w32(dev, MTK_WED_RRO_RX_D_RX(idx) + MTK_WED_RING_OFS_COUNT,
++ readl(regs + MTK_WED_RING_OFS_COUNT));
++
++ ring->flags |= MTK_WED_RING_CONFIGURED;
++
++ return 0;
++}
++
++static int
++mtk_wed_msdu_pg_rx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs)
++{
++ struct mtk_wed_ring *ring = &dev->rx_page_ring[idx];
++
++ ring->wpdma = regs;
++
++ wed_w32(dev, MTK_WED_RRO_MSDU_PG_CTRL0(idx) + MTK_WED_RING_OFS_BASE,
++ readl(regs));
++ wed_w32(dev, MTK_WED_RRO_MSDU_PG_CTRL0(idx) + MTK_WED_RING_OFS_COUNT,
++ readl(regs + MTK_WED_RING_OFS_COUNT));
++
++ ring->flags |= MTK_WED_RING_CONFIGURED;
++
++ return 0;
++}
++
++static int
++mtk_wed_ind_rx_ring_setup(struct mtk_wed_device *dev, void __iomem *regs)
++{
++ struct mtk_wed_ring *ring = &dev->ind_cmd_ring;
++ u32 val = readl(regs + MTK_WED_RING_OFS_COUNT);
++ int i = 0, cnt = 0;
++
++ ring->wpdma = regs;
++
++ if (readl(regs) & 0xf)
++ pr_info("%s(): address is not 16-byte alignment\n", __func__);
++
++ wed_w32(dev, MTK_WED_IND_CMD_RX_CTRL1 + MTK_WED_RING_OFS_BASE,
++ readl(regs) & 0xfffffff0);
++
++ wed_w32(dev, MTK_WED_IND_CMD_RX_CTRL1 + MTK_WED_RING_OFS_COUNT,
++ readl(regs + MTK_WED_RING_OFS_COUNT));
++
++ /* ack sn cr */
++ wed_w32(dev, MTK_WED_RRO_CFG0, dev->wlan.phy_base +
++ dev->wlan.ind_cmd.ack_sn_addr);
++ wed_w32(dev, MTK_WED_RRO_CFG1,
++ FIELD_PREP(MTK_WED_RRO_CFG1_MAX_WIN_SZ,
++ dev->wlan.ind_cmd.win_size) |
++ FIELD_PREP(MTK_WED_RRO_CFG1_PARTICL_SE_ID,
++ dev->wlan.ind_cmd.particular_sid));
++
++ /* particular session addr element */
++ wed_w32(dev, MTK_WED_ADDR_ELEM_CFG0, dev->wlan.ind_cmd.particular_se_phys);
++
++ for (i = 0; i < dev->wlan.ind_cmd.se_group_nums; i++) {
++ wed_w32(dev, MTK_WED_RADDR_ELEM_TBL_WDATA,
++ dev->wlan.ind_cmd.addr_elem_phys[i] >> 4);
++ wed_w32(dev, MTK_WED_ADDR_ELEM_TBL_CFG,
++ MTK_WED_ADDR_ELEM_TBL_WR | (i & 0x7f));
++
++ val = wed_r32(dev, MTK_WED_ADDR_ELEM_TBL_CFG);
++ while (!(val & MTK_WED_ADDR_ELEM_TBL_WR_RDY) &&
++ cnt < 100) {
++ val = wed_r32(dev, MTK_WED_ADDR_ELEM_TBL_CFG);
++ cnt++;
++ }
++ if (cnt >= 100) {
++ dev_err(dev->hw->dev, "mtk_wed%d: write ba session base failed!\n",
++ dev->hw->index);
++ }
++ /*if (mtk_wed_poll_busy(dev, MTK_WED_ADDR_ELEM_TBL_CFG,
++ MTK_WED_ADDR_ELEM_TBL_WR_RDY)) {
++ dev_err(dev->hw->dev, "mtk_wed%d: write ba session base failed!\n",
++ dev->hw->index);
++ return -1;
++ }*/
++ }
++
++ /* pn check init */
++ for (i = 0; i < dev->wlan.ind_cmd.particular_sid; i++) {
++ wed_w32(dev, MTK_WED_PN_CHECK_WDATA_M,
++ MTK_WED_PN_CHECK_IS_FIRST);
++
++ wed_w32(dev, MTK_WED_PN_CHECK_CFG, MTK_WED_PN_CHECK_WR |
++ FIELD_PREP(MTK_WED_PN_CHECK_SE_ID, i));
++
++ cnt = 0;
++ val = wed_r32(dev, MTK_WED_PN_CHECK_CFG);
++ while (!(val & MTK_WED_PN_CHECK_WR_RDY) &&
++ cnt < 100) {
++ val = wed_r32(dev, MTK_WED_PN_CHECK_CFG);
++ cnt++;
++ }
++ if (cnt >= 100) {
++ dev_err(dev->hw->dev, "mtk_wed%d: session(%d) init failed!\n",
++ dev->hw->index, i);
++ }
++ /*if (mtk_wed_poll_busy(dev, MTK_WED_PN_CHECK_CFG,
++ MTK_WED_PN_CHECK_WR_RDY)) {
++ dev_err(dev->hw->dev, "mtk_wed%d: session(%d) init failed!\n",
++ dev->hw->index, i);
++ //return -1;
++ }*/
++ }
++
++ wed_w32(dev, MTK_WED_RX_IND_CMD_CNT0, MTK_WED_RX_IND_CMD_DBG_CNT_EN);
++
++ wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_IND_CMD_EN);
++
++ return 0;
++}
++
++
+ static u32
+ mtk_wed_irq_get(struct mtk_wed_device *dev, u32 mask)
+ {
+@@ -1660,6 +2348,8 @@ mtk_wed_irq_get(struct mtk_wed_device *dev, u32 mask)
+ val = wed_r32(dev, MTK_WED_EXT_INT_STATUS);
+ wed_w32(dev, MTK_WED_EXT_INT_STATUS, val);
+ val &= MTK_WED_EXT_INT_STATUS_ERROR_MASK;
++ if (dev->hw->version == 3)
++ val &= MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT;
+ WARN_RATELIMIT(val, "mtk_wed%d: error status=%08x\n",
+ dev->hw->index, val);
+
+@@ -1752,6 +2442,9 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
+ .tx_ring_setup = mtk_wed_tx_ring_setup,
+ .txfree_ring_setup = mtk_wed_txfree_ring_setup,
+ .rx_ring_setup = mtk_wed_rx_ring_setup,
++ .rro_rx_ring_setup = mtk_wed_rro_rx_ring_setup,
++ .msdu_pg_rx_ring_setup = mtk_wed_msdu_pg_rx_ring_setup,
++ .ind_rx_ring_setup = mtk_wed_ind_rx_ring_setup,
+ .msg_update = mtk_wed_send_msg,
+ .start = mtk_wed_start,
+ .stop = mtk_wed_stop,
+@@ -1763,6 +2456,7 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
+ .detach = mtk_wed_detach,
+ .setup_tc = mtk_wed_eth_setup_tc,
+ .ppe_check = mtk_wed_ppe_check,
++ .start_hwrro = mtk_wed_start_hwrro,
+ };
+ struct device_node *eth_np = eth->dev->of_node;
+ struct platform_device *pdev;
+@@ -1802,9 +2496,10 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
+ hw->wdma_phy = wdma_phy;
+ hw->index = index;
+ hw->irq = irq;
+- hw->ver = MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ? 2 : 1;
++ hw->version = MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3) ?
++ 3 : MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ? 2 : 1;
+
+- if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
++ if (hw->version == 1) {
+ hw->mirror = syscon_regmap_lookup_by_phandle(eth_np,
+ "mediatek,pcie-mirror");
+ hw->hifsys = syscon_regmap_lookup_by_phandle(eth_np,
+@@ -1819,7 +2514,6 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
+ regmap_write(hw->mirror, 0, 0);
+ regmap_write(hw->mirror, 4, 0);
+ }
+- hw->ver = MTK_WED_V1;
+ }
+
+ mtk_wed_hw_add_debugfs(hw);
+diff --git a/drivers/net/ethernet/mediatek/mtk_wed.h b/drivers/net/ethernet/mediatek/mtk_wed.h
+index 490873c..fcf7bd0 100644
+--- a/drivers/net/ethernet/mediatek/mtk_wed.h
++++ b/drivers/net/ethernet/mediatek/mtk_wed.h
+@@ -10,10 +10,13 @@
+ #include <linux/netdevice.h>
+ #define MTK_PCIE_BASE(n) (0x1a143000 + (n) * 0x2000)
+
+-#define MTK_WED_PKT_SIZE 1900
++#define MTK_WED_PKT_SIZE 1920//1900
+ #define MTK_WED_BUF_SIZE 2048
++#define MTK_WED_PAGE_BUF_SIZE 128
+ #define MTK_WED_BUF_PER_PAGE (PAGE_SIZE / 2048)
++#define MTK_WED_RX_PAGE_BUF_PER_PAGE (PAGE_SIZE / 128)
+ #define MTK_WED_RX_RING_SIZE 1536
++#define MTK_WED_RX_PG_BM_CNT 8192
+
+ #define MTK_WED_TX_RING_SIZE 2048
+ #define MTK_WED_WDMA_RING_SIZE 512
+@@ -27,6 +30,9 @@
+ #define MTK_WED_RRO_QUE_CNT 8192
+ #define MTK_WED_MIOD_ENTRY_CNT 128
+
++#define MTK_WED_TX_BM_DMA_SIZE 65536
++#define MTK_WED_TX_BM_PKT_CNT 32768
++
+ #define MODULE_ID_WO 1
+
+ struct mtk_eth;
+@@ -43,6 +49,8 @@ struct mtk_wed_hw {
+ struct dentry *debugfs_dir;
+ struct mtk_wed_device *wed_dev;
+ struct mtk_wed_wo *wed_wo;
++ struct mtk_wed_pao *wed_pao;
++ u32 pci_base;
+ u32 debugfs_reg;
+ u32 num_flows;
+ u32 wdma_phy;
+@@ -50,7 +58,8 @@ struct mtk_wed_hw {
+ int ring_num;
+ int irq;
+ int index;
+- u32 ver;
++ int token_id;
++ u32 version;
+ };
+
+ struct mtk_wdma_info {
+@@ -58,6 +67,18 @@ struct mtk_wdma_info {
+ u8 queue;
+ u16 wcid;
+ u8 bss;
++ u32 usr_info;
++ u8 tid;
++ u8 is_fixedrate;
++ u8 is_prior;
++ u8 is_sp;
++ u8 hf;
++ u8 amsdu_en;
++};
++
++struct mtk_wed_pao {
++ char *hif_txd[32];
++ dma_addr_t hif_txd_phys[32];
+ };
+
+ #ifdef CONFIG_NET_MEDIATEK_SOC_WED
+diff --git a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
+index 4a9e684..51e3d7c 100644
+--- a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
++++ b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
+@@ -11,9 +11,11 @@ struct reg_dump {
+ u16 offset;
+ u8 type;
+ u8 base;
++ u32 mask;
+ };
+
+ enum {
++ DUMP_TYPE_END,
+ DUMP_TYPE_STRING,
+ DUMP_TYPE_WED,
+ DUMP_TYPE_WDMA,
+@@ -23,8 +25,11 @@ enum {
+ DUMP_TYPE_WED_RRO,
+ };
+
++#define DUMP_END() { .type = DUMP_TYPE_END }
+ #define DUMP_STR(_str) { _str, 0, DUMP_TYPE_STRING }
+ #define DUMP_REG(_reg, ...) { #_reg, MTK_##_reg, __VA_ARGS__ }
++#define DUMP_REG_MASK(_reg, _mask) { #_mask, MTK_##_reg, DUMP_TYPE_WED, 0, MTK_##_mask }
++
+ #define DUMP_RING(_prefix, _base, ...) \
+ { _prefix " BASE", _base, __VA_ARGS__ }, \
+ { _prefix " CNT", _base + 0x4, __VA_ARGS__ }, \
+@@ -32,6 +37,7 @@ enum {
+ { _prefix " DIDX", _base + 0xc, __VA_ARGS__ }
+
+ #define DUMP_WED(_reg) DUMP_REG(_reg, DUMP_TYPE_WED)
++#define DUMP_WED_MASK(_reg, _mask) DUMP_REG_MASK(_reg, _mask)
+ #define DUMP_WED_RING(_base) DUMP_RING(#_base, MTK_##_base, DUMP_TYPE_WED)
+
+ #define DUMP_WDMA(_reg) DUMP_REG(_reg, DUMP_TYPE_WDMA)
+@@ -52,36 +58,49 @@ print_reg_val(struct seq_file *s, const char *name, u32 val)
+
+ static void
+ dump_wed_regs(struct seq_file *s, struct mtk_wed_device *dev,
+- const struct reg_dump *regs, int n_regs)
++ const struct reg_dump **regs)
+ {
+- const struct reg_dump *cur;
++ const struct reg_dump **cur_o = regs, *cur;
++ bool newline = false;
+ u32 val;
+
+- for (cur = regs; cur < ®s[n_regs]; cur++) {
+- switch (cur->type) {
+- case DUMP_TYPE_STRING:
+- seq_printf(s, "%s======== %s:\n",
+- cur > regs ? "\n" : "",
+- cur->name);
+- continue;
+- case DUMP_TYPE_WED:
+- case DUMP_TYPE_WED_RRO:
+- val = wed_r32(dev, cur->offset);
+- break;
+- case DUMP_TYPE_WDMA:
+- val = wdma_r32(dev, cur->offset);
+- break;
+- case DUMP_TYPE_WPDMA_TX:
+- val = wpdma_tx_r32(dev, cur->base, cur->offset);
+- break;
+- case DUMP_TYPE_WPDMA_TXFREE:
+- val = wpdma_txfree_r32(dev, cur->offset);
+- break;
+- case DUMP_TYPE_WPDMA_RX:
+- val = wpdma_rx_r32(dev, cur->base, cur->offset);
+- break;
++ while (*cur_o) {
++ cur = *cur_o;
++
++ while (cur->type != DUMP_TYPE_END) {
++ switch (cur->type) {
++ case DUMP_TYPE_STRING:
++ seq_printf(s, "%s======== %s:\n",
++ newline ? "\n" : "",
++ cur->name);
++ newline = true;
++ cur++;
++ continue;
++ case DUMP_TYPE_WED:
++ case DUMP_TYPE_WED_RRO:
++ val = wed_r32(dev, cur->offset);
++ break;
++ case DUMP_TYPE_WDMA:
++ val = wdma_r32(dev, cur->offset);
++ break;
++ case DUMP_TYPE_WPDMA_TX:
++ val = wpdma_tx_r32(dev, cur->base, cur->offset);
++ break;
++ case DUMP_TYPE_WPDMA_TXFREE:
++ val = wpdma_txfree_r32(dev, cur->offset);
++ break;
++ case DUMP_TYPE_WPDMA_RX:
++ val = wpdma_rx_r32(dev, cur->base, cur->offset);
++ break;
++ }
++
++ if (cur->mask)
++ val = (cur->mask & val) >> (ffs(cur->mask) - 1);
++
++ print_reg_val(s, cur->name, val);
++ cur++;
+ }
+- print_reg_val(s, cur->name, val);
++ cur_o++;
+ }
+ }
+
+@@ -89,7 +108,7 @@ dump_wed_regs(struct seq_file *s, struct mtk_wed_device *dev,
+ static int
+ wed_txinfo_show(struct seq_file *s, void *data)
+ {
+- static const struct reg_dump regs[] = {
++ static const struct reg_dump regs_common[] = {
+ DUMP_STR("WED TX"),
+ DUMP_WED(WED_TX_MIB(0)),
+ DUMP_WED_RING(WED_RING_TX(0)),
+@@ -128,16 +147,32 @@ wed_txinfo_show(struct seq_file *s, void *data)
+ DUMP_WDMA_RING(WDMA_RING_RX(0)),
+ DUMP_WDMA_RING(WDMA_RING_RX(1)),
+
+- DUMP_STR("TX FREE"),
++ DUMP_STR("WED TX FREE"),
+ DUMP_WED(WED_RX_MIB(0)),
++ DUMP_WED_RING(WED_RING_RX(0)),
++ DUMP_WED(WED_WPDMA_RX_COHERENT_MIB(0)),
++
++ DUMP_WED(WED_RX_MIB(1)),
++ DUMP_WED_RING(WED_RING_RX(1)),
++ DUMP_WED(WED_WPDMA_RX_COHERENT_MIB(1)),
++ DUMP_STR("WED_WPDMA TX FREE"),
++ DUMP_WED_RING(WED_WPDMA_RING_RX(0)),
++ DUMP_WED_RING(WED_WPDMA_RING_RX(1)),
++ DUMP_END(),
++ };
++
++ static const struct reg_dump *regs[] = {
++ ®s_common[0],
++ NULL,
+ };
++
+ struct mtk_wed_hw *hw = s->private;
+ struct mtk_wed_device *dev = hw->wed_dev;
+
+ if (!dev)
+ return 0;
+
+- dump_wed_regs(s, dev, regs, ARRAY_SIZE(regs));
++ dump_wed_regs(s, dev, regs);
+
+ return 0;
+ }
+@@ -146,7 +181,7 @@ DEFINE_SHOW_ATTRIBUTE(wed_txinfo);
+ static int
+ wed_rxinfo_show(struct seq_file *s, void *data)
+ {
+- static const struct reg_dump regs[] = {
++ static const struct reg_dump regs_common[] = {
+ DUMP_STR("WPDMA RX"),
+ DUMP_WPDMA_RX_RING(0),
+ DUMP_WPDMA_RX_RING(1),
+@@ -164,7 +199,7 @@ wed_rxinfo_show(struct seq_file *s, void *data)
+ DUMP_WED_RING(WED_RING_RX_DATA(0)),
+ DUMP_WED_RING(WED_RING_RX_DATA(1)),
+
+- DUMP_STR("WED RRO"),
++ DUMP_STR("WED WO RRO"),
+ DUMP_WED_RRO_RING(WED_RROQM_MIOD_CTRL0),
+ DUMP_WED(WED_RROQM_MID_MIB),
+ DUMP_WED(WED_RROQM_MOD_MIB),
+@@ -175,16 +210,6 @@ wed_rxinfo_show(struct seq_file *s, void *data)
+ DUMP_WED(WED_RROQM_FDBK_ANC_MIB),
+ DUMP_WED(WED_RROQM_FDBK_ANC2H_MIB),
+
+- DUMP_STR("WED Route QM"),
+- DUMP_WED(WED_RTQM_R2H_MIB(0)),
+- DUMP_WED(WED_RTQM_R2Q_MIB(0)),
+- DUMP_WED(WED_RTQM_Q2H_MIB(0)),
+- DUMP_WED(WED_RTQM_R2H_MIB(1)),
+- DUMP_WED(WED_RTQM_R2Q_MIB(1)),
+- DUMP_WED(WED_RTQM_Q2H_MIB(1)),
+- DUMP_WED(WED_RTQM_Q2N_MIB),
+- DUMP_WED(WED_RTQM_Q2B_MIB),
+- DUMP_WED(WED_RTQM_PFDBK_MIB),
+
+ DUMP_STR("WED WDMA TX"),
+ DUMP_WED(WED_WDMA_TX_MIB),
+@@ -205,15 +230,99 @@ wed_rxinfo_show(struct seq_file *s, void *data)
+ DUMP_WED(WED_RX_BM_INTF2),
+ DUMP_WED(WED_RX_BM_INTF),
+ DUMP_WED(WED_RX_BM_ERR_STS),
++ DUMP_END()
++ };
++
++ static const struct reg_dump regs_v2[] = {
++ DUMP_STR("WED Route QM"),
++ DUMP_WED(WED_RTQM_R2H_MIB(0)),
++ DUMP_WED(WED_RTQM_R2Q_MIB(0)),
++ DUMP_WED(WED_RTQM_Q2H_MIB(0)),
++ DUMP_WED(WED_RTQM_R2H_MIB(1)),
++ DUMP_WED(WED_RTQM_R2Q_MIB(1)),
++ DUMP_WED(WED_RTQM_Q2H_MIB(1)),
++ DUMP_WED(WED_RTQM_Q2N_MIB),
++ DUMP_WED(WED_RTQM_Q2B_MIB),
++ DUMP_WED(WED_RTQM_PFDBK_MIB),
++
++ DUMP_END()
++ };
++
++ static const struct reg_dump regs_v3[] = {
++ DUMP_STR("WED RX RRO DATA"),
++ DUMP_WED_RING(WED_RRO_RX_D_RX(0)),
++ DUMP_WED_RING(WED_RRO_RX_D_RX(1)),
++
++ DUMP_STR("WED RX MSDU PAGE"),
++ DUMP_WED_RING(WED_RRO_MSDU_PG_CTRL0(0)),
++ DUMP_WED_RING(WED_RRO_MSDU_PG_CTRL0(1)),
++ DUMP_WED_RING(WED_RRO_MSDU_PG_CTRL0(2)),
++
++ DUMP_STR("WED RX IND CMD"),
++ DUMP_WED(WED_IND_CMD_RX_CTRL1),
++ DUMP_WED_MASK(WED_IND_CMD_RX_CTRL2, WED_IND_CMD_MAX_CNT),
++ DUMP_WED_MASK(WED_IND_CMD_RX_CTRL0, WED_IND_CMD_PROC_IDX),
++ DUMP_WED_MASK(RRO_IND_CMD_SIGNATURE, RRO_IND_CMD_DMA_IDX),
++ DUMP_WED_MASK(WED_IND_CMD_RX_CTRL0, WED_IND_CMD_MAGIC_CNT),
++ DUMP_WED_MASK(RRO_IND_CMD_SIGNATURE, RRO_IND_CMD_MAGIC_CNT),
++ DUMP_WED_MASK(WED_IND_CMD_RX_CTRL0,
++ WED_IND_CMD_PREFETCH_FREE_CNT),
++ DUMP_WED_MASK(WED_RRO_CFG1, WED_RRO_CFG1_PARTICL_SE_ID),
++
++ DUMP_STR("WED ADDR ELEM"),
++ DUMP_WED(WED_ADDR_ELEM_CFG0),
++ DUMP_WED_MASK(WED_ADDR_ELEM_CFG1,
++ WED_ADDR_ELEM_PREFETCH_FREE_CNT),
++
++ DUMP_STR("WED Route QM"),
++ DUMP_WED(WED_RTQM_ENQ_I2Q_DMAD_CNT),
++ DUMP_WED(WED_RTQM_ENQ_I2N_DMAD_CNT),
++ DUMP_WED(WED_RTQM_ENQ_I2Q_PKT_CNT),
++ DUMP_WED(WED_RTQM_ENQ_I2N_PKT_CNT),
++ DUMP_WED(WED_RTQM_ENQ_USED_ENTRY_CNT),
++ DUMP_WED(WED_RTQM_ENQ_ERR_CNT),
++
++ DUMP_WED(WED_RTQM_DEQ_DMAD_CNT),
++ DUMP_WED(WED_RTQM_DEQ_Q2I_DMAD_CNT),
++ DUMP_WED(WED_RTQM_DEQ_PKT_CNT),
++ DUMP_WED(WED_RTQM_DEQ_Q2I_PKT_CNT),
++ DUMP_WED(WED_RTQM_DEQ_USED_PFDBK_CNT),
++ DUMP_WED(WED_RTQM_DEQ_ERR_CNT),
++
++ DUMP_END()
++ };
++
++ static const struct reg_dump *regs_new_v2[] = {
++ ®s_common[0],
++ ®s_v2[0],
++ NULL,
++ };
++
++ static const struct reg_dump *regs_new_v3[] = {
++ ®s_common[0],
++ ®s_v3[0],
++ NULL,
+ };
+
+ struct mtk_wed_hw *hw = s->private;
+ struct mtk_wed_device *dev = hw->wed_dev;
++ const struct reg_dump **regs;
+
+ if (!dev)
+ return 0;
+
+- dump_wed_regs(s, dev, regs, ARRAY_SIZE(regs));
++ switch(dev->hw->version) {
++ case 2:
++ regs = regs_new_v2;
++ break;
++ case 3:
++ regs = regs_new_v3;
++ break;
++ default:
++ return 0;
++ }
++
++ dump_wed_regs(s, dev, regs);
+
+ return 0;
+ }
+@@ -248,6 +357,383 @@ mtk_wed_reg_get(void *data, u64 *val)
+ DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mtk_wed_reg_get, mtk_wed_reg_set,
+ "0x%08llx\n");
+
++static int
++wed_token_txd_show(struct seq_file *s, void *data)
++{
++ struct mtk_wed_hw *hw = s->private;
++ struct mtk_wed_device *dev = hw->wed_dev;
++ struct dma_page_info *page_list = dev->tx_buf_ring.pages;
++ int token = dev->wlan.token_start;
++ u32 val = hw->token_id, size = 1;
++ int page_idx = (val - token) / 2;
++ int i;
++
++ if (val < token) {
++ size = val;
++ page_idx = 0;
++ }
++
++ for (i = 0; i < size; i += MTK_WED_BUF_PER_PAGE) {
++ void *page = page_list[page_idx++].addr;
++ void *buf;
++ int j;
++
++ if (!page)
++ break;
++
++ buf = page_to_virt(page);
++
++ for (j = 0; j < MTK_WED_BUF_PER_PAGE; j++) {
++ printk("[TXD]:token id = %d\n", token + 2 * (page_idx - 1) + j);
++ print_hex_dump(KERN_ERR , "", DUMP_PREFIX_OFFSET, 16, 1, (u8 *)buf, 128, false);
++ seq_printf(s, "\n");
++
++ buf += MTK_WED_BUF_SIZE;
++ }
++ }
++
++ return 0;
++}
++
++DEFINE_SHOW_ATTRIBUTE(wed_token_txd);
++
++static int
++wed_pao_show(struct seq_file *s, void *data)
++{
++ static const struct reg_dump regs_common[] = {
++ DUMP_STR("PAO AMDSU INFO"),
++ DUMP_WED(WED_PAO_MON_AMSDU_FIFO_DMAD),
++
++ DUMP_STR("PAO AMDSU ENG0 INFO"),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_DMAD(0)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QFPL(0)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENI(0)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENO(0)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_MERG(0)),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(0),
++ WED_PAO_AMSDU_ENG_MAX_PL_CNT),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(0),
++ WED_PAO_AMSDU_ENG_MAX_QGPP_CNT),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(0),
++ WED_PAO_AMSDU_ENG_CUR_ENTRY),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(0),
++ WED_PAO_AMSDU_ENG_MAX_BUF_MERGED),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(0),
++ WED_PAO_AMSDU_ENG_MAX_MSDU_MERGED),
++
++ DUMP_STR("PAO AMDSU ENG1 INFO"),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_DMAD(1)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QFPL(1)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENI(1)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENO(1)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_MERG(1)),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(1),
++ WED_PAO_AMSDU_ENG_MAX_PL_CNT),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(1),
++ WED_PAO_AMSDU_ENG_MAX_QGPP_CNT),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(1),
++ WED_PAO_AMSDU_ENG_CUR_ENTRY),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(2),
++ WED_PAO_AMSDU_ENG_MAX_BUF_MERGED),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(2),
++ WED_PAO_AMSDU_ENG_MAX_MSDU_MERGED),
++
++ DUMP_STR("PAO AMDSU ENG2 INFO"),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_DMAD(2)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QFPL(2)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENI(2)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENO(2)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_MERG(2)),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(2),
++ WED_PAO_AMSDU_ENG_MAX_PL_CNT),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(2),
++ WED_PAO_AMSDU_ENG_MAX_QGPP_CNT),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(2),
++ WED_PAO_AMSDU_ENG_CUR_ENTRY),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(2),
++ WED_PAO_AMSDU_ENG_MAX_BUF_MERGED),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(2),
++ WED_PAO_AMSDU_ENG_MAX_MSDU_MERGED),
++
++ DUMP_STR("PAO AMDSU ENG3 INFO"),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_DMAD(3)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QFPL(3)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENI(3)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENO(3)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_MERG(3)),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(3),
++ WED_PAO_AMSDU_ENG_MAX_PL_CNT),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(3),
++ WED_PAO_AMSDU_ENG_MAX_QGPP_CNT),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(3),
++ WED_PAO_AMSDU_ENG_CUR_ENTRY),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(3),
++ WED_PAO_AMSDU_ENG_MAX_BUF_MERGED),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(3),
++ WED_PAO_AMSDU_ENG_MAX_MSDU_MERGED),
++
++ DUMP_STR("PAO AMDSU ENG4 INFO"),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_DMAD(4)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QFPL(4)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENI(4)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENO(4)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_MERG(4)),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(4),
++ WED_PAO_AMSDU_ENG_MAX_PL_CNT),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(4),
++ WED_PAO_AMSDU_ENG_MAX_QGPP_CNT),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(4),
++ WED_PAO_AMSDU_ENG_CUR_ENTRY),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(4),
++ WED_PAO_AMSDU_ENG_MAX_BUF_MERGED),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(4),
++ WED_PAO_AMSDU_ENG_MAX_MSDU_MERGED),
++
++ DUMP_STR("PAO AMDSU ENG5 INFO"),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_DMAD(5)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QFPL(5)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENI(5)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENO(5)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_MERG(5)),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(5),
++ WED_PAO_AMSDU_ENG_MAX_PL_CNT),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(5),
++ WED_PAO_AMSDU_ENG_MAX_QGPP_CNT),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(5),
++ WED_PAO_AMSDU_ENG_CUR_ENTRY),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(5),
++ WED_PAO_AMSDU_ENG_MAX_BUF_MERGED),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(5),
++ WED_PAO_AMSDU_ENG_MAX_MSDU_MERGED),
++
++ DUMP_STR("PAO AMDSU ENG6 INFO"),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_DMAD(6)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QFPL(6)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENI(6)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENO(6)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_MERG(6)),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(6),
++ WED_PAO_AMSDU_ENG_MAX_PL_CNT),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(6),
++ WED_PAO_AMSDU_ENG_MAX_QGPP_CNT),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(6),
++ WED_PAO_AMSDU_ENG_CUR_ENTRY),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(6),
++ WED_PAO_AMSDU_ENG_MAX_BUF_MERGED),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(6),
++ WED_PAO_AMSDU_ENG_MAX_MSDU_MERGED),
++
++ DUMP_STR("PAO AMDSU ENG7 INFO"),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_DMAD(7)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QFPL(7)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENI(7)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENO(7)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_MERG(7)),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(7),
++ WED_PAO_AMSDU_ENG_MAX_PL_CNT),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(7),
++ WED_PAO_AMSDU_ENG_MAX_QGPP_CNT),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(7),
++ WED_PAO_AMSDU_ENG_CUR_ENTRY),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(7),
++ WED_PAO_AMSDU_ENG_MAX_BUF_MERGED),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(4),
++ WED_PAO_AMSDU_ENG_MAX_MSDU_MERGED),
++
++ DUMP_STR("PAO AMDSU ENG8 INFO"),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_DMAD(8)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QFPL(8)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENI(8)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_QENO(8)),
++ DUMP_WED(WED_PAO_MON_AMSDU_ENG_MERG(8)),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(8),
++ WED_PAO_AMSDU_ENG_MAX_PL_CNT),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT8(8),
++ WED_PAO_AMSDU_ENG_MAX_QGPP_CNT),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(8),
++ WED_PAO_AMSDU_ENG_CUR_ENTRY),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(8),
++ WED_PAO_AMSDU_ENG_MAX_BUF_MERGED),
++ DUMP_WED_MASK(WED_PAO_MON_AMSDU_ENG_CNT9(8),
++ WED_PAO_AMSDU_ENG_MAX_MSDU_MERGED),
++
++ DUMP_STR("PAO QMEM INFO"),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_CNT(0), WED_PAO_QMEM_FQ_CNT),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_CNT(0), WED_PAO_QMEM_SP_QCNT),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_CNT(1), WED_PAO_QMEM_TID0_QCNT),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_CNT(1), WED_PAO_QMEM_TID1_QCNT),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_CNT(2), WED_PAO_QMEM_TID2_QCNT),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_CNT(2), WED_PAO_QMEM_TID3_QCNT),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_CNT(3), WED_PAO_QMEM_TID4_QCNT),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_CNT(3), WED_PAO_QMEM_TID5_QCNT),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_CNT(4), WED_PAO_QMEM_TID6_QCNT),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_CNT(4), WED_PAO_QMEM_TID7_QCNT),
++
++
++ DUMP_STR("PAO QMEM HEAD INFO"),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(0), WED_PAO_QMEM_FQ_HEAD),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(0), WED_PAO_QMEM_SP_QHEAD),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(1), WED_PAO_QMEM_TID0_QHEAD),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(1), WED_PAO_QMEM_TID1_QHEAD),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(2), WED_PAO_QMEM_TID2_QHEAD),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(2), WED_PAO_QMEM_TID3_QHEAD),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(3), WED_PAO_QMEM_TID4_QHEAD),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(3), WED_PAO_QMEM_TID5_QHEAD),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(4), WED_PAO_QMEM_TID6_QHEAD),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(4), WED_PAO_QMEM_TID7_QHEAD),
++
++ DUMP_STR("PAO QMEM TAIL INFO"),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(5), WED_PAO_QMEM_FQ_TAIL),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(5), WED_PAO_QMEM_SP_QTAIL),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(6), WED_PAO_QMEM_TID0_QTAIL),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(6), WED_PAO_QMEM_TID1_QTAIL),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(7), WED_PAO_QMEM_TID2_QTAIL),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(7), WED_PAO_QMEM_TID3_QTAIL),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(8), WED_PAO_QMEM_TID4_QTAIL),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(8), WED_PAO_QMEM_TID5_QTAIL),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(9), WED_PAO_QMEM_TID6_QTAIL),
++ DUMP_WED_MASK(WED_PAO_MON_QMEM_PTR(9), WED_PAO_QMEM_TID7_QTAIL),
++
++ DUMP_STR("PAO HIFTXD MSDU INFO"),
++ DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(1)),
++ DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(2)),
++ DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(3)),
++ DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(4)),
++ DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(5)),
++ DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(6)),
++ DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(7)),
++ DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(8)),
++ DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(9)),
++ DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(10)),
++ DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(11)),
++ DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(12)),
++ DUMP_WED(WED_PAO_MON_HIFTXD_FETCH_MSDU(13)),
++ DUMP_END()
++ };
++
++ static const struct reg_dump *regs[] = {
++ ®s_common[0],
++ NULL,
++ };
++ struct mtk_wed_hw *hw = s->private;
++ struct mtk_wed_device *dev = hw->wed_dev;
++
++ if (!dev)
++ return 0;
++
++ dump_wed_regs(s, dev, regs);
++
++ return 0;
++}
++DEFINE_SHOW_ATTRIBUTE(wed_pao);
++
++static int
++wed_rtqm_show(struct seq_file *s, void *data)
++{
++ static const struct reg_dump regs_common[] = {
++ DUMP_STR("WED Route QM IGRS0(N2H + Recycle)"),
++ DUMP_WED(WED_RTQM_IGRS0_I2HW_DMAD_CNT),
++ DUMP_WED(WED_RTQM_IGRS0_I2H_DMAD_CNT(0)),
++ DUMP_WED(WED_RTQM_IGRS0_I2H_DMAD_CNT(1)),
++ DUMP_WED(WED_RTQM_IGRS0_I2HW_PKT_CNT),
++ DUMP_WED(WED_RTQM_IGRS0_I2H_PKT_CNT(0)),
++ DUMP_WED(WED_RTQM_IGRS0_I2H_PKT_CNT(0)),
++ DUMP_WED(WED_RTQM_IGRS0_FDROP_CNT),
++
++
++ DUMP_STR("WED Route QM IGRS1(Legacy)"),
++ DUMP_WED(WED_RTQM_IGRS1_I2HW_DMAD_CNT),
++ DUMP_WED(WED_RTQM_IGRS1_I2H_DMAD_CNT(0)),
++ DUMP_WED(WED_RTQM_IGRS1_I2H_DMAD_CNT(1)),
++ DUMP_WED(WED_RTQM_IGRS1_I2HW_PKT_CNT),
++ DUMP_WED(WED_RTQM_IGRS1_I2H_PKT_CNT(0)),
++ DUMP_WED(WED_RTQM_IGRS1_I2H_PKT_CNT(1)),
++ DUMP_WED(WED_RTQM_IGRS1_FDROP_CNT),
++
++ DUMP_STR("WED Route QM IGRS2(RRO3.0)"),
++ DUMP_WED(WED_RTQM_IGRS2_I2HW_DMAD_CNT),
++ DUMP_WED(WED_RTQM_IGRS2_I2H_DMAD_CNT(0)),
++ DUMP_WED(WED_RTQM_IGRS2_I2H_DMAD_CNT(1)),
++ DUMP_WED(WED_RTQM_IGRS2_I2HW_PKT_CNT),
++ DUMP_WED(WED_RTQM_IGRS2_I2H_PKT_CNT(0)),
++ DUMP_WED(WED_RTQM_IGRS2_I2H_PKT_CNT(1)),
++ DUMP_WED(WED_RTQM_IGRS2_FDROP_CNT),
++
++ DUMP_STR("WED Route QM IGRS3(DEBUG)"),
++ DUMP_WED(WED_RTQM_IGRS2_I2HW_DMAD_CNT),
++ DUMP_WED(WED_RTQM_IGRS3_I2H_DMAD_CNT(0)),
++ DUMP_WED(WED_RTQM_IGRS3_I2H_DMAD_CNT(1)),
++ DUMP_WED(WED_RTQM_IGRS3_I2HW_PKT_CNT),
++ DUMP_WED(WED_RTQM_IGRS3_I2H_PKT_CNT(0)),
++ DUMP_WED(WED_RTQM_IGRS3_I2H_PKT_CNT(1)),
++ DUMP_WED(WED_RTQM_IGRS3_FDROP_CNT),
++
++ DUMP_END()
++ };
++
++ static const struct reg_dump *regs[] = {
++ ®s_common[0],
++ NULL,
++ };
++ struct mtk_wed_hw *hw = s->private;
++ struct mtk_wed_device *dev = hw->wed_dev;
++
++ if (!dev)
++ return 0;
++
++ dump_wed_regs(s, dev, regs);
++
++ return 0;
++}
++DEFINE_SHOW_ATTRIBUTE(wed_rtqm);
++
++
++static int
++wed_rro_show(struct seq_file *s, void *data)
++{
++ static const struct reg_dump regs_common[] = {
++ DUMP_STR("RRO/IND CMD CNT"),
++ DUMP_WED(WED_RX_IND_CMD_CNT(1)),
++ DUMP_WED(WED_RX_IND_CMD_CNT(2)),
++ DUMP_WED(WED_RX_IND_CMD_CNT(3)),
++ DUMP_WED(WED_RX_IND_CMD_CNT(4)),
++ DUMP_WED(WED_RX_IND_CMD_CNT(5)),
++ DUMP_WED(WED_RX_IND_CMD_CNT(6)),
++ DUMP_WED(WED_RX_IND_CMD_CNT(7)),
++ DUMP_WED(WED_RX_IND_CMD_CNT(8)),
++ DUMP_WED_MASK(WED_RX_IND_CMD_CNT(9),
++ WED_IND_CMD_MAGIC_CNT_FAIL_CNT),
++
++ DUMP_WED(WED_RX_ADDR_ELEM_CNT(0)),
++ DUMP_WED_MASK(WED_RX_ADDR_ELEM_CNT(1),
++ WED_ADDR_ELEM_SIG_FAIL_CNT),
++ DUMP_WED(WED_RX_MSDU_PG_CNT(1)),
++ DUMP_WED(WED_RX_MSDU_PG_CNT(2)),
++ DUMP_WED(WED_RX_MSDU_PG_CNT(3)),
++ DUMP_WED(WED_RX_MSDU_PG_CNT(4)),
++ DUMP_WED(WED_RX_MSDU_PG_CNT(5)),
++ DUMP_WED_MASK(WED_RX_PN_CHK_CNT,
++ WED_PN_CHK_FAIL_CNT),
++
++ DUMP_END()
++ };
++
++ static const struct reg_dump *regs[] = {
++ ®s_common[0],
++ NULL,
++ };
++ struct mtk_wed_hw *hw = s->private;
++ struct mtk_wed_device *dev = hw->wed_dev;
++
++ if (!dev)
++ return 0;
++
++ dump_wed_regs(s, dev, regs);
++
++ return 0;
++}
++DEFINE_SHOW_ATTRIBUTE(wed_rro);
++
+ void mtk_wed_hw_add_debugfs(struct mtk_wed_hw *hw)
+ {
+ struct dentry *dir;
+@@ -261,8 +747,18 @@ void mtk_wed_hw_add_debugfs(struct mtk_wed_hw *hw)
+ debugfs_create_u32("regidx", 0600, dir, &hw->debugfs_reg);
+ debugfs_create_file_unsafe("regval", 0600, dir, hw, &fops_regval);
+ debugfs_create_file_unsafe("txinfo", 0400, dir, hw, &wed_txinfo_fops);
+- debugfs_create_file_unsafe("rxinfo", 0400, dir, hw, &wed_rxinfo_fops);
+- if (hw->ver != MTK_WED_V1) {
++ debugfs_create_u32("token_id", 0600, dir, &hw->token_id);
++ debugfs_create_file_unsafe("token_txd", 0600, dir, hw, &wed_token_txd_fops);
++
++ if (hw->version == 3)
++ debugfs_create_file_unsafe("pao", 0400, dir, hw, &wed_pao_fops);
++
++ if (hw->version != 1) {
++ debugfs_create_file_unsafe("rxinfo", 0400, dir, hw, &wed_rxinfo_fops);
++ if (hw->version == 3) {
++ debugfs_create_file_unsafe("rtqm", 0400, dir, hw, &wed_rtqm_fops);
++ debugfs_create_file_unsafe("rro", 0400, dir, hw, &wed_rro_fops);
++ }
+ wed_wo_mcu_debugfs(hw, dir);
+ }
+ }
+diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
+index 96e30a3..055594d 100644
+--- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
++++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
+@@ -242,7 +242,7 @@ mtk_wed_load_firmware(struct mtk_wed_wo *wo)
+ u32 ofs = 0;
+ u32 boot_cr, val;
+
+- mcu = wo->hw->index ? MT7986_FIRMWARE_WO_2 : MT7986_FIRMWARE_WO_1;
++ mcu = wo->hw->index ? MTK_FIRMWARE_WO_1 : MTK_FIRMWARE_WO_0;
+
+ ret = request_firmware(&fw, mcu, wo->hw->dev);
+ if (ret)
+@@ -289,8 +289,12 @@ mtk_wed_load_firmware(struct mtk_wed_wo *wo)
+ }
+
+ /* write the start address */
+- boot_cr = wo->hw->index ?
+- WOX_MCU_CFG_LS_WA_BOOT_ADDR_ADDR : WOX_MCU_CFG_LS_WM_BOOT_ADDR_ADDR;
++ if (wo->hw->version == 3)
++ boot_cr = WOX_MCU_CFG_LS_WM_BOOT_ADDR_ADDR;
++ else
++ boot_cr = wo->hw->index ?
++ WOX_MCU_CFG_LS_WA_BOOT_ADDR_ADDR : WOX_MCU_CFG_LS_WM_BOOT_ADDR_ADDR;
++
+ wo_w32(wo, boot_cr, (wo->region[WO_REGION_EMI].addr_pa >> 16));
+
+ /* wo firmware reset */
+@@ -298,8 +302,7 @@ mtk_wed_load_firmware(struct mtk_wed_wo *wo)
+
+ val = wo_r32(wo, WOX_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR);
+
+- val |= wo->hw->index ? WOX_MCU_CFG_LS_WF_MCU_CFG_WM_WA_WA_CPU_RSTB_MASK :
+- WOX_MCU_CFG_LS_WF_MCU_CFG_WM_WA_WM_CPU_RSTB_MASK;
++ val |= WOX_MCU_CFG_LS_WF_MCU_CFG_WM_WA_WM_CPU_RSTB_MASK;
+
+ wo_w32(wo, WOX_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR, val);
+
+diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.h b/drivers/net/ethernet/mediatek/mtk_wed_mcu.h
+index 19e1199..c07bdb6 100644
+--- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.h
++++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.h
+@@ -16,8 +16,9 @@
+ #define WARP_OK_STATUS (0)
+ #define WARP_ALREADY_DONE_STATUS (1)
+
+-#define MT7986_FIRMWARE_WO_1 "mediatek/mt7986_wo_0.bin"
+-#define MT7986_FIRMWARE_WO_2 "mediatek/mt7986_wo_1.bin"
++#define MTK_FIRMWARE_WO_0 "mediatek/mtk_wo_0.bin"
++#define MTK_FIRMWARE_WO_1 "mediatek/mtk_wo_1.bin"
++#define MTK_FIRMWARE_WO_2 "mediatek/mtk_wo_2.bin"
+
+ #define WOCPU_EMI_DEV_NODE "mediatek,wocpu_emi"
+ #define WOCPU_ILM_DEV_NODE "mediatek,wocpu_ilm"
+diff --git a/drivers/net/ethernet/mediatek/mtk_wed_regs.h b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
+index 403a36b..4e619ff 100644
+--- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h
++++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
+@@ -20,6 +20,9 @@
+ #define MTK_WDMA_DESC_CTRL_DMA_DONE BIT(31)
+ #define MTK_WED_RX_BM_TOKEN GENMASK(31, 16)
+
++#define MTK_WDMA_TXD0_DESC_INFO_DMA_DONE BIT(29)
++#define MTK_WDMA_TXD1_DESC_INFO_DMA_DONE BIT(31)
++
+ struct mtk_wdma_desc {
+ __le32 buf0;
+ __le32 ctrl;
+@@ -51,6 +54,7 @@ struct mtk_wdma_desc {
+ #define MTK_WED_RESET_WDMA_INT_AGENT BIT(19)
+ #define MTK_WED_RESET_RX_RRO_QM BIT(20)
+ #define MTK_WED_RESET_RX_ROUTE_QM BIT(21)
++#define MTK_WED_RESET_TX_PAO BIT(22)
+ #define MTK_WED_RESET_WED BIT(31)
+
+ #define MTK_WED_CTRL 0x00c
+@@ -58,6 +62,9 @@ struct mtk_wdma_desc {
+ #define MTK_WED_CTRL_WPDMA_INT_AGENT_BUSY BIT(1)
+ #define MTK_WED_CTRL_WDMA_INT_AGENT_EN BIT(2)
+ #define MTK_WED_CTRL_WDMA_INT_AGENT_BUSY BIT(3)
++#define MTK_WED_CTRL_WED_RX_IND_CMD_EN BIT(5)
++#define MTK_WED_CTRL_WED_RX_PG_BM_EN BIT(6)
++#define MTK_WED_CTRL_WED_RX_PG_BM_BUSU BIT(7)
+ #define MTK_WED_CTRL_WED_TX_BM_EN BIT(8)
+ #define MTK_WED_CTRL_WED_TX_BM_BUSY BIT(9)
+ #define MTK_WED_CTRL_WED_TX_FREE_AGENT_EN BIT(10)
+@@ -68,9 +75,14 @@ struct mtk_wdma_desc {
+ #define MTK_WED_CTRL_RX_RRO_QM_BUSY BIT(15)
+ #define MTK_WED_CTRL_RX_ROUTE_QM_EN BIT(16)
+ #define MTK_WED_CTRL_RX_ROUTE_QM_BUSY BIT(17)
++#define MTK_WED_CTRL_TX_TKID_ALI_EN BIT(20)
++#define MTK_WED_CTRL_TX_TKID_ALI_BUSY BIT(21)
++#define MTK_WED_CTRL_TX_PAO_EN BIT(22)
++#define MTK_WED_CTRL_TX_PAO_BUSY BIT(23)
+ #define MTK_WED_CTRL_FINAL_DIDX_READ BIT(24)
+ #define MTK_WED_CTRL_ETH_DMAD_FMT BIT(25)
+ #define MTK_WED_CTRL_MIB_READ_CLEAR BIT(28)
++#define MTK_WED_CTRL_FLD_MIB_RD_CLR BIT(28)
+
+ #define MTK_WED_EXT_INT_STATUS 0x020
+ #define MTK_WED_EXT_INT_STATUS_TF_LEN_ERR BIT(0)
+@@ -78,12 +90,10 @@ struct mtk_wdma_desc {
+ #define MTK_WED_EXT_INT_STATUS_TKID_TITO_INVALID BIT(4)
+ #define MTK_WED_EXT_INT_STATUS_TX_FBUF_LO_TH BIT(8)
+ #define MTK_WED_EXT_INT_STATUS_TX_FBUF_HI_TH BIT(9)
+-#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+-#define MTK_WED_EXT_INT_STATUS_TX_TKID_LO_TH BIT(10)
+-#define MTK_WED_EXT_INT_STATUS_TX_TKID_HI_TH BIT(11)
+-#endif
+-#define MTK_WED_EXT_INT_STATUS_RX_FREE_AT_EMPTY BIT(12)
+-#define MTK_WED_EXT_INT_STATUS_RX_FBUF_DMAD_ER BIT(13)
++#define MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH2 BIT(10)
++#define MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH2 BIT(11)
++#define MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH BIT(12)
++#define MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH BIT(13)
+ #define MTK_WED_EXT_INT_STATUS_RX_DRV_R_RESP_ERR BIT(16)
+ #define MTK_WED_EXT_INT_STATUS_RX_DRV_W_RESP_ERR BIT(17)
+ #define MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT BIT(18)
+@@ -100,17 +110,15 @@ struct mtk_wdma_desc {
+ #define MTK_WED_EXT_INT_STATUS_ERROR_MASK (MTK_WED_EXT_INT_STATUS_TF_LEN_ERR | \
+ MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD | \
+ MTK_WED_EXT_INT_STATUS_TKID_TITO_INVALID | \
+- MTK_WED_EXT_INT_STATUS_RX_FREE_AT_EMPTY | \
+- MTK_WED_EXT_INT_STATUS_RX_FBUF_DMAD_ER | \
+ MTK_WED_EXT_INT_STATUS_RX_DRV_R_RESP_ERR | \
+ MTK_WED_EXT_INT_STATUS_RX_DRV_W_RESP_ERR | \
+ MTK_WED_EXT_INT_STATUS_RX_DRV_INIT_WDMA_EN | \
+- MTK_WED_EXT_INT_STATUS_TX_DMA_R_RESP_ERR | \
+- MTK_WED_EXT_INT_STATUS_TX_DMA_W_RESP_ERR)
++ MTK_WED_EXT_INT_STATUS_TX_DMA_R_RESP_ERR)
+
+ #define MTK_WED_EXT_INT_MASK 0x028
+ #define MTK_WED_EXT_INT_MASK1 0x02c
+ #define MTK_WED_EXT_INT_MASK2 0x030
++#define MTK_WED_EXT_INT_MASK3 0x034
+
+ #define MTK_WED_STATUS 0x060
+ #define MTK_WED_STATUS_TX GENMASK(15, 8)
+@@ -118,9 +126,14 @@ struct mtk_wdma_desc {
+ #define MTK_WED_TX_BM_CTRL 0x080
+ #define MTK_WED_TX_BM_CTRL_VLD_GRP_NUM GENMASK(6, 0)
+ #define MTK_WED_TX_BM_CTRL_RSV_GRP_NUM GENMASK(22, 16)
++#define MTK_WED_TX_BM_CTRL_LEGACY_EN BIT(26)
++#define MTK_WED_TX_TKID_CTRL_FREE_FORMAT BIT(27)
+ #define MTK_WED_TX_BM_CTRL_PAUSE BIT(28)
+
+ #define MTK_WED_TX_BM_BASE 0x084
++#define MTK_WED_TX_BM_INIT_PTR 0x088
++#define MTK_WED_TX_BM_SW_TAIL_IDX GENMASK(16, 0)
++#define MTK_WED_TX_BM_INIT_SW_TAIL_IDX BIT(16)
+
+ #define MTK_WED_TX_BM_BUF_LEN 0x08c
+
+@@ -134,22 +147,24 @@ struct mtk_wdma_desc {
+ #if defined(CONFIG_MEDIATEK_NETSYS_V2)
+ #define MTK_WED_TX_BM_DYN_THR_LO GENMASK(8, 0)
+ #define MTK_WED_TX_BM_DYN_THR_HI GENMASK(24, 16)
+-
+-#define MTK_WED_TX_BM_TKID 0x0c8
+-#define MTK_WED_TX_BM_TKID_START GENMASK(15, 0)
+-#define MTK_WED_TX_BM_TKID_END GENMASK(31, 16)
+ #else
+ #define MTK_WED_TX_BM_DYN_THR_LO GENMASK(6, 0)
+ #define MTK_WED_TX_BM_DYN_THR_HI GENMASK(22, 16)
++#endif
+
+-#define MTK_WED_TX_BM_TKID 0x088
++#define MTK_WED_TX_BM_TKID 0x0c8
+ #define MTK_WED_TX_BM_TKID_START GENMASK(15, 0)
+ #define MTK_WED_TX_BM_TKID_END GENMASK(31, 16)
+-#endif
+
+ #define MTK_WED_TX_TKID_CTRL 0x0c0
++#if defined(CONFIG_MEDIATEK_NETSYS_V3)
++#define MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM GENMASK(7, 0)
++#define MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM GENMASK(23, 16)
++#else
+ #define MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM GENMASK(6, 0)
+ #define MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM GENMASK(22, 16)
++#endif
++
+ #define MTK_WED_TX_TKID_CTRL_PAUSE BIT(28)
+
+ #define MTK_WED_TX_TKID_DYN_THR 0x0e0
+@@ -220,12 +235,15 @@ struct mtk_wdma_desc {
+ #define MTK_WED_WPDMA_GLO_CFG_RX_DRV_R1_PKT_PROC BIT(5)
+ #define MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC BIT(6)
+ #define MTK_WED_WPDMA_GLO_CFG_RX_DRV_R1_CRX_SYNC BIT(7)
+-#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_EVENT_PKT_FMT_VER GENMASK(18, 16)
++#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_EVENT_PKT_FMT_VER GENMASK(15, 12)
++#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_UNS_VER_FORCE_4 BIT(18)
+ #define MTK_WED_WPDMA_GLO_CFG_RX_DRV_UNSUPPORT_FMT BIT(19)
+-#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_UEVENT_PKT_FMT_CHK BIT(20)
++#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_EVENT_PKT_FMT_CHK BIT(20)
+ #define MTK_WED_WPDMA_GLO_CFG_RX_DDONE2_WR BIT(21)
+ #define MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP BIT(24)
++#define MTK_WED_WPDMA_GLO_CFG_TX_DDONE_CHK_LAST BIT(25)
+ #define MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV BIT(28)
++#define MTK_WED_WPDMA_GLO_CFG_TX_DDONE_CHK BIT(30)
+
+ /* CONFIG_MEDIATEK_NETSYS_V1 */
+ #define MTK_WED_WPDMA_GLO_CFG_RX_BT_SIZE GENMASK(5, 4)
+@@ -288,9 +306,11 @@ struct mtk_wdma_desc {
+ #define MTK_WED_PCIE_INT_TRIGGER_STATUS BIT(16)
+
+ #define MTK_WED_PCIE_INT_CTRL 0x57c
+-#define MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA BIT(20)
+-#define MTK_WED_PCIE_INT_CTRL_SRC_SEL GENMASK(17, 16)
+ #define MTK_WED_PCIE_INT_CTRL_POLL_EN GENMASK(13, 12)
++#define MTK_WED_PCIE_INT_CTRL_SRC_SEL GENMASK(17, 16)
++#define MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA BIT(20)
++#define MTK_WED_PCIE_INT_CTRL_MSK_IRQ_FILTER BIT(21)
++
+ #define MTK_WED_WPDMA_CFG_BASE 0x580
+ #define MTK_WED_WPDMA_CFG_INT_MASK 0x584
+ #define MTK_WED_WPDMA_CFG_TX 0x588
+@@ -319,20 +339,50 @@ struct mtk_wdma_desc {
+ #define MTK_WED_WPDMA_RX_D_RST_DRV_IDX GENMASK(25, 24)
+
+ #define MTK_WED_WPDMA_RX_GLO_CFG 0x76c
+-#define MTK_WED_WPDMA_RX_RING 0x770
++#if defined(CONFIG_MEDIATEK_NETSYS_V2)
++#define MTK_WED_WPDMA_RX_RING0 0x770
++#else
++#define MTK_WED_WPDMA_RX_RING0 0x7d0
++#endif
++#define MTK_WED_WPDMA_RX_RING1 0x7d8
+
+ #define MTK_WED_WPDMA_RX_D_MIB(_n) (0x774 + (_n) * 4)
+ #define MTK_WED_WPDMA_RX_D_PROCESSED_MIB(_n) (0x784 + (_n) * 4)
+ #define MTK_WED_WPDMA_RX_D_COHERENT_MIB 0x78c
+
++#define MTK_WED_WPDMA_RX_D_PREF_CFG 0x7b4
++#define MTK_WED_WPDMA_RX_D_PREF_EN BIT(0)
++#define MTK_WED_WPDMA_RX_D_PREF_BURST_SIZE GENMASK(12, 8)
++#define MTK_WED_WPDMA_RX_D_PREF_LOW_THRES GENMASK(21, 16)
++
++#define MTK_WED_WPDMA_RX_D_PREF_RX0_SIDX 0x7b8
++#define MTK_WED_WPDMA_RX_D_PREF_SIDX_IDX_CLR BIT(15)
++
++#define MTK_WED_WPDMA_RX_D_PREF_RX1_SIDX 0x7bc
++
++#define MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG 0x7c0
++#define MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG_R0_CLR BIT(0)
++#define MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG_R1_CLR BIT(16)
++
+ #define MTK_WED_WDMA_RING_TX 0x800
+
+ #define MTK_WED_WDMA_TX_MIB 0x810
+
+-
+ #define MTK_WED_WDMA_RING_RX(_n) (0x900 + (_n) * 0x10)
+ #define MTK_WED_WDMA_RX_THRES(_n) (0x940 + (_n) * 0x4)
+
++#define MTK_WED_WDMA_RX_PREF_CFG 0x950
++#define MTK_WED_WDMA_RX_PREF_EN BIT(0)
++#define MTK_WED_WDMA_RX_PREF_BURST_SIZE GENMASK(12, 8)
++#define MTK_WED_WDMA_RX_PREF_LOW_THRES GENMASK(21, 16)
++#define MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR BIT(24)
++#define MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR BIT(25)
++#define MTK_WED_WDMA_RX_PREF_DDONE2_EN BIT(26)
++
++#define MTK_WED_WDMA_RX_PREF_FIFO_CFG 0x95C
++#define MTK_WED_WDMA_RX_PREF_FIFO_RX0_CLR BIT(0)
++#define MTK_WED_WDMA_RX_PREF_FIFO_RX1_CLR BIT(16)
++
+ #define MTK_WED_WDMA_GLO_CFG 0xa04
+ #define MTK_WED_WDMA_GLO_CFG_TX_DRV_EN BIT(0)
+ #define MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK BIT(1)
+@@ -365,6 +415,7 @@ struct mtk_wdma_desc {
+ #define MTK_WED_WDMA_INT_TRIGGER_RX_DONE GENMASK(17, 16)
+
+ #define MTK_WED_WDMA_INT_CTRL 0xa2c
++#define MTK_WED_WDMA_INT_POLL_PRD GENMASK(7, 0)
+ #define MTK_WED_WDMA_INT_POLL_SRC_SEL GENMASK(17, 16)
+
+ #define MTK_WED_WDMA_CFG_BASE 0xaa0
+@@ -426,6 +477,18 @@ struct mtk_wdma_desc {
+ #define MTK_WDMA_INT_GRP1 0x250
+ #define MTK_WDMA_INT_GRP2 0x254
+
++#define MTK_WDMA_PREF_TX_CFG 0x2d0
++#define MTK_WDMA_PREF_TX_CFG_PREF_EN BIT(0)
++
++#define MTK_WDMA_PREF_RX_CFG 0x2dc
++#define MTK_WDMA_PREF_RX_CFG_PREF_EN BIT(0)
++
++#define MTK_WDMA_WRBK_TX_CFG 0x300
++#define MTK_WDMA_WRBK_TX_CFG_WRBK_EN BIT(30)
++
++#define MTK_WDMA_WRBK_RX_CFG 0x344
++#define MTK_WDMA_WRBK_RX_CFG_WRBK_EN BIT(30)
++
+ #define MTK_PCIE_MIRROR_MAP(n) ((n) ? 0x4 : 0x0)
+ #define MTK_PCIE_MIRROR_MAP_EN BIT(0)
+ #define MTK_PCIE_MIRROR_MAP_WED_ID BIT(1)
+@@ -439,6 +502,31 @@ struct mtk_wdma_desc {
+ #define MTK_WED_RTQM_Q_DBG_BYPASS BIT(5)
+ #define MTK_WED_RTQM_TXDMAD_FPORT GENMASK(23, 20)
+
++#define MTK_WED_RTQM_IGRS0_I2HW_DMAD_CNT 0xb1c
++#define MTK_WED_RTQM_IGRS0_I2H_DMAD_CNT(_n) (0xb20 + (_n) * 0x4)
++#define MTK_WED_RTQM_IGRS0_I2HW_PKT_CNT 0xb28
++#define MTK_WED_RTQM_IGRS0_I2H_PKT_CNT(_n) (0xb2c + (_n) * 0x4)
++#define MTK_WED_RTQM_IGRS0_FDROP_CNT 0xb34
++
++
++#define MTK_WED_RTQM_IGRS1_I2HW_DMAD_CNT 0xb44
++#define MTK_WED_RTQM_IGRS1_I2H_DMAD_CNT(_n) (0xb48 + (_n) * 0x4)
++#define MTK_WED_RTQM_IGRS1_I2HW_PKT_CNT 0xb50
++#define MTK_WED_RTQM_IGRS1_I2H_PKT_CNT(_n) (0xb54+ (_n) * 0x4)
++#define MTK_WED_RTQM_IGRS1_FDROP_CNT 0xb5c
++
++#define MTK_WED_RTQM_IGRS2_I2HW_DMAD_CNT 0xb6c
++#define MTK_WED_RTQM_IGRS2_I2H_DMAD_CNT(_n) (0xb70 + (_n) * 0x4)
++#define MTK_WED_RTQM_IGRS2_I2HW_PKT_CNT 0xb78
++#define MTK_WED_RTQM_IGRS2_I2H_PKT_CNT(_n) (0xb7c+ (_n) * 0x4)
++#define MTK_WED_RTQM_IGRS2_FDROP_CNT 0xb84
++
++#define MTK_WED_RTQM_IGRS3_I2HW_DMAD_CNT 0xb94
++#define MTK_WED_RTQM_IGRS3_I2H_DMAD_CNT(_n) (0xb98 + (_n) * 0x4)
++#define MTK_WED_RTQM_IGRS3_I2HW_PKT_CNT 0xba0
++#define MTK_WED_RTQM_IGRS3_I2H_PKT_CNT(_n) (0xba4+ (_n) * 0x4)
++#define MTK_WED_RTQM_IGRS3_FDROP_CNT 0xbac
++
+ #define MTK_WED_RTQM_R2H_MIB(_n) (0xb70 + (_n) * 0x4)
+ #define MTK_WED_RTQM_R2Q_MIB(_n) (0xb78 + (_n) * 0x4)
+ #define MTK_WED_RTQM_Q2N_MIB 0xb80
+@@ -447,6 +535,24 @@ struct mtk_wdma_desc {
+ #define MTK_WED_RTQM_Q2B_MIB 0xb8c
+ #define MTK_WED_RTQM_PFDBK_MIB 0xb90
+
++#define MTK_WED_RTQM_ENQ_CFG0 0xbb8
++#define MTK_WED_RTQM_ENQ_CFG_TXDMAD_FPORT GENMASK(15, 12)
++
++#define MTK_WED_RTQM_FDROP_MIB 0xb84
++#define MTK_WED_RTQM_ENQ_I2Q_DMAD_CNT 0xbbc
++#define MTK_WED_RTQM_ENQ_I2N_DMAD_CNT 0xbc0
++#define MTK_WED_RTQM_ENQ_I2Q_PKT_CNT 0xbc4
++#define MTK_WED_RTQM_ENQ_I2N_PKT_CNT 0xbc8
++#define MTK_WED_RTQM_ENQ_USED_ENTRY_CNT 0xbcc
++#define MTK_WED_RTQM_ENQ_ERR_CNT 0xbd0
++
++#define MTK_WED_RTQM_DEQ_DMAD_CNT 0xbd8
++#define MTK_WED_RTQM_DEQ_Q2I_DMAD_CNT 0xbdc
++#define MTK_WED_RTQM_DEQ_PKT_CNT 0xbe0
++#define MTK_WED_RTQM_DEQ_Q2I_PKT_CNT 0xbe4
++#define MTK_WED_RTQM_DEQ_USED_PFDBK_CNT 0xbe8
++#define MTK_WED_RTQM_DEQ_ERR_CNT 0xbec
++
+ #define MTK_WED_RROQM_GLO_CFG 0xc04
+ #define MTK_WED_RROQM_RST_IDX 0xc08
+ #define MTK_WED_RROQM_RST_IDX_MIOD BIT(0)
+@@ -487,8 +593,8 @@ struct mtk_wdma_desc {
+ #define MTK_WED_RX_BM_BASE 0xd84
+ #define MTK_WED_RX_BM_INIT_PTR 0xd88
+ #define MTK_WED_RX_BM_PTR 0xd8c
+-#define MTK_WED_RX_BM_PTR_HEAD GENMASK(32, 16)
+ #define MTK_WED_RX_BM_PTR_TAIL GENMASK(15, 0)
++#define MTK_WED_RX_BM_PTR_HEAD GENMASK(32, 16)
+
+ #define MTK_WED_RX_BM_BLEN 0xd90
+ #define MTK_WED_RX_BM_STS 0xd94
+@@ -496,7 +602,193 @@ struct mtk_wdma_desc {
+ #define MTK_WED_RX_BM_INTF 0xd9c
+ #define MTK_WED_RX_BM_ERR_STS 0xda8
+
++#define MTK_RRO_IND_CMD_SIGNATURE 0xe00
++#define MTK_RRO_IND_CMD_DMA_IDX GENMASK(11, 0)
++#define MTK_RRO_IND_CMD_MAGIC_CNT GENMASK(30, 28)
++
++#define MTK_WED_IND_CMD_RX_CTRL0 0xe04
++#define MTK_WED_IND_CMD_PROC_IDX GENMASK(11, 0)
++#define MTK_WED_IND_CMD_PREFETCH_FREE_CNT GENMASK(19, 16)
++#define MTK_WED_IND_CMD_MAGIC_CNT GENMASK(30, 28)
++
++#define MTK_WED_IND_CMD_RX_CTRL1 0xe08
++#define MTK_WED_IND_CMD_RX_CTRL2 0xe0c
++#define MTK_WED_IND_CMD_MAX_CNT GENMASK(11, 0)
++#define MTK_WED_IND_CMD_BASE_M GENMASK(19, 16)
++
++#define MTK_WED_RRO_CFG0 0xe10
++#define MTK_WED_RRO_CFG1 0xe14
++#define MTK_WED_RRO_CFG1_MAX_WIN_SZ GENMASK(31, 29)
++#define MTK_WED_RRO_CFG1_ACK_SN_BASE_M GENMASK(19, 16)
++#define MTK_WED_RRO_CFG1_PARTICL_SE_ID GENMASK(11, 0)
++
++#define MTK_WED_ADDR_ELEM_CFG0 0xe18
++#define MTK_WED_ADDR_ELEM_CFG1 0xe1c
++#define MTK_WED_ADDR_ELEM_PREFETCH_FREE_CNT GENMASK(19, 16)
++
++#define MTK_WED_ADDR_ELEM_TBL_CFG 0xe20
++#define MTK_WED_ADDR_ELEM_TBL_OFFSET GENMASK(6, 0)
++#define MTK_WED_ADDR_ELEM_TBL_RD_RDY BIT(28)
++#define MTK_WED_ADDR_ELEM_TBL_WR_RDY BIT(29)
++#define MTK_WED_ADDR_ELEM_TBL_RD BIT(30)
++#define MTK_WED_ADDR_ELEM_TBL_WR BIT(31)
++
++#define MTK_WED_RADDR_ELEM_TBL_WDATA 0xe24
++#define MTK_WED_RADDR_ELEM_TBL_RDATA 0xe28
++
++#define MTK_WED_PN_CHECK_CFG 0xe30
++#define MTK_WED_PN_CHECK_SE_ID GENMASK(11, 0)
++#define MTK_WED_PN_CHECK_RD_RDY BIT(28)
++#define MTK_WED_PN_CHECK_WR_RDY BIT(29)
++#define MTK_WED_PN_CHECK_RD BIT(30)
++#define MTK_WED_PN_CHECK_WR BIT(31)
++
++#define MTK_WED_PN_CHECK_WDATA_M 0xe38
++#define MTK_WED_PN_CHECK_IS_FIRST BIT(17)
++
++#define MTK_WED_RRO_MSDU_PG_RING_CFG(_n) (0xe44 + (_n) * 0x8)
++
++#define MTK_WED_RRO_MSDU_PG_RING2_CFG 0xe58
++#define MTK_WED_RRO_MSDU_PG_DRV_CLR BIT(26)
++#define MTK_WED_RRO_MSDU_PG_DRV_EN BIT(31)
++
++#define MTK_WED_RRO_MSDU_PG_CTRL0(_n) (0xe5c + (_n) * 0xc)
++#define MTK_WED_RRO_MSDU_PG_CTRL1(_n) (0xe60 + (_n) * 0xc)
++#define MTK_WED_RRO_MSDU_PG_CTRL2(_n) (0xe64 + (_n) * 0xc)
++
++#define MTK_WED_RRO_RX_D_RX(_n) (0xe80 + (_n) * 0x10)
++
++#define MTK_WED_RRO_RX_MAGIC_CNT BIT(13)
++
++#define MTK_WED_RRO_RX_D_CFG(_n) (0xea0 + (_n) * 0x4)
++#define MTK_WED_RRO_RX_D_DRV_CLR BIT(26)
++#define MTK_WED_RRO_RX_D_DRV_EN BIT(31)
++
++#define MTK_WED_RRO_PG_BM_RX_DMAM 0xeb0
++#define MTK_WED_RRO_PG_BM_RX_SDL0 GENMASK(13, 0)
++
++#define MTK_WED_RRO_PG_BM_BASE 0xeb4
++#define MTK_WED_RRO_PG_BM_INIT_PTR 0xeb8
++#define MTK_WED_RRO_PG_BM_SW_TAIL_IDX GENMASK(15, 0)
++#define MTK_WED_RRO_PG_BM_INIT_SW_TAIL_IDX BIT(16)
++
++#define MTK_WED_WPDMA_INT_CTRL_RRO_RX 0xeec
++#define MTK_WED_WPDMA_INT_CTRL_RRO_RX0_EN BIT(0)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_RX0_CLR BIT(1)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_RX0_DONE_TRIG GENMASK(6, 2)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_RX1_EN BIT(8)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_RX1_CLR BIT(9)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_RX1_DONE_TRIG GENMASK(14, 10)
++
++#define MTK_WED_WPDMA_INT_CTRL_RRO_MSDU_PG 0xef4
++#define MTK_WED_WPDMA_INT_CTRL_RRO_PG0_EN BIT(0)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_PG0_CLR BIT(1)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_PG0_DONE_TRIG GENMASK(6, 2)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_PG1_EN BIT(8)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_PG1_CLR BIT(9)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_PG1_DONE_TRIG GENMASK(14, 10)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_EN BIT(16)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_CLR BIT(17)
++#define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_DONE_TRIG GENMASK(22, 18)
++
++#define MTK_WED_RX_IND_CMD_CNT0 0xf20
++#define MTK_WED_RX_IND_CMD_DBG_CNT_EN BIT(31)
++
++#define MTK_WED_RX_IND_CMD_CNT(_n) (0xf20 + (_n) * 0x4)
++#define MTK_WED_IND_CMD_MAGIC_CNT_FAIL_CNT GENMASK(15, 0)
++
++#define MTK_WED_RX_ADDR_ELEM_CNT(_n) (0xf48 + (_n) * 0x4)
++#define MTK_WED_ADDR_ELEM_SIG_FAIL_CNT GENMASK(15, 0)
++#define MTK_WED_ADDR_ELEM_FIRST_SIG_FAIL_CNT GENMASK(31, 16)
++#define MTK_WED_ADDR_ELEM_ACKSN_CNT GENMASK(27, 0)
++
++#define MTK_WED_RX_MSDU_PG_CNT(_n) (0xf5c + (_n) * 0x4)
++
++#define MTK_WED_RX_PN_CHK_CNT 0xf70
++#define MTK_WED_PN_CHK_FAIL_CNT GENMASK(15, 0)
++
+ #define MTK_WED_WOCPU_VIEW_MIOD_BASE 0x8000
+ #define MTK_WED_PCIE_INT_MASK 0x0
+
++#define MTK_WED_PAO_AMSDU_FIFO 0x1800
++#define MTK_WED_PAO_AMSDU_IS_PRIOR0_RING BIT(10)
++
++#define MTK_WED_PAO_STA_INFO 0x01810
++#define MTK_WED_PAO_STA_INFO_DO_INIT BIT(0)
++#define MTK_WED_PAO_STA_INFO_SET_INIT BIT(1)
++
++#define MTK_WED_PAO_STA_INFO_INIT 0x01814
++#define MTK_WED_PAO_STA_WTBL_HDRT_MODE BIT(0)
++#define MTK_WED_PAO_STA_RMVL BIT(1)
++#define MTK_WED_PAO_STA_MAX_AMSDU_LEN GENMASK(7, 2)
++#define MTK_WED_PAO_STA_MAX_AMSDU_NUM GENMASK(11, 8)
++
++#define MTK_WED_PAO_HIFTXD_BASE_L(_n) (0x1980 + (_n) * 0x4)
++
++#define MTK_WED_PAO_PSE 0x1910
++#define MTK_WED_PAO_PSE_RESET BIT(16)
++
++#define MTK_WED_PAO_HIFTXD_CFG 0x1968
++#define MTK_WED_PAO_HIFTXD_SRC GENMASK(16, 15)
++
++#define MTK_WED_PAO_MON_AMSDU_FIFO_DMAD 0x1a34
++
++#define MTK_WED_PAO_MON_AMSDU_ENG_DMAD(_n) (0x1a80 + (_n) * 0x50)
++#define MTK_WED_PAO_MON_AMSDU_ENG_QFPL(_n) (0x1a84 + (_n) * 0x50)
++#define MTK_WED_PAO_MON_AMSDU_ENG_QENI(_n) (0x1a88 + (_n) * 0x50)
++#define MTK_WED_PAO_MON_AMSDU_ENG_QENO(_n) (0x1a8c + (_n) * 0x50)
++#define MTK_WED_PAO_MON_AMSDU_ENG_MERG(_n) (0x1a90 + (_n) * 0x50)
++
++#define MTK_WED_PAO_MON_AMSDU_ENG_CNT8(_n) (0x1a94 + (_n) * 0x50)
++#define MTK_WED_PAO_AMSDU_ENG_MAX_QGPP_CNT GENMASK(10, 0)
++#define MTK_WED_PAO_AMSDU_ENG_MAX_PL_CNT GENMASK(27, 16)
++
++#define MTK_WED_PAO_MON_AMSDU_ENG_CNT9(_n) (0x1a98 + (_n) * 0x50)
++#define MTK_WED_PAO_AMSDU_ENG_CUR_ENTRY GENMASK(10, 0)
++#define MTK_WED_PAO_AMSDU_ENG_MAX_BUF_MERGED GENMASK(20, 16)
++#define MTK_WED_PAO_AMSDU_ENG_MAX_MSDU_MERGED GENMASK(28, 24)
++
++#define MTK_WED_PAO_MON_QMEM_STS1 0x1e04
++
++#define MTK_WED_PAO_MON_QMEM_CNT(_n) (0x1e0c + (_n) * 0x4)
++#define MTK_WED_PAO_QMEM_FQ_CNT GENMASK(27, 16)
++#define MTK_WED_PAO_QMEM_SP_QCNT GENMASK(11, 0)
++#define MTK_WED_PAO_QMEM_TID0_QCNT GENMASK(27, 16)
++#define MTK_WED_PAO_QMEM_TID1_QCNT GENMASK(11, 0)
++#define MTK_WED_PAO_QMEM_TID2_QCNT GENMASK(27, 16)
++#define MTK_WED_PAO_QMEM_TID3_QCNT GENMASK(11, 0)
++#define MTK_WED_PAO_QMEM_TID4_QCNT GENMASK(27, 16)
++#define MTK_WED_PAO_QMEM_TID5_QCNT GENMASK(11, 0)
++#define MTK_WED_PAO_QMEM_TID6_QCNT GENMASK(27, 16)
++#define MTK_WED_PAO_QMEM_TID7_QCNT GENMASK(11, 0)
++
++#define MTK_WED_PAO_MON_QMEM_PTR(_n) (0x1e20 + (_n) * 0x4)
++#define MTK_WED_PAO_QMEM_FQ_HEAD GENMASK(27, 16)
++#define MTK_WED_PAO_QMEM_SP_QHEAD GENMASK(11, 0)
++#define MTK_WED_PAO_QMEM_TID0_QHEAD GENMASK(27, 16)
++#define MTK_WED_PAO_QMEM_TID1_QHEAD GENMASK(11, 0)
++#define MTK_WED_PAO_QMEM_TID2_QHEAD GENMASK(27, 16)
++#define MTK_WED_PAO_QMEM_TID3_QHEAD GENMASK(11, 0)
++#define MTK_WED_PAO_QMEM_TID4_QHEAD GENMASK(27, 16)
++#define MTK_WED_PAO_QMEM_TID5_QHEAD GENMASK(11, 0)
++#define MTK_WED_PAO_QMEM_TID6_QHEAD GENMASK(27, 16)
++#define MTK_WED_PAO_QMEM_TID7_QHEAD GENMASK(11, 0)
++#define MTK_WED_PAO_QMEM_FQ_TAIL GENMASK(27, 16)
++#define MTK_WED_PAO_QMEM_SP_QTAIL GENMASK(11, 0)
++#define MTK_WED_PAO_QMEM_TID0_QTAIL GENMASK(27, 16)
++#define MTK_WED_PAO_QMEM_TID1_QTAIL GENMASK(11, 0)
++#define MTK_WED_PAO_QMEM_TID2_QTAIL GENMASK(27, 16)
++#define MTK_WED_PAO_QMEM_TID3_QTAIL GENMASK(11, 0)
++#define MTK_WED_PAO_QMEM_TID4_QTAIL GENMASK(27, 16)
++#define MTK_WED_PAO_QMEM_TID5_QTAIL GENMASK(11, 0)
++#define MTK_WED_PAO_QMEM_TID6_QTAIL GENMASK(27, 16)
++#define MTK_WED_PAO_QMEM_TID7_QTAIL GENMASK(11, 0)
++
++#define MTK_WED_PAO_MON_HIFTXD_FETCH_MSDU(_n) (0x1ec4 + (_n) * 0x4)
++
++#define MTK_WED_PCIE_BASE 0x11280000
++
++#define MTK_WED_PCIE_BASE0 0x11300000
++#define MTK_WED_PCIE_BASE1 0x11310000
++#define MTK_WED_PCIE_BASE2 0x11290000
+ #endif
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index 58b5ce6..5e51790 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -873,6 +873,13 @@ struct net_device_path {
+ u8 queue;
+ u16 wcid;
+ u8 bss;
++ u32 usr_info;
++ u8 tid;
++ u8 is_fixedrate;
++ u8 is_prior;
++ u8 is_sp;
++ u8 hf;
++ u8 amsdu_en;
+ } mtk_wdma;
+ };
+ };
+diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h
+index 27cf284..60336e0 100644
+--- a/include/linux/soc/mediatek/mtk_wed.h
++++ b/include/linux/soc/mediatek/mtk_wed.h
+@@ -5,11 +5,14 @@
+ #include <linux/rcupdate.h>
+ #include <linux/regmap.h>
+ #include <linux/pci.h>
++#include <linux/skbuff.h>
++#include <linux/iopoll.h>
+
+ #define WED_WO_STA_REC 0x6
+
+ #define MTK_WED_TX_QUEUES 2
+ #define MTK_WED_RX_QUEUES 2
++#define MTK_WED_RX_PAGE_QUEUES 3
+
+ enum mtk_wed_wo_cmd {
+ MTK_WED_WO_CMD_WED_CFG,
+@@ -55,10 +58,13 @@ enum mtk_wed_bus_tye {
+ struct mtk_wed_hw;
+ struct mtk_wdma_desc;
+
++#define MTK_WED_RING_CONFIGURED BIT(0)
++
+ struct mtk_wed_ring {
+ struct mtk_wdma_desc *desc;
+ dma_addr_t desc_phys;
+ int size;
++ u32 flags;
+
+ u32 reg_base;
+ void __iomem *wpdma;
+@@ -69,11 +75,18 @@ struct mtk_rxbm_desc {
+ __le32 token;
+ } __packed __aligned(4);
+
++struct dma_page_info {
++ void *addr;
++ dma_addr_t addr_phys;
++};
++
+ struct dma_buf {
+ int size;
+- void **pages;
+- struct mtk_wdma_desc *desc;
++ int pkt_nums;
++ void *desc;
++ int desc_size;
+ dma_addr_t desc_phys;
++ struct dma_page_info *pages;
+ };
+
+ struct dma_entry {
+@@ -97,6 +110,7 @@ struct mtk_wed_device {
+ struct device *dev;
+ struct mtk_wed_hw *hw;
+ bool init_done, running;
++ bool wdma_init_done;
+ int wdma_idx;
+ int irq;
+ u8 ver;
+@@ -108,7 +122,11 @@ struct mtk_wed_device {
+ struct mtk_wed_ring rx_ring[MTK_WED_RX_QUEUES];
+ struct mtk_wed_ring rx_wdma[MTK_WED_RX_QUEUES];
+
+- struct dma_buf buf_ring;
++ struct mtk_wed_ring rx_rro_ring[MTK_WED_RX_QUEUES];
++ struct mtk_wed_ring rx_page_ring[MTK_WED_RX_PAGE_QUEUES];
++ struct mtk_wed_ring ind_cmd_ring;
++
++ struct dma_buf tx_buf_ring;
+
+ struct {
+ int size;
+@@ -117,6 +135,8 @@ struct mtk_wed_device {
+ dma_addr_t desc_phys;
+ } rx_buf_ring;
+
++ struct dma_buf rx_page_buf_ring;
++
+ struct {
+ struct mtk_wed_ring rro_ring;
+ void __iomem *rro_desc;
+@@ -131,8 +151,9 @@ struct mtk_wed_device {
+ struct platform_device *platform_dev;
+ struct pci_dev *pci_dev;
+ };
++ enum mtk_wed_bus_tye bus_type;
+ void __iomem *base;
+- u32 bus_type;
++ void __iomem *regs;
+ u32 phy_base;
+
+ u32 wpdma_phys;
+@@ -142,9 +163,13 @@ struct mtk_wed_device {
+ u32 wpdma_txfree;
+ u32 wpdma_rx_glo;
+ u32 wpdma_rx;
++ u32 wpdma_rx_rro[MTK_WED_RX_QUEUES];
++ u32 wpdma_rx_pg;
+
+ u8 tx_tbit[MTK_WED_TX_QUEUES];
+ u8 rx_tbit[MTK_WED_RX_QUEUES];
++ u8 rro_rx_tbit[MTK_WED_RX_QUEUES];
++ u8 rx_pg_tbit[MTK_WED_RX_PAGE_QUEUES];
+ u8 txfree_tbit;
+
+ u16 token_start;
+@@ -154,12 +179,26 @@ struct mtk_wed_device {
+ unsigned int rx_size;
+
+ bool wcid_512;
+-
++ bool hwrro;
++ bool msi;
++
++ u8 max_amsdu_nums;
++ u32 max_amsdu_len;
++
++ struct {
++ u8 se_group_nums;
++ u16 win_size;
++ u16 particular_sid;
++ u32 ack_sn_addr;
++ dma_addr_t particular_se_phys;
++ dma_addr_t addr_elem_phys[1024];
++ } ind_cmd;
++
++ u32 chip_id;
+ u32 (*init_buf)(void *ptr, dma_addr_t phys, int token_id);
+ int (*offload_enable)(struct mtk_wed_device *wed);
+ void (*offload_disable)(struct mtk_wed_device *wed);
+- u32 (*init_rx_buf)(struct mtk_wed_device *wed,
+- int pkt_num);
++ u32 (*init_rx_buf)(struct mtk_wed_device *wed, int size);
+ void (*release_rx_buf)(struct mtk_wed_device *wed);
+ void (*update_wo_rx_stats)(struct mtk_wed_device *wed,
+ struct mtk_wed_wo_rx_stats *stats);
+@@ -180,6 +219,11 @@ struct mtk_wed_ops {
+ void __iomem *regs);
+ int (*rx_ring_setup)(struct mtk_wed_device *dev, int ring,
+ void __iomem *regs, bool reset);
++ int (*rro_rx_ring_setup)(struct mtk_wed_device *dev, int ring,
++ void __iomem *regs);
++ int (*msdu_pg_rx_ring_setup)(struct mtk_wed_device *dev, int ring,
++ void __iomem *regs);
++ int (*ind_rx_ring_setup)(struct mtk_wed_device *dev, void __iomem *regs);
+ int (*msg_update)(struct mtk_wed_device *dev, int cmd_id,
+ void *data, int len);
+ void (*detach)(struct mtk_wed_device *dev);
+@@ -196,6 +240,7 @@ struct mtk_wed_ops {
+ void (*irq_set_mask)(struct mtk_wed_device *dev, u32 mask);
+ void (*ppe_check)(struct mtk_wed_device *dev, struct sk_buff *skb,
+ u32 reason, u32 hash);
++ void (*start_hwrro)(struct mtk_wed_device *dev, u32 irq_mask);
+ };
+
+ extern const struct mtk_wed_ops __rcu *mtk_soc_wed_ops;
+@@ -224,12 +269,21 @@ static inline bool
+ mtk_wed_get_rx_capa(struct mtk_wed_device *dev)
+ {
+ #ifdef CONFIG_NET_MEDIATEK_SOC_WED
++ if (dev->ver == 3 && !dev->wlan.hwrro)
++ return false;
++
+ return dev->ver != 1;
+ #else
+ return false;
+ #endif
+ }
+
++static inline bool
++mtk_wed_device_support_pao(struct mtk_wed_device *dev)
++{
++ return dev->ver == 3;
++}
++
+ #ifdef CONFIG_NET_MEDIATEK_SOC_WED
+ #define mtk_wed_device_active(_dev) !!(_dev)->ops
+ #define mtk_wed_device_detach(_dev) (_dev)->ops->detach(_dev)
+@@ -243,6 +297,12 @@ mtk_wed_get_rx_capa(struct mtk_wed_device *dev)
+ (_dev)->ops->txfree_ring_setup(_dev, _regs)
+ #define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs, _reset) \
+ (_dev)->ops->rx_ring_setup(_dev, _ring, _regs, _reset)
++#define mtk_wed_device_rro_rx_ring_setup(_dev, _ring, _regs) \
++ (_dev)->ops->rro_rx_ring_setup(_dev, _ring, _regs)
++#define mtk_wed_device_msdu_pg_rx_ring_setup(_dev, _ring, _regs) \
++ (_dev)->ops->msdu_pg_rx_ring_setup(_dev, _ring, _regs)
++#define mtk_wed_device_ind_rx_ring_setup(_dev, _regs) \
++ (_dev)->ops->ind_rx_ring_setup(_dev, _regs)
+ #define mtk_wed_device_update_msg(_dev, _id, _msg, _len) \
+ (_dev)->ops->msg_update(_dev, _id, _msg, _len)
+ #define mtk_wed_device_reg_read(_dev, _reg) \
+@@ -257,6 +317,9 @@ mtk_wed_get_rx_capa(struct mtk_wed_device *dev)
+ (_dev)->ops->reset_dma(_dev)
+ #define mtk_wed_device_ppe_check(_dev, _skb, _reason, _hash) \
+ (_dev)->ops->ppe_check(_dev, _skb, _reason, _hash)
++#define mtk_wed_device_start_hwrro(_dev, _mask) \
++ (_dev)->ops->start_hwrro(_dev, _mask)
++
+ #else
+ static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
+ {
+@@ -268,6 +331,9 @@ static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
+ #define mtk_wed_device_tx_ring_setup(_dev, _ring, _regs, _reset) -ENODEV
+ #define mtk_wed_device_txfree_ring_setup(_dev, _ring, _regs) -ENODEV
+ #define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs, _reset) -ENODEV
++#define mtk_wed_device_rro_rx_ring_setup(_dev, _ring, _regs) -ENODEV
++#define mtk_wed_device_msdu_pg_rx_ring_setup(_dev, _ring, _regs) -ENODEV
++#define mtk_wed_device_ind_rx_ring_setup(_dev, _regs) -ENODEV
+ #define mtk_wed_device_reg_read(_dev, _reg) 0
+ #define mtk_wed_device_reg_write(_dev, _reg, _val) do {} while (0)
+ #define mtk_wed_device_irq_get(_dev, _mask) 0
+@@ -275,6 +341,7 @@ static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
+ #define mtk_wed_device_dma_reset(_dev) do {} while (0)
+ #define mtk_wed_device_setup_tc(_dev, _ndev, _type, _data) do {} while (0)
+ #define mtk_wed_device_ppe_check(_dev, _hash) do {} while (0)
++#define mtk_wed_device_start_hwrro(_dev, _mask) do {} while (0)
+ #endif
+
+ #endif
+--
+2.18.0
+
diff --git a/autobuild_mac80211_release/mt7988_mt7996_mac80211/target/linux/mediatek/patches-5.4/999-3022-mtk-wed-add-wed3-ser-support.patch b/autobuild_mac80211_release/mt7988_mt7996_mac80211/target/linux/mediatek/patches-5.4/999-3022-mtk-wed-add-wed3-ser-support.patch
new file mode 100644
index 0000000..3837d8d
--- /dev/null
+++ b/autobuild_mac80211_release/mt7988_mt7996_mac80211/target/linux/mediatek/patches-5.4/999-3022-mtk-wed-add-wed3-ser-support.patch
@@ -0,0 +1,611 @@
+From 7304ce8edabcbc34433307b02de429c2d118abaa Mon Sep 17 00:00:00 2001
+From: mtk27745 <rex.lu@mediatek.com>
+Date: Tue, 23 May 2023 11:19:30 +0800
+Subject: [PATCH] mtk-wed-add-wed3-ser-support
+
+---
+ drivers/net/ethernet/mediatek/mtk_wed.c | 236 +++++++++++++++++--
+ drivers/net/ethernet/mediatek/mtk_wed_regs.h | 73 +++++-
+ include/linux/soc/mediatek/mtk_wed.h | 6 +-
+ 3 files changed, 291 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
+index 6ed1c83..990888d 100644
+--- a/drivers/net/ethernet/mediatek/mtk_wed.c
++++ b/drivers/net/ethernet/mediatek/mtk_wed.c
+@@ -99,11 +99,65 @@ mtk_wdma_rx_reset(struct mtk_wed_device *dev)
+ u32 status;
+ u32 mask = MTK_WDMA_GLO_CFG_RX_DMA_BUSY;
+ int busy, i;
++ u32 value;
+
+ wdma_clr(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_RX_DMA_EN);
+ busy = readx_poll_timeout(mtk_wdma_read_reset, dev, status,
+- !(status & mask), 0, 10000);
++ !(status & mask), 0, 10000);
+
++ if (dev->hw->version == 3) {
++ wdma_clr(dev, MTK_WDMA_PREF_TX_CFG, MTK_WDMA_PREF_TX_CFG_PREF_EN);
++ wdma_clr(dev, MTK_WDMA_PREF_RX_CFG, MTK_WDMA_PREF_RX_CFG_PREF_EN);
++ busy = read_poll_timeout(wdma_r32, status,
++ !(status & MTK_WDMA_PREF_TX_CFG_PREF_BUSY), 0, 10000,
++ false, dev, MTK_WDMA_PREF_TX_CFG);
++ busy = read_poll_timeout(wdma_r32, status,
++ !(status & MTK_WDMA_PREF_RX_CFG_PREF_BUSY), 0, 10000,
++ false, dev, MTK_WDMA_PREF_RX_CFG);
++
++ wdma_clr(dev, MTK_WDMA_WRBK_TX_CFG, MTK_WDMA_WRBK_TX_CFG_WRBK_EN);
++ wdma_clr(dev, MTK_WDMA_WRBK_RX_CFG, MTK_WDMA_WRBK_RX_CFG_WRBK_EN);
++ busy = read_poll_timeout(wdma_r32, status,
++ !(status & MTK_WDMA_WRBK_TX_CFG_WRBK_BUSY), 0, 10000,
++ false, dev, MTK_WDMA_WRBK_TX_CFG);
++ busy = read_poll_timeout(wdma_r32, status,
++ !(status & MTK_WDMA_WRBK_RX_CFG_WRBK_BUSY), 0, 10000,
++ false, dev, MTK_WDMA_WRBK_RX_CFG);
++
++ /* Prefetch FIFO */
++ wdma_w32(dev, MTK_WDMA_PREF_RX_FIFO_CFG,
++ MTK_WDMA_PREF_RX_FIFO_CFG_RING0_CLEAR |
++ MTK_WDMA_PREF_RX_FIFO_CFG_RING1_CLEAR);
++ wdma_clr(dev, MTK_WDMA_PREF_RX_FIFO_CFG,
++ MTK_WDMA_PREF_RX_FIFO_CFG_RING0_CLEAR |
++ MTK_WDMA_PREF_RX_FIFO_CFG_RING1_CLEAR);
++
++ /* Core FIFO */
++ value = (MTK_WDMA_XDMA_RX_FIFO_CFG_RX_PAR_FIFO_CLEAR |
++ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_CMD_FIFO_CLEAR |
++ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_DMAD_FIFO_CLEAR |
++ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_ARR_FIFO_CLEAR |
++ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_LEN_FIFO_CLEAR |
++ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_WID_FIFO_CLEAR |
++ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_BID_FIFO_CLEAR);
++
++ wdma_w32(dev, MTK_WDMA_XDMA_RX_FIFO_CFG, value);
++ wdma_clr(dev, MTK_WDMA_XDMA_RX_FIFO_CFG, value);
++
++ /* Writeback FIFO */
++ wdma_w32(dev, MTK_WDMA_WRBK_RX_FIFO_CFG(0), MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR);
++ wdma_w32(dev, MTK_WDMA_WRBK_RX_FIFO_CFG(1), MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR);
++
++ wdma_clr(dev, MTK_WDMA_WRBK_RX_FIFO_CFG(0), MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR);
++ wdma_clr(dev, MTK_WDMA_WRBK_RX_FIFO_CFG(1), MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR);
++
++ /* Prefetch ring status */
++ wdma_w32(dev, MTK_WDMA_PREF_SIDX_CFG, MTK_WDMA_PREF_SIDX_CFG_RX_RING_CLEAR);
++ wdma_clr(dev, MTK_WDMA_PREF_SIDX_CFG, MTK_WDMA_PREF_SIDX_CFG_RX_RING_CLEAR);
++ /* Writeback ring status */
++ wdma_w32(dev, MTK_WDMA_WRBK_SIDX_CFG, MTK_WDMA_WRBK_SIDX_CFG_RX_RING_CLEAR);
++ wdma_clr(dev, MTK_WDMA_WRBK_SIDX_CFG, MTK_WDMA_WRBK_SIDX_CFG_RX_RING_CLEAR);
++ }
+ wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_RX);
+ wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
+
+@@ -121,13 +175,62 @@ mtk_wdma_tx_reset(struct mtk_wed_device *dev)
+ {
+ u32 status;
+ u32 mask = MTK_WDMA_GLO_CFG_TX_DMA_BUSY;
+- int i;
++ int busy, i;
++ u32 value;
+
+ wdma_clr(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_TX_DMA_EN);
+ if (readx_poll_timeout(mtk_wdma_read_reset, dev, status,
+ !(status & mask), 0, 10000))
+ WARN_ON_ONCE(1);
+
++ if (dev->hw->version == 3) {
++ wdma_clr(dev, MTK_WDMA_PREF_TX_CFG, MTK_WDMA_PREF_TX_CFG_PREF_EN);
++ wdma_clr(dev, MTK_WDMA_PREF_RX_CFG, MTK_WDMA_PREF_RX_CFG_PREF_EN);
++ busy = read_poll_timeout(wdma_r32, status,
++ !(status & MTK_WDMA_PREF_TX_CFG_PREF_BUSY), 0, 10000,
++ false, dev, MTK_WDMA_PREF_TX_CFG);
++ busy = read_poll_timeout(wdma_r32, status,
++ !(status & MTK_WDMA_PREF_RX_CFG_PREF_BUSY), 0, 10000,
++ false, dev, MTK_WDMA_PREF_RX_CFG);
++
++ wdma_clr(dev, MTK_WDMA_WRBK_TX_CFG, MTK_WDMA_WRBK_TX_CFG_WRBK_EN);
++ wdma_clr(dev, MTK_WDMA_WRBK_RX_CFG, MTK_WDMA_WRBK_RX_CFG_WRBK_EN);
++ busy = read_poll_timeout(wdma_r32, status,
++ !(status & MTK_WDMA_WRBK_TX_CFG_WRBK_BUSY), 0, 10000,
++ false, dev, MTK_WDMA_WRBK_TX_CFG);
++ busy = read_poll_timeout(wdma_r32, status,
++ !(status & MTK_WDMA_WRBK_RX_CFG_WRBK_BUSY), 0, 10000,
++ false, dev, MTK_WDMA_WRBK_RX_CFG);
++
++ /* Prefetch FIFO */
++ wdma_w32(dev, MTK_WDMA_PREF_TX_FIFO_CFG,
++ MTK_WDMA_PREF_TX_FIFO_CFG_RING0_CLEAR |
++ MTK_WDMA_PREF_TX_FIFO_CFG_RING1_CLEAR);
++ wdma_clr(dev, MTK_WDMA_PREF_TX_FIFO_CFG,
++ MTK_WDMA_PREF_TX_FIFO_CFG_RING0_CLEAR |
++ MTK_WDMA_PREF_TX_FIFO_CFG_RING1_CLEAR);
++ /* Core FIFO */
++ value = (MTK_WDMA_XDMA_TX_FIFO_CFG_TX_PAR_FIFO_CLEAR |
++ MTK_WDMA_XDMA_TX_FIFO_CFG_TX_CMD_FIFO_CLEAR |
++ MTK_WDMA_XDMA_TX_FIFO_CFG_TX_DMAD_FIFO_CLEAR |
++ MTK_WDMA_XDMA_TX_FIFO_CFG_TX_ARR_FIFO_CLEAR);
++
++ wdma_w32(dev, MTK_WDMA_XDMA_TX_FIFO_CFG, value);
++ wdma_clr(dev, MTK_WDMA_XDMA_TX_FIFO_CFG, value);
++ /* Writeback FIFO */
++ wdma_w32(dev, MTK_WDMA_WRBK_TX_FIFO_CFG(0), MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR);
++ wdma_w32(dev, MTK_WDMA_WRBK_TX_FIFO_CFG(1), MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR);
++
++ wdma_clr(dev, MTK_WDMA_WRBK_TX_FIFO_CFG(0), MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR);
++ wdma_clr(dev, MTK_WDMA_WRBK_TX_FIFO_CFG(1), MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR);
++
++ /* Prefetch ring status */
++ wdma_w32(dev, MTK_WDMA_PREF_SIDX_CFG, MTK_WDMA_PREF_SIDX_CFG_TX_RING_CLEAR);
++ wdma_clr(dev, MTK_WDMA_PREF_SIDX_CFG, MTK_WDMA_PREF_SIDX_CFG_TX_RING_CLEAR);
++ /* Writeback ring status */
++ wdma_w32(dev, MTK_WDMA_WRBK_SIDX_CFG, MTK_WDMA_WRBK_SIDX_CFG_TX_RING_CLEAR);
++ wdma_clr(dev, MTK_WDMA_WRBK_SIDX_CFG, MTK_WDMA_WRBK_SIDX_CFG_TX_RING_CLEAR);
++ }
+ wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_TX);
+ wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
+ for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
+@@ -903,7 +1006,7 @@ mtk_wed_dma_enable(struct mtk_wed_device *dev)
+ MTK_WED_WPDMA_GLO_CFG_RX_DRV_UNS_VER_FORCE_4);
+
+ wdma_set(dev, MTK_WDMA_PREF_RX_CFG, MTK_WDMA_PREF_RX_CFG_PREF_EN);
+- //wdma_w32(dev, MTK_WDMA_WRBK_RX_CFG, MTK_WDMA_WRBK_RX_CFG_WRBK_EN);
++ wdma_set(dev, MTK_WDMA_WRBK_RX_CFG, MTK_WDMA_WRBK_RX_CFG_WRBK_EN);
+ if (mtk_wed_get_rx_capa(dev)) {
+ wed_set(dev, MTK_WED_WPDMA_RX_D_PREF_CFG,
+ MTK_WED_WPDMA_RX_D_PREF_EN |
+@@ -1477,13 +1580,30 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
+ mtk_wed_mcu_send_msg(wo, MODULE_ID_WO, MTK_WED_WO_CMD_CHANGE_STATE,
+ &state, sizeof(state), true);
+
++ if (dev->wlan.hwrro) {
++ wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_IND_CMD_EN);
++ mtk_wed_poll_busy(dev, MTK_WED_RRO_RX_HW_STS,
++ MTK_WED_RX_IND_CMD_BUSY);
++ mtk_wed_reset(dev, MTK_WED_RESET_RRO_RX_TO_PG);
++ }
+ wed_clr(dev, MTK_WED_WPDMA_RX_D_GLO_CFG, MTK_WED_WPDMA_RX_D_RX_DRV_EN);
+ busy = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
+ MTK_WED_WPDMA_RX_D_RX_DRV_BUSY);
++ if (dev->hw->version == 3)
++ busy = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_RX_D_PREF_CFG,
++ MTK_WED_WPDMA_RX_D_PREF_BUSY);
+ if (busy) {
+ mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_INT_AGENT);
+ mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_RX_D_DRV);
+ } else {
++ if (dev->hw->version == 3) {
++ /*1.a. Disable Prefetch HW*/
++ wed_clr(dev, MTK_WED_WPDMA_RX_D_PREF_CFG, MTK_WED_WPDMA_RX_D_PREF_EN);
++ mtk_wed_poll_busy(dev, MTK_WED_WPDMA_RX_D_PREF_CFG,
++ MTK_WED_WPDMA_RX_D_PREF_BUSY);
++ wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX,
++ MTK_WED_WPDMA_RX_D_RST_DRV_IDX_ALL);
++ }
+ wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX,
+ MTK_WED_WPDMA_RX_D_RST_CRX_IDX |
+ MTK_WED_WPDMA_RX_D_RST_DRV_IDX);
+@@ -1511,6 +1631,24 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
+ wed_w32(dev, MTK_WED_RROQM_RST_IDX, 0);
+ }
+
++ if (dev->wlan.hwrro) {
++ /* Disable RRO MSDU Page Drv */
++ wed_clr(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG, MTK_WED_RRO_MSDU_PG_DRV_EN);
++
++ /* Disable RRO Data Drv */
++ wed_clr(dev, MTK_WED_RRO_RX_D_CFG(2), MTK_WED_RRO_RX_D_DRV_EN);
++
++ /* RRO MSDU Page Drv Reset */
++ wed_w32(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG, MTK_WED_RRO_MSDU_PG_DRV_CLR);
++ mtk_wed_poll_busy(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG,
++ MTK_WED_RRO_MSDU_PG_DRV_CLR);
++
++ /* RRO Data Drv Reset */
++ wed_w32(dev, MTK_WED_RRO_RX_D_CFG(2), MTK_WED_RRO_RX_D_DRV_CLR);
++ mtk_wed_poll_busy(dev, MTK_WED_RRO_RX_D_CFG(2),
++ MTK_WED_RRO_RX_D_DRV_CLR);
++ }
++
+ /* reset route qm */
+ wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_ROUTE_QM_EN);
+ busy = mtk_wed_poll_busy(dev, MTK_WED_CTRL,
+@@ -1518,8 +1656,13 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
+ if (busy) {
+ mtk_wed_reset(dev, MTK_WED_RESET_RX_ROUTE_QM);
+ } else {
+- wed_set(dev, MTK_WED_RTQM_GLO_CFG,
+- MTK_WED_RTQM_Q_RST);
++ if (dev->hw->version == 3) {
++ wed_set(dev, MTK_WED_RTQM_RST, BIT(0));
++ wed_clr(dev, MTK_WED_RTQM_RST, BIT(0));
++ mtk_wed_reset(dev, MTK_WED_RESET_RX_ROUTE_QM);
++ } else
++ wed_set(dev, MTK_WED_RTQM_GLO_CFG,
++ MTK_WED_RTQM_Q_RST);
+ }
+
+ /* reset tx wdma */
+@@ -1527,8 +1670,13 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
+
+ /* reset tx wdma drv */
+ wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_TX_DRV_EN);
+- mtk_wed_poll_busy(dev, MTK_WED_CTRL,
+- MTK_WED_CTRL_WDMA_INT_AGENT_BUSY);
++ if (dev->hw->version == 3)
++ mtk_wed_poll_busy(dev, MTK_WED_WPDMA_STATUS,
++ MTK_WED_WPDMA_STATUS_TX_DRV);
++ else
++ mtk_wed_poll_busy(dev, MTK_WED_CTRL,
++ MTK_WED_CTRL_WDMA_INT_AGENT_BUSY);
++
+ mtk_wed_reset(dev, MTK_WED_RESET_WDMA_TX_DRV);
+
+ /* reset wed rx dma */
+@@ -1546,9 +1694,17 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
+ /* reset rx bm */
+ wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_BM_EN);
+ mtk_wed_poll_busy(dev, MTK_WED_CTRL,
+- MTK_WED_CTRL_WED_RX_BM_BUSY);
++ MTK_WED_CTRL_WED_RX_BM_BUSY);
+ mtk_wed_reset(dev, MTK_WED_RESET_RX_BM);
+
++ if (dev->wlan.hwrro) {
++ wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_PG_BM_EN);
++ mtk_wed_poll_busy(dev, MTK_WED_CTRL,
++ MTK_WED_CTRL_WED_RX_PG_BM_BUSY);
++ wed_set(dev, MTK_WED_RESET, MTK_WED_RESET_RX_PG_BM);
++ wed_clr(dev, MTK_WED_RESET, MTK_WED_RESET_RX_PG_BM);
++ }
++
+ /* wo change to enable state */
+ state = WO_STATE_ENABLE;
+ mtk_wed_mcu_send_msg(wo, MODULE_ID_WO, MTK_WED_WO_CMD_CHANGE_STATE,
+@@ -1565,6 +1721,9 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
+ }
+
+ mtk_wed_free_rx_buffer(dev);
++
++ if (dev->wlan.hwrro)
++ mtk_wed_rx_page_free_buffer(dev);
+ }
+
+
+@@ -1598,18 +1757,40 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
+
+ /* 2. Reset WDMA Rx DMA/Driver_Engine */
+ busy = !!mtk_wdma_rx_reset(dev);
++ if (dev->hw->version == 3) {
++ val = wed_r32(dev, MTK_WED_WDMA_GLO_CFG);
++ val |= MTK_WED_WDMA_GLO_CFG_RX_DIS_FSM_AUTO_IDLE;
++ val &= ~MTK_WED_WDMA_GLO_CFG_RX_DRV_EN;
++ wed_w32(dev, MTK_WED_WDMA_GLO_CFG, val);
++ } else
++ wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_RX_DRV_EN);
+
+- wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_RX_DRV_EN);
+ busy = !!(busy ||
+ mtk_wed_poll_busy(dev, MTK_WED_WDMA_GLO_CFG,
+- MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY));
++ MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY));
++ if (dev->hw->version == 3)
++ busy = !!(busy ||
++ mtk_wed_poll_busy(dev, MTK_WED_WDMA_RX_PREF_CFG,
++ MTK_WED_WDMA_RX_PREF_BUSY));
+
+ if (busy) {
+ mtk_wed_reset(dev, MTK_WED_RESET_WDMA_INT_AGENT);
+ mtk_wed_reset(dev, MTK_WED_RESET_WDMA_RX_DRV);
+ } else {
++ if (dev->hw->version == 3) {
++ /*1.a. Disable Prefetch HW*/
++ wed_clr(dev, MTK_WED_WDMA_RX_PREF_CFG, MTK_WED_WDMA_RX_PREF_EN);
++ mtk_wed_poll_busy(dev, MTK_WED_WDMA_RX_PREF_CFG,
++ MTK_WED_WDMA_RX_PREF_BUSY);
++ wed_clr(dev, MTK_WED_WDMA_RX_PREF_CFG, MTK_WED_WDMA_RX_PREF_DDONE2_EN);
++
++ /*2. Reset dma index*/
++ wed_w32(dev, MTK_WED_WDMA_RESET_IDX,
++ MTK_WED_WDMA_RESET_IDX_RX_ALL);
++ }
+ wed_w32(dev, MTK_WED_WDMA_RESET_IDX,
+- MTK_WED_WDMA_RESET_IDX_RX | MTK_WED_WDMA_RESET_IDX_DRV);
++ MTK_WED_WDMA_RESET_IDX_RX |
++ MTK_WED_WDMA_RESET_IDX_DRV);
+ wed_w32(dev, MTK_WED_WDMA_RESET_IDX, 0);
+
+ wed_set(dev, MTK_WED_WDMA_GLO_CFG,
+@@ -1624,9 +1805,15 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
+ MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
+
+ for (i = 0; i < 100; i++) {
+- val = wed_r32(dev, MTK_WED_TX_BM_INTF);
+- if (FIELD_GET(MTK_WED_TX_BM_INTF_TKFIFO_FDEP, val) == 0x40)
+- break;
++ if (dev->ver > MTK_WED_V1) {
++ val = wed_r32(dev, MTK_WED_TX_TKID_INTF);
++ if (FIELD_GET(MTK_WED_TX_TKID_INTF_TKFIFO_FDEP, val) == 0x40)
++ break;
++ } else {
++ val = wed_r32(dev, MTK_WED_TX_BM_INTF);
++ if (FIELD_GET(MTK_WED_TX_BM_INTF_TKFIFO_FDEP, val) == 0x40)
++ break;
++ }
+ }
+ mtk_wed_reset(dev, MTK_WED_RESET_TX_FREE_AGENT);
+
+@@ -1635,18 +1822,20 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
+
+ /* 4. Reset WED WPDMA Tx Driver Engine */
+ busy = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_GLO_CFG,
+- MTK_WED_WPDMA_GLO_CFG_TX_DRV_BUSY);
++ MTK_WED_WPDMA_GLO_CFG_TX_DRV_BUSY);
+ wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
+ MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN |
+ MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN);
+
+ busy = !!(busy ||
+ mtk_wed_poll_busy(dev, MTK_WED_WPDMA_GLO_CFG,
+- MTK_WED_WPDMA_GLO_CFG_RX_DRV_BUSY));
++ MTK_WED_WPDMA_GLO_CFG_RX_DRV_BUSY));
+ if (busy) {
+ mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_INT_AGENT);
+ mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_TX_DRV);
+ mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_RX_DRV);
++ if (dev->hw->version == 3)
++ wed_w32(dev, MTK_WED_RX1_CTRL2, 0);
+ } else {
+ wed_w32(dev, MTK_WED_WPDMA_RESET_IDX,
+ MTK_WED_WPDMA_RESET_IDX_TX |
+@@ -1659,7 +1848,13 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
+ }
+ }
+
+- if (dev->ver > MTK_WED_V1) {
++ if (dev->hw->version == 3) {
++ /*reset wed pao*/
++ wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_PAO_EN);
++ mtk_wed_reset(dev, MTK_WED_RESET_TX_PAO);
++ }
++
++ if (mtk_wed_get_rx_capa(dev)) {
+ dev->init_done = false;
+ mtk_wed_rx_reset(dev);
+ }
+@@ -1874,7 +2069,7 @@ mtk_wed_ppe_check(struct mtk_wed_device *dev, struct sk_buff *skb,
+ }
+
+ static void
+-mtk_wed_start_hwrro(struct mtk_wed_device *dev, u32 irq_mask)
++mtk_wed_start_hwrro(struct mtk_wed_device *dev, u32 irq_mask, bool reset)
+ {
+ int idx, ret;
+
+@@ -1884,6 +2079,11 @@ mtk_wed_start_hwrro(struct mtk_wed_device *dev, u32 irq_mask)
+ if (!mtk_wed_get_rx_capa(dev) || !dev->wlan.hwrro)
+ return;
+
++ if (reset) {
++ wed_set(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG, MTK_WED_RRO_MSDU_PG_DRV_EN);
++ return;
++ }
++
+ wed_set(dev, MTK_WED_RRO_RX_D_CFG(2), MTK_WED_RRO_MSDU_PG_DRV_CLR);
+ wed_w32(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG, MTK_WED_RRO_MSDU_PG_DRV_CLR);
+
+diff --git a/drivers/net/ethernet/mediatek/mtk_wed_regs.h b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
+index 25be547..4379dc4 100644
+--- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h
++++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
+@@ -42,6 +42,8 @@ struct mtk_wdma_desc {
+ #define MTK_WED_RESET 0x008
+ #define MTK_WED_RESET_TX_BM BIT(0)
+ #define MTK_WED_RESET_RX_BM BIT(1)
++#define MTK_WED_RESET_RX_PG_BM BIT(2)
++#define MTK_WED_RESET_RRO_RX_TO_PG BIT(3)
+ #define MTK_WED_RESET_TX_FREE_AGENT BIT(4)
+ #define MTK_WED_RESET_WPDMA_TX_DRV BIT(8)
+ #define MTK_WED_RESET_WPDMA_RX_DRV BIT(9)
+@@ -64,7 +66,7 @@ struct mtk_wdma_desc {
+ #define MTK_WED_CTRL_WDMA_INT_AGENT_BUSY BIT(3)
+ #define MTK_WED_CTRL_WED_RX_IND_CMD_EN BIT(5)
+ #define MTK_WED_CTRL_WED_RX_PG_BM_EN BIT(6)
+-#define MTK_WED_CTRL_WED_RX_PG_BM_BUSU BIT(7)
++#define MTK_WED_CTRL_WED_RX_PG_BM_BUSY BIT(7)
+ #define MTK_WED_CTRL_WED_TX_BM_EN BIT(8)
+ #define MTK_WED_CTRL_WED_TX_BM_BUSY BIT(9)
+ #define MTK_WED_CTRL_WED_TX_FREE_AGENT_EN BIT(10)
+@@ -123,6 +125,10 @@ struct mtk_wdma_desc {
+ #define MTK_WED_STATUS 0x060
+ #define MTK_WED_STATUS_TX GENMASK(15, 8)
+
++#define MTK_WED_WPDMA_STATUS 0x068
++#define MTK_WED_WPDMA_STATUS_TX_DRV GENMASK(15, 8)
++
++
+ #define MTK_WED_TX_BM_CTRL 0x080
+ #define MTK_WED_TX_BM_CTRL_VLD_GRP_NUM GENMASK(6, 0)
+ #define MTK_WED_TX_BM_CTRL_RSV_GRP_NUM GENMASK(22, 16)
+@@ -167,6 +173,9 @@ struct mtk_wdma_desc {
+
+ #define MTK_WED_TX_TKID_CTRL_PAUSE BIT(28)
+
++#define MTK_WED_TX_TKID_INTF 0x0dc
++#define MTK_WED_TX_TKID_INTF_TKFIFO_FDEP GENMASK(25, 16)
++
+ #define MTK_WED_TX_TKID_DYN_THR 0x0e0
+ #define MTK_WED_TX_TKID_DYN_THR_LO GENMASK(6, 0)
+ #define MTK_WED_TX_TKID_DYN_THR_HI GENMASK(22, 16)
+@@ -203,10 +212,11 @@ struct mtk_wdma_desc {
+ #define MTK_WED_GLO_CFG_RX_2B_OFFSET BIT(31)
+
+ #define MTK_WED_RESET_IDX 0x20c
+-#define MTK_WED_RESET_IDX_TX GENMASK(3, 0)
+-#if defined(CONFIG_MEDIATEK_NETSYS_V2)
++#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
++#define MTK_WED_RESET_IDX_TX GENMASK(1, 0)
+ #define MTK_WED_RESET_IDX_RX GENMASK(7, 6)
+ #else
++#define MTK_WED_RESET_IDX_TX GENMASK(3, 0)
+ #define MTK_WED_RESET_IDX_RX GENMASK(17, 16)
+ #endif
+ #define MTK_WED_RESET_WPDMA_IDX_RX GENMASK(31, 30)
+@@ -221,6 +231,7 @@ struct mtk_wdma_desc {
+ #define MTK_WED_RING_RX_DATA(_n) (0x420 + (_n) * 0x10)
+
+ #define MTK_WED_SCR0 0x3c0
++#define MTK_WED_RX1_CTRL2 0x418
+ #define MTK_WED_WPDMA_INT_TRIGGER 0x504
+ #define MTK_WED_WPDMA_INT_TRIGGER_RX_DONE BIT(1)
+ #define MTK_WED_WPDMA_INT_TRIGGER_TX_DONE GENMASK(5, 4)
+@@ -336,6 +347,7 @@ struct mtk_wdma_desc {
+
+ #define MTK_WED_WPDMA_RX_D_RST_IDX 0x760
+ #define MTK_WED_WPDMA_RX_D_RST_CRX_IDX GENMASK(17, 16)
++#define MTK_WED_WPDMA_RX_D_RST_DRV_IDX_ALL BIT(20)
+ #define MTK_WED_WPDMA_RX_D_RST_DRV_IDX GENMASK(25, 24)
+
+ #define MTK_WED_WPDMA_RX_GLO_CFG 0x76c
+@@ -352,6 +364,7 @@ struct mtk_wdma_desc {
+
+ #define MTK_WED_WPDMA_RX_D_PREF_CFG 0x7b4
+ #define MTK_WED_WPDMA_RX_D_PREF_EN BIT(0)
++#define MTK_WED_WPDMA_RX_D_PREF_BUSY BIT(1)
+ #define MTK_WED_WPDMA_RX_D_PREF_BURST_SIZE GENMASK(12, 8)
+ #define MTK_WED_WPDMA_RX_D_PREF_LOW_THRES GENMASK(21, 16)
+
+@@ -373,11 +386,13 @@ struct mtk_wdma_desc {
+
+ #define MTK_WED_WDMA_RX_PREF_CFG 0x950
+ #define MTK_WED_WDMA_RX_PREF_EN BIT(0)
++#define MTK_WED_WDMA_RX_PREF_BUSY BIT(1)
+ #define MTK_WED_WDMA_RX_PREF_BURST_SIZE GENMASK(12, 8)
+ #define MTK_WED_WDMA_RX_PREF_LOW_THRES GENMASK(21, 16)
+ #define MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR BIT(24)
+ #define MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR BIT(25)
+ #define MTK_WED_WDMA_RX_PREF_DDONE2_EN BIT(26)
++#define MTK_WED_WDMA_RX_PREF_DDONE2_BUSY BIT(27)
+
+ #define MTK_WED_WDMA_RX_PREF_FIFO_CFG 0x95C
+ #define MTK_WED_WDMA_RX_PREF_FIFO_RX0_CLR BIT(0)
+@@ -406,6 +421,7 @@ struct mtk_wdma_desc {
+
+ #define MTK_WED_WDMA_RESET_IDX 0xa08
+ #define MTK_WED_WDMA_RESET_IDX_RX GENMASK(17, 16)
++#define MTK_WED_WDMA_RESET_IDX_RX_ALL BIT(20)
+ #define MTK_WED_WDMA_RESET_IDX_DRV GENMASK(25, 24)
+
+ #define MTK_WED_WDMA_INT_CLR 0xa24
+@@ -474,21 +490,66 @@ struct mtk_wdma_desc {
+ #define MTK_WDMA_INT_MASK_RX_DELAY BIT(30)
+ #define MTK_WDMA_INT_MASK_RX_COHERENT BIT(31)
+
++#define MTK_WDMA_XDMA_TX_FIFO_CFG 0x238
++#define MTK_WDMA_XDMA_TX_FIFO_CFG_TX_PAR_FIFO_CLEAR BIT(0)
++#define MTK_WDMA_XDMA_TX_FIFO_CFG_TX_CMD_FIFO_CLEAR BIT(4)
++#define MTK_WDMA_XDMA_TX_FIFO_CFG_TX_DMAD_FIFO_CLEAR BIT(8)
++#define MTK_WDMA_XDMA_TX_FIFO_CFG_TX_ARR_FIFO_CLEAR BIT(12)
++
++#define MTK_WDMA_XDMA_RX_FIFO_CFG 0x23c
++#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_PAR_FIFO_CLEAR BIT(0)
++#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_CMD_FIFO_CLEAR BIT(4)
++#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_DMAD_FIFO_CLEAR BIT(8)
++#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_ARR_FIFO_CLEAR BIT(12)
++#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_LEN_FIFO_CLEAR BIT(15)
++#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_WID_FIFO_CLEAR BIT(18)
++#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_BID_FIFO_CLEAR BIT(21)
++
++
++
+ #define MTK_WDMA_INT_GRP1 0x250
+ #define MTK_WDMA_INT_GRP2 0x254
+
+ #define MTK_WDMA_PREF_TX_CFG 0x2d0
+ #define MTK_WDMA_PREF_TX_CFG_PREF_EN BIT(0)
++#define MTK_WDMA_PREF_TX_CFG_PREF_BUSY BIT(1)
+
+ #define MTK_WDMA_PREF_RX_CFG 0x2dc
+ #define MTK_WDMA_PREF_RX_CFG_PREF_EN BIT(0)
++#define MTK_WDMA_PREF_RX_CFG_PREF_BUSY BIT(1)
++
++#define MTK_WDMA_PREF_RX_FIFO_CFG 0x2e0
++#define MTK_WDMA_PREF_RX_FIFO_CFG_RING0_CLEAR BIT(0)
++#define MTK_WDMA_PREF_RX_FIFO_CFG_RING1_CLEAR BIT(16)
++
++#define MTK_WDMA_PREF_TX_FIFO_CFG 0x2d4
++#define MTK_WDMA_PREF_TX_FIFO_CFG_RING0_CLEAR BIT(0)
++#define MTK_WDMA_PREF_TX_FIFO_CFG_RING1_CLEAR BIT(16)
++
++#define MTK_WDMA_PREF_SIDX_CFG 0x2e4
++#define MTK_WDMA_PREF_SIDX_CFG_TX_RING_CLEAR GENMASK(3, 0)
++#define MTK_WDMA_PREF_SIDX_CFG_RX_RING_CLEAR GENMASK(5, 4)
+
+ #define MTK_WDMA_WRBK_TX_CFG 0x300
++#define MTK_WDMA_WRBK_TX_CFG_WRBK_BUSY BIT(0)
+ #define MTK_WDMA_WRBK_TX_CFG_WRBK_EN BIT(30)
+
++#define MTK_WDMA_WRBK_TX_FIFO_CFG(_n) (0x304 + (_n) * 0x4)
++#define MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR BIT(0)
++
++
+ #define MTK_WDMA_WRBK_RX_CFG 0x344
++#define MTK_WDMA_WRBK_RX_CFG_WRBK_BUSY BIT(0)
+ #define MTK_WDMA_WRBK_RX_CFG_WRBK_EN BIT(30)
+
++#define MTK_WDMA_WRBK_RX_FIFO_CFG(_n) (0x348 + (_n) * 0x4)
++#define MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR BIT(0)
++
++
++#define MTK_WDMA_WRBK_SIDX_CFG 0x388
++#define MTK_WDMA_WRBK_SIDX_CFG_TX_RING_CLEAR GENMASK(3, 0)
++#define MTK_WDMA_WRBK_SIDX_CFG_RX_RING_CLEAR GENMASK(5, 4)
++
+ #define MTK_PCIE_MIRROR_MAP(n) ((n) ? 0x4 : 0x0)
+ #define MTK_PCIE_MIRROR_MAP_EN BIT(0)
+ #define MTK_PCIE_MIRROR_MAP_WED_ID BIT(1)
+@@ -502,6 +563,9 @@ struct mtk_wdma_desc {
+ #define MTK_WED_RTQM_Q_DBG_BYPASS BIT(5)
+ #define MTK_WED_RTQM_TXDMAD_FPORT GENMASK(23, 20)
+
++#define MTK_WED_RTQM_RST 0xb04
++
++
+ #define MTK_WED_RTQM_IGRS0_I2HW_DMAD_CNT 0xb1c
+ #define MTK_WED_RTQM_IGRS0_I2H_DMAD_CNT(_n) (0xb20 + (_n) * 0x4)
+ #define MTK_WED_RTQM_IGRS0_I2HW_PKT_CNT 0xb28
+@@ -691,6 +755,9 @@ struct mtk_wdma_desc {
+ #define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_CLR BIT(17)
+ #define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_DONE_TRIG GENMASK(22, 18)
+
++#define MTK_WED_RRO_RX_HW_STS 0xf00
++#define MTK_WED_RX_IND_CMD_BUSY GENMASK(31, 0)
++
+ #define MTK_WED_RX_IND_CMD_CNT0 0xf20
+ #define MTK_WED_RX_IND_CMD_DBG_CNT_EN BIT(31)
+
+diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h
+index 2b389e8..bb02ba5 100644
+--- a/include/linux/soc/mediatek/mtk_wed.h
++++ b/include/linux/soc/mediatek/mtk_wed.h
+@@ -240,7 +240,7 @@ struct mtk_wed_ops {
+ void (*irq_set_mask)(struct mtk_wed_device *dev, u32 mask);
+ void (*ppe_check)(struct mtk_wed_device *dev, struct sk_buff *skb,
+ u32 reason, u32 hash);
+- void (*start_hwrro)(struct mtk_wed_device *dev, u32 irq_mask);
++ void (*start_hwrro)(struct mtk_wed_device *dev, u32 irq_mask, bool reset);
+ };
+
+ extern const struct mtk_wed_ops __rcu *mtk_soc_wed_ops;
+@@ -317,8 +317,8 @@ mtk_wed_device_support_pao(struct mtk_wed_device *dev)
+ (_dev)->ops->reset_dma(_dev)
+ #define mtk_wed_device_ppe_check(_dev, _skb, _reason, _hash) \
+ (_dev)->ops->ppe_check(_dev, _skb, _reason, _hash)
+-#define mtk_wed_device_start_hwrro(_dev, _mask) \
+- (_dev)->ops->start_hwrro(_dev, _mask)
++#define mtk_wed_device_start_hwrro(_dev, _mask, _reset) \
++ (_dev)->ops->start_hwrro(_dev, _mask, _reset)
+
+ #else
+ static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
+--
+2.18.0
+
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0001-prefligt-add-cmd-to-speedup-build-image.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0001-prefligt-add-cmd-to-speedup-build-image.patch
new file mode 100755
index 0000000..377aefb
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0001-prefligt-add-cmd-to-speedup-build-image.patch
@@ -0,0 +1,39 @@
+diff --git a/include/kernel-build.mk b/include/kernel-build.mk
+index 9dfb19c..e2d97da 100644
+--- a/include/kernel-build.mk
++++ b/include/kernel-build.mk
+@@ -184,4 +184,10 @@ define BuildKernel
+
+ prereq: image-prereq
+
++ install-image:
++ @echo Only install image........
++ +$(MAKE) -C image compile install TARGET_BUILD=
++
++ clean-linux: FORCE
++ rm -rf $(LINUX_DIR)
+ endef
+diff --git a/rules.mk b/rules.mk
+index 8b2424f..1787d75 100644
+--- a/rules.mk
++++ b/rules.mk
+@@ -103,7 +103,7 @@ ifdef CONFIG_MIPS64_ABI
+ endif
+ endif
+
+-DEFAULT_SUBDIR_TARGETS:=clean download prepare compile update refresh prereq dist distcheck configure check check-depends
++DEFAULT_SUBDIR_TARGETS:=clean download prepare compile update refresh prereq dist distcheck configure check check-depends install-image clean-linux
+
+ define DefaultTargets
+ $(foreach t,$(DEFAULT_SUBDIR_TARGETS) $(1),
+diff --git a/target/linux/Makefile b/target/linux/Makefile
+index 3a70b80..e3fe1ca 100644
+--- a/target/linux/Makefile
++++ b/target/linux/Makefile
+@@ -9,5 +9,5 @@ include $(INCLUDE_DIR)/target.mk
+
+ export TARGET_BUILD=1
+
+-prereq clean download prepare compile install oldconfig menuconfig nconfig xconfig update refresh: FORCE
++prereq clean download prepare compile install oldconfig menuconfig nconfig xconfig update refresh install-image clean-linux: FORCE
+ @+$(NO_TRACE_MAKE) -C $(BOARD) $@
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0002-busybox-mtk-defconfig.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0002-busybox-mtk-defconfig.patch
new file mode 100644
index 0000000..66e174c
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0002-busybox-mtk-defconfig.patch
@@ -0,0 +1,83 @@
+diff --git a/package/utils/busybox/Config-defaults.in b/package/utils/busybox/Config-defaults.in
+index 168c73b..377c15f 100644
+--- a/package/utils/busybox/Config-defaults.in
++++ b/package/utils/busybox/Config-defaults.in
+@@ -1606,10 +1606,10 @@ config BUSYBOX_DEFAULT_LOSETUP
+ default n
+ config BUSYBOX_DEFAULT_LSPCI
+ bool
+- default n
++ default y
+ config BUSYBOX_DEFAULT_LSUSB
+ bool
+- default n
++ default y
+ config BUSYBOX_DEFAULT_MDEV
+ bool
+ default n
+@@ -2519,28 +2519,28 @@ config BUSYBOX_DEFAULT_UDPSVD
+ default n
+ config BUSYBOX_DEFAULT_TELNET
+ bool
+- default n
++ default y
+ config BUSYBOX_DEFAULT_FEATURE_TELNET_TTYPE
+ bool
+- default n
++ default y
+ config BUSYBOX_DEFAULT_FEATURE_TELNET_AUTOLOGIN
+ bool
+- default n
++ default y
+ config BUSYBOX_DEFAULT_FEATURE_TELNET_WIDTH
+ bool
+ default n
+ config BUSYBOX_DEFAULT_TELNETD
+ bool
+- default n
++ default y
+ config BUSYBOX_DEFAULT_FEATURE_TELNETD_STANDALONE
+ bool
+- default n
++ default y
+ config BUSYBOX_DEFAULT_FEATURE_TELNETD_INETD_WAIT
+ bool
+ default n
+ config BUSYBOX_DEFAULT_TFTP
+ bool
+- default n
++ default y
+ config BUSYBOX_DEFAULT_FEATURE_TFTP_PROGRESS_BAR
+ bool
+ default n
+@@ -2552,10 +2552,10 @@ config BUSYBOX_DEFAULT_TFTPD
+ default n
+ config BUSYBOX_DEFAULT_FEATURE_TFTP_GET
+ bool
+- default n
++ default y
+ config BUSYBOX_DEFAULT_FEATURE_TFTP_PUT
+ bool
+- default n
++ default y
+ config BUSYBOX_DEFAULT_FEATURE_TFTP_BLOCKSIZE
+ bool
+ default n
+@@ -2585,7 +2585,7 @@ config BUSYBOX_DEFAULT_FEATURE_TUNCTL_UG
+ default n
+ config BUSYBOX_DEFAULT_VCONFIG
+ bool
+- default n
++ default y
+ config BUSYBOX_DEFAULT_WGET
+ bool
+ default n
+@@ -2729,7 +2729,7 @@ config BUSYBOX_DEFAULT_LSOF
+ default n
+ config BUSYBOX_DEFAULT_MPSTAT
+ bool
+- default n
++ default y
+ config BUSYBOX_DEFAULT_NMETER
+ bool
+ default n
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0003-fstool-mtk-samba-test.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0003-fstool-mtk-samba-test.patch
new file mode 100644
index 0000000..7e1eba0
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0003-fstool-mtk-samba-test.patch
@@ -0,0 +1,65 @@
+diff -urN a/package/system/fstools/patches/0100-automount.patch b/package/system/fstools/patches/0100-automount.patch
+--- a/package/system/fstools/patches/0100-automount.patch 1970-01-01 08:00:00.000000000 +0800
++++ b/package/system/fstools/patches/0100-automount.patch 2020-07-30 18:16:13.122072146 +0800
+@@ -0,0 +1,22 @@
++Index: fstools-2016-12-04-84b530a7/block.c
++===================================================================
++--- fstools-2016-12-04-84b530a7.orig/block.c 2017-08-17 16:10:43.236274000 +0800
+++++ fstools-2016-12-04-84b530a7/block.c 2017-08-17 16:11:02.423958000 +0800
++@@ -530,7 +530,7 @@
++ printf("\toption\tuuid\t'%s'\n", pr->uuid);
++ else
++ printf("\toption\tdevice\t'%s'\n", pr->dev);
++- printf("\toption\tenabled\t'0'\n\n");
+++ printf("\toption\tenabled\t'1'\n\n");
++
++ return 0;
++ }
++@@ -1454,7 +1454,7 @@
++ cache_load(0);
++ printf("config 'global'\n");
++ printf("\toption\tanon_swap\t'0'\n");
++- printf("\toption\tanon_mount\t'0'\n");
+++ printf("\toption\tanon_mount\t'1'\n");
++ printf("\toption\tauto_swap\t'1'\n");
++ printf("\toption\tauto_mount\t'1'\n");
++ printf("\toption\tdelay_root\t'5'\n");
+diff -urN a/package/system/fstools/patches/0102-mount-options.patch b/package/system/fstools/patches/0102-mount-options.patch
+--- a/package/system/fstools/patches/0102-mount-options.patch 1970-01-01 08:00:00.000000000 +0800
++++ b/package/system/fstools/patches/0102-mount-options.patch 2020-07-30 18:16:13.190070353 +0800
+@@ -0,0 +1,19 @@
++Index: fstools-2016-12-04-84b530a7/block.c
++===================================================================
++--- fstools-2016-12-04-84b530a7.orig/block.c 2017-10-31 18:34:40.867026783 +0800
+++++ fstools-2016-12-04-84b530a7/block.c 2017-10-31 18:39:16.417175783 +0800
++@@ -854,9 +854,13 @@
++ int i, err;
++ size_t mount_opts_len;
++ char *mount_opts = NULL, *ptr;
+++ char _data[128] = {0};
+++ if (strstr(fstype, "fat") || strstr(fstype, "ntfs")) {
+++ snprintf(_data, sizeof(_data), "%s", "iocharset=utf8,uid=65534,gid=65534");
+++ }
++
++ err = mount(source, target, fstype, m ? m->flags : 0,
++- (m && m->options) ? m->options : "");
+++ (m && m->options) ? m->options : _data);
++
++ /* Requested file system type is not available in kernel,
++ attempt to call mount helper. */
+diff -urN a/package/system/fstools/patches/0103-mtk-ntfs-mount-by-ufsd.patch b/package/system/fstools/patches/0103-mtk-ntfs-mount-by-ufsd.patch
+--- a/package/system/fstools/patches/0103-mtk-ntfs-mount-by-ufsd.patch 1970-01-01 08:00:00.000000000 +0800
++++ b/package/system/fstools/patches/0103-mtk-ntfs-mount-by-ufsd.patch 2021-01-26 14:21:31.235330174 +0800
+@@ -0,0 +1,12 @@
++--- a/block.c 2017-11-07 11:13:11.502259230 +0800
+++++ b/block.c 2017-11-07 11:16:43.484684786 +0800
++@@ -859,6 +859,9 @@
++ snprintf(_data, sizeof(_data), "%s", "iocharset=utf8,uid=65534,gid=65534");
++ }
++
+++ if (strstr(fstype, "ntfs"))
+++ fstype= "ufsd";
+++
++ err = mount(source, target, fstype, m ? m->flags : 0,
++ (m && m->options) ? m->options : _data);
++
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0600-mtd-utils-enable-install-test-load.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0600-mtd-utils-enable-install-test-load.patch
new file mode 100644
index 0000000..2287bf8
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0600-mtd-utils-enable-install-test-load.patch
@@ -0,0 +1,23 @@
+diff --git a/package/utils/mtd-utils/Makefile b/package/utils/mtd-utils/Makefile
+index 5a4b03d..5a9372d 100644
+--- a/package/utils/mtd-utils/Makefile
++++ b/package/utils/mtd-utils/Makefile
+@@ -57,7 +57,8 @@ endef
+ MAKE_FLAGS += LDLIBS+="$(LIBGCC_S)"
+
+ CONFIGURE_ARGS += \
+- --disable-tests \
++ --enable-tests \
++ --enable-install-tests \
+ --without-crypto \
+ --without-xattr \
+ --without-zstd \
+@@ -78,6 +79,8 @@ define Package/nand-utils/install
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_BIN) \
+ $(PKG_INSTALL_DIR)/usr/sbin/{flash_erase,nanddump,nandwrite,nandtest,mtdinfo} $(1)/usr/sbin/
++ $(INSTALL_BIN) \
++ $(PKG_INSTALL_DIR)/usr/lib/mtd-utils/{flash_speed,flash_stress,nandbiterrs} $(1)/usr/sbin/
+ endef
+
+ $(eval $(call BuildPackage,ubi-utils))
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0900-sbc-create-related-tools-and-scripts.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0900-sbc-create-related-tools-and-scripts.patch
new file mode 100644
index 0000000..332ee64
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0900-sbc-create-related-tools-and-scripts.patch
@@ -0,0 +1,465 @@
+diff --git a/scripts/make-squashfs-hashed.sh b/scripts/make-squashfs-hashed.sh
+new file mode 100755
+index 0000000..a4b183e
+--- /dev/null
++++ b/scripts/make-squashfs-hashed.sh
+@@ -0,0 +1,23 @@
++#!/bin/bash
++#
++# 1. Using veritysetup to append hash image into squashfs
++# 2. Parsing output of veritysetup to generate uboot script
++#
++SQUASHFS_FILE_PATH=$1
++STAGING_DIR_HOST=$2
++TOPDIR=$3
++SUMMARY_FILE=$4
++
++FILE_SIZE=`stat -c "%s" ${SQUASHFS_FILE_PATH}`
++BLOCK_SIZE=4096
++
++DATA_BLOCKS=$((${FILE_SIZE} / ${BLOCK_SIZE}))
++[ $((${FILE_SIZE} % ${BLOCK_SIZE})) -ne 0 ] && DATA_BLOCKS=$((${DATA_BLOCKS} + 1))
++
++HASH_OFFSET=$((${DATA_BLOCKS} * ${BLOCK_SIZE}))
++
++${STAGING_DIR_HOST}/bin/veritysetup format \
++ --data-blocks=${DATA_BLOCKS} \
++ --hash-offset=${HASH_OFFSET} \
++ ${SQUASHFS_FILE_PATH} ${SQUASHFS_FILE_PATH} \
++ > ${SUMMARY_FILE}
+diff --git a/scripts/prepare-dm-verity-uboot-script.sh b/scripts/prepare-dm-verity-uboot-script.sh
+new file mode 100755
+index 0000000..a66b921
+--- /dev/null
++++ b/scripts/prepare-dm-verity-uboot-script.sh
+@@ -0,0 +1,54 @@
++#!/bin/bash
++
++ROOT_DEVICE=$1
++EXTRA_ARGS=$2
++
++while read line; do
++ key=$(echo ${line} | cut -f1 -d':')
++ value=$(echo ${line} | cut -f2 -d':')
++
++ case "${key}" in
++ "UUID")
++ UUID=${value}
++ ;;
++ "Data blocks")
++ DATA_BLOCKS=${value}
++ ;;
++ "Data block size")
++ DATA_BLOCK_SIZE=${value}
++ ;;
++ "Hash block size")
++ HASH_BLOCK_SIZE=${value}
++ ;;
++ "Hash algorithm")
++ HASH_ALG=${value}
++ ;;
++ "Salt")
++ SALT=${value}
++ ;;
++ "Root hash")
++ ROOT_HASH=${value}
++ ;;
++ esac
++done
++
++#
++# dm-mod.create=<name>,<uuid>,<minor>,<flags>,
++# <start_sector> <num_sectors> <target_type> <target_args>
++# <target_type>=verity
++# <target_args>=<version> <data_dev> <hash_dev> <data_block_size> <hash_block_size>
++# <num_data_blocks> <hash_start_block> <algorithm> <root_hash> <salt>
++#
++# <uuid> ::= xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | ""
++# <minor> ::= The device minor number | ""
++# <flags> ::= "ro" | "rw"
++#
++# More detail in field you can ref.
++# Documentation/admin-guide/device-mapper/dm-init.rst
++# Documentation/admin-guide/device-mapper/verity.rst
++#
++
++BOOTARGS=$( printf '%s root=/dev/dm-0 dm-mod.create="dm-verity,,,ro,0 %s verity 1 %s %s %s %s %s %s %s %s %s"' \
++ "${EXTRA_ARGS}" $((${DATA_BLOCKS} * 8)) ${ROOT_DEVICE} ${ROOT_DEVICE} ${DATA_BLOCK_SIZE} ${HASH_BLOCK_SIZE} ${DATA_BLOCKS} $((${DATA_BLOCKS} + 1)) ${HASH_ALG} ${ROOT_HASH} ${SALT} )
++
++echo setenv bootargs ${BOOTARGS}
+diff --git a/tools/ar-tool/Makefile b/tools/ar-tool/Makefile
+new file mode 100644
+index 0000000..2b22ac0
+--- /dev/null
++++ b/tools/ar-tool/Makefile
+@@ -0,0 +1,36 @@
++#
++# Copyright (C) 2011-2012 OpenWrt.org
++#
++# This is free software, licensed under the GNU General Public License v2.
++# See /LICENSE for more information.
++#
++
++include $(TOPDIR)/rules.mk
++
++PKG_NAME:=ar-tool
++PKG_VERSION:=1
++
++include $(INCLUDE_DIR)/host-build.mk
++
++define Host/Prepare
++ mkdir -p $(HOST_BUILD_DIR)
++ $(CP) ./src/* $(HOST_BUILD_DIR)/
++endef
++
++define Host/Compile
++ $(MAKE) -C $(HOST_BUILD_DIR)
++endef
++
++define Host/Configure
++endef
++
++define Host/Install
++ $(CP) $(HOST_BUILD_DIR)/ar-tool $(STAGING_DIR_HOST)/bin/
++endef
++
++define Host/Clean
++ rm -f $(HOST_BUILD_DIR)/ar-tool
++ rm -f $(STAGING_DIR_HOST)/bin/ar-tool
++endef
++
++$(eval $(call HostBuild))
+diff --git a/tools/ar-tool/src/Makefile b/tools/ar-tool/src/Makefile
+new file mode 100644
+index 0000000..26ab3cf
+--- /dev/null
++++ b/tools/ar-tool/src/Makefile
+@@ -0,0 +1,20 @@
++#
++# Copyright (C) 2019 MediaTek Inc.
++#
++# Author: Sam Shih <sam.shih@mediatek.com>
++#
++# SPDX-License-Identifier: BSD-3-Clause
++# https://spdx.org/licenses
++#
++
++TARGET := ar-tool
++
++.PHONY: all clean
++
++all: ${TARGET}
++
++%: %.py Makefile
++ cp $< $@
++
++clean:
++ rm ${TARGET}
+diff --git a/tools/ar-tool/src/ar-tool.py b/tools/ar-tool/src/ar-tool.py
+new file mode 100755
+index 0000000..e33510b
+--- /dev/null
++++ b/tools/ar-tool/src/ar-tool.py
+@@ -0,0 +1,302 @@
++#!/usr/bin/python
++import os
++import sys
++from xml.dom import minidom
++import pdb
++import traceback
++import re
++
++
++class bl_ar_table_t:
++
++ def __init__(self, input_file):
++ self.input_file = input_file
++ self.ar_ver_list = []
++
++ def generate_ar_ver_code(self):
++ code = ""
++ code += "/* \n"
++ code += " * This file is auto-generated by ar-tool\n"
++ code += " * please do not modify this file manually\n"
++ code += " */\n"
++ code += "#include <plat/common/platform.h>\n"
++ code += "const uint32_t bl_ar_ver = %d;\n" % self.ar_ver_list[-1]
++ return code
++
++ def generate_ar_conf_code(self):
++ code = ""
++ code += "BL_AR_VER\t:=\t%d\n" % self.ar_ver_list[-1]
++ return code
++
++ def check_and_set_ar_ver_list(self, ar_ver):
++ if ((ar_ver not in self.ar_ver_list) and (ar_ver <= 64) and (ar_ver >= 0)):
++ self.ar_ver_list.append(ar_ver)
++ return True
++ else:
++ return False
++
++ def get_data_by_name_from_ar_entry(self, xml_node, entry_id, name, print_err=True):
++ i = entry_id
++ datalist = xml_node.getElementsByTagName(name)
++ if not datalist:
++ if print_err is True:
++ print("XML parse fail in ar_entry[%d]:" % i)
++ print(" Chilld node '%s' not exist" % name)
++ return None
++ data = None
++ if len(datalist) != 1:
++ if print_err is True:
++ print("XML parse fail in ar_entry[%d]:" % i)
++ print(" Duplicate '%s' node exist" % name)
++ return None
++ datanode = datalist[0].firstChild
++ if not datanode:
++ if print_err is True:
++ print("XML parse fail in ar_entry[%d].%s:" % (i, name))
++ print(" '%s' data not exist" % name)
++ return None
++ if datanode.nodeType != datanode.TEXT_NODE:
++ if print_err is True:
++ print("XML parse fail in ar_entry[%d].%s:" % (i, name))
++ print(" '%s' data not exist" % name)
++ return None
++ return str(datanode.data)
++
++ def get_int_by_name_from_ar_entry(self, xml_node, entry_id, name, print_err=True):
++ data = self.get_data_by_name_from_ar_entry(xml_node, entry_id, name, print_err)
++ if data:
++ data = data.strip()
++ if not data.isdigit():
++ if print_err is True:
++ print("XML parse fail in ar_entry[%d].%s:" % (i, name))
++ print(" '%s' must be an integer" % name)
++ return None
++ return data
++ return None
++
++ def xml_debug_show(self, line, column):
++ f = open(self.input_file, "r")
++ if not f:
++ sys.stderr.write("Unable to open file '%s'\n" % self.input_file)
++ raise
++ xml_data = f.read()
++ xml_lines = xml_data.split("\n")
++ f.close()
++ print("input xml fail at line %d, column %d" % (line, column))
++ if line < 2:
++ show_lines = [xml_lines[line]]
++ elif line+2 >= len(xml_lines):
++ show_lines = [xml_lines[line]]
++ else:
++ show_lines = xml_lines[line-1:line+1]
++ for line in show_lines:
++ print(line)
++
++ def parse(self):
++ data = None
++ try:
++ f = open(self.input_file, "r")
++ if not f:
++ raise
++ f.close()
++ except:
++ sys.stderr.write("Unable to open file '%s'\n" % self.input_file)
++ return 1
++ try:
++ xmldoc = minidom.parse(self.input_file)
++ ar_entry_list = xmldoc.getElementsByTagName('bl_ar_entry')
++
++ for i in range(0, len(ar_entry_list)):
++ ar_entry = ar_entry_list[i]
++ data = self.get_int_by_name_from_ar_entry(ar_entry, i, "USED", False)
++ if not data:
++ continue
++
++ data = self.get_int_by_name_from_ar_entry(ar_entry, i, "BL_AR_VER")
++ if not data:
++ return 1
++ if data:
++ data = data.strip()
++ if self.check_and_set_ar_ver_list(int(data)) is False:
++ print("XML parse fail in bl_ar_entry[%d].BL_AR_VER:" % i)
++ print(" 'BL_AR_VER' value duplicate or exceed range")
++ return 1
++ print("Get %d record in bl_ar_table" % len(self.ar_ver_list))
++ except:
++ sys.stderr.write("Unable to parse file '%s'\n" % self.input_file)
++ crash_info = traceback.format_exc()
++ m = re.search("ExpatError: mismatched tag: line (.+), column (.+)", crash_info)
++ if m:
++ line = int(m.group(1))
++ column = int(m.group(2))
++ self.xml_debug_show(line, column)
++ print(m.group(0))
++ else:
++ print(crash_info)
++ return 1
++ return 0
++
++
++class fw_ar_table_t:
++
++ def __init__(self, input_file):
++ self.input_file = input_file
++ self.ar_ver_list = []
++
++ def generate_ar_ver_code(self):
++ code = ""
++ code += "/* \n"
++ code += " * This file is auto-generated by ar-tool\n"
++ code += " * please do not modify this file manually\n"
++ code += " */\n"
++ code += "const uint32_t fw_ar_ver = %d;\n" % self.ar_ver_list[-1]
++ return code
++
++ def generate_ar_conf_code(self):
++ code = ""
++ code += "FW_AR_VER\t:=\t%d\n" % self.ar_ver_list[-1]
++ return code
++
++ def check_and_set_ar_ver_list(self, ar_ver):
++ if ((ar_ver not in self.ar_ver_list) and (ar_ver <= 64) and (ar_ver >= 0)):
++ self.ar_ver_list.append(ar_ver)
++ return True
++ else:
++ return False
++
++ def get_data_by_name_from_ar_entry(self, xml_node, entry_id, name, print_err=True):
++ i = entry_id
++ datalist = xml_node.getElementsByTagName(name)
++ if not datalist:
++ if print_err is True:
++ print("XML parse fail in ar_entry[%d]:" % i)
++ print(" Chilld node '%s' not exist" % name)
++ return None
++ data = None
++ if len(datalist) != 1:
++ if print_err is True:
++ print("XML parse fail in ar_entry[%d]:" % i)
++ print(" Duplicate '%s' node exist" % name)
++ return None
++ datanode = datalist[0].firstChild
++ if not datanode:
++ if print_err is True:
++ print("XML parse fail in ar_entry[%d].%s:" % (i, name))
++ print(" '%s' data not exist" % name)
++ return None
++ if datanode.nodeType != datanode.TEXT_NODE:
++ if print_err is True:
++ print("XML parse fail in ar_entry[%d].%s:" % (i, name))
++ print(" '%s' data not exist" % name)
++ return None
++ return str(datanode.data)
++
++ def get_int_by_name_from_ar_entry(self, xml_node, entry_id, name, print_err=True):
++ data = self.get_data_by_name_from_ar_entry(xml_node, entry_id, name, print_err)
++ if data:
++ data = data.strip()
++ if not data.isdigit():
++ if print_err is True:
++ print("XML parse fail in ar_entry[%d].%s:" % (i, name))
++ print(" '%s' must be an integer" % name)
++ return None
++ return data
++ return None
++
++ def xml_debug_show(self, line, column):
++ f = open(self.input_file, "r")
++ if not f:
++ sys.stderr.write("Unable to open file '%s'\n" % self.input_file)
++ raise
++ xml_data = f.read()
++ xml_lines = xml_data.split("\n")
++ f.close()
++ print("input xml fail at line %d, column %d" % (line, column))
++ if line < 2:
++ show_lines = [xml_lines[line]]
++ elif line+2 >= len(xml_lines):
++ show_lines = [xml_lines[line]]
++ else:
++ show_lines = xml_lines[line-1:line+1]
++ for line in show_lines:
++ print(line)
++
++ def parse(self):
++ data = None
++ try:
++ f = open(self.input_file, "r")
++ if not f:
++ raise
++ f.close()
++ except:
++ sys.stderr.write("Unable to open file '%s'\n" % self.input_file)
++ return 1
++ try:
++ xmldoc = minidom.parse(self.input_file)
++ ar_entry_list = xmldoc.getElementsByTagName('fw_ar_entry')
++
++ for i in range(0, len(ar_entry_list)):
++ ar_entry = ar_entry_list[i]
++ data = self.get_int_by_name_from_ar_entry(ar_entry, i, "USED", False)
++ if not data:
++ continue
++
++ data = self.get_int_by_name_from_ar_entry(ar_entry, i, "FW_AR_VER")
++ if not data:
++ return 1
++ if data:
++ data = data.strip()
++ if self.check_and_set_ar_ver_list(int(data)) is False:
++ print("XML parse fail in fw_ar_entry[%d].FW_AR_VER:" % i)
++ print(" 'FW_AR_VER' value duplicate or exceed range")
++ return 1
++ print("Get %d record in fw_ar_table" % len(self.ar_ver_list))
++ except:
++ sys.stderr.write("Unable to parse file '%s'\n" % self.input_file)
++ crash_info = traceback.format_exc()
++ m = re.search("ExpatError: mismatched tag: line (.+), column (.+)", crash_info)
++ if m:
++ line = int(m.group(1))
++ column = int(m.group(2))
++ self.xml_debug_show(line, column)
++ print(m.group(0))
++ else:
++ print(crash_info)
++ return 1
++ return 0
++
++
++def main(argc, argv):
++ if argc != 5:
++ sys.stdout.write("ar-tool [bl_ar_table|fw_ar_table] [create_ar_ver|create_ar_conf] $(input_file) $(output_file)\n")
++ return 1
++ if argv[1] == "bl_ar_table":
++ ar_table = bl_ar_table_t(argv[3])
++ else:
++ ar_table = fw_ar_table_t(argv[3])
++ if ar_table.parse() != 0:
++ return 1
++ if argv[2] == "create_ar_ver":
++ code = ar_table.generate_ar_ver_code()
++ print("(%s) --> (%s)" % (argv[3], argv[4]))
++ #print(code)
++ f = open(argv[4], "w")
++ f.write(code)
++ f.close()
++ return 0
++ elif argv[2] == "create_ar_conf":
++ code = ar_table.generate_ar_conf_code()
++ print("(%s) --> (%s)" % (argv[3], argv[4]))
++ #print(code)
++ f = open(argv[4], "w")
++ f.write(code)
++ f.close()
++ return 0
++ else:
++ print("Unknow option '%s'" % argv[1])
++ return 1
++
++
++if __name__ == '__main__':
++ sys.exit(main(len(sys.argv), sys.argv))
++
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0901-sbc-build-host-tool-ar-tool.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0901-sbc-build-host-tool-ar-tool.patch
new file mode 100644
index 0000000..2541654
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0901-sbc-build-host-tool-ar-tool.patch
@@ -0,0 +1,10 @@
+--- a/tools/Makefile
++++ b/tools/Makefile
+@@ -21,6 +21,7 @@ ifneq ($(CONFIG_SDK)$(CONFIG_PACKAGE_kmo
+ BUILD_B43_TOOLS = y
+ endif
+
++tools-y += ar-tool
+ tools-y += autoconf autoconf-archive automake bc bison cmake dosfstools
+ tools-y += e2fsprogs fakeroot findutils firmware-utils flex gengetopt
+ tools-y += libressl libtool lzma m4 make-ext4fs missing-macros mkimage
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0901-sbc-build-host-tool-cryptsetup.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0901-sbc-build-host-tool-cryptsetup.patch
new file mode 100644
index 0000000..8d69a8a
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0901-sbc-build-host-tool-cryptsetup.patch
@@ -0,0 +1,382 @@
+diff --git a/feeds/packages/libs/libaio/Makefile b/feeds/packages/libs/libaio/Makefile
+index 463b965..a0a2719 100644
+--- a/feeds/packages/libs/libaio/Makefile
++++ b/feeds/packages/libs/libaio/Makefile
+@@ -23,7 +23,10 @@ PKG_BUILD_PARALLEL:=1
+ PKG_USE_MIPS16:=0
+ PKG_INSTALL:=1
+
++HOST_BUILD_PREFIX:=$(STAGING_DIR_HOST)
++
+ include $(INCLUDE_DIR)/package.mk
++include $(INCLUDE_DIR)/host-build.mk
+
+ define Package/libaio
+ SECTION:=libs
+@@ -44,4 +47,13 @@ define Package/libaio/install
+ $(CP) $(PKG_INSTALL_DIR)/usr/lib/libaio.so.* $(1)/usr/lib/
+ endef
+
++define Host/Compile
++ $(MAKE) -C $(HOST_BUILD_DIR)
++endef
++
++define Host/Install
++ $(MAKE) -C $(HOST_BUILD_DIR) prefix=$(HOST_BUILD_PREFIX) install
++endef
++
+ $(eval $(call BuildPackage,libaio))
++$(eval $(call HostBuild))
+diff --git a/feeds/packages/utils/cryptsetup/Makefile b/feeds/packages/utils/cryptsetup/Makefile
+index bdb249f..8d98957 100644
+--- a/feeds/packages/utils/cryptsetup/Makefile
++++ b/feeds/packages/utils/cryptsetup/Makefile
+@@ -8,12 +8,12 @@
+ include $(TOPDIR)/rules.mk
+
+ PKG_NAME:=cryptsetup
+-PKG_VERSION:=2.5.0
+-PKG_RELEASE:=$(AUTORELEASE)
++PKG_VERSION:=2.3.4
++PKG_RELEASE:=2
+
+ PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+ PKG_SOURCE_URL:=@KERNEL/linux/utils/cryptsetup/v2.5
+-PKG_HASH:=9184a6ebbd9ce7eb211152e7f741a6c82f2d1cc0e24a84ec9c52939eee0f0542
++PKG_HASH:=9d16eebb96b53b514778e813019b8dd15fea9fec5aafde9fae5febf59df83773
+
+ PKG_MAINTAINER:=Daniel Golle <daniel@makrotopia.org>
+ PKG_LICENSE:=GPL-2.0-or-later LGPL-2.1-or-later
+@@ -24,8 +24,12 @@ PKG_BUILD_PARALLEL:=1
+
+ PKG_BUILD_DEPENDS:=!USE_GLIBC:argp-standalone
+
++HOST_BUILD_DEPENDS:=lvm2/host libjson-c/host popt/host
++HOST_BUILD_PREFIX:=$(STAGING_DIR_HOST)
++
+ include $(INCLUDE_DIR)/package.mk
+ include $(INCLUDE_DIR)/nls.mk
++include $(INCLUDE_DIR)/host-build.mk
+
+ define Package/cryptsetup
+ SECTION:=utils
+@@ -75,6 +79,13 @@ CONFIGURE_VARS += \
+
+ TARGET_LDFLAGS += -Wl,--gc-sections $(if $(INTL_FULL),-lintl)
+
++HOST_CONFIGURE_ARGS += \
++ --with-crypto-backend=openssl \
++ $(STAGING_DIR_HOST) \
++ --disable-kernel_crypto \
++ --disable-blkid \
++ --enable-libiconv-tiny
++
+ define Build/InstallDev
+ $(INSTALL_DIR) $(1)/usr/include
+ $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/include/libcryptsetup.h $(1)/usr/include
+@@ -98,5 +109,11 @@ define Package/cryptsetup-ssh/install
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/cryptsetup-ssh $(1)/usr/sbin
+ endef
+
++define Host/Install
++ $(INSTALL_BIN) $(HOST_BUILD_DIR)/veritysetup $(STAGING_DIR_HOST)/bin/veritysetup
++ $(CP) $(HOST_BUILD_DIR)/.libs $(STAGING_DIR_HOST)/bin/
++endef
++
+ $(eval $(call BuildPackage,cryptsetup))
+ $(eval $(call BuildPackage,cryptsetup-ssh))
++$(eval $(call HostBuild))
+diff --git a/feeds/packages/utils/cryptsetup/patches/0001-dont-use-c89.patch b/feeds/packages/utils/cryptsetup/patches/0001-dont-use-c89.patch
+new file mode 100644
+index 0000000000..c5d4ee90d7
+--- /dev/null
++++ b/feeds/packages/utils/cryptsetup/patches/0001-dont-use-c89.patch
+@@ -0,0 +1,10 @@
++--- a/lib/crypto_backend/argon2/Makemodule.am
+++++ b/lib/crypto_backend/argon2/Makemodule.am
++@@ -1,6 +1,6 @@
++ noinst_LTLIBRARIES += libargon2.la
++
++-libargon2_la_CFLAGS = $(AM_CFLAGS) -std=c89 -pthread -O3
+++libargon2_la_CFLAGS = $(AM_CFLAGS) -pthread -O3
++ libargon2_la_CPPFLAGS = $(AM_CPPFLAGS) \
++ -I lib/crypto_backend/argon2 \
++ -I lib/crypto_backend/argon2/blake2
+diff --git a/feeds/packages/utils/cryptsetup/patches/0100-add-configure-arg-to-link-with-tiny-libiconv-in-host-build.patch b/feeds/packages/utils/cryptsetup/patches/0100-add-configure-arg-to-link-with-tiny-libiconv-in-host-build.patch
+new file mode 100644
+index 0000000..d418a91
+--- /dev/null
++++ b/feeds/packages/utils/cryptsetup/patches/0100-add-configure-arg-to-link-with-tiny-libiconv-in-host-build.patch
+@@ -0,0 +1,33 @@
++--- a/configure
+++++ b/configure
++@@ -856,6 +856,7 @@ enable_rpath
++ with_libiconv_prefix
++ enable_keyring
++ enable_largefile
+++enable_libiconv_tiny
++ enable_nls
++ with_libintl_prefix
++ enable_fips
++@@ -1583,6 +1584,7 @@ Optional Features:
++ --disable-keyring disable kernel keyring support and builtin kernel
++ keyring token
++ --disable-largefile omit support for large files
+++ --enable-libiconv-tiny build with libiconv-tiny from OpenWrt
++ --disable-nls do not use Native Language Support
++ --enable-fips enable FIPS mode restrictions
++ --enable-pwquality enable password quality checking using pwquality
++@@ -15038,6 +15040,14 @@ if test "x$enable_largefile" = "xno"; th
++ as_fn_error $? "Building with --disable-largefile is not supported, it can cause data corruption." "$LINENO" 5
++ fi
++
+++# Check whether --enable-libiconv-tiny was given.
+++if test "${enable_libiconv_tiny+set}" = set; then
+++ enableval=$enable_libiconv_tiny;
+++ if test ".$enableval" = .yes; then
+++ LIBS="$LIBS -liconv"
+++ fi
+++fi
+++
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5
++ $as_echo_n "checking for an ANSI C-conforming const... " >&6; }
++ if ${ac_cv_c_const+:} false; then :
+diff --git a/feeds/packages/utils/lvm2/Makefile b/feeds/packages/utils/lvm2/Makefile
+index af35899..24b485a 100644
+--- a/feeds/packages/utils/lvm2/Makefile
++++ b/feeds/packages/utils/lvm2/Makefile
+@@ -24,7 +24,11 @@ PKG_CPE_ID:=cpe:/a:heinz_mauelshagen:lvm
+
+ PKG_BUILD_PARALLEL:=1
+
++HOST_BUILD_DEPENDS:=libaio/host
++HOST_BUILD_PREFIX:=$(STAGING_DIR_HOST)
++
+ include $(INCLUDE_DIR)/package.mk
++include $(INCLUDE_DIR)/host-build.mk
+
+ define Package/libdevmapper/Default
+ SECTION:=libs
+@@ -58,6 +62,15 @@ $(call Package/libdevmapper/description)
+
+ endef
+
++define Package/dmsetup
++ SECTION:=utils
++ CATEGORY:=Utilities
++ SUBMENU:=Disc
++ TITLE:=The Linux Kernel Device Mapper userspace setup utility
++ URL:=https://sourceware.org/dm/
++ DEPENDS:=+libdevmapper
++endef
++
+ define Package/lvm2/default
+ SECTION:=utils
+ CATEGORY:=Utilities
+@@ -70,7 +83,7 @@ endef
+ define Package/lvm2
+ $(call Package/lvm2/default)
+ VARIANT := normal
+- DEPENDS += +libdevmapper
++ DEPENDS += +libdevmapper +dmsetup
+ endef
+
+ define Package/lvm2-selinux
+@@ -105,6 +118,16 @@ ifneq ($(shell /bin/sh -c "echo -n 'X'")
+ MAKE_SHELL = SHELL=/bin/bash
+ endif
+
++HOST_CONFIGURE_ARGS += \
++ --enable-write_install \
++ --enable-pkgconfig \
++ --disable-cmdlib \
++ --disable-dmeventd \
++ --disable-applib \
++ --disable-fsadm \
++ --disable-readline \
++ --disable-selinux
++
+ define Build/Compile
+ $(MAKE) -C $(PKG_BUILD_DIR) \
+ CC="$(TARGET_CC)" \
+@@ -130,10 +153,15 @@ endef
+
+ Package/libdevmapper-selinux/install = $(Package/libdevmapper/install)
+
++define Package/dmsetup/install
++ $(INSTALL_DIR) $(1)/sbin
++ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/dmsetup $(1)/sbin
++ ln -sf dmsetup $(1)/sbin/dmstats
++endef
++
+ define Package/lvm2/install
+ $(INSTALL_DIR) $(1)/sbin
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/lvm $(1)/sbin
+- $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/dmsetup $(1)/sbin
+ $(INSTALL_DIR) $(1)/etc/lvm
+ $(SED) '/^[[:space:]]*\(#\|$$$$\)/d; /cache_dir/s@.*@ cache_dir = "/tmp/lvm/cache"@' $(PKG_INSTALL_DIR)/etc/lvm/lvm.conf
+ $(INSTALL_CONF) $(PKG_INSTALL_DIR)/etc/lvm/lvm.conf $(1)/etc/lvm/
+@@ -146,7 +174,7 @@ define Package/lvm2/install
+ $(INSTALL_BIN) ./files/lvm2.init $(1)/etc/init.d/lvm2
+ $(INSTALL_DIR) $(1)/etc/hotplug.d/block
+ $(INSTALL_DATA) ./files/lvm2.hotplug $(1)/etc/hotplug.d/block/20-lvm2
+- $(FIND) $(PKG_INSTALL_DIR)/usr/sbin/ -type l -exec $(CP) -a {} $(1)/sbin/ \;
++ $(FIND) $(PKG_INSTALL_DIR)/usr/sbin/ -type l ! -name dmstats -exec $(CP) -a {} $(1)/sbin/ \;
+ endef
+
+ Package/lvm2-selinux/install = $(Package/lvm2/install)
+@@ -155,9 +183,30 @@ define Package/lvm2/conffiles
+ /etc/lvm/lvm.conf
+ endef
+
++define Host/Prepare
++ $(HOST_UNPACK)
++ [ ! -d ./src/ ] || $(CP) ./src/* $(HOST_BUILD_DIR)
++
++ mv $(HOST_BUILD_DIR)/../$(PKG_NAME).$(PKG_VERSION)/* $(HOST_BUILD_DIR)/
++ rmdir $(HOST_BUILD_DIR)/../$(PKG_NAME).$(PKG_VERSION)
++
++ $(Host/Patch)
++endef
++
++define Host/Compile
++ $(call Host/Compile/Default,device-mapper)
++endef
++
++define Host/Install
++ $(call Host/Compile/Default,install_device-mapper)
++endef
++
++
+ Package/lvm2-selinux/conffiles = $(Package/lvm2/conffiles)
+
+ $(eval $(call BuildPackage,libdevmapper))
+ $(eval $(call BuildPackage,libdevmapper-selinux))
++$(eval $(call BuildPackage,dmsetup))
+ $(eval $(call BuildPackage,lvm2))
+ $(eval $(call BuildPackage,lvm2-selinux))
++$(eval $(call HostBuild))
+diff -Nurp a/feeds/packages/utils/lvm2/patches/100-change-linker-search-dir-order.patch b/feeds/packages/utils/lvm2/patches/100-change-linker-search-dir-order.patch
+--- a/feeds/packages/utils/lvm2/patches/100-change-linker-search-dir-order.patch
++++ b/feeds/packages/utils/lvm2/patches/100-change-linker-search-dir-order.patch
+@@ -0,0 +1,39 @@
++--- a/libdm/dm-tools/Makefile.in
+++++ b/libdm/dm-tools/Makefile.in
++@@ -52,18 +52,18 @@ include $(top_builddir)/libdm/make.tmpl
++
++ CFLAGS_dmsetup.o += $(UDEV_CFLAGS) $(EXTRA_EXEC_CFLAGS)
++ CFLAGS_dmfilemapd.o += $(EXTRA_EXEC_CFLAGS)
++-LIBDM_LIBS = -L$(interfacebuilddir) -ldevmapper
+++LIBDM_LIBS = -ldevmapper
++ LIBDM_SHARED = $(interfacebuilddir)/libdevmapper.so
++ LIBDM_STATIC = $(interfacebuilddir)/libdevmapper.a
++
++ dmsetup: dmsetup.o $(LIBDM_SHARED)
++ @echo " [CC] $@"
++- $(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) \
+++ $(Q) $(CC) $(CFLAGS) -L$(interfacebuilddir) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) \
++ -o $@ $< $(LIBDM_LIBS) $(LIBS)
++
++ dmsetup.static: dmsetup.o $(LIBDM_STATIC)
++ @echo " [CC] $@"
++- $(Q) $(CC) $(CFLAGS) $(LDFLAGS) -static \
+++ $(Q) $(CC) $(CFLAGS) -L$(interfacebuilddir) $(LDFLAGS) -static \
++ -o $@ $< $(LIBDM_LIBS) $(LIBS) $(STATIC_LIBS)
++
++ install_dmsetup_dynamic: dmsetup
++@@ -79,12 +79,12 @@ install_dmsetup_static: dmsetup.static
++
++ dmfilemapd: dmfilemapd.o $(LIBDM_SHARED)
++ @echo " [CC] $@"
++- $(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) \
+++ $(Q) $(CC) $(CFLAGS) -L$(interfacebuilddir) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) \
++ -o $@ $< $(LIBDM_LIBS) $(LIBS)
++
++ dmfilemapd.static: dmfilemapd.o $(LIBDM_STATIC)
++ @echo " [CC] $@"
++- $(Q) $(CC) $(CFLAGS) $(LDFLAGS) -static \
+++ $(Q) $(CC) $(CFLAGS) -L$(interfacebuilddir) $(LDFLAGS) -static \
++ -o $@ $< $(LIBDM_LIBS) $(LIBS) $(STATIC_LIBS)
++
++ install_dmfilemapd_dynamic: dmfilemapd
+diff --git a/package/Makefile b/package/Makefile
+index 58c1ba2..a66851b 100644
+--- a/package/Makefile
++++ b/package/Makefile
+@@ -60,6 +60,7 @@ $(curdir)/merge-index: $(curdir)/merge
+ ifndef SDK
+ $(curdir)/compile: $(curdir)/system/opkg/host/compile
+ endif
++$(curdir)/compile: $(curdir)/cryptsetup/host/compile
+
+ $(curdir)/install: $(TMP_DIR)/.build $(curdir)/merge $(if $(CONFIG_TARGET_PER_DEVICE_ROOTFS),$(curdir)/merge-index)
+ - find $(STAGING_DIR_ROOT) -type d | $(XARGS) chmod 0755
+diff --git a/package/libs/popt/Makefile b/package/libs/popt/Makefile
+index 34ae4d7..2075542 100644
+--- a/package/libs/popt/Makefile
++++ b/package/libs/popt/Makefile
+@@ -19,15 +19,17 @@ PKG_SOURCE_URL:= \
+ PKG_HASH:=e728ed296fe9f069a0e005003c3d6b2dde3d9cad453422a10d6558616d304cc8
+ PKG_LICENSE:=MIT
+
+-PKG_FIXUP:=autoreconf
+-PKG_REMOVE_FILES:=autogen.sh aclocal.m4
+-
+ PKG_INSTALL:=1
+ PKG_BUILD_PARALLEL:=1
+
++HOST_BUILD_PREFIX:=$(STAGING_DIR_HOST)
++
+ include $(INCLUDE_DIR)/package.mk
++include $(INCLUDE_DIR)/host-build.mk
+
+ TARGET_CFLAGS += $(FPIC)
++HOST_CONFIGURE_ARGS += --enable-libiconv-tiny
++HOST_BUILD_DEPENDS := libiconv/host
+
+ define Package/libpopt
+ SECTION:=libs
+@@ -54,4 +56,4 @@ define Package/libpopt/install
+ endef
+
+ $(eval $(call BuildPackage,libpopt))
+-
++$(eval $(call HostBuild))
+diff -urN a/package/libs/popt/patches/0001-add-configure-arg-to-link-with-tiny-libiconv-in-host-build.patch b/package/libs/popt/patches/0001-add-configure-arg-to-link-with-tiny-libiconv-in-host-build.patch
+--- a/package/libs/popt/patches/0001-add-configure-arg-to-link-with-tiny-libiconv-in-host-build.patch 1970-01-01 08:00:00.000000000 +0800
++++ b/package/libs/popt/patches/0001-add-configure-arg-to-link-with-tiny-libiconv-in-host-build.patch 2021-01-06 13:46:47.514721593 +0800
+@@ -0,0 +1,34 @@
++--- a/configure
+++++ b/configure
++@@ -945,6 +945,7 @@ enable_libtool_lock
++ enable_largefile
++ enable_ld_version_script
++ enable_build_gcov
+++enable_libiconv_tiny
++ enable_nls
++ enable_rpath
++ with_libiconv_prefix
++@@ -1604,6 +1605,7 @@ Optional Features:
++ enable/disable use of linker version script.
++ (default is system dependent)
++ --enable-build-gcov build POPT instrumented for gcov
+++ --enable-libiconv-tiny build with libiconv-tiny from OpenWrt
++ --disable-nls do not use Native Language Support
++ --disable-rpath do not hardcode runtime library paths
++
++@@ -13334,6 +13336,15 @@ if test "${enable_build_gcov+set}" = set
++ fi
++
++
+++# Check whether --enable-libiconv-tiny was given.
+++if test "${enable_libiconv_tiny+set}" = set; then
+++ enableval=$enable_libiconv_tiny;
+++ if test ".$enableval" = .yes; then
+++ LIBS="$LIBS -liconv"
+++ fi
+++fi
+++
+++
++ { $as_echo "$as_me:$LINENO: checking for setreuid" >&5
++ $as_echo_n "checking for setreuid... " >&6; }
++ if test "${ac_cv_func_setreuid+set}" = set; then
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0902-sbc-secure-boot-and-anti-rollback-support.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0902-sbc-secure-boot-and-anti-rollback-support.patch
new file mode 100644
index 0000000..d4110ac
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0902-sbc-secure-boot-and-anti-rollback-support.patch
@@ -0,0 +1,156 @@
+--- a/include/image.mk
++++ b/include/image.mk
+@@ -227,8 +227,7 @@ $(eval $(foreach S,$(NAND_BLOCKSIZE),$(c
+ define Image/mkfs/squashfs-common
+ $(STAGING_DIR_HOST)/bin/mksquashfs4 $(call mkfs_target_dir,$(1)) $@ \
+ -nopad -noappend -root-owned \
+- -comp $(SQUASHFSCOMP) $(SQUASHFSOPT) \
+- -processors 1
++ -comp $(SQUASHFSCOMP) $(SQUASHFSOPT)
+ endef
+
+ ifeq ($(CONFIG_TARGET_ROOTFS_SECURITY_LABELS),y)
+@@ -441,6 +440,9 @@ else
+ DEVICE_CHECK_PROFILE = $(CONFIG_TARGET_$(if $(CONFIG_TARGET_MULTI_PROFILE),DEVICE_)$(call target_conf,$(BOARD)$(if $(SUBTARGET),_$(SUBTARGET)))_$(1))
+ endif
+
++DEVICE_CHECK_FIT_KEY = $(if $(wildcard $(FIT_KEY_DIR)/$(FIT_KEY_NAME).key),install-images,install-disabled)
++DEVICE_CHECK_FIT_DIR = $(if $(FIT_KEY_DIR),$(DEVICE_CHECK_FIT_KEY),install-images)
++
+ DEVICE_EXTRA_PACKAGES = $(call qstrip,$(CONFIG_TARGET_DEVICE_PACKAGES_$(call target_conf,$(BOARD)$(if $(SUBTARGET),_$(SUBTARGET)))_DEVICE_$(1)))
+
+ define merge_packages
+@@ -463,7 +465,7 @@ endef
+ define Device/Check
+ $(Device/Check/Common)
+ KDIR_KERNEL_IMAGE := $(KDIR)/$(1)$$(KERNEL_SUFFIX)
+- _TARGET := $$(if $$(_PROFILE_SET),install-images,install-disabled)
++ _TARGET := $$(if $$(_PROFILE_SET),$$(DEVICE_CHECK_FIT_DIR),install-disabled)
+ ifndef IB
+ _COMPILE_TARGET := $$(if $(CONFIG_IB)$$(_PROFILE_SET),compile,compile-disabled)
+ endif
+@@ -527,6 +527,21 @@ define Device/Build/compile
+
+ endef
+
++define Device/Build/per-device-fs
++ ROOTFS/$(1)/$(3) := \
++ $(KDIR)/root.$(1)$$(strip \
++ $$(if $$(FS_OPTIONS/$(1)),+fs=$$(call param_mangle,$$(FS_OPTIONS/$(1)))) \
++ )$$(strip \
++ $(if $(TARGET_PER_DEVICE_ROOTFS),+pkg=$$(ROOTFS_ID/$(3))) \
++ )
++ ifndef IB
++ $$(ROOTFS/$(1)/$(3)): $(if $(TARGET_PER_DEVICE_ROOTFS),target-dir-$$(ROOTFS_ID/$(3)))
++ endif
++
++ $$(KDIR_KERNEL_IMAGE): $$(ROOTFS/$(1)/$(3))
++
++endef
++
+ ifndef IB
+ define Device/Build/dtb
+ ifndef BUILD_DTS_$(1)
+@@ -571,15 +586,6 @@ define Device/Build/image
+ $(BIN_DIR)/$(call IMAGE_NAME,$(1),$(2))$$(GZ_SUFFIX))
+ $(eval $(call Device/Export,$(KDIR)/tmp/$(call IMAGE_NAME,$(1),$(2)),$(1)))
+
+- ROOTFS/$(1)/$(3) := \
+- $(KDIR)/root.$(1)$$(strip \
+- $$(if $$(FS_OPTIONS/$(1)),+fs=$$(call param_mangle,$$(FS_OPTIONS/$(1)))) \
+- )$$(strip \
+- $(if $(TARGET_PER_DEVICE_ROOTFS),+pkg=$$(ROOTFS_ID/$(3))) \
+- )
+- ifndef IB
+- $$(ROOTFS/$(1)/$(3)): $(if $(TARGET_PER_DEVICE_ROOTFS),target-dir-$$(ROOTFS_ID/$(3)))
+- endif
+ $(KDIR)/tmp/$(call IMAGE_NAME,$(1),$(2)): $$(KDIR_KERNEL_IMAGE) $$(ROOTFS/$(1)/$(3))
+ @rm -f $$@
+ [ -f $$(word 1,$$^) -a -f $$(word 2,$$^) ]
+@@ -640,6 +646,10 @@ define Device/Build/artifact
+ endef
+
+ define Device/Build
++ $$(eval $$(foreach image,$$(IMAGES), \
++ $$(foreach fs,$$(filter $(TARGET_FILESYSTEMS),$$(FILESYSTEMS)), \
++ $$(call Device/Build/per-device-fs,$$(fs),$$(image),$(1)))))
++
+ $(if $(CONFIG_TARGET_ROOTFS_INITRAMFS),$(call Device/Build/initramfs,$(1)))
+ $(call Device/Build/kernel,$(1))
+
+--- a/include/image-commands.mk
++++ b/include/image-commands.mk
+@@ -87,7 +87,7 @@ define Build/append-ubi
+ $(if $(UBOOTENV_IN_UBI),--uboot-env) \
+ $(if $(KERNEL_IN_UBI),--kernel $(IMAGE_KERNEL)) \
+ $(foreach part,$(UBINIZE_PARTS),--part $(part)) \
+- $(IMAGE_ROOTFS) \
++ $(call param_get_default,rootfs,$(1),$(IMAGE_ROOTFS)) \
+ $@.tmp \
+ -p $(BLOCKSIZE:%k=%KiB) -m $(PAGESIZE) \
+ $(if $(SUBPAGESIZE),-s $(SUBPAGESIZE)) \
+--- a/target/linux/mediatek/image/Makefile
++++ b/target/linux/mediatek/image/Makefile
+@@ -16,6 +16,53 @@ define Build/sysupgrade-emmc
+ $(IMAGE_ROOTFS)
+ endef
+
++# build squashfs-hashed
++define Build/squashfs-hashed
++ $(CP) $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME)) $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME))-hashed
++ $(TOPDIR)/scripts/make-squashfs-hashed.sh \
++ $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME))-hashed \
++ $(STAGING_DIR_HOST) \
++ $(TOPDIR) \
++ $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME))-hashed-summary
++ fdt-patch-dm-verify $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME))-hashed-summary \
++ $(KDIR)/image-$(firstword $(DEVICE_DTS)).dtb $(KDIR)/image-sb-$(firstword $(DEVICE_DTS)).dtb \
++ $(HASHED_BOOT_DEVICE)
++endef
++
++# build fw-ar-ver
++get_fw_ar_ver = \
++ $(if $(wildcard $(2)),$(shell rm -rf $(2))) \
++ $(if $(wildcard $(1)),$(info $(shell $(STAGING_DIR_HOST)/bin/ar-tool fw_ar_table create_ar_conf $(1) $(2)))) \
++ $(if $(wildcard $(2)),$(eval include $(2))) \
++ $(if $(FW_AR_VER),$(info FW_AR_VER = $(FW_AR_VER)))
++
++define Build/fw-ar-ver
++ $(call get_fw_ar_ver,$(ANTI_ROLLBACK_TABLE),$(AUTO_AR_CONF))
++endef
++
++# build signed fit
++define Build/fit-sign
++ $(TOPDIR)/scripts/mkits.sh \
++ -D $(DEVICE_NAME) \
++ -o $@.its \
++ -k $@ \
++ $(if $(word 2,$(1)),-d $(word 2,$(1))) -C $(word 1,$(1)) \
++ -a $(KERNEL_LOADADDR) \
++ -e $(if $(KERNEL_ENTRY),$(KERNEL_ENTRY),$(KERNEL_LOADADDR)) \
++ -c $(if $(DEVICE_DTS_CONFIG),$(DEVICE_DTS_CONFIG),"config-1") \
++ -A $(LINUX_KARCH) \
++ -v $(LINUX_VERSION) \
++ $(if $(FIT_KEY_NAME),-S $(FIT_KEY_NAME)) \
++ $(if $(FW_AR_VER),-r $(FW_AR_VER)) \
++ $(if $(CONFIG_TARGET_ROOTFS_SQUASHFS),-R $(ROOTFS/squashfs/$(DEVICE_NAME)))
++ PATH=$(LINUX_DIR)/scripts/dtc:$(PATH) mkimage \
++ -f $@.its \
++ $(if $(FIT_KEY_DIR),-k $(FIT_KEY_DIR)) \
++ -r \
++ $@.new
++ @mv $@.new $@
++endef
++
+ # default all platform image(fit) build
+ define Device/Default
+ PROFILES = Default $$(DEVICE_NAME)
+@@ -29,6 +79,8 @@ define Device/Default
+ IMAGES := sysupgrade.bin
+ IMAGE/sysupgrade.bin := append-kernel | pad-to 128k | append-rootfs | \
+ pad-rootfs | append-metadata
++ FIT_KEY_DIR :=
++ FIT_KEY_NAME :=
+ endef
+
+ include $(SUBTARGET).mk
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0903-sbc-make-dm-mod-dax-built-in.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0903-sbc-make-dm-mod-dax-built-in.patch
new file mode 100644
index 0000000..4bf7bc9
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0903-sbc-make-dm-mod-dax-built-in.patch
@@ -0,0 +1,31 @@
+--- a/package/kernel/linux/modules/block.mk
++++ b/package/kernel/linux/modules/block.mk
+@@ -208,8 +208,7 @@ $(eval $(call KernelPackage,block2mtd))
+ define KernelPackage/dax
+ SUBMENU:=$(BLOCK_MENU)
+ TITLE:=DAX: direct access to differentiated memory
+- KCONFIG:=CONFIG_DAX
+- FILES:=$(LINUX_DIR)/drivers/dax/dax.ko
++ KCONFIG:=CONFIG_DAX=y
+ endef
+
+ $(eval $(call KernelPackage,dax))
+@@ -234,16 +233,15 @@ define KernelPackage/dm
+ CONFIG_DM_SNAPSHOT=n \
+ CONFIG_DM_LOG_USERSPACE=n \
+ CONFIG_MD=y \
+- CONFIG_BLK_DEV_DM \
++ CONFIG_BLK_DEV_DM=y \
+ CONFIG_DM_CRYPT \
+ CONFIG_DM_MIRROR
+ FILES:= \
+- $(LINUX_DIR)/drivers/md/dm-mod.ko \
+ $(LINUX_DIR)/drivers/md/dm-crypt.ko \
+ $(LINUX_DIR)/drivers/md/dm-log.ko \
+ $(LINUX_DIR)/drivers/md/dm-mirror.ko \
+ $(LINUX_DIR)/drivers/md/dm-region-hash.ko
+- AUTOLOAD:=$(call AutoLoad,30,dm-mod dm-log dm-region-hash dm-mirror dm-crypt)
++ AUTOLOAD:=$(call AutoLoad,30,dm-log dm-region-hash dm-mirror dm-crypt)
+ endef
+
+ define KernelPackage/dm/description
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0904-sbc-remove-dm-device-before-sysupgrade.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0904-sbc-remove-dm-device-before-sysupgrade.patch
new file mode 100644
index 0000000..b89ada9
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0904-sbc-remove-dm-device-before-sysupgrade.patch
@@ -0,0 +1,44 @@
+--- a/package/base-files/files/lib/upgrade/nand.sh
++++ b/package/base-files/files/lib/upgrade/nand.sh
+@@ -460,6 +460,11 @@ ubi_do_upgrade() {
+ local dual_boot=$(cat /sys/module/boot_param/parameters/dual_boot 2>/dev/null)
+ local file_type=$(identify $1)
+
++ if [ -b /dev/dm-0 ]; then
++ v "Detach all device mapper devices"
++ dmsetup remove_all
++ fi
++
+ if [ x"${dual_boot}" != xY ]; then
+ nand_do_upgrade "$1"
+ return
+--- a/target/linux/mediatek/base-files/lib/upgrade/mmc.sh
++++ b/target/linux/mediatek/base-files/lib/upgrade/mmc.sh
+@@ -217,6 +217,11 @@ mtk_mmc_do_upgrade_dual_boot() {
+ mtk_mmc_do_upgrade() {
+ local dual_boot=$(cat /sys/module/boot_param/parameters/dual_boot 2>/dev/null)
+
++ if [ -b /dev/dm-0 ]; then
++ v "Detach all device mapper devices"
++ dmsetup remove_all
++ fi
++
+ if [ x"${dual_boot}" = xY ]; then
+ mtk_mmc_do_upgrade_dual_boot "$1"
+ else
+--- a/target/linux/mediatek/mt7981/base-files/lib/upgrade/platform.sh
++++ b/target/linux/mediatek/mt7981/base-files/lib/upgrade/platform.sh
+@@ -1,4 +1,4 @@
+-RAMFS_COPY_BIN='mkfs.f2fs blkid blockdev fw_printenv fw_setenv'
++RAMFS_COPY_BIN='mkfs.f2fs blkid blockdev fw_printenv fw_setenv dmsetup'
+ RAMFS_COPY_DATA="/etc/fw_env.config /var/lock/fw_printenv.lock"
+ platform_do_upgrade() {
+ local board=$(board_name)
+--- a/target/linux/mediatek/mt7986/base-files/lib/upgrade/platform.sh
++++ b/target/linux/mediatek/mt7986/base-files/lib/upgrade/platform.sh
+@@ -1,4 +1,4 @@
+-RAMFS_COPY_BIN='mkfs.f2fs blkid blockdev fw_printenv fw_setenv'
++RAMFS_COPY_BIN='mkfs.f2fs blkid blockdev fw_printenv fw_setenv dmsetup'
+ RAMFS_COPY_DATA="/etc/fw_env.config /var/lock/fw_printenv.lock"
+
+ platform_do_upgrade() {
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0905-fix-boot-up-failed.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0905-fix-boot-up-failed.patch
new file mode 100644
index 0000000..b95cff1
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0905-fix-boot-up-failed.patch
@@ -0,0 +1,22 @@
+Index: lede/target/linux/mediatek/image/Makefile
+===================================================================
+--- lede.orig/target/linux/mediatek/image/Makefile 2023-03-14 10:22:26.601486141 +0800
++++ lede/target/linux/mediatek/image/Makefile 2023-03-14 10:25:01.346275356 +0800
+@@ -18,13 +18,13 @@
+
+ # build squashfs-hashed
+ define Build/squashfs-hashed
+- $(CP) $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME)) $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME))-hashed
++ $(CP) $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME)) $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME))-hashed-$(firstword $(DEVICE_DTS))
+ $(TOPDIR)/scripts/make-squashfs-hashed.sh \
+- $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME))-hashed \
++ $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME))-hashed-$(firstword $(DEVICE_DTS)) \
+ $(STAGING_DIR_HOST) \
+ $(TOPDIR) \
+- $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME))-hashed-summary
+- fdt-patch-dm-verify $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME))-hashed-summary \
++ $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME))-hashed-summary-$(firstword $(DEVICE_DTS))
++ fdt-patch-dm-verify $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME))-hashed-summary-$(firstword $(DEVICE_DTS)) \
+ $(KDIR)/image-$(firstword $(DEVICE_DTS)).dtb $(KDIR)/image-sb-$(firstword $(DEVICE_DTS)).dtb \
+ $(HASHED_BOOT_DEVICE)
+ endef
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0906-fsek-build-host-tool-openssl3.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0906-fsek-build-host-tool-openssl3.patch
new file mode 100644
index 0000000..1305332
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0906-fsek-build-host-tool-openssl3.patch
@@ -0,0 +1,62 @@
+diff --git a/tools/Makefile b/tools/Makefile
+index dc07de7..ccd60a5 100644
+--- a/tools/Makefile
++++ b/tools/Makefile
+@@ -37,6 +37,7 @@ tools-$(CONFIG_TARGET_mxs) += elftosb sdimage
+ tools-$(CONFIG_TARGET_tegra) += cbootimage cbootimage-configs
+ tools-$(CONFIG_USES_MINOR) += kernel2minor
+ tools-$(CONFIG_USE_SPARSE) += sparse
++tools-y += openssl
+
+ # builddir dependencies
+ $(curdir)/autoconf/compile := $(curdir)/m4/compile
+diff --git a/tools/openssl/Makefile b/tools/openssl/Makefile
+new file mode 100644
+index 0000000..087b33f
+--- /dev/null
++++ b/tools/openssl/Makefile
+@@ -0,0 +1,44 @@
++#
++# Copyright (C) 2006-2016 OpenWrt.org
++#
++# This is free software, licensed under the GNU General Public License v2.
++# See /LICENSE for more information.
++#
++
++include $(TOPDIR)/rules.mk
++
++PKG_NAME:=openssl
++PKG_VERSION:=3.0.7
++PKG_RELEASE:=3
++
++PKG_BUILD_PARALLEL:=1
++
++PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
++PKG_SOURCE_URL:= \
++ http://www.openssl.org/source/ \
++ http://ftp.fi.muni.cz/pub/openssl/source/ \
++ ftp://ftp.pca.dfn.de/pub/tools/net/openssl/source/ \
++
++PKG_HASH:=83049d042a260e696f62406ac5c08bf706fd84383f945cf21bd61e9ed95c396e
++
++PKG_LICENSE:=OpenSSL
++PKG_LICENSE_FILES:=LICENSE
++PKG_MAINTAINER:=Eneas U de Queiroz <cotequeiroz@gmail.com>
++PKG_CPE_ID:=cpe:/a:openssl:openssl
++
++include $(INCLUDE_DIR)/host-build.mk
++
++define Host/Configure
++ (cd $(HOST_BUILD_DIR); \
++ ./Configure -no-shared)
++endef
++
++define Host/Install
++ $(CP) $(HOST_BUILD_DIR)/apps/openssl $(STAGING_DIR_HOST)/bin/openssl-$(PKG_RELEASE)
++ mkdir -p $(STAGING_DIR_HOST)/lib/openssl-$(PKG_RELEASE)
++ $(CP) $(HOST_BUILD_DIR)/libssl.a $(STAGING_DIR_HOST)/lib/openssl-$(PKG_RELEASE)
++ $(CP) $(HOST_BUILD_DIR)/libcrypto.a $(STAGING_DIR_HOST)/lib/openssl-$(PKG_RELEASE)
++ ln -sf $(HOST_BUILD_DIR)/include $(STAGING_DIR_HOST)/include/openssl-$(PKG_RELEASE)
++endef
++
++$(eval $(call HostBuild))
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0907-fsek-build-host-tool-aesgcm.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0907-fsek-build-host-tool-aesgcm.patch
new file mode 100644
index 0000000..665f417
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0907-fsek-build-host-tool-aesgcm.patch
@@ -0,0 +1,443 @@
+diff --git a/tools/Makefile b/tools/Makefile
+index ccd60a5..e487530 100644
+--- a/tools/Makefile
++++ b/tools/Makefile
+@@ -38,6 +38,7 @@ tools-$(CONFIG_TARGET_tegra) += cbootimage cbootimage-configs
+ tools-$(CONFIG_USES_MINOR) += kernel2minor
+ tools-$(CONFIG_USE_SPARSE) += sparse
+ tools-y += openssl
++tools-y += aesgcm
+
+ # builddir dependencies
+ $(curdir)/autoconf/compile := $(curdir)/m4/compile
+@@ -76,6 +77,7 @@ $(curdir)/squashfs/compile := $(curdir)/lzma-old/compile
+ $(curdir)/squashfskit4/compile := $(curdir)/xz/compile $(curdir)/zlib/compile
+ $(curdir)/zlib/compile := $(curdir)/cmake/compile
+ $(curdir)/zstd/compile := $(curdir)/cmake/compile
++$(curdir)/aesgcm/compile := $(curdir)/openssl/compile
+
+ ifneq ($(HOST_OS),Linux)
+ $(curdir)/squashfskit4/compile += $(curdir)/coreutils/compile
+diff --git a/tools/aesgcm/Makefile b/tools/aesgcm/Makefile
+new file mode 100644
+index 0000000..f7ffc53
+--- /dev/null
++++ b/tools/aesgcm/Makefile
+@@ -0,0 +1,29 @@
++#
++# Copyright (C) 2022 MediaTek Inc. All rights reserved.
++#
++# This is free software, licensed under the GNU General Public License v2.
++# See /LICENSE for more information.
++#
++include $(TOPDIR)/rules.mk
++
++PKG_NAME:=aesgcm
++PKG_VERSION:=1.0
++
++include $(INCLUDE_DIR)/host-build.mk
++
++define Host/Compile
++ $(MAKE) -C $(HOST_BUILD_DIR) \
++ OPENSSL_INCS_LOCATION=-I$(STAGING_DIR_HOST)/include/openssl-3 \
++ OPENSSL_LIBS_LOCATION=-L$(STAGING_DIR_HOST)/lib/openssl-3
++endef
++
++define Host/Prepare
++ mkdir -p $(HOST_BUILD_DIR)
++ $(CP) -a ./src/* $(HOST_BUILD_DIR)/
++endef
++
++define Host/Install
++ $(CP) $(HOST_BUILD_DIR)/aesgcm $(STAGING_DIR_HOST)/bin/
++endef
++
++$(eval $(call HostBuild))
+diff --git a/tools/aesgcm/src/Makefile b/tools/aesgcm/src/Makefile
+new file mode 100644
+index 0000000..18d2e7b
+--- /dev/null
++++ b/tools/aesgcm/src/Makefile
+@@ -0,0 +1,12 @@
++CFLAGS = $(OPENSSL_INCS_LOCATION)
++LDFLAGS = $(OPENSSL_LIBS_LOCATION) -lssl -lcrypto -ldl -lpthread
++
++all: aesgcm
++
++aesgcm: aesgcm.o
++
++aesgcm:
++ $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
++
++clean:
++ $(RM) aesgcm
+diff --git a/tools/aesgcm/src/aesgcm.c b/tools/aesgcm/src/aesgcm.c
+new file mode 100644
+index 0000000..05aa373
+--- /dev/null
++++ b/tools/aesgcm/src/aesgcm.c
+@@ -0,0 +1,364 @@
++/*
++ * Copyright 2022 Mediatek Inc. All Rights Reserved.
++ *
++ * Licensed under the Apache License 2.0 (the "License"). You may not use
++ * this file except in compliance with the License. You can obtain a copy
++ * in the file LICENSE in the source distribution or at
++ * https://www.openssl.org/source/license.html
++ */
++
++/*
++ * Simple AES GCM authenticated encryption with additional data (AEAD)
++ * demonstration program.
++ */
++
++#include <stdlib.h>
++#include <stddef.h>
++#include <string.h>
++#include <unistd.h>
++#include <openssl/err.h>
++#include <openssl/bio.h>
++#include <openssl/evp.h>
++#include <openssl/core_names.h>
++
++#define MAX_TEXT_LENGTH 4096
++#define MAX_AAD_LENGTH 256
++#define MAX_TAG_LENGTH 32
++
++#define ERR_ENC 1
++#define ERR_DEC 2
++#define ERR_UNK_MOD 3
++
++typedef enum {
++ UNK,
++ ENCRYPT,
++ DECRYPT
++} OPERATION;
++
++/*
++ * A library context and property query can be used to select & filter
++ * algorithm implementations. If they are NULL then the default library
++ * context and properties are used.
++ */
++OSSL_LIB_CTX *libctx = NULL;
++const char *propq = NULL;
++
++int aes_gcm_encrypt(uint8_t *key, uint8_t *iv, long iv_len, uint8_t *aad,
++ long aad_len, uint8_t *pt, long pt_len, BIO *out)
++{
++ int ret = 0;
++ EVP_CIPHER_CTX *ctx;
++ EVP_CIPHER *cipher = NULL;
++ int outlen, tmplen;
++ uint8_t *outbuf;
++ uint8_t *outtag[16];
++ OSSL_PARAM params[2] = {
++ OSSL_PARAM_END, OSSL_PARAM_END
++ };
++
++ outbuf = calloc(MAX_TEXT_LENGTH, sizeof(uint8_t));
++ if (!outbuf)
++ return 0;
++
++ /* Create a context for the encrypt operation */
++ if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
++ goto err;
++
++ /* Fetch the cipher implementation */
++ if ((cipher = EVP_CIPHER_fetch(libctx, "AES-256-GCM", propq)) == NULL)
++ goto err;
++
++ /* Set IV length if default 96 bits is not appropriate */
++ params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_AEAD_IVLEN,
++ &iv_len);
++ /*
++ * Initialise an encrypt operation with the cipher/mode, key, IV and
++ * IV length parameter.
++ * For demonstration purposes the IV is being set here. In a compliant
++ * application the IV would be generated internally so the iv passed in
++ * would be NULL.
++ */
++ if (!EVP_EncryptInit_ex2(ctx, cipher, key, iv, params))
++ goto err;
++
++ /* Zero or more calls to specify any AAD */
++ if (!EVP_EncryptUpdate(ctx, NULL, &outlen, aad, aad_len))
++ goto err;
++
++ /* Encrypt plaintext */
++ if (!EVP_EncryptUpdate(ctx, outbuf, &outlen, pt, pt_len))
++ goto err;
++
++ /* Finalise: note get no output for GCM */
++ if (!EVP_EncryptFinal_ex(ctx, outbuf, &tmplen))
++ goto err;
++
++ /* Get tag */
++ params[0] = OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG,
++ outtag, 16);
++
++ if (!EVP_CIPHER_CTX_get_params(ctx, params))
++ goto err;
++
++ /* Output IV */
++ if (BIO_write(out, iv, iv_len) <= 0)
++ goto err;
++
++ /* Output tag */
++ if (BIO_write(out, outtag, 16) <= 0)
++ goto err;
++
++ /* Output encrypted block */
++ if (BIO_write(out, outbuf, outlen) <= 0)
++ goto err;
++
++ ret = 1;
++err:
++ if (!ret)
++ ERR_print_errors_fp(stderr);
++
++ free(outbuf);
++ EVP_CIPHER_free(cipher);
++ EVP_CIPHER_CTX_free(ctx);
++
++ return ret;
++}
++
++int aes_gcm_decrypt(uint8_t *key, uint8_t *iv, long iv_len,
++ uint8_t *aad, long aad_len, uint8_t *ct, long ct_len,
++ uint8_t *tag, long tag_len, BIO *out)
++{
++ int ret = 0;
++ EVP_CIPHER_CTX *ctx;
++ EVP_CIPHER *cipher = NULL;
++ int outlen, rv;
++ uint8_t *outbuf;
++ OSSL_PARAM params[2] = {
++ OSSL_PARAM_END, OSSL_PARAM_END
++ };
++
++ outbuf = calloc(MAX_TEXT_LENGTH, sizeof(uint8_t));
++ if (!outbuf)
++ return 0;
++
++ if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
++ goto err;
++
++ /* Fetch the cipher implementation */
++ if ((cipher = EVP_CIPHER_fetch(libctx, "AES-256-GCM", propq)) == NULL)
++ goto err;
++
++ /* Set IV length if default 96 bits is not appropriate */
++ params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_AEAD_IVLEN,
++ &iv_len);
++
++ /*
++ * Initialise an encrypt operation with the cipher/mode, key, IV and
++ * IV length parameter.
++ */
++ if (!EVP_DecryptInit_ex2(ctx, cipher, key, iv, params))
++ goto err;
++
++ /* Zero or more calls to specify any AAD */
++ if (!EVP_DecryptUpdate(ctx, NULL, &outlen, aad, aad_len))
++ goto err;
++
++ /* Decrypt plaintext */
++ if (!EVP_DecryptUpdate(ctx, outbuf, &outlen, ct, ct_len))
++ goto err;
++
++ /* Output decrypted block */
++ if (BIO_write(out, outbuf, outlen) <= 0)
++ goto err;
++
++ /* Set expected tag value. */
++ params[0] = OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG,
++ (void *)tag, tag_len);
++
++ if (!EVP_CIPHER_CTX_set_params(ctx, params))
++ goto err;
++
++ /* Finalise: note get no output for GCM */
++ rv = EVP_DecryptFinal_ex(ctx, outbuf, &outlen);
++ /*
++ * Print out return value. If this is not successful authentication
++ * failed and plaintext is not trustworthy.
++ */
++ printf("Tag Verify %s\n", rv > 0 ? "Successful!" : "Failed!");
++
++ ret = rv > 0 ? 1 : 0;
++err:
++ if (!ret)
++ ERR_print_errors_fp(stderr);
++
++ free(outbuf);
++ EVP_CIPHER_free(cipher);
++ EVP_CIPHER_CTX_free(ctx);
++
++ return ret;
++}
++
++void usage(void)
++{
++ printf(
++ "simple aes-256-gcm tool: \n"
++ "Operations:\n"
++ "-e - encrypt\n"
++ "-d - decrypt\n"
++ "Common requirement parameters:\n"
++ "-i infile - input file\n"
++ "-o outfile - out file\n"
++ "-k key(hex) - key in hex\n"
++ "-n iv(hex) - initial vector in hex\n"
++ "-a aad(hex) - additional authentication data in hex\n"
++ "Decryption requirement paremters:\n"
++ "-t intagfile - tag file as input\n");
++}
++
++int main(int argc, char **argv)
++{
++ int ret = 0, opt, oper = UNK;
++ long key_len = 0, iv_len = 0, aad_len = 0, tag_len = 0, in_len = 0;
++ BIO *in = NULL, *out = NULL, *in_tag = NULL;
++ uint8_t *in_buf;
++ uint8_t key[EVP_MAX_KEY_LENGTH] = {0};
++ uint8_t iv[EVP_MAX_IV_LENGTH] = {0};
++ uint8_t aad[MAX_AAD_LENGTH] = {0};
++ uint8_t tag[MAX_TAG_LENGTH] = {0};
++
++ in_buf = calloc(MAX_TEXT_LENGTH, sizeof(uint8_t));
++ if (!in_buf)
++ return -ENOMEM;
++
++ while ((opt = getopt(argc, argv, "a:dei:g:k:n:o:t:")) > 0) {
++ switch(opt) {
++ case 'a':
++ ret = OPENSSL_hexstr2buf_ex(aad, MAX_AAD_LENGTH,
++ &aad_len, optarg, '\0');
++ if (!ret) {
++ ret = -EINVAL;
++ fprintf(stderr, "Failed to read aad\n");
++ goto end;
++ }
++ break;
++ case 'd':
++ if (oper) {
++ ret = -EINVAL;
++ fprintf(stderr, "Duplicate operations\n");
++ goto end;
++ }
++ oper = DECRYPT;
++ break;
++ case 'e':
++ if (oper) {
++ ret = -EINVAL;
++ fprintf(stderr, "Duplicate operations\n");
++ goto end;
++ }
++ oper = ENCRYPT;
++ break;
++ case 'i':
++ in = BIO_new_file(optarg, "rb");
++ if (!in) {
++ ret = -EINVAL;
++ fprintf(stderr, "Failed to open input file\n");
++ goto end;
++ }
++
++ in_len = BIO_read(in, in_buf, MAX_TEXT_LENGTH);
++ if (in_len <= 0) {
++ ret = -EINVAL;
++ fprintf(stderr, "Failed to read input file\n");
++ goto end;
++ }
++ break;
++ case 'k':
++ ret = OPENSSL_hexstr2buf_ex(key, EVP_MAX_KEY_LENGTH,
++ &key_len, optarg, '\0');
++ if (!ret) {
++ ret = -EINVAL;
++ fprintf(stderr, "Failed to read key\n");
++ goto end;
++ }
++ break;
++ case 'n':
++ ret = OPENSSL_hexstr2buf_ex(iv, EVP_MAX_IV_LENGTH,
++ &iv_len, optarg, '\0');
++ if (!ret) {
++ ret = -EINVAL;
++ fprintf(stderr, "Failed to read iv\n");
++ goto end;
++ }
++ break;
++ case 'o':
++ out = BIO_new_file(optarg, "w");
++ if (!out) {
++ ret = -EINVAL;
++ fprintf(stderr, "Failed to open output file\n");
++ goto end;
++ }
++ break;
++ case 't':
++ in_tag = BIO_new_file(optarg, "rb");
++ if (!in_tag) {
++ ret = -EINVAL;
++ fprintf(stderr, "Failed to open tag file\n");
++ goto end;
++ }
++
++ tag_len = BIO_read(in_tag, tag, MAX_TAG_LENGTH);
++ if (tag_len <= 0) {
++ ret = -EINVAL;
++ fprintf(stderr, "Failed to read tag file\n");
++ goto end;
++ }
++ break;
++ default:
++ break;
++ }
++
++ }
++
++ if (!key_len || !iv_len || !aad_len || !in_len || !out) {
++ ret = -EINVAL;
++ goto end;
++ }
++
++ if (oper == ENCRYPT) {
++ ret = aes_gcm_encrypt(key, iv, iv_len, aad, aad_len,
++ in_buf, in_len, out);
++ if (!ret) {
++ ret = -ERR_ENC;
++ goto end;
++ }
++ } else if (oper == DECRYPT) {
++ if (!tag_len) {
++ ret = -EINVAL;
++ goto end;
++ }
++
++ ret = aes_gcm_decrypt(key, iv, iv_len, aad, aad_len,
++ in_buf, in_len, tag, tag_len, out);
++ if (!ret) {
++ ret = -ERR_DEC;
++ goto end;
++ }
++ } else {
++ ret = -ERR_UNK_MOD;
++ goto end;
++ }
++
++end:
++ free(in_buf);
++ if (in)
++ BIO_free(in);
++ if (out)
++ BIO_free(out);
++ if (in_tag)
++ BIO_free(in_tag);
++
++ if (ret == -EINVAL)
++ usage();
++
++ return ret;
++}
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0907-fsek-build-host-tools.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0907-fsek-build-host-tools.patch
new file mode 100644
index 0000000..9f2cdd2
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0907-fsek-build-host-tools.patch
@@ -0,0 +1,53 @@
+diff --git a/package/Makefile b/package/Makefile
+index 392d773..15af01b 100644
+--- a/package/Makefile
++++ b/package/Makefile
+@@ -62,6 +62,7 @@ ifndef SDK
+ $(curdir)/compile: $(curdir)/system/opkg/host/compile
+ endif
+ $(curdir)/compile: $(curdir)/cryptsetup/host/compile
++$(curdir)/compile: $(curdir)/dtc/host/compile
+
+ $(curdir)/install: $(TMP_DIR)/.build $(curdir)/merge $(if $(CONFIG_TARGET_PER_DEVICE_ROOTFS),$(curdir)/merge-index)
+ - find $(STAGING_DIR_ROOT) -type d | $(XARGS) chmod 0755
+diff --git a/package/utils/dtc/Makefile b/package/utils/dtc/Makefile
+index deec4e3..88ad84c 100644
+--- a/package/utils/dtc/Makefile
++++ b/package/utils/dtc/Makefile
+@@ -16,7 +16,10 @@ PKG_INSTALL:=1
+ PKG_MAINTAINER:=Yousong Zhou <yszhou4tech@gmail.com>
+
+ include $(INCLUDE_DIR)/package.mk
++include $(INCLUDE_DIR)/host-build.mk
+
++HOST_BUILD_PREFIX:=$(STAGING_DIR_HOST)
++HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/$(PKG_NAME)-$(PKG_VERSION)
+
+ define Package/dtc
+ SECTION:=utils
+@@ -87,6 +90,13 @@ define Build/InstallDev
+ $(CP) $(PKG_INSTALL_DIR)/lib/* $(1)/usr/lib
+ endef
+
++define Host/Install
++ $(CP) $(HOST_BUILD_DIR)/libfdt/libfdt*.so* $(STAGING_DIR_HOST)/lib/
++ $(CP) $(HOST_BUILD_DIR)/fdtget $(STAGING_DIR_HOST)/bin/
++ $(CP) $(HOST_BUILD_DIR)/fdtput $(STAGING_DIR_HOST)/bin/
++endef
++
+ $(eval $(call BuildPackage,dtc))
+ $(eval $(call BuildPackage,fdt-utils))
+ $(eval $(call BuildPackage,libfdt))
++$(eval $(call HostBuild))
+diff --git a/feeds/packages/utils/cryptsetup/Makefile b/feeds/packages/utils/cryptsetup/Makefile
+index 6d5264d..25553df 100644
+--- a/feeds/packages/utils/cryptsetup/Makefile
++++ b/feeds/packages/utils/cryptsetup/Makefile
+@@ -113,6 +113,7 @@ endef
+
+ define Host/Install
+ $(INSTALL_BIN) $(HOST_BUILD_DIR)/veritysetup $(STAGING_DIR_HOST)/bin/veritysetup
++ $(INSTALL_BIN) $(HOST_BUILD_DIR)/cryptsetup $(STAGING_DIR_HOST)/bin/cryptsetup
+ $(CP) $(HOST_BUILD_DIR)/.libs $(STAGING_DIR_HOST)/bin/
+ endef
+
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0908-fsek-build-libuboot-envtools.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0908-fsek-build-libuboot-envtools.patch
new file mode 100644
index 0000000..1863f6e
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0908-fsek-build-libuboot-envtools.patch
@@ -0,0 +1,15 @@
+diff --git a/package/boot/uboot-envtools/Makefile b/package/boot/uboot-envtools/Makefile
+index a9eccec..0728b88 100644
+--- a/package/boot/uboot-envtools/Makefile
++++ b/package/boot/uboot-envtools/Makefile
+@@ -76,4 +76,10 @@ define Package/uboot-envtools/install
+ )
+ endef
+
++define Build/InstallDev
++ ln -sf $(PKG_BUILD_DIR)/include $(STAGING_DIR)/usr/include/u-boot
++ $(CP) $(PKG_BUILD_DIR)/tools/env/lib.a $(STAGING_DIR)/usr/lib/libuboot-envtools.a
++ $(CP) $(PKG_BUILD_DIR)/tools/env/fw_env.h $(STAGING_DIR)/usr/include/fw_env.h
++endef
++
+ $(eval $(call BuildPackage,uboot-envtools))
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0909-fsek-setup-host-scripts.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0909-fsek-setup-host-scripts.patch
new file mode 100644
index 0000000..27f455e
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0909-fsek-setup-host-scripts.patch
@@ -0,0 +1,349 @@
+diff --git a/scripts/enc-rfsk.sh b/scripts/enc-rfsk.sh
+new file mode 100755
+index 0000000..d396127
+--- /dev/null
++++ b/scripts/enc-rfsk.sh
+@@ -0,0 +1,194 @@
++#!/bin/bash
++# use roe-key to encrypt rootfs-key, and generate fit-secret
++usage() {
++ printf "Usage: %s -s build_dir -d key_dir -f fit" "$(basename "$0")"
++ printf "encrypt rootfs key: [-k roe_key] "
++ printf "generate FIT-secret: [-k roe_key -c config_name]\n"
++ printf "\n\t-c ==> config name with signature node"
++ printf "\n\t-d ==> key_directory"
++ printf "\n\t-f ==> fit image file"
++ printf "\n\t-k ==> roe key"
++ printf "\n\t-s ==> build directory"
++ exit 1
++}
++
++hex2bin() {
++ $PERL -e 'print pack "H*", <STDIN>'
++}
++
++bin2hex() {
++ od -An -t x1 -w128 | sed "s/ //g"
++}
++
++hkdf() {
++ local key=$1
++ local info=$2
++ local salt=$3
++ local k_derived=$(${OPENSSL} kdf -keylen 32 -kdfopt digest:SHA2-256 \
++ -kdfopt hexkey:$(cat ${key} | bin2hex) \
++ -kdfopt hexsalt:$salt \
++ -kdfopt info:$info HKDF | sed "s/://g")
++ echo $k_derived
++}
++
++gen_aes_key() {
++ out=$1
++ $OPENSSL rand -out $out 32
++}
++
++aes_cbc_enc() {
++ local in=$1
++ local out=$2
++ local key=$3
++ local iv=$(${OPENSSL} rand -hex 16)
++ $OPENSSL enc -e -aes-256-cbc -in $in -out ${out}.tmp -K $key -iv $iv
++
++ echo -n $iv | hex2bin > $out
++ cat ${out}.tmp >> $out
++ rm ${out}.tmp
++}
++
++aes_gcm_enc() {
++ local in=$1
++ local out=$2
++ local key=$3
++ local aad=$4
++ local iv=$(${OPENSSL} rand -hex 12)
++ $AESGCM -e -i $in -o $out -k $key -n $iv -a $aad
++}
++
++# encrypt data with AES
++# encrypted-data-format:
++# -----------------------------------------------
++# | salt | iv | k-tempx.enc | iv | tag | in.enc |
++# -----------------------------------------------
++enc_data() {
++ local k_temp=$1
++ local in=$2
++ local out=$3
++ local info=$4
++ local salt=$(${OPENSSL} rand -hex 16)
++
++ echo -n $salt | hex2bin > $out
++
++ # encrypt k-tempx
++ aes_cbc_enc $k_temp ${out}.tmp $(hkdf ${ROE_KEY}.key ${info} ${salt})
++
++ cat ${out}.tmp >> $out
++
++ aad=$(cat ${out} | bin2hex)
++ # encrypt in
++ aes_gcm_enc $in ${out}.tmp $(cat $k_temp | bin2hex) $aad
++
++ cat ${out}.tmp >> $out
++ rm ${out}.tmp
++}
++
++# generate FIT-secret and insert back into FIT
++gen_fit_secret() {
++ echo "Generating fit-secret"
++
++ if [ ! -f "${FIT}" ]; then
++ printf "%s not found\n" "${FIT}"
++ exit 1
++ fi
++
++ SECRETS_DIR=$BUILD_DIR/fit-secrets
++ if [ ! -d "${SECRETS_DIR}" ]; then
++ mkdir -p $SECRETS_DIR
++ fi
++
++ LD_LIBRARY_PATH=${LIBFDT_PATH} \
++ $FDTGET $FIT /configurations/$CONFIG/signature value -t bi > \
++ $SECRETS_DIR/$FIT_NAME-signature.tmp || exit 1
++
++ echo -n $(cat ${SECRETS_DIR}/${FIT_NAME}-signature.tmp) | xargs printf "%02x" | \
++ hex2bin > $SECRETS_DIR/$FIT_NAME-signature.raw
++
++ $OPENSSL dgst -sha256 -binary -out $SECRETS_DIR/$FIT_NAME-signature.hash \
++ $SECRETS_DIR/$FIT_NAME-signature.raw || exit 1
++
++ gen_aes_key $KEY_DIR/${TEMP2_KEY_NAME}.key
++
++ enc_data $KEY_DIR/${TEMP2_KEY_NAME}.key \
++ $SECRETS_DIR/$FIT_NAME-signature.hash \
++ $SECRETS_DIR/$FIT_NAME-secret.enc \
++ fit-secret
++
++ LD_LIBRARY_PATH=${LIBFDT_PATH} \
++ $FDTPUT -c -p $FIT /fit-secrets/$CONFIG || exit 1
++ LD_LIBRARY_PATH=${LIBFDT_PATH} \
++ $FDTPUT $FIT /fit-secrets/$CONFIG algo -t s "sha256"
++ LD_LIBRARY_PATH=${LIBFDT_PATH} \
++ $FDTPUT $FIT /fit-secrets/$CONFIG data -t x \
++ $(cat ${SECRETS_DIR}/${FIT_NAME}-secret.enc | bin2hex | \
++ sed 's/ //g; s/.\{8\}/0x& /g; s/.$//g')
++}
++
++# encrypt rootfs key
++enc_rfsk() {
++ echo "Encrypting rootfs key"
++
++ gen_aes_key $KEY_DIR/${ROOTFS_KEY_NAME}.key
++ gen_aes_key $KEY_DIR/${TEMP1_KEY_NAME}.key
++
++ enc_data $KEY_DIR/${TEMP1_KEY_NAME}.key \
++ $KEY_DIR/${ROOTFS_KEY_NAME}.key \
++ $BUILD_DIR/${FIT_NAME}-rfsk.enc \
++ k-rootfs
++}
++
++while getopts "c:d:f:k:s:" OPTION
++do
++ case $OPTION in
++ c ) CONFIG=$OPTARG;;
++ d ) KEY_DIR=$OPTARG;;
++ f ) FIT=$OPTARG;;
++ k ) ROE_KEY=$OPTARG;;
++ s ) BUILD_DIR=$OPTARG;;
++ * ) echo "Invalid option passed to '$0' (options:$*)"
++ usage;;
++ esac
++done
++
++if [ ! -d "${KEY_DIR}" ]; then
++ echo "key directory not found"
++ usage;
++fi
++
++if [ ! -d "${BUILD_DIR}" ]; then
++ echo "build directory not found"
++ usage;
++fi
++
++if [ -z "${FIT}" ]; then
++ echo "FIT name is empty"
++ usage;
++fi
++
++if [ -z "${BIN}" ]; then
++ echo "bin directory not found"
++ exit 1
++fi
++
++if [ ! -f "${ROE_KEY}".key ]; then
++ echo "roe-key not found"
++ usage;
++fi
++
++OPENSSL=$BIN/openssl-3
++AESGCM=$BIN/aesgcm
++PERL=$BIN/perl
++FDTGET=$BIN/fdtget
++FDTPUT=$BIN/fdtput
++
++FIT_NAME=$(basename ${FIT} | sed "s/\.[^.]*$//g")
++ROOTFS_KEY_NAME=${FIT_NAME}-rootfs-key
++TEMP1_KEY_NAME=${FIT_NAME}-temp1-key
++TEMP2_KEY_NAME=${FIT_NAME}-temp2-key
++
++if [ ! -z "${CONFIG}" ]; then
++ gen_fit_secret;
++else
++ enc_rfsk;
++fi
+diff --git a/scripts/fdt-patch-dm-crypt.sh b/scripts/fdt-patch-dm-crypt.sh
+new file mode 100755
+index 0000000..9ad87c7
+--- /dev/null
++++ b/scripts/fdt-patch-dm-crypt.sh
+@@ -0,0 +1,26 @@
++# !/bin/bash
++FDTGET=$BIN/fdtget
++FDTPUT=$BIN/fdtput
++PERL=$BIN/perl
++
++FDT=$1
++SUMMARY=$2
++BOOTARGS=$(LD_LIBRARY_PATH=${LIBFDT_PATH} \
++ ${FDTGET} ${FDT} /chosen bootargs | sed "s/\"*$/;/g")
++DEVICE_PATH=$(echo -n ${BOOTARGS} | grep -o "root=/dev/dm-[0-9]\+" | \
++ grep -o "/dev/dm-[0-9]\+")
++DEVICE_NUM=$(echo -n ${DEVICE_PATH} | grep -o "[0-9]\+")
++BOOTARGS=$(echo -n ${BOOTARGS} | \
++ sed "s/root=\/dev\/dm-${DEVICE_NUM}/root=\/dev\/dm-$((DEVICE_NUM+1))/g")
++DATABLOCKS_NUM=$(cat ${SUMMARY} | grep "Data blocks:" | grep -o "[0-9]\+")
++CIPHER="aes-xts-plain64"
++KEY=$(${PERL} -E 'say "0" x 64')
++IV_OFFSET=0
++OFFSET=0
++
++NEW_BOOTARGS=$( printf '%sdm-crypt,,,ro,0 %d crypt %s %s %d %s %d"' \
++ "${BOOTARGS}" $((DATABLOCKS_NUM*8)) ${CIPHER} ${KEY} \
++ ${IV_OFFSET} ${DEVICE_PATH} ${OFFSET} )
++
++LD_LIBRARY_PATH=${LIBFDT_PATH}
++$FDTPUT $FDT /chosen bootargs -t s "${NEW_BOOTARGS}" || exit 1
+diff --git a/scripts/make-squashfs-encrypted.sh b/scripts/make-squashfs-encrypted.sh
+new file mode 100755
+index 0000000..9bb522b
+--- /dev/null
++++ b/scripts/make-squashfs-encrypted.sh
+@@ -0,0 +1,37 @@
++# !/bin/bash
++ROOTFS=$1
++ENCRYPTED_ROOTFS=$2
++ROOTFS_KEY_DIR=$3
++TARGET_DEVICE=$4
++
++if [ -z "${BIN}" ]; then
++ echo "bin directory not found"
++ exit 1
++fi
++
++CRYPTSETUP=$BIN/cryptsetup
++DEVICE_NAME=$(basename ${TARGET_DEVICE} | sed "s/\.[^.]*$//g")
++ROOTFS_KEY=${ROOTFS_KEY_DIR}/${DEVICE_NAME}-rootfs-key.key
++if [ ! -f "${ROOTFS}" ] || [ -z "${ENCRYPTED_ROOTFS}" ] ||
++ [ ! -f "${ROOTFS_KEY}" ] || [ -z "${DEVICE_NAME}" ]; then
++ exit 1
++fi
++
++FILE_SIZE=`stat -c "%s" ${ROOTFS}`
++BLOCK_SIZE=4096
++DATA_BLOCKS=$((${FILE_SIZE} / ${BLOCK_SIZE}))
++[ $((${FILE_SIZE} % ${BLOCK_SIZE})) -ne 0 ] && DATA_BLOCKS=$((${DATA_BLOCKS} + 1))
++
++# create container
++dd if=/dev/zero of=$ENCRYPTED_ROOTFS bs=4096 count=$DATA_BLOCKS
++
++# mapping encrypted device
++sudo $CRYPTSETUP open --type=plain --cipher=aes-xts-plain64 --key-size=256 \
++ --key-file=$ROOTFS_KEY $ENCRYPTED_ROOTFS ${DEVICE_NAME}
++
++# encrypt squashfs
++sudo dd if=$ROOTFS of=/dev/mapper/${DEVICE_NAME}
++
++# close mapping device
++sudo $CRYPTSETUP close /dev/mapper/${DEVICE_NAME}
++
+diff --git a/scripts/mkits.sh b/scripts/mkits.sh
+index 1c7f292..26bcf70 100755
+--- a/scripts/mkits.sh
++++ b/scripts/mkits.sh
+@@ -17,7 +17,7 @@
+ usage() {
+ printf "Usage: %s -A arch -C comp -a addr -e entry" "$(basename "$0")"
+ printf " -v version -k kernel [-D name -n address -d dtb] -o its_file"
+- printf " [-s script] [-S key_name_hint] [-r ar_ver] [-R rootfs]"
++ printf " [-s script] [-S key_name_hint] [-r ar_ver] [-R rootfs] [-m rfsk]"
+
+ printf "\n\t-A ==> set architecture to 'arch'"
+ printf "\n\t-C ==> set compression type 'comp'"
+@@ -33,13 +33,14 @@ usage() {
+ printf "\n\t-s ==> include u-boot script 'script'"
+ printf "\n\t-S ==> add signature at configurations and assign its key_name_hint by 'key_name_hint'"
+ printf "\n\t-r ==> set anti-rollback version to 'fw_ar_ver' (dec)"
+- printf "\n\t-R ==> specify rootfs file for embedding hash\n"
++ printf "\n\t-R ==> specify rootfs file for embedding hash"
++ printf "\n\t-m ==> include encrypted rootfs key'\n"
+ exit 1
+ }
+
+ FDTNUM=1
+
+-while getopts ":A:a:c:C:D:d:e:k:n:o:v:s:S:r:R:" OPTION
++while getopts ":A:a:c:C:D:d:e:k:n:o:v:s:S:r:R:m:" OPTION
+ do
+ case $OPTION in
+ A ) ARCH=$OPTARG;;
+@@ -57,6 +58,7 @@ do
+ S ) KEY_NAME_HINT=$OPTARG;;
+ r ) AR_VER=$OPTARG;;
+ R ) ROOTFS_FILE=$OPTARG;;
++ m ) ROOTFS_KEY=$OPTARG;;
+ * ) echo "Invalid option passed to '$0' (options:$*)"
+ usage;;
+ esac
+@@ -91,6 +93,19 @@ if [ -n "${DTB}" ]; then
+ FDT_PROP="fdt = \"fdt-$FDTNUM\";"
+ fi
+
++# Conditionally create encrypted rootfs-key information
++if [ -n "${ROOTFS_KEY}" ]; then
++ RFSK_NODE="
++ rfsk = <$(cat ${ROOTFS_KEY} | od -An -t x1 -w256 | sed 's/ //g; s/.\{8\}/0x& /g; s/.$//g')>;";
++
++ FIT_SECRET_NODE="
++ fit-secrets {
++ ${CONFIG} {
++ };
++ };
++"
++fi
++
+ # Conditionally create rootfs hash information
+ if [ -f "${ROOTFS_FILE}" ]; then
+ ROOTFS_SIZE=$(stat -c %s ${ROOTFS_FILE})
+@@ -200,12 +215,15 @@ ${ROOTFS}
+ ${CONFIG} {
+ description = \"OpenWrt\";
+ ${FW_AR_VER}
++${RFSK_NODE}
+ ${LOADABLES}
+ kernel = \"kernel-1\";
+ ${FDT_PROP}
+ ${SIGNATURE}
+ };
+ };
++
++${FIT_SECRET_NODE}
+ };"
+
+ # Write .its file to disk
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0910-fsek-encrypt-rfsk-and-patch-dm-crypt.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0910-fsek-encrypt-rfsk-and-patch-dm-crypt.patch
new file mode 100644
index 0000000..7aca849
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0910-fsek-encrypt-rfsk-and-patch-dm-crypt.patch
@@ -0,0 +1,100 @@
+diff --git a/include/image.mk b/include/image.mk
+index 92d343c..f93fb01 100644
+--- a/include/image.mk
++++ b/include/image.mk
+@@ -440,6 +440,8 @@ else
+ DEVICE_CHECK_PROFILE = $(CONFIG_TARGET_$(if $(CONFIG_TARGET_MULTI_PROFILE),DEVICE_)$(call target_conf,$(BOARD)$(if $(SUBTARGET),_$(SUBTARGET)))_$(1))
+ endif
+
++ROOTFS_ENCRYPT = $(if $(ROE_KEY_DIR),$(wildcard $(ROE_KEY_DIR)/$(ROE_KEY_NAME).key),)
++
+ DEVICE_CHECK_FIT_KEY = $(if $(wildcard $(FIT_KEY_DIR)/$(FIT_KEY_NAME).key),install-images,install-disabled)
+ DEVICE_CHECK_FIT_DIR = $(if $(FIT_KEY_DIR),$(DEVICE_CHECK_FIT_KEY),install-images)
+
+diff --git a/target/linux/mediatek/image/Makefile b/target/linux/mediatek/image/Makefile
+index 20e5977..52c266e 100644
+--- a/target/linux/mediatek/image/Makefile
++++ b/target/linux/mediatek/image/Makefile
+@@ -16,6 +16,14 @@ define Build/sysupgrade-emmc
+ $(IMAGE_ROOTFS)
+ endef
+
++define Build/fdt-patch-dm-crypt
++ BIN=$(STAGING_DIR_HOST)/bin \
++ LIBFDT_PATH=$(STAGING_DIR_HOST)/lib \
++ $(TOPDIR)/scripts/fdt-patch-dm-crypt.sh \
++ $(KDIR)/image-sb-$(firstword $(DEVICE_DTS)).dtb \
++ $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME))-hashed-summary-$(firstword $(DEVICE_DTS))
++endef
++
+ # build squashfs-hashed
+ define Build/squashfs-hashed
+ $(CP) $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME)) $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME))-hashed-$(firstword $(DEVICE_DTS))
+@@ -27,6 +35,7 @@ define Build/squashfs-hashed
+ fdt-patch-dm-verify $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME))-hashed-summary-$(firstword $(DEVICE_DTS)) \
+ $(KDIR)/image-$(firstword $(DEVICE_DTS)).dtb $(KDIR)/image-sb-$(firstword $(DEVICE_DTS)).dtb \
+ $(HASHED_BOOT_DEVICE)
++ $(if $(ROOTFS_ENCRYPT),$(call Build/fdt-patch-dm-crypt))
+ endef
+
+ # build fw-ar-ver
+@@ -40,6 +49,30 @@ define Build/fw-ar-ver
+ $(call get_fw_ar_ver,$(ANTI_ROLLBACK_TABLE),$(AUTO_AR_CONF))
+ endef
+
++define Build/rfsk-encrypt
++ BIN=$(STAGING_DIR_HOST)/bin \
++ $(TOPDIR)/scripts/enc-rfsk.sh \
++ -d $(ROE_KEY_DIR) \
++ -f $@ \
++ -k $(ROE_KEY_DIR)/$(ROE_KEY_NAME) \
++ -s $(dir $@)
++endef
++
++define Build/fit-secret
++ BIN=$(STAGING_DIR_HOST)/bin \
++ LIBFDT_PATH=$(STAGING_DIR_HOST)/lib \
++ $(TOPDIR)/scripts/enc-rfsk.sh \
++ -c "config-1" \
++ -d $(ROE_KEY_DIR) \
++ -f $@ \
++ -k $(ROE_KEY_DIR)/$(ROE_KEY_NAME) \
++ -s $(dir $@)
++endef
++
++define Build/rootfs-encrypt
++ $(if $(ROOTFS_ENCRYPT),$(call Build/rfsk-encrypt))
++endef
++
+ # build signed fit
+ define Build/fit-sign
+ $(TOPDIR)/scripts/mkits.sh \
+@@ -54,13 +87,18 @@ define Build/fit-sign
+ -v $(LINUX_VERSION) \
+ $(if $(FIT_KEY_NAME),-S $(FIT_KEY_NAME)) \
+ $(if $(FW_AR_VER),-r $(FW_AR_VER)) \
+- $(if $(CONFIG_TARGET_ROOTFS_SQUASHFS),-R $(ROOTFS/squashfs/$(DEVICE_NAME)))
++ $(if $(CONFIG_TARGET_ROOTFS_SQUASHFS), \
++ $(if $(ROOTFS_ENCRYPT), \
++ -R $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME))-hashed-$(firstword $(DEVICE_DTS)), \
++ -R $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME)))) \
++ $(if $(ROOTFS_ENCRYPT),-m $(addsuffix -rfsk.enc,$(basename $@)))
+ PATH=$(LINUX_DIR)/scripts/dtc:$(PATH) mkimage \
+ -f $@.its \
+ $(if $(FIT_KEY_DIR),-k $(FIT_KEY_DIR)) \
+ -r \
+ $@.new
+ @mv $@.new $@
++ $(if $(ROOTFS_ENCRYPT),$(call Build/fit-secret))
+ endef
+
+ # default all platform image(fit) build
+@@ -78,6 +116,8 @@ define Device/Default
+ pad-rootfs | append-metadata
+ FIT_KEY_DIR :=
+ FIT_KEY_NAME :=
++ ROE_KEY_DIR :=
++ ROE_KEY_NAME :=
+ endef
+
+ include $(SUBTARGET).mk
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0911-fsek-encrypt-rootfs.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0911-fsek-encrypt-rootfs.patch
new file mode 100644
index 0000000..3c39aef
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0911-fsek-encrypt-rootfs.patch
@@ -0,0 +1,35 @@
+diff --git a/target/linux/mediatek/image/Makefile b/target/linux/mediatek/image/Makefile
+index 52c266e..36deb6f 100644
+--- a/target/linux/mediatek/image/Makefile
++++ b/target/linux/mediatek/image/Makefile
+@@ -24,9 +24,21 @@ define Build/fdt-patch-dm-crypt
+ $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME))-hashed-summary-$(firstword $(DEVICE_DTS))
+ endef
+
++define Build/squashfs-encrypt
++ BIN=$(STAGING_DIR_HOST)/bin \
++ $(TOPDIR)/scripts/make-squashfs-encrypted.sh \
++ $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME)) \
++ $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME))-encrypted-$(firstword $(DEVICE_DTS)) \
++ $(ROE_KEY_DIR) \
++ $@
++endef
++
+ # build squashfs-hashed
+ define Build/squashfs-hashed
+- $(CP) $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME)) $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME))-hashed-$(firstword $(DEVICE_DTS))
++ $(CP) $(if $(ROOTFS_ENCRYPT), \
++ $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME))-encrypted-$(firstword $(DEVICE_DTS)), \
++ $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME))) \
++ $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME))-hashed-$(firstword $(DEVICE_DTS))
+ $(TOPDIR)/scripts/make-squashfs-hashed.sh \
+ $(ROOTFS/$(FILESYSTEMS)/$(DEVICE_NAME))-hashed-$(firstword $(DEVICE_DTS)) \
+ $(STAGING_DIR_HOST) \
+@@ -71,6 +83,7 @@ endef
+
+ define Build/rootfs-encrypt
+ $(if $(ROOTFS_ENCRYPT),$(call Build/rfsk-encrypt))
++ $(if $(ROOTFS_ENCRYPT),$(call Build/squashfs-encrypt))
+ endef
+
+ # build signed fit
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0912-sbc-upgrade-mkimage-to-2022-07.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0912-sbc-upgrade-mkimage-to-2022-07.patch
new file mode 100644
index 0000000..59b3cbe
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0912-sbc-upgrade-mkimage-to-2022-07.patch
@@ -0,0 +1,239 @@
+--- a/tools/libressl/Makefile
++++ b/tools/libressl/Makefile
+@@ -8,8 +8,8 @@
+ include $(TOPDIR)/rules.mk
+
+ PKG_NAME:=libressl
+-PKG_VERSION:=3.4.3
+-PKG_HASH:=ff88bffe354818b3ccf545e3cafe454c5031c7a77217074f533271d63c37f08d
++PKG_VERSION:=3.5.3
++PKG_HASH:=3ab5e5eaef69ce20c6b170ee64d785b42235f48f2e62b095fca5d7b6672b8b28
+ PKG_RELEASE:=1
+
+ PKG_CPE_ID:=cpe:/a:openbsd:libressl
+@@ -24,11 +24,14 @@ HOST_BUILD_PARALLEL:=1
+ include $(INCLUDE_DIR)/host-build.mk
+
+ HOSTCC := $(HOSTCC_NOCACHE)
+-HOST_CONFIGURE_ARGS += --enable-static --disable-shared --disable-tests
++
+ HOST_CFLAGS += $(HOST_FPIC)
+
+-ifeq ($(GNU_HOST_NAME),x86_64-linux-gnux32)
+-HOST_CONFIGURE_ARGS += --disable-asm
+-endif
++HOST_CONFIGURE_ARGS += \
++ --enable-static \
++ --disable-shared \
++ --disable-asm \
++ --with-pic \
++ --disable-tests
+
+ $(eval $(call HostBuild))
+--- a/tools/Makefile
++++ b/tools/Makefile
+@@ -59,7 +59,7 @@ $(curdir)/libtool/compile := $(curdir)/m
+ $(curdir)/lzma-old/compile := $(curdir)/zlib/compile
+ $(curdir)/make-ext4fs/compile := $(curdir)/zlib/compile
+ $(curdir)/missing-macros/compile := $(curdir)/autoconf/compile
+-$(curdir)/mkimage/compile += $(curdir)/libressl/compile
++$(curdir)/mkimage/compile += $(curdir)/bison/compile $(curdir)/libressl/compile
+ $(curdir)/mklibs/compile := $(curdir)/libtool/compile
+ $(curdir)/mm-macros/compile := $(curdir)/libtool/compile
+ $(curdir)/mpc/compile := $(curdir)/mpfr/compile $(curdir)/gmp/compile
+--- a/tools/mkimage/Makefile
++++ b/tools/mkimage/Makefile
+@@ -7,36 +7,36 @@
+ include $(TOPDIR)/rules.mk
+
+ PKG_NAME:=mkimage
+-PKG_VERSION:=2021.01
++PKG_VERSION:=2022.07
+
+ PKG_SOURCE:=u-boot-$(PKG_VERSION).tar.bz2
+ PKG_SOURCE_URL:= \
+ https://mirror.cyberbits.eu/u-boot \
+ https://ftp.denx.de/pub/u-boot \
+ ftp://ftp.denx.de/pub/u-boot
+-PKG_HASH:=b407e1510a74e863b8b5cb42a24625344f0e0c2fc7582d8c866bd899367d0454
++PKG_HASH:=92b08eb49c24da14c1adbf70a71ae8f37cc53eeb4230e859ad8b6733d13dcf5e
+
+ HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/u-boot-$(PKG_VERSION)
+
+ include $(INCLUDE_DIR)/host-build.mk
+
+-define Host/Prepare
+- $(Host/Prepare/Default)
+- mkdir -p $(HOST_BUILD_DIR)/include/config
+- touch $(HOST_BUILD_DIR)/include/config/auto.conf
+- mkdir -p $(HOST_BUILD_DIR)/include/generated/
+- touch $(HOST_BUILD_DIR)/include/generated/autoconf.h
++define Host/Configure
++ $(MAKE) -C $(HOST_BUILD_DIR) \
++ HOSTCFLAGS="$(HOST_CFLAGS)" \
++ HOSTLDFLAGS="$(HOST_LDFLAGS)" \
++ PKG_CONFIG_EXTRAARGS="--static" \
++ V=$(if $(findstring c,$(OPENWRT_VERBOSE)),1) \
++ tools-only_config
++
++ sed -i 's/CONFIG_TOOLS_MKEFICAPSULE=y/# CONFIG_TOOLS_MKEFICAPSULE is not set/' $(HOST_BUILD_DIR)/.config
+ endef
+
+ define Host/Compile
+ $(MAKE) -C $(HOST_BUILD_DIR) \
+ HOSTCFLAGS="$(HOST_CFLAGS)" \
+ HOSTLDFLAGS="$(HOST_LDFLAGS)" \
+- no-dot-config-targets=tools-only \
+- CONFIG_MKIMAGE_DTC_PATH=dtc \
+- CONFIG_FIT=y \
+- CONFIG_FIT_SIGNATURE=y \
+- CONFIG_FIT_SIGNATURE_MAX_SIZE=0x10000000 \
++ PKG_CONFIG_EXTRAARGS="--static" \
++ V=$(if $(findstring c,$(OPENWRT_VERBOSE)),1) \
+ tools-only
+ endef
+
+--- a/tools/mkimage/patches/030-allow-to-use-different-magic.patch
++++ b/tools/mkimage/patches/030-allow-to-use-different-magic.patch
+@@ -2,7 +2,7 @@ This patch makes it possible to set a cu
+
+ --- a/tools/mkimage.c
+ +++ b/tools/mkimage.c
+-@@ -21,6 +21,7 @@ static struct image_tool_params params =
++@@ -25,6 +25,7 @@ static struct image_tool_params params =
+ .arch = IH_ARCH_PPC,
+ .type = IH_TYPE_KERNEL,
+ .comp = IH_COMP_GZIP,
+@@ -10,8 +10,8 @@ This patch makes it possible to set a cu
+ .dtc = MKIMAGE_DEFAULT_DTC_OPTIONS,
+ .imagename = "",
+ .imagename2 = "",
+-@@ -82,11 +83,12 @@ static void usage(const char *msg)
+- " -l ==> list image header information\n",
++@@ -88,11 +89,12 @@ static void usage(const char *msg)
++ " -q ==> quiet\n",
+ params.cmdname);
+ fprintf(stderr,
+ - " %s [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image\n"
+@@ -24,16 +24,16 @@ This patch makes it possible to set a cu
+ " -a ==> set load address to 'addr' (hex)\n"
+ " -e ==> set entry point to 'ep' (hex)\n"
+ " -n ==> set image name to 'name'\n"
+-@@ -150,7 +152,7 @@ static void process_args(int argc, char
++@@ -163,7 +165,7 @@ static void process_args(int argc, char
+ int opt;
+
+ while ((opt = getopt(argc, argv,
+-- "a:A:b:B:c:C:d:D:e:Ef:Fk:i:K:ln:N:p:O:rR:qstT:vVx")) != -1) {
+-+ "a:A:b:B:c:C:d:D:e:Ef:Fk:i:K:lM:n:N:p:O:rR:qstT:vVx")) != -1) {
++- "a:A:b:B:c:C:d:D:e:Ef:FG:k:i:K:ln:N:p:o:O:rR:qstT:vVx")) != -1) {
+++ "a:A:b:B:c:C:d:D:e:Ef:FG:k:i:K:lM:n:N:p:o:O:rR:qstT:vVx")) != -1) {
+ switch (opt) {
+ case 'a':
+ params.addr = strtoull(optarg, &ptr, 16);
+-@@ -237,6 +239,14 @@ static void process_args(int argc, char
++@@ -254,6 +256,14 @@ static void process_args(int argc, char
+ case 'l':
+ params.lflag = 1;
+ break;
+@@ -61,7 +61,7 @@ This patch makes it possible to set a cu
+ image_set_load(hdr, addr);
+ --- a/tools/imagetool.h
+ +++ b/tools/imagetool.h
+-@@ -56,6 +56,7 @@ struct image_tool_params {
++@@ -59,6 +59,7 @@ struct image_tool_params {
+ int arch;
+ int type;
+ int comp;
+--- a/tools/mkimage/patches/050-Add-compatibility-with-non-Linux-hosts.patch
++++ b/tools/mkimage/patches/050-Add-compatibility-with-non-Linux-hosts.patch
+@@ -15,11 +15,9 @@ __u64 is not available on FreeBSD, remov
+ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+ ---
+ include/image.h | 2 ++
+- include/imx8image.h | 5 +++++
+ include/linux/posix_types.h | 2 ++
+ include/linux/types.h | 4 +++-
+- lib/rsa/rsa-sign.c | 2 +-
+- 5 files changed, 13 insertions(+), 2 deletions(-)
++ 3 files changed, 7 insertions(+), 1 deletion(-)
+
+ --- a/include/image.h
+ +++ b/include/image.h
+--- a/tools/mkimage/patches/090-macos-arm64-builing-fix.patch
++++ /dev/null
+@@ -1,47 +0,0 @@
+-This patch fixes compilation issues on MacOS arm64.
+-Based on discussion
+-https://github.com/u-boot/u-boot/commit/3b142045e8a7f0ab17b6099e9226296af45967d0
+-
+-diff --git a/Makefile b/Makefile
+-index b4f1cbc..551041f 100644
+---- a/Makefile
+-+++ b/Makefile
+-@@ -324,11 +324,6 @@ HOSTCC = $(call os_x_before, 10, 5, "cc", "gcc")
+- KBUILD_HOSTCFLAGS += $(call os_x_before, 10, 4, "-traditional-cpp")
+- KBUILD_HOSTLDFLAGS += $(call os_x_before, 10, 5, "-multiply_defined suppress")
+-
+--# since Lion (10.7) ASLR is on by default, but we use linker generated lists
+--# in some host tools which is a problem then ... so disable ASLR for these
+--# tools
+--KBUILD_HOSTLDFLAGS += $(call os_x_before, 10, 7, "", "-Xlinker -no_pie")
+--
+- # macOS Mojave (10.14.X)
+- # Undefined symbols for architecture x86_64: "_PyArg_ParseTuple"
+- KBUILD_HOSTLDFLAGS += $(call os_x_after, 10, 14, "-lpython -dynamclib", "")
+-diff --git a/tools/imagetool.h b/tools/imagetool.h
+-index 8726792..d1b72ef 100644
+---- a/tools/imagetool.h
+-+++ b/tools/imagetool.h
+-@@ -270,17 +270,20 @@ int rockchip_copy_image(int fd, struct image_tool_params *mparams);
+- * b) we need a API call to get the respective section symbols */
+- #if defined(__MACH__)
+- #include <mach-o/getsect.h>
+-+#include <mach-o/dyld.h>
+-
+- #define INIT_SECTION(name) do { \
+- unsigned long name ## _len; \
+-- char *__cat(pstart_, name) = getsectdata("__TEXT", \
+-+ char *__cat(pstart_, name) = getsectdata("__DATA", \
+- #name, &__cat(name, _len)); \
+-+ __cat(pstart_, name) += \
+-+ _dyld_get_image_vmaddr_slide(0); \
+- char *__cat(pstop_, name) = __cat(pstart_, name) + \
+- __cat(name, _len); \
+- __cat(__start_, name) = (void *)__cat(pstart_, name); \
+- __cat(__stop_, name) = (void *)__cat(pstop_, name); \
+- } while (0)
+--#define SECTION(name) __attribute__((section("__TEXT, " #name)))
+-+#define SECTION(name) __attribute__((section("__DATA, " #name)))
+-
+- struct image_type_params **__start_image_type, **__stop_image_type;
+- #else
+--- /dev/null
++++ b/tools/mkimage/patches/095-tools-disable-TOOLS_FIT_FULL_CHECK.patch
+@@ -0,0 +1,24 @@
++From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
++From: Huangbin Zhan <zhanhb88@gmail.com>
++Date: Fri, 18 Feb 2022 14:19:23 +0800
++Subject: [PATCH] tools: disable TOOLS_FIT_FULL_CHECK
++
++ U-Boot disallows unit addresses by default. Disable TOOLS_FIT_FULL_CHECK
++ to allow at symbol in node names.
++
++https://github.com/openwrt/openwrt/commits/master/scripts/mkits.sh
++https://github.com/u-boot/u-boot/commit/3f04db891a353f4b127ed57279279f851c6b4917
++---
++ tools/Kconfig | 2 +-
++ 1 file changed, 1 insertion(+), 1 deletion(-)
++
++--- a/tools/Kconfig
+++++ b/tools/Kconfig
++@@ -31,7 +31,7 @@ config TOOLS_FIT
++ Enable FIT support in the tools builds.
++
++ config TOOLS_FIT_FULL_CHECK
++- def_bool y
+++ bool "Do a full check of the FIT"
++ help
++ Do a full check of the FIT before using it in the tools builds
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0913-sbc-add-offline-sign-support.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0913-sbc-add-offline-sign-support.patch
new file mode 100644
index 0000000..191eb53
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0913-sbc-add-offline-sign-support.patch
@@ -0,0 +1,428 @@
+--- a/include/image.mk
++++ b/include/image.mk
+@@ -443,7 +443,10 @@ endif
+ ROOTFS_ENCRYPT = $(if $(ROE_KEY_DIR),$(wildcard $(ROE_KEY_DIR)/$(ROE_KEY_NAME).key),)
+
+ DEVICE_CHECK_FIT_KEY = $(if $(wildcard $(FIT_KEY_DIR)/$(FIT_KEY_NAME).key),install-images,install-disabled)
+-DEVICE_CHECK_FIT_DIR = $(if $(FIT_KEY_DIR),$(DEVICE_CHECK_FIT_KEY),install-images)
++DEVICE_CHECK_FIT_DIR = $(if $(FIT_KEY_DIR),$(DEVICE_CHECK_FIT_KEY),install-disabled)
++
++DEVICE_CHECK_OFFLINE_FIT_KEY = $(if $(filter offline%,$(FIT_KEY_NAME)),install-images,$(DEVICE_CHECK_FIT_DIR))
++DEVICE_CHECK_FIT_KEY_NAME = $(if $(FIT_KEY_NAME),$(DEVICE_CHECK_OFFLINE_FIT_KEY),install-images)
+
+ DEVICE_EXTRA_PACKAGES = $(call qstrip,$(CONFIG_TARGET_DEVICE_PACKAGES_$(call target_conf,$(BOARD)$(if $(SUBTARGET),_$(SUBTARGET)))_DEVICE_$(1)))
+
+@@ -467,7 +470,7 @@ endef
+ define Device/Check
+ $(Device/Check/Common)
+ KDIR_KERNEL_IMAGE := $(KDIR)/$(1)$$(KERNEL_SUFFIX)
+- _TARGET := $$(if $$(_PROFILE_SET),$$(DEVICE_CHECK_FIT_DIR),install-disabled)
++ _TARGET := $$(if $$(_PROFILE_SET),$$(DEVICE_CHECK_FIT_KEY_NAME),install-disabled)
+ ifndef IB
+ _COMPILE_TARGET := $$(if $(CONFIG_IB)$$(_PROFILE_SET),compile,compile-disabled)
+ endif
+--- a/scripts/mkits.sh
++++ b/scripts/mkits.sh
+@@ -164,11 +164,17 @@ fi
+
+ # Conditionally create signature information
+ if [ -n "${KEY_NAME_HINT}" ]; then
++ if [[ "${KEY_NAME_HINT}" == "offline,"* ]]; then
++ KEY_NAME_HINT=$(echo -n "${KEY_NAME_HINT}" | sed "s/^.*[,]//g")
++ SIGN_OFFLINE="
++ sign-offline = <1>;"
++ fi
+ SIGNATURE="\
+ signature {
+ algo = \"sha1,rsa2048\";
+ key-name-hint = \"${KEY_NAME_HINT}\";
+ ${SIGN_IMAGES}
++${SIGN_OFFLINE}
+ };\
+ "
+ fi
+--- /dev/null
++++ b/tools/mkimage/patches/901-mtk-mkimage-add-offline-sign-support.patch
+@@ -0,0 +1,382 @@
++--- a/tools/image-host.c
+++++ b/tools/image-host.c
++@@ -168,6 +168,9 @@ static int fit_image_setup_sig(struct im
++ {
++ const char *node_name;
++ const char *padding_name;
+++ const char *offline;
+++ const char offline_suffix[] = ",offline";
+++ char *offline_algo_name = NULL;
++
++ node_name = fit_get_name(fit, noffset, NULL);
++ if (!algo_name) {
++@@ -188,7 +191,21 @@ static int fit_image_setup_sig(struct im
++ info->node_offset = noffset;
++ info->name = strdup(algo_name);
++ info->checksum = image_get_checksum_algo(algo_name);
++- info->crypto = image_get_crypto_algo(algo_name);
+++
+++ offline = fdt_getprop(fit, noffset, "sign-offline", NULL);
+++ if (offline) {
+++ offline_algo_name = calloc(strlen(algo_name) + strlen(offline_suffix) + 1, sizeof(char));
+++ if (!offline_algo_name)
+++ return -ENOMEM;
+++
+++ strcpy(offline_algo_name, algo_name);
+++ strcat(offline_algo_name, offline_suffix);
+++
+++ info->crypto = image_get_crypto_algo(offline_algo_name);
+++ } else {
+++ info->crypto = image_get_crypto_algo(algo_name);
+++ }
+++
++ info->padding = image_get_padding_algo(padding_name);
++ info->require_keys = require_keys;
++ info->engine_id = engine_id;
++--- a/tools/image-sig-host.c
+++++ b/tools/image-sig-host.c
++@@ -11,6 +11,7 @@
++ #include <u-boot/ecdsa.h>
++ #include <u-boot/rsa.h>
++ #include <u-boot/hash-checksum.h>
+++#include "signoffline.h"
++
++ struct checksum_algo checksum_algos[] = {
++ {
++@@ -76,6 +77,27 @@ struct crypto_algo crypto_algos[] = {
++ .add_verify_data = ecdsa_add_verify_data,
++ .verify = ecdsa_verify,
++ },
+++ {
+++ .name = "rsa2048,offline",
+++ .key_len = RSA2048_BYTES,
+++ .sign = offline_sign,
+++ .add_verify_data = rsa_add_verify_data,
+++ .verify = offline_verify,
+++ },
+++ {
+++ .name = "rsa3072,offline",
+++ .key_len = RSA3072_BYTES,
+++ .sign = offline_sign,
+++ .add_verify_data = rsa_add_verify_data,
+++ .verify = offline_verify,
+++ },
+++ {
+++ .name = "rsa4096,offline",
+++ .key_len = RSA4096_BYTES,
+++ .sign = offline_sign,
+++ .add_verify_data = rsa_add_verify_data,
+++ .verify = offline_verify,
+++ },
++ };
++
++ struct padding_algo padding_algos[] = {
++--- a/tools/Makefile
+++++ b/tools/Makefile
++@@ -89,6 +89,8 @@ RSA_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := $(
++ rsa-sign.o rsa-verify.o \
++ rsa-mod-exp.o)
++
+++SIGNOFFLINE_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := signoffline.o
+++
++ ECDSA_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := $(addprefix lib/ecdsa/, ecdsa-libcrypto.o)
++
++ AES_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := $(addprefix lib/aes/, \
++@@ -149,7 +151,8 @@ dumpimage-mkimage-objs := aisimage.o \
++ mtk_image.o \
++ $(ECDSA_OBJS-y) \
++ $(RSA_OBJS-y) \
++- $(AES_OBJS-y)
+++ $(AES_OBJS-y) \
+++ $(SIGNOFFLINE_OBJS-y)
++
++ dumpimage-objs := $(dumpimage-mkimage-objs) dumpimage.o
++ mkimage-objs := $(dumpimage-mkimage-objs) mkimage.o
++--- /dev/null
+++++ b/tools/signoffline.h
++@@ -0,0 +1,18 @@
+++// SPDX-License-Identifier: GPL-2.0+
+++/*
+++ * Copyright (C) 2022 MediaTek Incorporation. All Rights Reserved.
+++ *
+++ */
+++
+++#ifndef SIGNOFFLINE_H_
+++#define SIGNOFFLINE_H_
+++
+++int offline_sign(struct image_sign_info *info,
+++ const struct image_region region[], int region_count,
+++ uint8_t **sigp, uint *sig_len);
+++
+++int offline_verify(struct image_sign_info *info,
+++ const struct image_region region[], int region_count,
+++ uint8_t *sig, uint sig_len);
+++
+++#endif /* SIGNOFFLINE_H_ */
++--- /dev/null
+++++ b/tools/signoffline.c
++@@ -0,0 +1,264 @@
+++// SPDX-License-Identifier: GPL-2.0+
+++/*
+++ * Copyright (C) 2022 MediaTek Incorporation. All Rights Reserved.
+++ *
+++ */
+++#include <stdio.h>
+++#include <stdint.h>
+++#include <image.h>
+++#include <linux/libfdt.h>
+++#include <malloc.h>
+++#include <u-boot/sha512.h>
+++#include "mkimage.h"
+++
+++#define OFFSIGN_MSG_FILE ".msg"
+++#define OFFSIGN_SIG_FILE ".sig"
+++#define OFFSIGN_MAX_TMPFILE_LEN 256
+++#define OFFSIGN_MAX_CMDLINE_LEN 3 * OFFSIGN_MAX_TMPFILE_LEN + 128 + 1
+++#define OPENSSL_PKEYUTL_CMD "openssl pkeyutl"
+++#define OPENSSL_PKEYUTL_OPER "-sign"
+++#define OPENSSL_PKEYUTL_PADDING "-pkeyopt rsa_padding_mode"
+++#define OPENSSL_PKEYUTL_SALT "-pkeyopt rsa_pss_saltlen:32"
+++
+++static char img_prefix[OFFSIGN_MAX_TMPFILE_LEN];
+++
+++static int get_fit_identifier(const void *fit, char *img_prefix)
+++{
+++ int ret = 0;
+++ int noffset = 0;
+++ int img_noffset = 0;
+++ int len = 0;
+++ const char *prop = NULL;
+++ char *p = NULL, *end_p = NULL;
+++
+++ img_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
+++ if (img_noffset < 0) {
+++ fprintf(stderr, "Can't find image parent node: %s\n", FIT_IMAGES_PATH);
+++ return img_noffset;
+++ }
+++
+++ noffset = fdt_subnode_offset(fit, img_noffset, "fdt-1");
+++ if (noffset < 0) {
+++ fprintf(stderr, "Can't find fdt-1 node in %s\n", FIT_IMAGES_PATH);
+++ return noffset;
+++ }
+++
+++ prop = fdt_getprop(fit, noffset, FIT_DESC_PROP, &len);
+++ if (!prop) {
+++ fprintf(stderr, "Can't find %s property in node: fdt-1\n", FIT_DESC_PROP);
+++ return -EINVAL;
+++ }
+++
+++ /* find FIT image name as tmpfile prefix */
+++ p = strstr(prop, "OpenWrt ");
+++ if (!p)
+++ return -EINVAL;
+++
+++ p = strchr(p, ' ');
+++ if (!p)
+++ return -EINVAL;
+++ p += 1;
+++
+++ end_p = strchr(p, ' ');
+++ if (!end_p)
+++ return -EINVAL;
+++
+++ if ((end_p - p) >= OFFSIGN_MAX_TMPFILE_LEN)
+++ return -EINVAL;
+++
+++ strncpy(img_prefix, p, end_p - p);
+++
+++ return ret;
+++}
+++
+++static int prepare_offline_sign(struct image_sign_info *info,
+++ const struct image_region region[],
+++ int region_count)
+++{
+++ int ret = 0;
+++ size_t len = 0;
+++ FILE *f = NULL;
+++ char msg_file[OFFSIGN_MAX_TMPFILE_LEN] = {0};
+++ uint8_t checksum[SHA512_SUM_LEN] = {0};
+++
+++ ret = get_fit_identifier(info->fit, img_prefix);
+++ if (ret)
+++ return ret;
+++
+++ len = snprintf(msg_file, sizeof(msg_file),
+++ "%s/%s%s", info->keydir, img_prefix, OFFSIGN_MSG_FILE);
+++ if (len < 0)
+++ return -EINVAL;
+++
+++ /* calculate digest */
+++ ret = info->checksum->calculate(info->checksum->name, region,
+++ region_count, checksum);
+++ if (ret) {
+++ fprintf(stderr, "Failed to calculate checksum of regions\n");
+++ return ret;
+++ }
+++
+++ /* write message to be signed to msg_file */
+++ f = fopen(msg_file, "w");
+++ if (!f) {
+++ fprintf(stderr, "Failed to open %s\n", msg_file);
+++ return -EINVAL;
+++ }
+++
+++ len = fwrite(checksum, sizeof(uint8_t),
+++ info->checksum->checksum_len, f);
+++ if (len < 0) {
+++ fprintf(stderr, "Failed to write to %s\n", msg_file);
+++ ret = -EINVAL;
+++ }
+++
+++ fclose(f);
+++
+++ return ret;
+++}
+++
+++static int sign_offline(struct image_sign_info *info,
+++ const struct image_region region[],
+++ int region_count,
+++ uint8_t **sigp, uint *sig_len)
+++{
+++ int ret = 0;
+++ size_t len = 0;
+++ char cmd[OFFSIGN_MAX_CMDLINE_LEN] = {0};
+++ char padding[8] = {0};
+++
+++ /* check padding */
+++ if (info->padding && !strcmp(info->padding->name, "pss"))
+++ strncpy(padding, "pss", sizeof(padding));
+++ else
+++ strncpy(padding, "pkcs1", sizeof(padding));
+++
+++ len = snprintf(cmd, sizeof(cmd),
+++ "%s %s -in %s/%s%s -inkey %s/%s.key -out %s/%s%s -pkeyopt digest:%s %s:%s",
+++ OPENSSL_PKEYUTL_CMD,
+++ OPENSSL_PKEYUTL_OPER,
+++ info->keydir,
+++ img_prefix,
+++ OFFSIGN_MSG_FILE,
+++ info->keydir,
+++ info->keyname,
+++ info->keydir,
+++ img_prefix,
+++ OFFSIGN_SIG_FILE,
+++ info->checksum->name,
+++ OPENSSL_PKEYUTL_PADDING,
+++ padding);
+++ if (len < 0)
+++ return -EINVAL;
+++
+++ if (!strcmp(padding, "pss")) {
+++ len = snprintf(cmd + len, sizeof(cmd), "%s", OPENSSL_PKEYUTL_SALT);
+++ if (len < 0)
+++ return -EINVAL;
+++ }
+++
+++ printf("%s\n", cmd);
+++
+++ /* execute openssl command */
+++ if (system(cmd) == -1) {
+++ fprintf(stderr,"%s: failed to sign FIT\n", OPENSSL_PKEYUTL_CMD);
+++ return -EINVAL;
+++ }
+++
+++ return ret;
+++}
+++
+++static int post_offline_sign(struct image_sign_info *info,
+++ uint8_t **sigp, uint *sig_len)
+++{
+++ int ret = 0;
+++ FILE *f = NULL;
+++ size_t len = 0;
+++ void *sig = NULL;
+++ char sig_file[OFFSIGN_MAX_TMPFILE_LEN] = {0};
+++
+++ len = snprintf(sig_file, sizeof(sig_file),
+++ "%s/%s%s", info->keydir, img_prefix, OFFSIGN_SIG_FILE);
+++ if (len < 0)
+++ return -EINVAL;
+++
+++ /* read signature from sig_file */
+++ f = fopen(sig_file, "rb");
+++ if (!f) {
+++ fprintf(stderr, "Failed to open %s\n", sig_file);
+++ return -EINVAL;
+++ }
+++
+++ sig = calloc(info->crypto->key_len, sizeof(uint8_t));
+++ if (!sig) {
+++ ret = -ENOMEM;
+++ goto post_offline_sign_err;
+++ }
+++
+++ len = fread(sig, sizeof(uint8_t), info->crypto->key_len, f);
+++ if (len < 0) {
+++ fprintf(stderr, "Failed to read from %s\n", sig_file);
+++ ret = -EINVAL;
+++ goto post_offline_sign_err;
+++ }
+++
+++ if (len != info->crypto->key_len) {
+++ fprintf(stderr, "Signature length is invalid\n");
+++ ret = -EINVAL;
+++ goto post_offline_sign_err;
+++ }
+++
+++ fclose(f);
+++
+++ *sigp = sig;
+++ *sig_len= info->crypto->key_len;
+++
+++ return 0;
+++
+++post_offline_sign_err:
+++ fclose(f);
+++ if (sig)
+++ free(sig);
+++
+++ return ret;
+++}
+++
+++int offline_sign(struct image_sign_info *info,
+++ const struct image_region region[], int region_count,
+++ uint8_t **sigp, uint *sig_len)
+++{
+++ int ret = 0;
+++
+++ printf("%s:\n", __func__);
+++
+++ ret = prepare_offline_sign(info, region, region_count);
+++ if (ret) {
+++ fprintf(stderr, "prepare_offline_sign() failed\n");
+++ return -EINVAL;
+++ }
+++
+++ ret = sign_offline(info, region, region_count, sigp, sig_len);
+++ if (ret) {
+++ fprintf(stderr, "sign_offline() failed\n");
+++ return -EINVAL;
+++ }
+++
+++ ret = post_offline_sign(info, sigp, sig_len);
+++ if (ret) {
+++ fprintf(stderr, "post_offline_sign() failed\n");
+++ return -EINVAL;
+++ }
+++
+++ return ret;
+++}
+++
+++int offline_verify(struct image_sign_info *info,
+++ const struct image_region region[], int region_count,
+++ uint8_t *sig, uint sig_len)
+++{
+++ int ret = 0;
+++
+++ printf("%s:\n", __func__);
+++
+++ return ret;
+++}
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0914-sbc-add-key-algo-option.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0914-sbc-add-key-algo-option.patch
new file mode 100644
index 0000000..9694e8a
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0914-sbc-add-key-algo-option.patch
@@ -0,0 +1,65 @@
+--- a/scripts/mkits.sh
++++ b/scripts/mkits.sh
+@@ -17,7 +17,7 @@
+ usage() {
+ printf "Usage: %s -A arch -C comp -a addr -e entry" "$(basename "$0")"
+ printf " -v version -k kernel [-D name -n address -d dtb] -o its_file"
+- printf " [-s script] [-S key_name_hint] [-r ar_ver] [-R rootfs] [-m rfsk]"
++ printf " [-s script] [-S key_name_hint] [-b key_alg] [-r ar_ver] [-R rootfs] [-m rfsk]"
+
+ printf "\n\t-A ==> set architecture to 'arch'"
+ printf "\n\t-C ==> set compression type 'comp'"
+@@ -32,6 +32,7 @@ usage() {
+ printf "\n\t-o ==> create output file 'its_file'"
+ printf "\n\t-s ==> include u-boot script 'script'"
+ printf "\n\t-S ==> add signature at configurations and assign its key_name_hint by 'key_name_hint'"
++ printf "\n\t-b ==> set key algorithm"
+ printf "\n\t-r ==> set anti-rollback version to 'fw_ar_ver' (dec)"
+ printf "\n\t-R ==> specify rootfs file for embedding hash"
+ printf "\n\t-m ==> include encrypted rootfs key'\n"
+@@ -40,11 +41,12 @@ usage() {
+
+ FDTNUM=1
+
+-while getopts ":A:a:c:C:D:d:e:k:n:o:v:s:S:r:R:m:" OPTION
++while getopts ":A:a:b:c:C:D:d:e:k:n:o:v:s:S:r:R:m:" OPTION
+ do
+ case $OPTION in
+ A ) ARCH=$OPTARG;;
+ a ) LOAD_ADDR=$OPTARG;;
++ b ) KEY_ALG=$OPTARG;;
+ c ) CONFIG=$OPTARG;;
+ C ) COMPRESS=$OPTARG;;
+ D ) DEVICE=$OPTARG;;
+@@ -169,9 +171,12 @@ if [ -n "${KEY_NAME_HINT}" ]; then
+ SIGN_OFFLINE="
+ sign-offline = <1>;"
+ fi
++ if [ -z "${KEY_ALG}" ]; then
++ KEY_ALG="sha256,rsa2048"
++ fi
+ SIGNATURE="\
+ signature {
+- algo = \"sha1,rsa2048\";
++ algo = \"${KEY_ALG}\";
+ key-name-hint = \"${KEY_NAME_HINT}\";
+ ${SIGN_IMAGES}
+ ${SIGN_OFFLINE}
+--- a/target/linux/mediatek/image/Makefile
++++ b/target/linux/mediatek/image/Makefile
+@@ -99,6 +99,7 @@ define Build/fit-sign
+ -A $(LINUX_KARCH) \
+ -v $(LINUX_VERSION) \
+ $(if $(FIT_KEY_NAME),-S $(FIT_KEY_NAME)) \
++ $(if $(FIT_KEY_ALG),-b $(FIT_KEY_ALG)) \
+ $(if $(FW_AR_VER),-r $(FW_AR_VER)) \
+ $(if $(CONFIG_TARGET_ROOTFS_SQUASHFS), \
+ $(if $(ROOTFS_ENCRYPT), \
+@@ -129,6 +130,7 @@ define Device/Default
+ pad-rootfs | append-metadata
+ FIT_KEY_DIR :=
+ FIT_KEY_NAME :=
++ FIT_KEY_ALG :=
+ ROE_KEY_DIR :=
+ ROE_KEY_NAME :=
+ endef
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0915-append-opteenode-in-kernel-dtb.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0915-append-opteenode-in-kernel-dtb.patch
new file mode 100644
index 0000000..c07f99a
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/0915-append-opteenode-in-kernel-dtb.patch
@@ -0,0 +1,27 @@
+--- a/target/linux/mediatek/image/Makefile
++++ b/target/linux/mediatek/image/Makefile
+@@ -86,6 +86,24 @@ define Build/rootfs-encrypt
+ $(if $(ROOTFS_ENCRYPT),$(call Build/squashfs-encrypt))
+ endef
+
++define append-opteenode
++ LD_LIBRARY_PATH=$(STAGING_DIR_HOST)/lib \
++ fdtput $(1) "/reserved-memory/secmon@43000000" -tx reg 0 0x43000000 0 0x11f0000
++ LD_LIBRARY_PATH=$(STAGING_DIR_HOST)/lib \
++ fdtput $(1) /firmware -cp
++ LD_LIBRARY_PATH=$(STAGING_DIR_HOST)/lib \
++ fdtput $(1) /firmware/optee -cp
++ LD_LIBRARY_PATH=$(STAGING_DIR_HOST)/lib \
++ fdtput $(1) /firmware/optee -ts compatible "linaro,optee-tz"
++ LD_LIBRARY_PATH=$(STAGING_DIR_HOST)/lib \
++ fdtput $(1) /firmware/optee -ts method "smc"
++ LD_LIBRARY_PATH=$(STAGING_DIR_HOST)/lib \
++ fdtput $(1) /firmware/optee -ts status "okay"
++endef
++
++define Build/append-opteenode
++ $(if $(CONFIG_PACKAGE_optee-mediatek),$(call append-opteenode, $(1)))
++endef
+ # build signed fit
+ define Build/fit-sign
+ $(TOPDIR)/scripts/mkits.sh \
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/8000-uboot-mediatek-makefile.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/8000-uboot-mediatek-makefile.patch
new file mode 100644
index 0000000..1727ad6
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/8000-uboot-mediatek-makefile.patch
@@ -0,0 +1,43 @@
+diff --git a/package/boot/uboot-mediatek/Makefile b/package/boot/uboot-mediatek/Makefile
+index c46b906..63610fb 100644
+--- a/package/boot/uboot-mediatek/Makefile
++++ b/package/boot/uboot-mediatek/Makefile
+@@ -1,8 +1,12 @@
+ include $(TOPDIR)/rules.mk
+ include $(INCLUDE_DIR)/kernel.mk
+
+-PKG_VERSION:=2020.10
+-PKG_HASH:=0d481bbdc05c0ee74908ec2f56a6daa53166cc6a78a0e4fac2ac5d025770a622
++PKG_NAME:=u-boot-mtk
++PKG_VERSION:=2021.01
++PKG_RELEASE:=1
++PKG_SOURCE_PROTO:=git
++PKG_SOURCE_URL:=https://gerrit.mediatek.inc/gateway/bootloader/Uboot-upstream
++PKG_SOURCE_VERSION:=icb-rebb-main
+
+ include $(INCLUDE_DIR)/u-boot.mk
+ include $(INCLUDE_DIR)/package.mk
+@@ -17,6 +21,7 @@ endef
+ define U-Boot/mt7622
+ NAME:=MT7622
+ BUILD_SUBTARGET:=mt7622
++ UBOOT_IMAGE:=u-boot.bin
+ UBOOT_CONFIG:=mt7622_rfb
+ endef
+
+@@ -39,7 +44,14 @@ define U-Boot/mt7629
+ UBOOT_CONFIG:=mt7629_rfb
+ endef
+
+-UBOOT_TARGETS := mt7629 mt7622 mt7623n_bpir2 mt7623a_unielec_u7623
++define U-Boot/mt7986
++ NAME:=MT7986
++ BUILD_SUBTARGET:=mt7986
++ UBOOT_IMAGE:=u-boot.bin
++ UBOOT_CONFIG:=mt7986_fpga
++endef
++
++UBOOT_TARGETS := mt7629 mt7622 mt7623n_bpir2 mt7623a_unielec_u7623 mt7986
+
+ UBOOT_MAKE_FLAGS += $(UBOOT_IMAGE)
+
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/8001-uboot-mediatek-remove-old-nand-driver.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/8001-uboot-mediatek-remove-old-nand-driver.patch
new file mode 100644
index 0000000..8642159
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/8001-uboot-mediatek-remove-old-nand-driver.patch
@@ -0,0 +1,8809 @@
+diff --git a/package/boot/uboot-mediatek/patches/002-nand-add-spi-nand-driver.patch b/package/boot/uboot-mediatek/patches/002-nand-add-spi-nand-driver.patch
+deleted file mode 100644
+index dc3ebaf..0000000
+--- a/package/boot/uboot-mediatek/patches/002-nand-add-spi-nand-driver.patch
++++ /dev/null
+@@ -1,8659 +0,0 @@
+-From de8b6cf615be20b25d0f3c817866de2c0d46a704 Mon Sep 17 00:00:00 2001
+-From: Sam Shih <sam.shih@mediatek.com>
+-Date: Mon, 20 Apr 2020 17:10:05 +0800
+-Subject: [PATCH 1/3] nand: add spi nand driver
+-
+-Add spi nand driver support for mt7622 based on nfi controller
+-
+-Signed-off-by: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
+----
+- drivers/mtd/Kconfig | 7 +
+- drivers/mtd/Makefile | 4 +
+- drivers/mtd/nand/raw/nand.c | 2 +
+- drivers/mtd/nandx/NOTICE | 52 +
+- drivers/mtd/nandx/Nandx.config | 17 +
+- drivers/mtd/nandx/Nandx.mk | 91 ++
+- drivers/mtd/nandx/README | 31 +
+- drivers/mtd/nandx/core/Nandx.mk | 38 +
+- drivers/mtd/nandx/core/core_io.c | 735 +++++++++
+- drivers/mtd/nandx/core/core_io.h | 39 +
+- drivers/mtd/nandx/core/nand/device_spi.c | 200 +++
+- drivers/mtd/nandx/core/nand/device_spi.h | 132 ++
+- drivers/mtd/nandx/core/nand/nand_spi.c | 526 +++++++
+- drivers/mtd/nandx/core/nand/nand_spi.h | 35 +
+- drivers/mtd/nandx/core/nand_base.c | 304 ++++
+- drivers/mtd/nandx/core/nand_base.h | 71 +
+- drivers/mtd/nandx/core/nand_chip.c | 272 ++++
+- drivers/mtd/nandx/core/nand_chip.h | 103 ++
+- drivers/mtd/nandx/core/nand_device.c | 285 ++++
+- drivers/mtd/nandx/core/nand_device.h | 608 ++++++++
+- drivers/mtd/nandx/core/nfi.h | 51 +
+- drivers/mtd/nandx/core/nfi/nfi_base.c | 1357 +++++++++++++++++
+- drivers/mtd/nandx/core/nfi/nfi_base.h | 95 ++
+- drivers/mtd/nandx/core/nfi/nfi_regs.h | 114 ++
+- drivers/mtd/nandx/core/nfi/nfi_spi.c | 689 +++++++++
+- drivers/mtd/nandx/core/nfi/nfi_spi.h | 44 +
+- drivers/mtd/nandx/core/nfi/nfi_spi_regs.h | 64 +
+- drivers/mtd/nandx/core/nfi/nfiecc.c | 510 +++++++
+- drivers/mtd/nandx/core/nfi/nfiecc.h | 90 ++
+- drivers/mtd/nandx/core/nfi/nfiecc_regs.h | 51 +
+- drivers/mtd/nandx/driver/Nandx.mk | 18 +
+- drivers/mtd/nandx/driver/bbt/bbt.c | 408 +++++
+- drivers/mtd/nandx/driver/uboot/driver.c | 574 +++++++
+- drivers/mtd/nandx/include/Nandx.mk | 16 +
+- drivers/mtd/nandx/include/internal/bbt.h | 62 +
+- .../mtd/nandx/include/internal/nandx_core.h | 250 +++
+- .../mtd/nandx/include/internal/nandx_errno.h | 40 +
+- .../mtd/nandx/include/internal/nandx_util.h | 221 +++
+- drivers/mtd/nandx/include/uboot/nandx_os.h | 78 +
+- include/configs/mt7622.h | 25 +
+- 40 files changed, 8309 insertions(+)
+- create mode 100644 drivers/mtd/nandx/NOTICE
+- create mode 100644 drivers/mtd/nandx/Nandx.config
+- create mode 100644 drivers/mtd/nandx/Nandx.mk
+- create mode 100644 drivers/mtd/nandx/README
+- create mode 100644 drivers/mtd/nandx/core/Nandx.mk
+- create mode 100644 drivers/mtd/nandx/core/core_io.c
+- create mode 100644 drivers/mtd/nandx/core/core_io.h
+- create mode 100644 drivers/mtd/nandx/core/nand/device_spi.c
+- create mode 100644 drivers/mtd/nandx/core/nand/device_spi.h
+- create mode 100644 drivers/mtd/nandx/core/nand/nand_spi.c
+- create mode 100644 drivers/mtd/nandx/core/nand/nand_spi.h
+- create mode 100644 drivers/mtd/nandx/core/nand_base.c
+- create mode 100644 drivers/mtd/nandx/core/nand_base.h
+- create mode 100644 drivers/mtd/nandx/core/nand_chip.c
+- create mode 100644 drivers/mtd/nandx/core/nand_chip.h
+- create mode 100644 drivers/mtd/nandx/core/nand_device.c
+- create mode 100644 drivers/mtd/nandx/core/nand_device.h
+- create mode 100644 drivers/mtd/nandx/core/nfi.h
+- create mode 100644 drivers/mtd/nandx/core/nfi/nfi_base.c
+- create mode 100644 drivers/mtd/nandx/core/nfi/nfi_base.h
+- create mode 100644 drivers/mtd/nandx/core/nfi/nfi_regs.h
+- create mode 100644 drivers/mtd/nandx/core/nfi/nfi_spi.c
+- create mode 100644 drivers/mtd/nandx/core/nfi/nfi_spi.h
+- create mode 100644 drivers/mtd/nandx/core/nfi/nfi_spi_regs.h
+- create mode 100644 drivers/mtd/nandx/core/nfi/nfiecc.c
+- create mode 100644 drivers/mtd/nandx/core/nfi/nfiecc.h
+- create mode 100644 drivers/mtd/nandx/core/nfi/nfiecc_regs.h
+- create mode 100644 drivers/mtd/nandx/driver/Nandx.mk
+- create mode 100644 drivers/mtd/nandx/driver/bbt/bbt.c
+- create mode 100644 drivers/mtd/nandx/driver/uboot/driver.c
+- create mode 100644 drivers/mtd/nandx/include/Nandx.mk
+- create mode 100644 drivers/mtd/nandx/include/internal/bbt.h
+- create mode 100644 drivers/mtd/nandx/include/internal/nandx_core.h
+- create mode 100644 drivers/mtd/nandx/include/internal/nandx_errno.h
+- create mode 100644 drivers/mtd/nandx/include/internal/nandx_util.h
+- create mode 100644 drivers/mtd/nandx/include/uboot/nandx_os.h
+-
+-diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
+-index 5e7571cf3d..34a59b44b9 100644
+---- a/drivers/mtd/Kconfig
+-+++ b/drivers/mtd/Kconfig
+-@@ -101,6 +101,13 @@ config HBMC_AM654
+- This is the driver for HyperBus controller on TI's AM65x and
+- other SoCs
+-
+-+config MTK_SPI_NAND
+-+ tristate "Mediatek SPI Nand"
+-+ depends on DM_MTD
+-+ help
+-+ This option will support SPI Nand device via Mediatek
+-+ NFI controller.
+-+
+- source "drivers/mtd/nand/Kconfig"
+-
+- source "drivers/mtd/spi/Kconfig"
+-diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
+-index 318788c5e2..1df1031b23 100644
+---- a/drivers/mtd/Makefile
+-+++ b/drivers/mtd/Makefile
+-@@ -41,3 +41,7 @@ obj-$(CONFIG_$(SPL_TPL_)SPI_FLASH_SUPPORT) += spi/
+- obj-$(CONFIG_SPL_UBI) += ubispl/
+-
+- endif
+-+
+-+ifeq ($(CONFIG_MTK_SPI_NAND), y)
+-+include $(srctree)/drivers/mtd/nandx/Nandx.mk
+-+endif
+-diff --git a/drivers/mtd/nand/raw/nand.c b/drivers/mtd/nand/raw/nand.c
+-index 026419e4e6..4be0c7d8f3 100644
+---- a/drivers/mtd/nand/raw/nand.c
+-+++ b/drivers/mtd/nand/raw/nand.c
+-@@ -91,8 +91,10 @@ static void nand_init_chip(int i)
+- if (board_nand_init(nand))
+- return;
+-
+-+#ifndef CONFIG_MTK_SPI_NAND
+- if (nand_scan(mtd, maxchips))
+- return;
+-+#endif
+-
+- nand_register(i, mtd);
+- }
+-diff --git a/drivers/mtd/nandx/NOTICE b/drivers/mtd/nandx/NOTICE
+-new file mode 100644
+-index 0000000000..1a06ca3867
+---- /dev/null
+-+++ b/drivers/mtd/nandx/NOTICE
+-@@ -0,0 +1,52 @@
+-+
+-+/*
+-+ * Nandx - Mediatek Common Nand Driver
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ *
+-+ * Nandx is dual licensed: you can use it either under the terms of
+-+ * the GPL, or the BSD license, at your option.
+-+ *
+-+ * a) This program is free software; you can redistribute it and/or modify
+-+ * it under the terms of the GNU General Public License version 2 as
+-+ * published by the Free Software Foundation.
+-+ *
+-+ * This library is distributed in the hope that it will be useful,
+-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-+ * GNU General Public License for more details.
+-+ *
+-+ * This program is distributed in the hope that it will be useful,
+-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+-+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+-+ *
+-+ * Alternatively,
+-+ *
+-+ * b) Redistribution and use in source and binary forms, with or
+-+ * without modification, are permitted provided that the following
+-+ * conditions are met:
+-+ *
+-+ * 1. Redistributions of source code must retain the above
+-+ * copyright notice, this list of conditions and the following
+-+ * disclaimer.
+-+ * 2. Redistributions in binary form must reproduce the above
+-+ * copyright notice, this list of conditions and the following
+-+ * disclaimer in the documentation and/or other materials
+-+ * provided with the distribution.
+-+ *
+-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+-+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+-+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+-+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+-+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+-+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+-+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+-+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+-+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+-+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+-+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+-+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+-+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-+ */
+-+
+-+####################################################################################################
+-\ No newline at end of file
+-diff --git a/drivers/mtd/nandx/Nandx.config b/drivers/mtd/nandx/Nandx.config
+-new file mode 100644
+-index 0000000000..35705ee28d
+---- /dev/null
+-+++ b/drivers/mtd/nandx/Nandx.config
+-@@ -0,0 +1,17 @@
+-+NANDX_SIMULATOR_SUPPORT := n
+-+NANDX_CTP_SUPPORT := n
+-+NANDX_DA_SUPPORT := n
+-+NANDX_PRELOADER_SUPPORT := n
+-+NANDX_LK_SUPPORT := n
+-+NANDX_KERNEL_SUPPORT := n
+-+NANDX_BROM_SUPPORT := n
+-+NANDX_UBOOT_SUPPORT := y
+-+NANDX_BBT_SUPPORT := y
+-+
+-+NANDX_NAND_SPI := y
+-+NANDX_NAND_SLC := n
+-+NANDX_NAND_MLC := n
+-+NANDX_NAND_TLC := n
+-+NANDX_NFI_BASE := y
+-+NANDX_NFI_ECC := y
+-+NANDX_NFI_SPI := y
+-diff --git a/drivers/mtd/nandx/Nandx.mk b/drivers/mtd/nandx/Nandx.mk
+-new file mode 100644
+-index 0000000000..f5a6f2a628
+---- /dev/null
+-+++ b/drivers/mtd/nandx/Nandx.mk
+-@@ -0,0 +1,91 @@
+-+#
+-+# Copyright (C) 2017 MediaTek Inc.
+-+# Licensed under either
+-+# BSD Licence, (see NOTICE for more details)
+-+# GNU General Public License, version 2.0, (see NOTICE for more details)
+-+#
+-+
+-+nandx_dir := $(shell dirname $(lastword $(MAKEFILE_LIST)))
+-+include $(nandx_dir)/Nandx.config
+-+
+-+ifeq ($(NANDX_SIMULATOR_SUPPORT), y)
+-+sim-obj :=
+-+sim-inc :=
+-+nandx-obj := sim-obj
+-+nandx-prefix := .
+-+nandx-postfix := %.o
+-+sim-inc += -I$(nandx-prefix)/include/internal
+-+sim-inc += -I$(nandx-prefix)/include/simulator
+-+endif
+-+
+-+ifeq ($(NANDX_CTP_SUPPORT), y)
+-+nandx-obj := C_SRC_FILES
+-+nandx-prefix := $(nandx_dir)
+-+nandx-postfix := %.c
+-+INC_DIRS += $(nandx_dir)/include/internal
+-+INC_DIRS += $(nandx_dir)/include/ctp
+-+endif
+-+
+-+ifeq ($(NANDX_DA_SUPPORT), y)
+-+nandx-obj := obj-y
+-+nandx-prefix := $(nandx_dir)
+-+nandx-postfix := %.o
+-+INCLUDE_PATH += $(TOPDIR)/platform/$(CODE_BASE)/dev/nand/nandx/include/internal
+-+INCLUDE_PATH += $(TOPDIR)/platform/$(CODE_BASE)/dev/nand/nandx/include/da
+-+endif
+-+
+-+ifeq ($(NANDX_PRELOADER_SUPPORT), y)
+-+nandx-obj := MOD_SRC
+-+nandx-prefix := $(nandx_dir)
+-+nandx-postfix := %.c
+-+C_OPTION += -I$(MTK_PATH_PLATFORM)/src/drivers/nandx/include/internal
+-+C_OPTION += -I$(MTK_PATH_PLATFORM)/src/drivers/nandx/include/preloader
+-+endif
+-+
+-+ifeq ($(NANDX_LK_SUPPORT), y)
+-+nandx-obj := MODULE_SRCS
+-+nandx-prefix := $(nandx_dir)
+-+nandx-postfix := %.c
+-+GLOBAL_INCLUDES += $(nandx_dir)/include/internal
+-+GLOBAL_INCLUDES += $(nandx_dir)/include/lk
+-+endif
+-+
+-+ifeq ($(NANDX_KERNEL_SUPPORT), y)
+-+nandx-obj := obj-y
+-+nandx-prefix := nandx
+-+nandx-postfix := %.o
+-+ccflags-y += -I$(nandx_dir)/include/internal
+-+ccflags-y += -I$(nandx_dir)/include/kernel
+-+endif
+-+
+-+ifeq ($(NANDX_UBOOT_SUPPORT), y)
+-+nandx-obj := obj-y
+-+nandx-prefix := nandx
+-+nandx-postfix := %.o
+-+ccflags-y += -I$(nandx_dir)/include/internal
+-+ccflags-y += -I$(nandx_dir)/include/uboot
+-+endif
+-+
+-+nandx-y :=
+-+include $(nandx_dir)/core/Nandx.mk
+-+nandx-target := $(nandx-prefix)/core/$(nandx-postfix)
+-+$(nandx-obj) += $(patsubst %.c, $(nandx-target), $(nandx-y))
+-+
+-+
+-+nandx-y :=
+-+include $(nandx_dir)/driver/Nandx.mk
+-+nandx-target := $(nandx-prefix)/driver/$(nandx-postfix)
+-+$(nandx-obj) += $(patsubst %.c, $(nandx-target), $(nandx-y))
+-+
+-+ifeq ($(NANDX_SIMULATOR_SUPPORT), y)
+-+cc := gcc
+-+CFLAGS += $(sim-inc)
+-+
+-+.PHONY:nandx
+-+nandx: $(sim-obj)
+-+ $(cc) $(sim-obj) -o nandx
+-+
+-+.PHONY:clean
+-+clean:
+-+ rm -rf $(sim-obj) nandx
+-+endif
+-diff --git a/drivers/mtd/nandx/README b/drivers/mtd/nandx/README
+-new file mode 100644
+-index 0000000000..0feaeaeb88
+---- /dev/null
+-+++ b/drivers/mtd/nandx/README
+-@@ -0,0 +1,31 @@
+-+
+-+ NAND2.0
+-+ ===============================
+-+
+-+ NAND2.0 is a common nand driver which designed for accessing
+-+different type of NANDs(SLC, SPI-NAND, MLC, TLC) on various OS. This
+-+driver can work on mostly SoCs of Mediatek.
+-+
+-+ Although there already has a common nand driver, it doesn't cover
+-+SPI-NAND, and not match our IC-Verification's reqirement. We need
+-+a driver that can be exten or cut easily.
+-+
+-+ This driver is base on NANDX & SLC. We try to refactor structures,
+-+and make them inheritable. We also refactor some operations' flow
+-+principally for adding SPI-NAND support.
+-+
+-+ This driver's architecture is like:
+-+
+-+ Driver @LK/Uboot/DA... |IC verify/other purposes
+-+ ----------------------------------------------------------------
+-+ partition | BBM |
+-+ -------------------------------------- | extend_core
+-+ nandx_core/core_io |
+-+ ----------------------------------------------------------------
+-+ nand_chip/nand_base |
+-+ -------------------------------------- | extend_nfi
+-+ nand_device | nfi/nfi_base |
+-+
+-+ Any block of above graph can be extended at your will, if you
+-+want add new feature into this code, please make sure that your code
+-+would follow the framework, and we will be appreciated about it.
+-diff --git a/drivers/mtd/nandx/core/Nandx.mk b/drivers/mtd/nandx/core/Nandx.mk
+-new file mode 100644
+-index 0000000000..7a5661c044
+---- /dev/null
+-+++ b/drivers/mtd/nandx/core/Nandx.mk
+-@@ -0,0 +1,38 @@
+-+#
+-+# Copyright (C) 2017 MediaTek Inc.
+-+# Licensed under either
+-+# BSD Licence, (see NOTICE for more details)
+-+# GNU General Public License, version 2.0, (see NOTICE for more details)
+-+#
+-+
+-+nandx-y += nand_device.c
+-+nandx-y += nand_base.c
+-+nandx-y += nand_chip.c
+-+nandx-y += core_io.c
+-+
+-+nandx-header-y += nand_device.h
+-+nandx-header-y += nand_base.h
+-+nandx-header-y += nand_chip.h
+-+nandx-header-y += core_io.h
+-+nandx-header-y += nfi.h
+-+
+-+nandx-$(NANDX_NAND_SPI) += nand/device_spi.c
+-+nandx-$(NANDX_NAND_SPI) += nand/nand_spi.c
+-+nandx-$(NANDX_NAND_SLC) += nand/device_slc.c
+-+nandx-$(NANDX_NAND_SLC) += nand/nand_slc.c
+-+
+-+nandx-header-$(NANDX_NAND_SPI) += nand/device_spi.h
+-+nandx-header-$(NANDX_NAND_SPI) += nand/nand_spi.h
+-+nandx-header-$(NANDX_NAND_SLC) += nand/device_slc.h
+-+nandx-header-$(NANDX_NAND_SLC) += nand/nand_slc.h
+-+
+-+nandx-$(NANDX_NFI_BASE) += nfi/nfi_base.c
+-+nandx-$(NANDX_NFI_ECC) += nfi/nfiecc.c
+-+nandx-$(NANDX_NFI_SPI) += nfi/nfi_spi.c
+-+
+-+nandx-header-$(NANDX_NFI_BASE) += nfi/nfi_base.h
+-+nandx-header-$(NANDX_NFI_BASE) += nfi/nfi_regs.h
+-+nandx-header-$(NANDX_NFI_ECC) += nfi/nfiecc.h
+-+nandx-header-$(NANDX_NFI_ECC) += nfi/nfiecc_regs.h
+-+nandx-header-$(NANDX_NFI_SPI) += nfi/nfi_spi.h
+-+nandx-header-$(NANDX_NFI_SPI) += nfi/nfi_spi_regs.h
+-diff --git a/drivers/mtd/nandx/core/core_io.c b/drivers/mtd/nandx/core/core_io.c
+-new file mode 100644
+-index 0000000000..716eeed38d
+---- /dev/null
+-+++ b/drivers/mtd/nandx/core/core_io.c
+-@@ -0,0 +1,735 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+/*NOTE: switch cache/multi*/
+-+#include "nandx_util.h"
+-+#include "nandx_core.h"
+-+#include "nand_chip.h"
+-+#include "core_io.h"
+-+
+-+static struct nandx_desc *g_nandx;
+-+
+-+static inline bool is_sector_align(u64 val)
+-+{
+-+ return reminder(val, g_nandx->chip->sector_size) ? false : true;
+-+}
+-+
+-+static inline bool is_page_align(u64 val)
+-+{
+-+ return reminder(val, g_nandx->chip->page_size) ? false : true;
+-+}
+-+
+-+static inline bool is_block_align(u64 val)
+-+{
+-+ return reminder(val, g_nandx->chip->block_size) ? false : true;
+-+}
+-+
+-+static inline u32 page_sectors(void)
+-+{
+-+ return div_down(g_nandx->chip->page_size, g_nandx->chip->sector_size);
+-+}
+-+
+-+static inline u32 sector_oob(void)
+-+{
+-+ return div_down(g_nandx->chip->oob_size, page_sectors());
+-+}
+-+
+-+static inline u32 sector_padded_size(void)
+-+{
+-+ return g_nandx->chip->sector_size + g_nandx->chip->sector_spare_size;
+-+}
+-+
+-+static inline u32 page_padded_size(void)
+-+{
+-+ return page_sectors() * sector_padded_size();
+-+}
+-+
+-+static inline u32 offset_to_padded_col(u64 offset)
+-+{
+-+ struct nandx_desc *nandx = g_nandx;
+-+ u32 col, sectors;
+-+
+-+ col = reminder(offset, nandx->chip->page_size);
+-+ sectors = div_down(col, nandx->chip->sector_size);
+-+
+-+ return col + sectors * nandx->chip->sector_spare_size;
+-+}
+-+
+-+static inline u32 offset_to_row(u64 offset)
+-+{
+-+ return div_down(offset, g_nandx->chip->page_size);
+-+}
+-+
+-+static inline u32 offset_to_col(u64 offset)
+-+{
+-+ return reminder(offset, g_nandx->chip->page_size);
+-+}
+-+
+-+static inline u32 oob_upper_size(void)
+-+{
+-+ return g_nandx->ecc_en ? g_nandx->chip->oob_size :
+-+ g_nandx->chip->sector_spare_size * page_sectors();
+-+}
+-+
+-+static inline bool is_upper_oob_align(u64 val)
+-+{
+-+ return reminder(val, oob_upper_size()) ? false : true;
+-+}
+-+
+-+#define prepare_op(_op, _row, _col, _len, _data, _oob) \
+-+ do { \
+-+ (_op).row = (_row); \
+-+ (_op).col = (_col); \
+-+ (_op).len = (_len); \
+-+ (_op).data = (_data); \
+-+ (_op).oob = (_oob); \
+-+ } while (0)
+-+
+-+static int operation_multi(enum nandx_op_mode mode, u8 *data, u8 *oob,
+-+ u64 offset, size_t len)
+-+{
+-+ struct nandx_desc *nandx = g_nandx;
+-+ u32 row = offset_to_row(offset);
+-+ u32 col = offset_to_padded_col(offset);
+-+
+-+ if (nandx->mode == NANDX_IDLE) {
+-+ nandx->mode = mode;
+-+ nandx->ops_current = 0;
+-+ } else if (nandx->mode != mode) {
+-+ pr_info("forbid mixed operations.\n");
+-+ return -EOPNOTSUPP;
+-+ }
+-+
+-+ prepare_op(nandx->ops[nandx->ops_current], row, col, len, data, oob);
+-+ nandx->ops_current++;
+-+
+-+ if (nandx->ops_current == nandx->ops_multi_len)
+-+ return nandx_sync();
+-+
+-+ return nandx->ops_multi_len - nandx->ops_current;
+-+}
+-+
+-+static int operation_sequent(enum nandx_op_mode mode, u8 *data, u8 *oob,
+-+ u64 offset, size_t len)
+-+{
+-+ struct nandx_desc *nandx = g_nandx;
+-+ struct nand_chip *chip = nandx->chip;
+-+ u32 row = offset_to_row(offset);
+-+ func_chip_ops chip_ops;
+-+ u8 *ref_data = data, *ref_oob = oob;
+-+ int align, ops, row_step;
+-+ int i, rem;
+-+
+-+ align = data ? chip->page_size : oob_upper_size();
+-+ ops = data ? div_down(len, align) : div_down(len, oob_upper_size());
+-+ row_step = 1;
+-+
+-+ switch (mode) {
+-+ case NANDX_ERASE:
+-+ chip_ops = chip->erase_block;
+-+ align = chip->block_size;
+-+ ops = div_down(len, align);
+-+ row_step = chip->block_pages;
+-+ break;
+-+
+-+ case NANDX_READ:
+-+ chip_ops = chip->read_page;
+-+ break;
+-+
+-+ case NANDX_WRITE:
+-+ chip_ops = chip->write_page;
+-+ break;
+-+
+-+ default:
+-+ return -EINVAL;
+-+ }
+-+
+-+ if (!data) {
+-+ ref_data = nandx->head_buf;
+-+ memset(ref_data, 0xff, chip->page_size);
+-+ }
+-+
+-+ if (!oob) {
+-+ ref_oob = nandx->head_buf + chip->page_size;
+-+ memset(ref_oob, 0xff, oob_upper_size());
+-+ }
+-+
+-+ for (i = 0; i < ops; i++) {
+-+ prepare_op(nandx->ops[nandx->ops_current],
+-+ row + i * row_step, 0, align, ref_data, ref_oob);
+-+ nandx->ops_current++;
+-+ /* if data or oob is null, nandx->head_buf or
+-+ * nandx->head_buf + chip->page_size should not been used
+-+ * so, here it is safe to use the buf.
+-+ */
+-+ ref_data = data ? ref_data + chip->page_size : nandx->head_buf;
+-+ ref_oob = oob ? ref_oob + oob_upper_size() :
+-+ nandx->head_buf + chip->page_size;
+-+ }
+-+
+-+ if (nandx->mode == NANDX_WRITE) {
+-+ rem = reminder(nandx->ops_current, nandx->min_write_pages);
+-+ if (rem)
+-+ return nandx->min_write_pages - rem;
+-+ }
+-+
+-+ nandx->ops_current = 0;
+-+ return chip_ops(chip, nandx->ops, ops);
+-+}
+-+
+-+static int read_pages(u8 *data, u8 *oob, u64 offset, size_t len)
+-+{
+-+ struct nandx_desc *nandx = g_nandx;
+-+ struct nand_chip *chip = nandx->chip;
+-+ struct nandx_split64 split = {0};
+-+ u8 *ref_data = data, *ref_oob;
+-+ u32 row, col;
+-+ int ret = 0, i, ops;
+-+ u32 head_offset = 0;
+-+ u64 val;
+-+
+-+ if (!data)
+-+ return operation_sequent(NANDX_READ, NULL, oob, offset, len);
+-+
+-+ ref_oob = oob ? oob : nandx->head_buf + chip->page_size;
+-+
+-+ nandx_split(&split, offset, len, val, chip->page_size);
+-+
+-+ if (split.head_len) {
+-+ row = offset_to_row(split.head);
+-+ col = offset_to_col(split.head);
+-+ prepare_op(nandx->ops[nandx->ops_current], row, 0,
+-+ chip->page_size,
+-+ nandx->head_buf, ref_oob);
+-+ nandx->ops_current++;
+-+
+-+ head_offset = col;
+-+
+-+ ref_data += split.head_len;
+-+ ref_oob = oob ? ref_oob + oob_upper_size() :
+-+ nandx->head_buf + chip->page_size;
+-+ }
+-+
+-+ if (split.body_len) {
+-+ ops = div_down(split.body_len, chip->page_size);
+-+ row = offset_to_row(split.body);
+-+ for (i = 0; i < ops; i++) {
+-+ prepare_op(nandx->ops[nandx->ops_current],
+-+ row + i, 0, chip->page_size,
+-+ ref_data, ref_oob);
+-+ nandx->ops_current++;
+-+ ref_data += chip->page_size;
+-+ ref_oob = oob ? ref_oob + oob_upper_size() :
+-+ nandx->head_buf + chip->page_size;
+-+ }
+-+ }
+-+
+-+ if (split.tail_len) {
+-+ row = offset_to_row(split.tail);
+-+ prepare_op(nandx->ops[nandx->ops_current], row, 0,
+-+ chip->page_size, nandx->tail_buf, ref_oob);
+-+ nandx->ops_current++;
+-+ }
+-+
+-+ ret = chip->read_page(chip, nandx->ops, nandx->ops_current);
+-+
+-+ if (split.head_len)
+-+ memcpy(data, nandx->head_buf + head_offset, split.head_len);
+-+ if (split.tail_len)
+-+ memcpy(ref_data, nandx->tail_buf, split.tail_len);
+-+
+-+ nandx->ops_current = 0;
+-+ return ret;
+-+}
+-+
+-+int nandx_read(u8 *data, u8 *oob, u64 offset, size_t len)
+-+{
+-+ struct nandx_desc *nandx = g_nandx;
+-+
+-+ if (!len || len > nandx->info.total_size)
+-+ return -EINVAL;
+-+ if (div_up(len, nandx->chip->page_size) > nandx->ops_len)
+-+ return -EINVAL;
+-+ if (!data && !oob)
+-+ return -EINVAL;
+-+ /**
+-+ * as design, oob not support partial read
+-+ * and, the length of oob buf should be oob size aligned
+-+ */
+-+ if (!data && !is_upper_oob_align(len))
+-+ return -EINVAL;
+-+
+-+ if (g_nandx->multi_en) {
+-+ /* as design, there only 2 buf for partial read,
+-+ * if partial read allowed for multi read,
+-+ * there are not enough buf
+-+ */
+-+ if (!is_sector_align(offset))
+-+ return -EINVAL;
+-+ if (data && !is_sector_align(len))
+-+ return -EINVAL;
+-+ return operation_multi(NANDX_READ, data, oob, offset, len);
+-+ }
+-+
+-+ nandx->ops_current = 0;
+-+ nandx->mode = NANDX_IDLE;
+-+ return read_pages(data, oob, offset, len);
+-+}
+-+
+-+static int write_pages(u8 *data, u8 *oob, u64 offset, size_t len)
+-+{
+-+ struct nandx_desc *nandx = g_nandx;
+-+ struct nand_chip *chip = nandx->chip;
+-+ struct nandx_split64 split = {0};
+-+ int ret, rem, i, ops;
+-+ u32 row, col;
+-+ u8 *ref_oob = oob;
+-+ u64 val;
+-+
+-+ nandx->mode = NANDX_WRITE;
+-+
+-+ if (!data)
+-+ return operation_sequent(NANDX_WRITE, NULL, oob, offset, len);
+-+
+-+ if (!oob) {
+-+ ref_oob = nandx->head_buf + chip->page_size;
+-+ memset(ref_oob, 0xff, oob_upper_size());
+-+ }
+-+
+-+ nandx_split(&split, offset, len, val, chip->page_size);
+-+
+-+ /*NOTE: slc can support sector write, here copy too many data.*/
+-+ if (split.head_len) {
+-+ row = offset_to_row(split.head);
+-+ col = offset_to_col(split.head);
+-+ memset(nandx->head_buf, 0xff, page_padded_size());
+-+ memcpy(nandx->head_buf + col, data, split.head_len);
+-+ prepare_op(nandx->ops[nandx->ops_current], row, 0,
+-+ chip->page_size, nandx->head_buf, ref_oob);
+-+ nandx->ops_current++;
+-+
+-+ data += split.head_len;
+-+ ref_oob = oob ? ref_oob + oob_upper_size() :
+-+ nandx->head_buf + chip->page_size;
+-+ }
+-+
+-+ if (split.body_len) {
+-+ row = offset_to_row(split.body);
+-+ ops = div_down(split.body_len, chip->page_size);
+-+ for (i = 0; i < ops; i++) {
+-+ prepare_op(nandx->ops[nandx->ops_current],
+-+ row + i, 0, chip->page_size, data, ref_oob);
+-+ nandx->ops_current++;
+-+ data += chip->page_size;
+-+ ref_oob = oob ? ref_oob + oob_upper_size() :
+-+ nandx->head_buf + chip->page_size;
+-+ }
+-+ }
+-+
+-+ if (split.tail_len) {
+-+ row = offset_to_row(split.tail);
+-+ memset(nandx->tail_buf, 0xff, page_padded_size());
+-+ memcpy(nandx->tail_buf, data, split.tail_len);
+-+ prepare_op(nandx->ops[nandx->ops_current], row, 0,
+-+ chip->page_size, nandx->tail_buf, ref_oob);
+-+ nandx->ops_current++;
+-+ }
+-+
+-+ rem = reminder(nandx->ops_current, nandx->min_write_pages);
+-+ if (rem)
+-+ return nandx->min_write_pages - rem;
+-+
+-+ ret = chip->write_page(chip, nandx->ops, nandx->ops_current);
+-+
+-+ nandx->ops_current = 0;
+-+ nandx->mode = NANDX_IDLE;
+-+ return ret;
+-+}
+-+
+-+int nandx_write(u8 *data, u8 *oob, u64 offset, size_t len)
+-+{
+-+ struct nandx_desc *nandx = g_nandx;
+-+
+-+ if (!len || len > nandx->info.total_size)
+-+ return -EINVAL;
+-+ if (div_up(len, nandx->chip->page_size) > nandx->ops_len)
+-+ return -EINVAL;
+-+ if (!data && !oob)
+-+ return -EINVAL;
+-+ if (!data && !is_upper_oob_align(len))
+-+ return -EINVAL;
+-+
+-+ if (nandx->multi_en) {
+-+ if (!is_page_align(offset))
+-+ return -EINVAL;
+-+ if (data && !is_page_align(len))
+-+ return -EINVAL;
+-+
+-+ return operation_multi(NANDX_WRITE, data, oob, offset, len);
+-+ }
+-+
+-+ return write_pages(data, oob, offset, len);
+-+}
+-+
+-+int nandx_erase(u64 offset, size_t len)
+-+{
+-+ struct nandx_desc *nandx = g_nandx;
+-+
+-+ if (!len || len > nandx->info.total_size)
+-+ return -EINVAL;
+-+ if (div_down(len, nandx->chip->block_size) > nandx->ops_len)
+-+ return -EINVAL;
+-+ if (!is_block_align(offset) || !is_block_align(len))
+-+ return -EINVAL;
+-+
+-+ if (g_nandx->multi_en)
+-+ return operation_multi(NANDX_ERASE, NULL, NULL, offset, len);
+-+
+-+ nandx->ops_current = 0;
+-+ nandx->mode = NANDX_IDLE;
+-+ return operation_sequent(NANDX_ERASE, NULL, NULL, offset, len);
+-+}
+-+
+-+int nandx_sync(void)
+-+{
+-+ struct nandx_desc *nandx = g_nandx;
+-+ struct nand_chip *chip = nandx->chip;
+-+ func_chip_ops chip_ops;
+-+ int ret, i, rem;
+-+
+-+ if (!nandx->ops_current)
+-+ return 0;
+-+
+-+ rem = reminder(nandx->ops_current, nandx->ops_multi_len);
+-+ if (nandx->multi_en && rem) {
+-+ ret = -EIO;
+-+ goto error;
+-+ }
+-+
+-+ switch (nandx->mode) {
+-+ case NANDX_IDLE:
+-+ return 0;
+-+ case NANDX_ERASE:
+-+ chip_ops = chip->erase_block;
+-+ break;
+-+ case NANDX_READ:
+-+ chip_ops = chip->read_page;
+-+ break;
+-+ case NANDX_WRITE:
+-+ chip_ops = chip->write_page;
+-+ break;
+-+ default:
+-+ return -EINVAL;
+-+ }
+-+
+-+ rem = reminder(nandx->ops_current, nandx->min_write_pages);
+-+ if (!nandx->multi_en && nandx->mode == NANDX_WRITE && rem) {
+-+ /* in one process of program, only allow 2 pages to do partial
+-+ * write, here we supposed 1st buf would be used, and 2nd
+-+ * buf should be not used.
+-+ */
+-+ memset(nandx->tail_buf, 0xff,
+-+ chip->page_size + oob_upper_size());
+-+ for (i = 0; i < rem; i++) {
+-+ prepare_op(nandx->ops[nandx->ops_current],
+-+ nandx->ops[nandx->ops_current - 1].row + 1,
+-+ 0, chip->page_size, nandx->tail_buf,
+-+ nandx->tail_buf + chip->page_size);
+-+ nandx->ops_current++;
+-+ }
+-+ }
+-+
+-+ ret = chip_ops(nandx->chip, nandx->ops, nandx->ops_current);
+-+
+-+error:
+-+ nandx->mode = NANDX_IDLE;
+-+ nandx->ops_current = 0;
+-+
+-+ return ret;
+-+}
+-+
+-+int nandx_ioctl(int cmd, void *arg)
+-+{
+-+ struct nandx_desc *nandx = g_nandx;
+-+ struct nand_chip *chip = nandx->chip;
+-+ int ret = 0;
+-+
+-+ switch (cmd) {
+-+ case CORE_CTRL_NAND_INFO:
+-+ *(struct nandx_info *)arg = nandx->info;
+-+ break;
+-+
+-+ case CHIP_CTRL_OPS_MULTI:
+-+ ret = chip->chip_ctrl(chip, cmd, arg);
+-+ if (!ret)
+-+ nandx->multi_en = *(bool *)arg;
+-+ break;
+-+
+-+ case NFI_CTRL_ECC:
+-+ ret = chip->chip_ctrl(chip, cmd, arg);
+-+ if (!ret)
+-+ nandx->ecc_en = *(bool *)arg;
+-+ break;
+-+
+-+ default:
+-+ ret = chip->chip_ctrl(chip, cmd, arg);
+-+ break;
+-+ }
+-+
+-+ return ret;
+-+}
+-+
+-+bool nandx_is_bad_block(u64 offset)
+-+{
+-+ struct nandx_desc *nandx = g_nandx;
+-+
+-+ prepare_op(nandx->ops[0], offset_to_row(offset), 0,
+-+ nandx->chip->page_size, nandx->head_buf,
+-+ nandx->head_buf + nandx->chip->page_size);
+-+
+-+ return nandx->chip->is_bad_block(nandx->chip, nandx->ops, 1);
+-+}
+-+
+-+int nandx_suspend(void)
+-+{
+-+ return g_nandx->chip->suspend(g_nandx->chip);
+-+}
+-+
+-+int nandx_resume(void)
+-+{
+-+ return g_nandx->chip->resume(g_nandx->chip);
+-+}
+-+
+-+int nandx_init(struct nfi_resource *res)
+-+{
+-+ struct nand_chip *chip;
+-+ struct nandx_desc *nandx;
+-+ int ret = 0;
+-+
+-+ if (!res)
+-+ return -EINVAL;
+-+
+-+ chip = nand_chip_init(res);
+-+ if (!chip) {
+-+ pr_info("nand chip init fail.\n");
+-+ return -EFAULT;
+-+ }
+-+
+-+ nandx = (struct nandx_desc *)mem_alloc(1, sizeof(struct nandx_desc));
+-+ if (!nandx)
+-+ return -ENOMEM;
+-+
+-+ g_nandx = nandx;
+-+
+-+ nandx->chip = chip;
+-+ nandx->min_write_pages = chip->min_program_pages;
+-+ nandx->ops_multi_len = nandx->min_write_pages * chip->plane_num;
+-+ nandx->ops_len = chip->block_pages * chip->plane_num;
+-+ nandx->ops = mem_alloc(1, sizeof(struct nand_ops) * nandx->ops_len);
+-+ if (!nandx->ops) {
+-+ ret = -ENOMEM;
+-+ goto ops_error;
+-+ }
+-+
+-+#if NANDX_BULK_IO_USE_DRAM
+-+ nandx->head_buf = NANDX_CORE_BUF_ADDR;
+-+#else
+-+ nandx->head_buf = mem_alloc(2, page_padded_size());
+-+#endif
+-+ if (!nandx->head_buf) {
+-+ ret = -ENOMEM;
+-+ goto buf_error;
+-+ }
+-+ nandx->tail_buf = nandx->head_buf + page_padded_size();
+-+ memset(nandx->head_buf, 0xff, 2 * page_padded_size());
+-+ nandx->multi_en = false;
+-+ nandx->ecc_en = false;
+-+ nandx->ops_current = 0;
+-+ nandx->mode = NANDX_IDLE;
+-+
+-+ nandx->info.max_io_count = nandx->ops_len;
+-+ nandx->info.min_write_pages = nandx->min_write_pages;
+-+ nandx->info.plane_num = chip->plane_num;
+-+ nandx->info.oob_size = chip->oob_size;
+-+ nandx->info.page_parity_size = chip->sector_spare_size * page_sectors();
+-+ nandx->info.page_size = chip->page_size;
+-+ nandx->info.block_size = chip->block_size;
+-+ nandx->info.total_size = chip->block_size * chip->block_num;
+-+ nandx->info.fdm_ecc_size = chip->fdm_ecc_size;
+-+ nandx->info.fdm_reg_size = chip->fdm_reg_size;
+-+ nandx->info.ecc_strength = chip->ecc_strength;
+-+ nandx->info.sector_size = chip->sector_size;
+-+
+-+ return 0;
+-+
+-+buf_error:
+-+#if !NANDX_BULK_IO_USE_DRAM
+-+ mem_free(nandx->head_buf);
+-+#endif
+-+ops_error:
+-+ mem_free(nandx);
+-+
+-+ return ret;
+-+}
+-+
+-+void nandx_exit(void)
+-+{
+-+ nand_chip_exit(g_nandx->chip);
+-+#if !NANDX_BULK_IO_USE_DRAM
+-+ mem_free(g_nandx->head_buf);
+-+#endif
+-+ mem_free(g_nandx->ops);
+-+ mem_free(g_nandx);
+-+}
+-+
+-+#ifdef NANDX_UNIT_TEST
+-+static void dump_buf(u8 *buf, u32 len)
+-+{
+-+ u32 i;
+-+
+-+ pr_info("dump buf@0x%X start", (u32)buf);
+-+ for (i = 0; i < len; i++) {
+-+ if (!reminder(i, 16))
+-+ pr_info("\n0x");
+-+ pr_info("%x ", buf[i]);
+-+ }
+-+ pr_info("\ndump buf done.\n");
+-+}
+-+
+-+int nandx_unit_test(u64 offset, size_t len)
+-+{
+-+ u8 *src_buf, *dst_buf;
+-+ u32 i, j;
+-+ int ret;
+-+
+-+ if (!len || len > g_nandx->chip->block_size)
+-+ return -EINVAL;
+-+
+-+#if NANDX_BULK_IO_USE_DRAM
+-+ src_buf = NANDX_UT_SRC_ADDR;
+-+ dst_buf = NANDX_UT_DST_ADDR;
+-+
+-+#else
+-+ src_buf = mem_alloc(1, g_nandx->chip->page_size);
+-+ if (!src_buf)
+-+ return -ENOMEM;
+-+ dst_buf = mem_alloc(1, g_nandx->chip->page_size);
+-+ if (!dst_buf) {
+-+ mem_free(src_buf);
+-+ return -ENOMEM;
+-+ }
+-+#endif
+-+
+-+ pr_info("%s: src_buf address 0x%x, dst_buf address 0x%x\n",
+-+ __func__, (int)((unsigned long)src_buf),
+-+ (int)((unsigned long)dst_buf));
+-+
+-+ memset(dst_buf, 0, g_nandx->chip->page_size);
+-+ pr_info("read page 0 data...!\n");
+-+ ret = nandx_read(dst_buf, NULL, 0, g_nandx->chip->page_size);
+-+ if (ret < 0) {
+-+ pr_info("read fail with ret %d\n", ret);
+-+ } else {
+-+ pr_info("read page success!\n");
+-+ }
+-+
+-+ for (i = 0; i < g_nandx->chip->page_size; i++) {
+-+ src_buf[i] = 0x5a;
+-+ }
+-+
+-+ ret = nandx_erase(offset, g_nandx->chip->block_size);
+-+ if (ret < 0) {
+-+ pr_info("erase fail with ret %d\n", ret);
+-+ goto error;
+-+ }
+-+
+-+ for (j = 0; j < g_nandx->chip->block_pages; j++) {
+-+ memset(dst_buf, 0, g_nandx->chip->page_size);
+-+ pr_info("check data after erase...!\n");
+-+ ret = nandx_read(dst_buf, NULL, offset, g_nandx->chip->page_size);
+-+ if (ret < 0) {
+-+ pr_info("read fail with ret %d\n", ret);
+-+ goto error;
+-+ }
+-+
+-+ for (i = 0; i < g_nandx->chip->page_size; i++) {
+-+ if (dst_buf[i] != 0xff) {
+-+ pr_info("read after erase, check fail @%d\n", i);
+-+ pr_info("all data should be 0xff\n");
+-+ ret = -ENANDERASE;
+-+ dump_buf(dst_buf, 128);
+-+ //goto error;
+-+ break;
+-+ }
+-+ }
+-+
+-+ pr_info("write data...!\n");
+-+ ret = nandx_write(src_buf, NULL, offset, g_nandx->chip->page_size);
+-+ if (ret < 0) {
+-+ pr_info("write fail with ret %d\n", ret);
+-+ goto error;
+-+ }
+-+
+-+ memset(dst_buf, 0, g_nandx->chip->page_size);
+-+ pr_info("read data...!\n");
+-+ ret = nandx_read(dst_buf, NULL, offset, g_nandx->chip->page_size);
+-+ if (ret < 0) {
+-+ pr_info("read fail with ret %d\n", ret);
+-+ goto error;
+-+ }
+-+
+-+ for (i = 0; i < g_nandx->chip->page_size; i++) {
+-+ if (dst_buf[i] != src_buf[i]) {
+-+ pr_info("read after write, check fail @%d\n", i);
+-+ pr_info("dst_buf should be same as src_buf\n");
+-+ ret = -EIO;
+-+ dump_buf(src_buf + i, 128);
+-+ dump_buf(dst_buf + i, 128);
+-+ break;
+-+ }
+-+ }
+-+
+-+ pr_err("%s %d %s@%d\n", __func__, __LINE__, ret?"Failed":"OK", j);
+-+ if (ret)
+-+ break;
+-+
+-+ offset += g_nandx->chip->page_size;
+-+ }
+-+
+-+ ret = nandx_erase(offset, g_nandx->chip->block_size);
+-+ if (ret < 0) {
+-+ pr_info("erase fail with ret %d\n", ret);
+-+ goto error;
+-+ }
+-+
+-+ memset(dst_buf, 0, g_nandx->chip->page_size);
+-+ ret = nandx_read(dst_buf, NULL, offset, g_nandx->chip->page_size);
+-+ if (ret < 0) {
+-+ pr_info("read fail with ret %d\n", ret);
+-+ goto error;
+-+ }
+-+
+-+ for (i = 0; i < g_nandx->chip->page_size; i++) {
+-+ if (dst_buf[i] != 0xff) {
+-+ pr_info("read after erase, check fail\n");
+-+ pr_info("all data should be 0xff\n");
+-+ ret = -ENANDERASE;
+-+ dump_buf(dst_buf, 128);
+-+ goto error;
+-+ }
+-+ }
+-+
+-+ return 0;
+-+
+-+error:
+-+#if !NANDX_BULK_IO_USE_DRAM
+-+ mem_free(src_buf);
+-+ mem_free(dst_buf);
+-+#endif
+-+ return ret;
+-+}
+-+#endif
+-diff --git a/drivers/mtd/nandx/core/core_io.h b/drivers/mtd/nandx/core/core_io.h
+-new file mode 100644
+-index 0000000000..edcb60908a
+---- /dev/null
+-+++ b/drivers/mtd/nandx/core/core_io.h
+-@@ -0,0 +1,39 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#ifndef __CORE_IO_H__
+-+#define __CORE_IO_H__
+-+
+-+typedef int (*func_chip_ops)(struct nand_chip *, struct nand_ops *,
+-+ int);
+-+
+-+enum nandx_op_mode {
+-+ NANDX_IDLE,
+-+ NANDX_WRITE,
+-+ NANDX_READ,
+-+ NANDX_ERASE
+-+};
+-+
+-+struct nandx_desc {
+-+ struct nand_chip *chip;
+-+ struct nandx_info info;
+-+ enum nandx_op_mode mode;
+-+
+-+ bool multi_en;
+-+ bool ecc_en;
+-+
+-+ struct nand_ops *ops;
+-+ int ops_len;
+-+ int ops_multi_len;
+-+ int ops_current;
+-+ int min_write_pages;
+-+
+-+ u8 *head_buf;
+-+ u8 *tail_buf;
+-+};
+-+
+-+#endif /* __CORE_IO_H__ */
+-diff --git a/drivers/mtd/nandx/core/nand/device_spi.c b/drivers/mtd/nandx/core/nand/device_spi.c
+-new file mode 100644
+-index 0000000000..db338c28c2
+---- /dev/null
+-+++ b/drivers/mtd/nandx/core/nand/device_spi.c
+-@@ -0,0 +1,200 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#include "nandx_util.h"
+-+#include "../nand_device.h"
+-+#include "device_spi.h"
+-+
+-+/* spi nand basic commands */
+-+static struct nand_cmds spi_cmds = {
+-+ .reset = 0xff,
+-+ .read_id = 0x9f,
+-+ .read_status = 0x0f,
+-+ .read_param_page = 0x03,
+-+ .set_feature = 0x1f,
+-+ .get_feature = 0x0f,
+-+ .read_1st = 0x13,
+-+ .read_2nd = -1,
+-+ .random_out_1st = 0x03,
+-+ .random_out_2nd = -1,
+-+ .program_1st = 0x02,
+-+ .program_2nd = 0x10,
+-+ .erase_1st = 0xd8,
+-+ .erase_2nd = -1,
+-+ .read_cache = 0x30,
+-+ .read_cache_last = 0x3f,
+-+ .program_cache = 0x02
+-+};
+-+
+-+/* spi nand extend commands */
+-+static struct spi_extend_cmds spi_extend_cmds = {
+-+ .die_select = 0xc2,
+-+ .write_enable = 0x06
+-+};
+-+
+-+/* means the start bit of addressing type */
+-+static struct nand_addressing spi_addressing = {
+-+ .row_bit_start = 0,
+-+ .block_bit_start = 0,
+-+ .plane_bit_start = 12,
+-+ .lun_bit_start = 0,
+-+};
+-+
+-+/* spi nand endurance */
+-+static struct nand_endurance spi_endurance = {
+-+ .pe_cycle = 100000,
+-+ .ecc_req = 1,
+-+ .max_bitflips = 1
+-+};
+-+
+-+/* array_busy, write_protect, erase_fail, program_fail */
+-+static struct nand_status spi_status[] = {
+-+ {.array_busy = BIT(0),
+-+ .write_protect = BIT(1),
+-+ .erase_fail = BIT(2),
+-+ .program_fail = BIT(3)}
+-+};
+-+
+-+/* measure time by the us */
+-+static struct nand_array_timing spi_array_timing = {
+-+ .tRST = 500,
+-+ .tWHR = 1,
+-+ .tR = 25,
+-+ .tRCBSY = 25,
+-+ .tFEAT = 1,
+-+ .tPROG = 600,
+-+ .tPCBSY = 600,
+-+ .tBERS = 10000,
+-+ .tDBSY = 1
+-+};
+-+
+-+/* spi nand device table */
+-+static struct device_spi spi_nand[] = {
+-+ {
+-+ NAND_DEVICE("W25N01GV",
+-+ NAND_PACK_ID(0xef, 0xaa, 0x21, 0, 0, 0, 0, 0),
+-+ 3, 0, 3, 3,
+-+ 1, 1, 1, 1024, KB(128), KB(2), 64, 1,
+-+ &spi_cmds, &spi_addressing, &spi_status[0],
+-+ &spi_endurance, &spi_array_timing),
+-+ {
+-+ NAND_SPI_PROTECT(0xa0, 1, 2, 6),
+-+ NAND_SPI_CONFIG(0xb0, 4, 6, 0),
+-+ NAND_SPI_STATUS(0xc0, 4, 5),
+-+ NAND_SPI_CHARACTER(0xff, 0xff, 0xff, 0xff)
+-+ },
+-+ &spi_extend_cmds, 0xff, 0xff
+-+ },
+-+ {
+-+ NAND_DEVICE("MX35LF1G",
+-+ NAND_PACK_ID(0xc2, 0x12, 0x21, 0, 0, 0, 0, 0),
+-+ 2, 0, 3, 3,
+-+ 1, 1, 1, 1024, KB(128), KB(2), 64, 1,
+-+ &spi_cmds, &spi_addressing, &spi_status[0],
+-+ &spi_endurance, &spi_array_timing),
+-+ {
+-+ NAND_SPI_PROTECT(0xa0, 1, 2, 6),
+-+ NAND_SPI_CONFIG(0xb0, 4, 6, 1),
+-+ NAND_SPI_STATUS(0xc0, 4, 5),
+-+ NAND_SPI_CHARACTER(0xff, 0xff, 0xff, 0xff)
+-+ },
+-+ &spi_extend_cmds, 0xff, 0xff
+-+ },
+-+ {
+-+ NAND_DEVICE("MT29F4G01ABAFDWB",
+-+ NAND_PACK_ID(0x2c, 0x34, 0, 0, 0, 0, 0, 0),
+-+ 2, 0, 3, 3,
+-+ 1, 1, 1, 2048, KB(256), KB(4), 256, 1,
+-+ &spi_cmds, &spi_addressing, &spi_status[0],
+-+ &spi_endurance, &spi_array_timing),
+-+ {
+-+ NAND_SPI_PROTECT(0xa0, 1, 2, 6),
+-+ NAND_SPI_CONFIG(0xb0, 4, 6, 1),
+-+ NAND_SPI_STATUS(0xc0, 4, 5),
+-+ NAND_SPI_CHARACTER(0xff, 0xff, 0xff, 0xff)
+-+ },
+-+ &spi_extend_cmds, 0xff, 0xff
+-+ },
+-+ {
+-+ NAND_DEVICE("GD5F4GQ4UB",
+-+ NAND_PACK_ID(0xc8, 0xd4, 0, 0, 0, 0, 0, 0),
+-+ 2, 0, 3, 3,
+-+ 1, 1, 1, 2048, KB(256), KB(4), 256, 1,
+-+ &spi_cmds, &spi_addressing, &spi_status[0],
+-+ &spi_endurance, &spi_array_timing),
+-+ {
+-+ NAND_SPI_PROTECT(0xa0, 1, 2, 6),
+-+ NAND_SPI_CONFIG(0xb0, 4, 6, 1),
+-+ NAND_SPI_STATUS(0xc0, 4, 5),
+-+ NAND_SPI_CHARACTER(0xff, 0xff, 0xff, 0xff)
+-+ },
+-+ &spi_extend_cmds, 0xff, 0xff
+-+ },
+-+ {
+-+ NAND_DEVICE("TC58CVG2S0HRAIJ",
+-+ NAND_PACK_ID(0x98, 0xED, 0x51, 0, 0, 0, 0, 0),
+-+ 3, 0, 3, 3,
+-+ 1, 1, 1, 2048, KB(256), KB(4), 256, 1,
+-+ &spi_cmds, &spi_addressing, &spi_status[0],
+-+ &spi_endurance, &spi_array_timing),
+-+ {
+-+ NAND_SPI_PROTECT(0xa0, 1, 2, 6),
+-+ NAND_SPI_CONFIG(0xb0, 4, 6, 1),
+-+ NAND_SPI_STATUS(0xc0, 4, 5),
+-+ NAND_SPI_CHARACTER(0xff, 0xff, 0xff, 0xff)
+-+ },
+-+ &spi_extend_cmds, 0xff, 0xff
+-+ },
+-+ {
+-+ NAND_DEVICE("NO-DEVICE",
+-+ NAND_PACK_ID(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, 0,
+-+ 0, 0, 0, 0, 0, 0, 0, 1,
+-+ &spi_cmds, &spi_addressing, &spi_status[0],
+-+ &spi_endurance, &spi_array_timing),
+-+ {
+-+ NAND_SPI_PROTECT(0xa0, 1, 2, 6),
+-+ NAND_SPI_CONFIG(0xb0, 4, 6, 0),
+-+ NAND_SPI_STATUS(0xc0, 4, 5),
+-+ NAND_SPI_CHARACTER(0xff, 0xff, 0xff, 0xff)
+-+ },
+-+ &spi_extend_cmds, 0xff, 0xff
+-+ }
+-+};
+-+
+-+u8 spi_replace_rx_cmds(u8 mode)
+-+{
+-+ u8 rx_replace_cmds[] = {0x03, 0x3b, 0x6b, 0xbb, 0xeb};
+-+
+-+ return rx_replace_cmds[mode];
+-+}
+-+
+-+u8 spi_replace_tx_cmds(u8 mode)
+-+{
+-+ u8 tx_replace_cmds[] = {0x02, 0x32};
+-+
+-+ return tx_replace_cmds[mode];
+-+}
+-+
+-+u8 spi_replace_rx_col_cycle(u8 mode)
+-+{
+-+ u8 rx_replace_col_cycle[] = {3, 3, 3, 3, 4};
+-+
+-+ return rx_replace_col_cycle[mode];
+-+}
+-+
+-+u8 spi_replace_tx_col_cycle(u8 mode)
+-+{
+-+ u8 tx_replace_col_cycle[] = {2, 2};
+-+
+-+ return tx_replace_col_cycle[mode];
+-+}
+-+
+-+struct nand_device *nand_get_device(int index)
+-+{
+-+ return &spi_nand[index].dev;
+-+}
+-+
+-diff --git a/drivers/mtd/nandx/core/nand/device_spi.h b/drivers/mtd/nandx/core/nand/device_spi.h
+-new file mode 100644
+-index 0000000000..1676b61fc8
+---- /dev/null
+-+++ b/drivers/mtd/nandx/core/nand/device_spi.h
+-@@ -0,0 +1,132 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#ifndef __DEVICE_SPI_H__
+-+#define __DEVICE_SPI_H__
+-+
+-+/*
+-+ * extend commands
+-+ * @die_select: select nand device die command
+-+ * @write_enable: enable write command before write data to spi nand
+-+ * spi nand device will auto to be disable after write done
+-+ */
+-+struct spi_extend_cmds {
+-+ short die_select;
+-+ short write_enable;
+-+};
+-+
+-+/*
+-+ * protection feature register
+-+ * @addr: register address
+-+ * @wp_en_bit: write protection enable bit
+-+ * @bp_start_bit: block protection mask start bit
+-+ * @bp_end_bit: block protection mask end bit
+-+ */
+-+struct feature_protect {
+-+ u8 addr;
+-+ u8 wp_en_bit;
+-+ u8 bp_start_bit;
+-+ u8 bp_end_bit;
+-+};
+-+
+-+/*
+-+ * configuration feature register
+-+ * @addr: register address
+-+ * @ecc_en_bit: in-die ecc enable bit
+-+ * @otp_en_bit: enter otp access mode bit
+-+ * @need_qe: quad io enable bit
+-+ */
+-+struct feature_config {
+-+ u8 addr;
+-+ u8 ecc_en_bit;
+-+ u8 otp_en_bit;
+-+ u8 need_qe;
+-+};
+-+
+-+/*
+-+ * status feature register
+-+ * @addr: register address
+-+ * @ecc_start_bit: ecc status mask start bit for error bits number
+-+ * @ecc_end_bit: ecc status mask end bit for error bits number
+-+ * note that:
+-+ * operations status (ex. array busy status) could see on struct nand_status
+-+ */
+-+struct feature_status {
+-+ u8 addr;
+-+ u8 ecc_start_bit;
+-+ u8 ecc_end_bit;
+-+};
+-+
+-+/*
+-+ * character feature register
+-+ * @addr: register address
+-+ * @die_sel_bit: die select bit
+-+ * @drive_start_bit: drive strength mask start bit
+-+ * @drive_end_bit: drive strength mask end bit
+-+ */
+-+struct feature_character {
+-+ u8 addr;
+-+ u8 die_sel_bit;
+-+ u8 drive_start_bit;
+-+ u8 drive_end_bit;
+-+};
+-+
+-+/*
+-+ * spi features
+-+ * @protect: protection feature register
+-+ * @config: configuration feature register
+-+ * @status: status feature register
+-+ * @character: character feature register
+-+ */
+-+struct spi_features {
+-+ struct feature_protect protect;
+-+ struct feature_config config;
+-+ struct feature_status status;
+-+ struct feature_character character;
+-+};
+-+
+-+/*
+-+ * device_spi
+-+ * configurations of spi nand device table
+-+ * @dev: base information of nand device
+-+ * @feature: feature information for spi nand
+-+ * @extend_cmds: extended the nand base commands
+-+ * @tx_mode_mask: tx mode mask for chip read
+-+ * @rx_mode_mask: rx mode mask for chip write
+-+ */
+-+struct device_spi {
+-+ struct nand_device dev;
+-+ struct spi_features feature;
+-+ struct spi_extend_cmds *extend_cmds;
+-+
+-+ u8 tx_mode_mask;
+-+ u8 rx_mode_mask;
+-+};
+-+
+-+#define NAND_SPI_PROTECT(addr, wp_en_bit, bp_start_bit, bp_end_bit) \
+-+ {addr, wp_en_bit, bp_start_bit, bp_end_bit}
+-+
+-+#define NAND_SPI_CONFIG(addr, ecc_en_bit, otp_en_bit, need_qe) \
+-+ {addr, ecc_en_bit, otp_en_bit, need_qe}
+-+
+-+#define NAND_SPI_STATUS(addr, ecc_start_bit, ecc_end_bit) \
+-+ {addr, ecc_start_bit, ecc_end_bit}
+-+
+-+#define NAND_SPI_CHARACTER(addr, die_sel_bit, drive_start_bit, drive_end_bit) \
+-+ {addr, die_sel_bit, drive_start_bit, drive_end_bit}
+-+
+-+static inline struct device_spi *device_to_spi(struct nand_device *dev)
+-+{
+-+ return container_of(dev, struct device_spi, dev);
+-+}
+-+
+-+u8 spi_replace_rx_cmds(u8 mode);
+-+u8 spi_replace_tx_cmds(u8 mode);
+-+u8 spi_replace_rx_col_cycle(u8 mode);
+-+u8 spi_replace_tx_col_cycle(u8 mode);
+-+
+-+#endif /* __DEVICE_SPI_H__ */
+-diff --git a/drivers/mtd/nandx/core/nand/nand_spi.c b/drivers/mtd/nandx/core/nand/nand_spi.c
+-new file mode 100644
+-index 0000000000..2ae03e1cf4
+---- /dev/null
+-+++ b/drivers/mtd/nandx/core/nand/nand_spi.c
+-@@ -0,0 +1,526 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#include "nandx_util.h"
+-+#include "nandx_core.h"
+-+#include "../nand_chip.h"
+-+#include "../nand_device.h"
+-+#include "../nfi.h"
+-+#include "../nand_base.h"
+-+#include "device_spi.h"
+-+#include "nand_spi.h"
+-+
+-+#define READY_TIMEOUT 500000 /* us */
+-+
+-+static int nand_spi_read_status(struct nand_base *nand)
+-+{
+-+ struct device_spi *dev = device_to_spi(nand->dev);
+-+ u8 status;
+-+
+-+ nand->get_feature(nand, dev->feature.status.addr, &status, 1);
+-+
+-+ return status;
+-+}
+-+
+-+static int nand_spi_wait_ready(struct nand_base *nand, u32 timeout)
+-+{
+-+ u64 now, end;
+-+ int status;
+-+
+-+ end = get_current_time_us() + timeout;
+-+
+-+ do {
+-+ status = nand_spi_read_status(nand);
+-+ status &= nand->dev->status->array_busy;
+-+ now = get_current_time_us();
+-+
+-+ if (now > end)
+-+ break;
+-+ } while (status);
+-+
+-+ return status ? -EBUSY : 0;
+-+}
+-+
+-+static int nand_spi_set_op_mode(struct nand_base *nand, u8 mode)
+-+{
+-+ struct nand_spi *spi_nand = base_to_spi(nand);
+-+ struct nfi *nfi = nand->nfi;
+-+ int ret = 0;
+-+
+-+ if (spi_nand->op_mode != mode) {
+-+ ret = nfi->nfi_ctrl(nfi, SNFI_CTRL_OP_MODE, (void *)&mode);
+-+ spi_nand->op_mode = mode;
+-+ }
+-+
+-+ return ret;
+-+}
+-+
+-+static int nand_spi_set_config(struct nand_base *nand, u8 addr, u8 mask,
+-+ bool en)
+-+{
+-+ u8 configs = 0;
+-+
+-+ nand->get_feature(nand, addr, &configs, 1);
+-+
+-+ if (en)
+-+ configs |= mask;
+-+ else
+-+ configs &= ~mask;
+-+
+-+ nand->set_feature(nand, addr, &configs, 1);
+-+
+-+ configs = 0;
+-+ nand->get_feature(nand, addr, &configs, 1);
+-+
+-+ return (configs & mask) == en ? 0 : -EFAULT;
+-+}
+-+
+-+static int nand_spi_die_select(struct nand_base *nand, int *row)
+-+{
+-+ struct device_spi *dev = device_to_spi(nand->dev);
+-+ struct nfi *nfi = nand->nfi;
+-+ int lun_blocks, block_pages, lun, blocks;
+-+ int page = *row, ret = 0;
+-+ u8 param = 0, die_sel;
+-+
+-+ if (nand->dev->lun_num < 2)
+-+ return 0;
+-+
+-+ block_pages = nand_block_pages(nand->dev);
+-+ lun_blocks = nand_lun_blocks(nand->dev);
+-+ blocks = div_down(page, block_pages);
+-+ lun = div_down(blocks, lun_blocks);
+-+
+-+ if (dev->extend_cmds->die_select == -1) {
+-+ die_sel = (u8)(lun << dev->feature.character.die_sel_bit);
+-+ nand->get_feature(nand, dev->feature.character.addr, ¶m, 1);
+-+ param |= die_sel;
+-+ nand->set_feature(nand, dev->feature.character.addr, ¶m, 1);
+-+ param = 0;
+-+ nand->get_feature(nand, dev->feature.character.addr, ¶m, 1);
+-+ ret = (param & die_sel) ? 0 : -EFAULT;
+-+ } else {
+-+ nfi->reset(nfi);
+-+ nfi->send_cmd(nfi, dev->extend_cmds->die_select);
+-+ nfi->send_addr(nfi, lun, 0, 1, 0);
+-+ nfi->trigger(nfi);
+-+ }
+-+
+-+ *row = page - (lun_blocks * block_pages) * lun;
+-+
+-+ return ret;
+-+}
+-+
+-+static int nand_spi_select_device(struct nand_base *nand, int cs)
+-+{
+-+ struct nand_spi *spi = base_to_spi(nand);
+-+ struct nand_base *parent = spi->parent;
+-+
+-+ nand_spi_set_op_mode(nand, SNFI_MAC_MODE);
+-+
+-+ return parent->select_device(nand, cs);
+-+}
+-+
+-+static int nand_spi_reset(struct nand_base *nand)
+-+{
+-+ struct nand_spi *spi = base_to_spi(nand);
+-+ struct nand_base *parent = spi->parent;
+-+
+-+ nand_spi_set_op_mode(nand, SNFI_MAC_MODE);
+-+
+-+ parent->reset(nand);
+-+
+-+ return nand_spi_wait_ready(nand, READY_TIMEOUT);
+-+}
+-+
+-+static int nand_spi_read_id(struct nand_base *nand, u8 *id, int count)
+-+{
+-+ struct nand_spi *spi = base_to_spi(nand);
+-+ struct nand_base *parent = spi->parent;
+-+
+-+ nand_spi_set_op_mode(nand, SNFI_MAC_MODE);
+-+
+-+ return parent->read_id(nand, id, count);
+-+}
+-+
+-+static int nand_spi_read_param_page(struct nand_base *nand, u8 *data,
+-+ int count)
+-+{
+-+ struct device_spi *dev = device_to_spi(nand->dev);
+-+ struct nand_spi *spi = base_to_spi(nand);
+-+ struct nfi *nfi = nand->nfi;
+-+ int sectors, value;
+-+ u8 param = 0;
+-+
+-+ sectors = div_round_up(count, nfi->sector_size);
+-+
+-+ nand->get_feature(nand, dev->feature.config.addr, ¶m, 1);
+-+ param |= BIT(dev->feature.config.otp_en_bit);
+-+ nand->set_feature(nand, dev->feature.config.addr, ¶m, 1);
+-+
+-+ param = 0;
+-+ nand->get_feature(nand, dev->feature.config.addr, ¶m, 1);
+-+ if (param & BIT(dev->feature.config.otp_en_bit)) {
+-+ value = 0;
+-+ nfi->nfi_ctrl(nfi, NFI_CTRL_ECC, &value);
+-+ nand->dev->col_cycle = spi_replace_rx_col_cycle(spi->rx_mode);
+-+ nand->read_page(nand, 0x01);
+-+ nand->read_data(nand, 0x01, 0, sectors, data, NULL);
+-+ }
+-+
+-+ param &= ~BIT(dev->feature.config.otp_en_bit);
+-+ nand->set_feature(nand, dev->feature.config.addr, ¶m, 1);
+-+
+-+ return 0;
+-+}
+-+
+-+static int nand_spi_set_feature(struct nand_base *nand, u8 addr,
+-+ u8 *param,
+-+ int count)
+-+{
+-+ struct nand_spi *spi = base_to_spi(nand);
+-+ struct nand_base *parent = spi->parent;
+-+
+-+ nand->write_enable(nand);
+-+
+-+ nand_spi_set_op_mode(nand, SNFI_MAC_MODE);
+-+
+-+ return parent->set_feature(nand, addr, param, count);
+-+}
+-+
+-+static int nand_spi_get_feature(struct nand_base *nand, u8 addr,
+-+ u8 *param,
+-+ int count)
+-+{
+-+ struct nand_spi *spi = base_to_spi(nand);
+-+ struct nand_base *parent = spi->parent;
+-+
+-+ nand_spi_set_op_mode(nand, SNFI_MAC_MODE);
+-+
+-+ return parent->get_feature(nand, addr, param, count);
+-+}
+-+
+-+static int nand_spi_addressing(struct nand_base *nand, int *row,
+-+ int *col)
+-+{
+-+ struct nand_device *dev = nand->dev;
+-+ int plane, block, block_pages;
+-+ int ret;
+-+
+-+ ret = nand_spi_die_select(nand, row);
+-+ if (ret)
+-+ return ret;
+-+
+-+ block_pages = nand_block_pages(dev);
+-+ block = div_down(*row, block_pages);
+-+
+-+ plane = block % dev->plane_num;
+-+ *col |= (plane << dev->addressing->plane_bit_start);
+-+
+-+ return 0;
+-+}
+-+
+-+static int nand_spi_read_page(struct nand_base *nand, int row)
+-+{
+-+ struct nand_spi *spi = base_to_spi(nand);
+-+ struct nand_base *parent = spi->parent;
+-+
+-+ if (spi->op_mode == SNFI_AUTO_MODE)
+-+ nand_spi_set_op_mode(nand, SNFI_AUTO_MODE);
+-+ else
+-+ nand_spi_set_op_mode(nand, SNFI_MAC_MODE);
+-+
+-+ parent->read_page(nand, row);
+-+
+-+ return nand_spi_wait_ready(nand, READY_TIMEOUT);
+-+}
+-+
+-+static int nand_spi_read_data(struct nand_base *nand, int row, int col,
+-+ int sectors, u8 *data, u8 *oob)
+-+{
+-+ struct device_spi *dev = device_to_spi(nand->dev);
+-+ struct nand_spi *spi = base_to_spi(nand);
+-+ struct nand_base *parent = spi->parent;
+-+ int ret;
+-+
+-+ if ((spi->rx_mode == SNFI_RX_114 || spi->rx_mode == SNFI_RX_144) &&
+-+ dev->feature.config.need_qe)
+-+ nand_spi_set_config(nand, dev->feature.config.addr,
+-+ BIT(0), true);
+-+
+-+ nand->dev->col_cycle = spi_replace_rx_col_cycle(spi->rx_mode);
+-+
+-+ nand_spi_set_op_mode(nand, SNFI_CUSTOM_MODE);
+-+
+-+ ret = parent->read_data(nand, row, col, sectors, data, oob);
+-+ if (ret)
+-+ return -ENANDREAD;
+-+
+-+ if (spi->ondie_ecc) {
+-+ ret = nand_spi_read_status(nand);
+-+ ret &= GENMASK(dev->feature.status.ecc_end_bit,
+-+ dev->feature.status.ecc_start_bit);
+-+ ret >>= dev->feature.status.ecc_start_bit;
+-+ if (ret > nand->dev->endurance->ecc_req)
+-+ return -ENANDREAD;
+-+ else if (ret > nand->dev->endurance->max_bitflips)
+-+ return -ENANDFLIPS;
+-+ }
+-+
+-+ return 0;
+-+}
+-+
+-+static int nand_spi_write_enable(struct nand_base *nand)
+-+{
+-+ struct device_spi *dev = device_to_spi(nand->dev);
+-+ struct nfi *nfi = nand->nfi;
+-+ int status;
+-+
+-+ nand_spi_set_op_mode(nand, SNFI_MAC_MODE);
+-+
+-+ nfi->reset(nfi);
+-+ nfi->send_cmd(nfi, dev->extend_cmds->write_enable);
+-+
+-+ nfi->trigger(nfi);
+-+
+-+ status = nand_spi_read_status(nand);
+-+ status &= nand->dev->status->write_protect;
+-+
+-+ return !status;
+-+}
+-+
+-+static int nand_spi_program_data(struct nand_base *nand, int row,
+-+ int col,
+-+ u8 *data, u8 *oob)
+-+{
+-+ struct device_spi *dev = device_to_spi(nand->dev);
+-+ struct nand_spi *spi = base_to_spi(nand);
+-+
+-+ if (spi->tx_mode == SNFI_TX_114 && dev->feature.config.need_qe)
+-+ nand_spi_set_config(nand, dev->feature.config.addr,
+-+ BIT(0), true);
+-+
+-+ nand_spi_set_op_mode(nand, SNFI_CUSTOM_MODE);
+-+
+-+ nand->dev->col_cycle = spi_replace_tx_col_cycle(spi->tx_mode);
+-+
+-+ return spi->parent->program_data(nand, row, col, data, oob);
+-+}
+-+
+-+static int nand_spi_program_page(struct nand_base *nand, int row)
+-+{
+-+ struct nand_spi *spi = base_to_spi(nand);
+-+ struct nand_device *dev = nand->dev;
+-+ struct nfi *nfi = nand->nfi;
+-+
+-+ if (spi->op_mode == SNFI_AUTO_MODE)
+-+ nand_spi_set_op_mode(nand, SNFI_AUTO_MODE);
+-+ else
+-+ nand_spi_set_op_mode(nand, SNFI_MAC_MODE);
+-+
+-+ nfi->reset(nfi);
+-+ nfi->send_cmd(nfi, dev->cmds->program_2nd);
+-+ nfi->send_addr(nfi, 0, row, dev->col_cycle, dev->row_cycle);
+-+ nfi->trigger(nfi);
+-+
+-+ return nand_spi_wait_ready(nand, READY_TIMEOUT);
+-+}
+-+
+-+static int nand_spi_erase_block(struct nand_base *nand, int row)
+-+{
+-+ struct nand_spi *spi = base_to_spi(nand);
+-+ struct nand_base *parent = spi->parent;
+-+
+-+ nand_spi_set_op_mode(nand, SNFI_MAC_MODE);
+-+
+-+ parent->erase_block(nand, row);
+-+
+-+ return nand_spi_wait_ready(nand, READY_TIMEOUT);
+-+}
+-+
+-+static int nand_chip_spi_ctrl(struct nand_chip *chip, int cmd,
+-+ void *args)
+-+{
+-+ struct nand_base *nand = chip->nand;
+-+ struct device_spi *dev = device_to_spi(nand->dev);
+-+ struct nand_spi *spi = base_to_spi(nand);
+-+ struct nfi *nfi = nand->nfi;
+-+ int ret = 0, value = *(int *)args;
+-+
+-+ switch (cmd) {
+-+ case CHIP_CTRL_ONDIE_ECC:
+-+ spi->ondie_ecc = (bool)value;
+-+ ret = nand_spi_set_config(nand, dev->feature.config.addr,
+-+ BIT(dev->feature.config.ecc_en_bit),
+-+ spi->ondie_ecc);
+-+ break;
+-+
+-+ case SNFI_CTRL_TX_MODE:
+-+ if (value < 0 || value > SNFI_TX_114)
+-+ return -EOPNOTSUPP;
+-+
+-+ if (dev->tx_mode_mask & BIT(value)) {
+-+ spi->tx_mode = value;
+-+ nand->dev->cmds->random_out_1st = spi_replace_tx_cmds(
+-+ spi->tx_mode);
+-+ ret = nfi->nfi_ctrl(nfi, cmd, args);
+-+ }
+-+
+-+ break;
+-+
+-+ case SNFI_CTRL_RX_MODE:
+-+ if (value < 0 || value > SNFI_RX_144)
+-+ return -EOPNOTSUPP;
+-+
+-+ if (dev->rx_mode_mask & BIT(value)) {
+-+ spi->rx_mode = value;
+-+ nand->dev->cmds->program_1st = spi_replace_rx_cmds(
+-+ spi->rx_mode);
+-+ ret = nfi->nfi_ctrl(nfi, cmd, args);
+-+ }
+-+
+-+ break;
+-+
+-+ case CHIP_CTRL_OPS_CACHE:
+-+ case CHIP_CTRL_OPS_MULTI:
+-+ case CHIP_CTRL_PSLC_MODE:
+-+ case CHIP_CTRL_DDR_MODE:
+-+ case CHIP_CTRL_DRIVE_STRENGTH:
+-+ case CHIP_CTRL_TIMING_MODE:
+-+ ret = -EOPNOTSUPP;
+-+ break;
+-+
+-+ default:
+-+ ret = nfi->nfi_ctrl(nfi, cmd, args);
+-+ break;
+-+ }
+-+
+-+ return ret;
+-+}
+-+
+-+int nand_chip_spi_resume(struct nand_chip *chip)
+-+{
+-+ struct nand_base *nand = chip->nand;
+-+ struct nand_spi *spi = base_to_spi(nand);
+-+ struct device_spi *dev = device_to_spi(nand->dev);
+-+ struct nfi *nfi = nand->nfi;
+-+ struct nfi_format format;
+-+ u8 mask;
+-+
+-+ nand->reset(nand);
+-+
+-+ mask = GENMASK(dev->feature.protect.bp_end_bit,
+-+ dev->feature.protect.bp_start_bit);
+-+ nand_spi_set_config(nand, dev->feature.config.addr, mask, false);
+-+ mask = BIT(dev->feature.config.ecc_en_bit);
+-+ nand_spi_set_config(nand, dev->feature.config.addr, mask,
+-+ spi->ondie_ecc);
+-+
+-+ format.page_size = nand->dev->page_size;
+-+ format.spare_size = nand->dev->spare_size;
+-+ format.ecc_req = nand->dev->endurance->ecc_req;
+-+
+-+ return nfi->set_format(nfi, &format);
+-+}
+-+
+-+static int nand_spi_set_format(struct nand_base *nand)
+-+{
+-+ struct nfi_format format = {
+-+ nand->dev->page_size,
+-+ nand->dev->spare_size,
+-+ nand->dev->endurance->ecc_req
+-+ };
+-+
+-+ return nand->nfi->set_format(nand->nfi, &format);
+-+}
+-+
+-+struct nand_base *nand_device_init(struct nand_chip *chip)
+-+{
+-+ struct nand_base *nand;
+-+ struct nand_spi *spi;
+-+ struct device_spi *dev;
+-+ int ret;
+-+ u8 mask;
+-+
+-+ spi = mem_alloc(1, sizeof(struct nand_spi));
+-+ if (!spi) {
+-+ pr_info("alloc nand_spi fail\n");
+-+ return NULL;
+-+ }
+-+
+-+ spi->ondie_ecc = false;
+-+ spi->op_mode = SNFI_CUSTOM_MODE;
+-+ spi->rx_mode = SNFI_RX_114;
+-+ spi->tx_mode = SNFI_TX_114;
+-+
+-+ spi->parent = chip->nand;
+-+ nand = &spi->base;
+-+ nand->dev = spi->parent->dev;
+-+ nand->nfi = spi->parent->nfi;
+-+
+-+ nand->select_device = nand_spi_select_device;
+-+ nand->reset = nand_spi_reset;
+-+ nand->read_id = nand_spi_read_id;
+-+ nand->read_param_page = nand_spi_read_param_page;
+-+ nand->set_feature = nand_spi_set_feature;
+-+ nand->get_feature = nand_spi_get_feature;
+-+ nand->read_status = nand_spi_read_status;
+-+ nand->addressing = nand_spi_addressing;
+-+ nand->read_page = nand_spi_read_page;
+-+ nand->read_data = nand_spi_read_data;
+-+ nand->write_enable = nand_spi_write_enable;
+-+ nand->program_data = nand_spi_program_data;
+-+ nand->program_page = nand_spi_program_page;
+-+ nand->erase_block = nand_spi_erase_block;
+-+
+-+ chip->chip_ctrl = nand_chip_spi_ctrl;
+-+ chip->nand_type = NAND_SPI;
+-+ chip->resume = nand_chip_spi_resume;
+-+
+-+ ret = nand_detect_device(nand);
+-+ if (ret)
+-+ goto err;
+-+
+-+ nand->select_device(nand, 0);
+-+
+-+ ret = nand_spi_set_format(nand);
+-+ if (ret)
+-+ goto err;
+-+
+-+ dev = (struct device_spi *)nand->dev;
+-+
+-+ nand->dev->cmds->random_out_1st =
+-+ spi_replace_rx_cmds(spi->rx_mode);
+-+ nand->dev->cmds->program_1st =
+-+ spi_replace_tx_cmds(spi->tx_mode);
+-+
+-+ mask = GENMASK(dev->feature.protect.bp_end_bit,
+-+ dev->feature.protect.bp_start_bit);
+-+ ret = nand_spi_set_config(nand, dev->feature.protect.addr, mask, false);
+-+ if (ret)
+-+ goto err;
+-+
+-+ mask = BIT(dev->feature.config.ecc_en_bit);
+-+ ret = nand_spi_set_config(nand, dev->feature.config.addr, mask,
+-+ spi->ondie_ecc);
+-+ if (ret)
+-+ goto err;
+-+
+-+ return nand;
+-+
+-+err:
+-+ mem_free(spi);
+-+ return NULL;
+-+}
+-+
+-+void nand_exit(struct nand_base *nand)
+-+{
+-+ struct nand_spi *spi = base_to_spi(nand);
+-+
+-+ nand_base_exit(spi->parent);
+-+ mem_free(spi);
+-+}
+-diff --git a/drivers/mtd/nandx/core/nand/nand_spi.h b/drivers/mtd/nandx/core/nand/nand_spi.h
+-new file mode 100644
+-index 0000000000..e55e4de6f7
+---- /dev/null
+-+++ b/drivers/mtd/nandx/core/nand/nand_spi.h
+-@@ -0,0 +1,35 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#ifndef __NAND_SPI_H__
+-+#define __NAND_SPI_H__
+-+
+-+/*
+-+ * spi nand handler
+-+ * @base: spi nand base functions
+-+ * @parent: common parent nand base functions
+-+ * @tx_mode: spi bus width of transfer to device
+-+ * @rx_mode: spi bus width of transfer from device
+-+ * @op_mode: spi nand controller (NFI) operation mode
+-+ * @ondie_ecc: spi nand on-die ecc flag
+-+ */
+-+
+-+struct nand_spi {
+-+ struct nand_base base;
+-+ struct nand_base *parent;
+-+ u8 tx_mode;
+-+ u8 rx_mode;
+-+ u8 op_mode;
+-+ bool ondie_ecc;
+-+};
+-+
+-+static inline struct nand_spi *base_to_spi(struct nand_base *base)
+-+{
+-+ return container_of(base, struct nand_spi, base);
+-+}
+-+
+-+#endif /* __NAND_SPI_H__ */
+-diff --git a/drivers/mtd/nandx/core/nand_base.c b/drivers/mtd/nandx/core/nand_base.c
+-new file mode 100644
+-index 0000000000..65998e5460
+---- /dev/null
+-+++ b/drivers/mtd/nandx/core/nand_base.c
+-@@ -0,0 +1,304 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#include "nandx_util.h"
+-+#include "nandx_core.h"
+-+#include "nand_chip.h"
+-+#include "nand_device.h"
+-+#include "nfi.h"
+-+#include "nand_base.h"
+-+
+-+static int nand_base_select_device(struct nand_base *nand, int cs)
+-+{
+-+ struct nfi *nfi = nand->nfi;
+-+
+-+ nfi->reset(nfi);
+-+
+-+ return nfi->select_chip(nfi, cs);
+-+}
+-+
+-+static int nand_base_reset(struct nand_base *nand)
+-+{
+-+ struct nfi *nfi = nand->nfi;
+-+ struct nand_device *dev = nand->dev;
+-+
+-+ nfi->reset(nfi);
+-+ nfi->send_cmd(nfi, dev->cmds->reset);
+-+ nfi->trigger(nfi);
+-+
+-+ return nfi->wait_ready(nfi, NAND_WAIT_POLLING, dev->array_timing->tRST);
+-+}
+-+
+-+static int nand_base_read_id(struct nand_base *nand, u8 *id, int count)
+-+{
+-+ struct nfi *nfi = nand->nfi;
+-+ struct nand_device *dev = nand->dev;
+-+
+-+ nfi->reset(nfi);
+-+ nfi->send_cmd(nfi, dev->cmds->read_id);
+-+ nfi->wait_ready(nfi, NAND_WAIT_POLLING, dev->array_timing->tWHR);
+-+ nfi->send_addr(nfi, 0, 0, 1, 0);
+-+
+-+ return nfi->read_bytes(nfi, id, count);
+-+}
+-+
+-+static int nand_base_read_param_page(struct nand_base *nand, u8 *data,
+-+ int count)
+-+{
+-+ struct nfi *nfi = nand->nfi;
+-+ struct nand_device *dev = nand->dev;
+-+
+-+ nfi->reset(nfi);
+-+ nfi->send_cmd(nfi, dev->cmds->read_param_page);
+-+ nfi->send_addr(nfi, 0, 0, 1, 0);
+-+
+-+ nfi->wait_ready(nfi, NAND_WAIT_POLLING, dev->array_timing->tR);
+-+
+-+ return nfi->read_bytes(nfi, data, count);
+-+}
+-+
+-+static int nand_base_set_feature(struct nand_base *nand, u8 addr,
+-+ u8 *param,
+-+ int count)
+-+{
+-+ struct nfi *nfi = nand->nfi;
+-+ struct nand_device *dev = nand->dev;
+-+
+-+ nfi->reset(nfi);
+-+ nfi->send_cmd(nfi, dev->cmds->set_feature);
+-+ nfi->send_addr(nfi, addr, 0, 1, 0);
+-+
+-+ nfi->write_bytes(nfi, param, count);
+-+
+-+ return nfi->wait_ready(nfi, NAND_WAIT_POLLING,
+-+ dev->array_timing->tFEAT);
+-+}
+-+
+-+static int nand_base_get_feature(struct nand_base *nand, u8 addr,
+-+ u8 *param,
+-+ int count)
+-+{
+-+ struct nfi *nfi = nand->nfi;
+-+ struct nand_device *dev = nand->dev;
+-+
+-+ nfi->reset(nfi);
+-+ nfi->send_cmd(nfi, dev->cmds->get_feature);
+-+ nfi->send_addr(nfi, addr, 0, 1, 0);
+-+ nfi->wait_ready(nfi, NAND_WAIT_POLLING, dev->array_timing->tFEAT);
+-+
+-+ return nfi->read_bytes(nfi, param, count);
+-+}
+-+
+-+static int nand_base_read_status(struct nand_base *nand)
+-+{
+-+ struct nfi *nfi = nand->nfi;
+-+ struct nand_device *dev = nand->dev;
+-+ u8 status = 0;
+-+
+-+ nfi->reset(nfi);
+-+ nfi->send_cmd(nfi, dev->cmds->read_status);
+-+ nfi->wait_ready(nfi, NAND_WAIT_POLLING, dev->array_timing->tWHR);
+-+ nfi->read_bytes(nfi, &status, 1);
+-+
+-+ return status;
+-+}
+-+
+-+static int nand_base_addressing(struct nand_base *nand, int *row,
+-+ int *col)
+-+{
+-+ struct nand_device *dev = nand->dev;
+-+ int lun, plane, block, page, cs = 0;
+-+ int block_pages, target_blocks, wl = 0;
+-+ int icol = *col;
+-+
+-+ if (dev->target_num > 1) {
+-+ block_pages = nand_block_pages(dev);
+-+ target_blocks = nand_target_blocks(dev);
+-+ cs = div_down(*row, block_pages * target_blocks);
+-+ *row -= cs * block_pages * target_blocks;
+-+ }
+-+
+-+ nand->select_device(nand, cs);
+-+
+-+ block_pages = nand_block_pages(dev);
+-+ block = div_down(*row, block_pages);
+-+ page = *row - block * block_pages;
+-+ plane = reminder(block, dev->plane_num);
+-+ lun = div_down(block, nand_lun_blocks(dev));
+-+
+-+ wl |= (page << dev->addressing->row_bit_start);
+-+ wl |= (block << dev->addressing->block_bit_start);
+-+ wl |= (plane << dev->addressing->plane_bit_start);
+-+ wl |= (lun << dev->addressing->lun_bit_start);
+-+
+-+ *row = wl;
+-+ *col = icol;
+-+
+-+ return 0;
+-+}
+-+
+-+static int nand_base_read_page(struct nand_base *nand, int row)
+-+{
+-+ struct nfi *nfi = nand->nfi;
+-+ struct nand_device *dev = nand->dev;
+-+
+-+ nfi->reset(nfi);
+-+ nfi->send_cmd(nfi, dev->cmds->read_1st);
+-+ nfi->send_addr(nfi, 0, row, dev->col_cycle, dev->row_cycle);
+-+ nfi->send_cmd(nfi, dev->cmds->read_2nd);
+-+ nfi->trigger(nfi);
+-+
+-+ return nfi->wait_ready(nfi, NAND_WAIT_POLLING, dev->array_timing->tR);
+-+}
+-+
+-+static int nand_base_read_data(struct nand_base *nand, int row, int col,
+-+ int sectors, u8 *data, u8 *oob)
+-+{
+-+ struct nfi *nfi = nand->nfi;
+-+ struct nand_device *dev = nand->dev;
+-+
+-+ nfi->reset(nfi);
+-+ nfi->send_cmd(nfi, dev->cmds->random_out_1st);
+-+ nfi->send_addr(nfi, col, row, dev->col_cycle, dev->row_cycle);
+-+ nfi->send_cmd(nfi, dev->cmds->random_out_2nd);
+-+ nfi->wait_ready(nfi, NAND_WAIT_POLLING, dev->array_timing->tRCBSY);
+-+
+-+ return nfi->read_sectors(nfi, data, oob, sectors);
+-+}
+-+
+-+static int nand_base_write_enable(struct nand_base *nand)
+-+{
+-+ struct nand_device *dev = nand->dev;
+-+ int status;
+-+
+-+ status = nand_base_read_status(nand);
+-+ if (status & dev->status->write_protect)
+-+ return 0;
+-+
+-+ return -ENANDWP;
+-+}
+-+
+-+static int nand_base_program_data(struct nand_base *nand, int row,
+-+ int col,
+-+ u8 *data, u8 *oob)
+-+{
+-+ struct nfi *nfi = nand->nfi;
+-+ struct nand_device *dev = nand->dev;
+-+
+-+ nfi->reset(nfi);
+-+ nfi->send_cmd(nfi, dev->cmds->program_1st);
+-+ nfi->send_addr(nfi, 0, row, dev->col_cycle, dev->row_cycle);
+-+
+-+ return nfi->write_page(nfi, data, oob);
+-+}
+-+
+-+static int nand_base_program_page(struct nand_base *nand, int row)
+-+{
+-+ struct nfi *nfi = nand->nfi;
+-+ struct nand_device *dev = nand->dev;
+-+
+-+ nfi->reset(nfi);
+-+ nfi->send_cmd(nfi, dev->cmds->program_2nd);
+-+ nfi->trigger(nfi);
+-+
+-+ return nfi->wait_ready(nfi, NAND_WAIT_POLLING,
+-+ dev->array_timing->tPROG);
+-+}
+-+
+-+static int nand_base_erase_block(struct nand_base *nand, int row)
+-+{
+-+ struct nfi *nfi = nand->nfi;
+-+ struct nand_device *dev = nand->dev;
+-+
+-+ nfi->reset(nfi);
+-+ nfi->send_cmd(nfi, dev->cmds->erase_1st);
+-+ nfi->send_addr(nfi, 0, row, 0, dev->row_cycle);
+-+ nfi->send_cmd(nfi, dev->cmds->erase_2nd);
+-+ nfi->trigger(nfi);
+-+
+-+ return nfi->wait_ready(nfi, NAND_WAIT_POLLING,
+-+ dev->array_timing->tBERS);
+-+}
+-+
+-+static int nand_base_read_cache(struct nand_base *nand, int row)
+-+{
+-+ struct nfi *nfi = nand->nfi;
+-+ struct nand_device *dev = nand->dev;
+-+
+-+ nfi->reset(nfi);
+-+ nfi->send_cmd(nfi, dev->cmds->read_1st);
+-+ nfi->send_addr(nfi, 0, row, dev->col_cycle, dev->row_cycle);
+-+ nfi->send_cmd(nfi, dev->cmds->read_cache);
+-+ nfi->trigger(nfi);
+-+
+-+ return nfi->wait_ready(nfi, NAND_WAIT_POLLING,
+-+ dev->array_timing->tRCBSY);
+-+}
+-+
+-+static int nand_base_read_last(struct nand_base *nand)
+-+{
+-+ struct nfi *nfi = nand->nfi;
+-+ struct nand_device *dev = nand->dev;
+-+
+-+ nfi->reset(nfi);
+-+ nfi->send_cmd(nfi, dev->cmds->read_cache_last);
+-+ nfi->trigger(nfi);
+-+
+-+ return nfi->wait_ready(nfi, NAND_WAIT_POLLING,
+-+ dev->array_timing->tRCBSY);
+-+}
+-+
+-+static int nand_base_program_cache(struct nand_base *nand)
+-+{
+-+ struct nfi *nfi = nand->nfi;
+-+ struct nand_device *dev = nand->dev;
+-+
+-+ nfi->reset(nfi);
+-+ nfi->send_cmd(nfi, dev->cmds->program_cache);
+-+ nfi->trigger(nfi);
+-+
+-+ return nfi->wait_ready(nfi, NAND_WAIT_POLLING,
+-+ dev->array_timing->tPCBSY);
+-+}
+-+
+-+struct nand_base *nand_base_init(struct nand_device *dev,
+-+ struct nfi *nfi)
+-+{
+-+ struct nand_base *nand;
+-+
+-+ nand = mem_alloc(1, sizeof(struct nand_base));
+-+ if (!nand)
+-+ return NULL;
+-+
+-+ nand->dev = dev;
+-+ nand->nfi = nfi;
+-+ nand->select_device = nand_base_select_device;
+-+ nand->reset = nand_base_reset;
+-+ nand->read_id = nand_base_read_id;
+-+ nand->read_param_page = nand_base_read_param_page;
+-+ nand->set_feature = nand_base_set_feature;
+-+ nand->get_feature = nand_base_get_feature;
+-+ nand->read_status = nand_base_read_status;
+-+ nand->addressing = nand_base_addressing;
+-+ nand->read_page = nand_base_read_page;
+-+ nand->read_data = nand_base_read_data;
+-+ nand->read_cache = nand_base_read_cache;
+-+ nand->read_last = nand_base_read_last;
+-+ nand->write_enable = nand_base_write_enable;
+-+ nand->program_data = nand_base_program_data;
+-+ nand->program_page = nand_base_program_page;
+-+ nand->program_cache = nand_base_program_cache;
+-+ nand->erase_block = nand_base_erase_block;
+-+
+-+ return nand;
+-+}
+-+
+-+void nand_base_exit(struct nand_base *base)
+-+{
+-+ nfi_exit(base->nfi);
+-+ mem_free(base);
+-+}
+-diff --git a/drivers/mtd/nandx/core/nand_base.h b/drivers/mtd/nandx/core/nand_base.h
+-new file mode 100644
+-index 0000000000..13217978e5
+---- /dev/null
+-+++ b/drivers/mtd/nandx/core/nand_base.h
+-@@ -0,0 +1,71 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#ifndef __NAND_BASE_H__
+-+#define __NAND_BASE_H__
+-+
+-+/*
+-+ * nand base functions
+-+ * @dev: nand device infomations
+-+ * @nfi: nand host controller
+-+ * @select_device: select one nand device of multi nand on chip
+-+ * @reset: reset current nand device
+-+ * @read_id: read current nand id
+-+ * @read_param_page: read current nand parameters page
+-+ * @set_feature: configurate the nand device feature
+-+ * @get_feature: get the nand device feature
+-+ * @read_status: read nand device status
+-+ * @addressing: addressing the address to nand device physical address
+-+ * @read_page: read page data to device cache register
+-+ * @read_data: read data from device cache register by bus protocol
+-+ * @read_cache: nand cache read operation for data output
+-+ * @read_last: nand cache read operation for last page output
+-+ * @write_enable: enable program/erase for nand, especially spi nand
+-+ * @program_data: program data to nand device cache register
+-+ * @program_page: program page data from nand device cache register to array
+-+ * @program_cache: nand cache program operation for data input
+-+ * @erase_block: erase nand block operation
+-+ */
+-+struct nand_base {
+-+ struct nand_device *dev;
+-+ struct nfi *nfi;
+-+ int (*select_device)(struct nand_base *nand, int cs);
+-+ int (*reset)(struct nand_base *nand);
+-+ int (*read_id)(struct nand_base *nand, u8 *id, int count);
+-+ int (*read_param_page)(struct nand_base *nand, u8 *data, int count);
+-+ int (*set_feature)(struct nand_base *nand, u8 addr, u8 *param,
+-+ int count);
+-+ int (*get_feature)(struct nand_base *nand, u8 addr, u8 *param,
+-+ int count);
+-+ int (*read_status)(struct nand_base *nand);
+-+ int (*addressing)(struct nand_base *nand, int *row, int *col);
+-+
+-+ int (*read_page)(struct nand_base *nand, int row);
+-+ int (*read_data)(struct nand_base *nand, int row, int col, int sectors,
+-+ u8 *data, u8 *oob);
+-+ int (*read_cache)(struct nand_base *nand, int row);
+-+ int (*read_last)(struct nand_base *nand);
+-+
+-+ int (*write_enable)(struct nand_base *nand);
+-+ int (*program_data)(struct nand_base *nand, int row, int col, u8 *data,
+-+ u8 *oob);
+-+ int (*program_page)(struct nand_base *nand, int row);
+-+ int (*program_cache)(struct nand_base *nand);
+-+
+-+ int (*erase_block)(struct nand_base *nand, int row);
+-+};
+-+
+-+struct nand_base *nand_base_init(struct nand_device *device,
+-+ struct nfi *nfi);
+-+void nand_base_exit(struct nand_base *base);
+-+
+-+struct nand_base *nand_device_init(struct nand_chip *nand);
+-+void nand_exit(struct nand_base *nand);
+-+
+-+int nand_detect_device(struct nand_base *nand);
+-+
+-+#endif /* __NAND_BASE_H__ */
+-diff --git a/drivers/mtd/nandx/core/nand_chip.c b/drivers/mtd/nandx/core/nand_chip.c
+-new file mode 100644
+-index 0000000000..02adc6f52e
+---- /dev/null
+-+++ b/drivers/mtd/nandx/core/nand_chip.c
+-@@ -0,0 +1,272 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#include "nandx_util.h"
+-+#include "nandx_core.h"
+-+#include "nand_chip.h"
+-+#include "nand_device.h"
+-+#include "nfi.h"
+-+#include "nand_base.h"
+-+
+-+static int nand_chip_read_page(struct nand_chip *chip,
+-+ struct nand_ops *ops,
+-+ int count)
+-+{
+-+ struct nand_base *nand = chip->nand;
+-+ struct nand_device *dev = nand->dev;
+-+ int i, ret = 0;
+-+ int row, col, sectors;
+-+ u8 *data, *oob;
+-+
+-+ for (i = 0; i < count; i++) {
+-+ row = ops[i].row;
+-+ col = ops[i].col;
+-+
+-+ nand->addressing(nand, &row, &col);
+-+ ops[i].status = nand->read_page(nand, row);
+-+ if (ops[i].status < 0) {
+-+ ret = ops[i].status;
+-+ continue;
+-+ }
+-+
+-+ data = ops[i].data;
+-+ oob = ops[i].oob;
+-+ sectors = ops[i].len / chip->sector_size;
+-+ ops[i].status = nand->read_data(nand, row, col,
+-+ sectors, data, oob);
+-+ if (ops[i].status > 0)
+-+ ops[i].status = ops[i].status >=
+-+ dev->endurance->max_bitflips ?
+-+ -ENANDFLIPS : 0;
+-+
+-+ ret = min_t(int, ret, ops[i].status);
+-+ }
+-+
+-+ return ret;
+-+}
+-+
+-+static int nand_chip_write_page(struct nand_chip *chip,
+-+ struct nand_ops *ops,
+-+ int count)
+-+{
+-+ struct nand_base *nand = chip->nand;
+-+ struct nand_device *dev = nand->dev;
+-+ int i, ret = 0;
+-+ int row, col;
+-+ u8 *data, *oob;
+-+
+-+ for (i = 0; i < count; i++) {
+-+ row = ops[i].row;
+-+ col = ops[i].col;
+-+
+-+ nand->addressing(nand, &row, &col);
+-+
+-+ ops[i].status = nand->write_enable(nand);
+-+ if (ops[i].status) {
+-+ pr_debug("Write Protect at %x!\n", row);
+-+ ops[i].status = -ENANDWP;
+-+ return -ENANDWP;
+-+ }
+-+
+-+ data = ops[i].data;
+-+ oob = ops[i].oob;
+-+ ops[i].status = nand->program_data(nand, row, col, data, oob);
+-+ if (ops[i].status < 0) {
+-+ ret = ops[i].status;
+-+ continue;
+-+ }
+-+
+-+ ops[i].status = nand->program_page(nand, row);
+-+ if (ops[i].status < 0) {
+-+ ret = ops[i].status;
+-+ continue;
+-+ }
+-+
+-+ ops[i].status = nand->read_status(nand);
+-+ if (ops[i].status & dev->status->program_fail)
+-+ ops[i].status = -ENANDWRITE;
+-+
+-+ ret = min_t(int, ret, ops[i].status);
+-+ }
+-+
+-+ return ret;
+-+}
+-+
+-+static int nand_chip_erase_block(struct nand_chip *chip,
+-+ struct nand_ops *ops,
+-+ int count)
+-+{
+-+ struct nand_base *nand = chip->nand;
+-+ struct nand_device *dev = nand->dev;
+-+ int i, ret = 0;
+-+ int row, col;
+-+
+-+ for (i = 0; i < count; i++) {
+-+ row = ops[i].row;
+-+ col = ops[i].col;
+-+
+-+ nand->addressing(nand, &row, &col);
+-+
+-+ ops[i].status = nand->write_enable(nand);
+-+ if (ops[i].status) {
+-+ pr_debug("Write Protect at %x!\n", row);
+-+ ops[i].status = -ENANDWP;
+-+ return -ENANDWP;
+-+ }
+-+
+-+ ops[i].status = nand->erase_block(nand, row);
+-+ if (ops[i].status < 0) {
+-+ ret = ops[i].status;
+-+ continue;
+-+ }
+-+
+-+ ops[i].status = nand->read_status(nand);
+-+ if (ops[i].status & dev->status->erase_fail)
+-+ ops[i].status = -ENANDERASE;
+-+
+-+ ret = min_t(int, ret, ops[i].status);
+-+ }
+-+
+-+ return ret;
+-+}
+-+
+-+/* read first bad mark on spare */
+-+static int nand_chip_is_bad_block(struct nand_chip *chip,
+-+ struct nand_ops *ops,
+-+ int count)
+-+{
+-+ int i, ret, value;
+-+ int status = 0;
+-+ u8 *data, *tmp_buf;
+-+
+-+ tmp_buf = mem_alloc(1, chip->page_size);
+-+ if (!tmp_buf)
+-+ return -ENOMEM;
+-+
+-+ memset(tmp_buf, 0x00, chip->page_size);
+-+
+-+ /* Disable ECC */
+-+ value = 0;
+-+ ret = chip->chip_ctrl(chip, NFI_CTRL_ECC, &value);
+-+ if (ret)
+-+ goto out;
+-+
+-+ ret = chip->read_page(chip, ops, count);
+-+ if (ret)
+-+ goto out;
+-+
+-+ for (i = 0; i < count; i++) {
+-+ data = ops[i].data;
+-+
+-+ /* temp solution for mt7622, because of no bad mark swap */
+-+ if (!memcmp(data, tmp_buf, chip->page_size)) {
+-+ ops[i].status = -ENANDBAD;
+-+ status = -ENANDBAD;
+-+
+-+ } else {
+-+ ops[i].status = 0;
+-+ }
+-+ }
+-+
+-+ /* Enable ECC */
+-+ value = 1;
+-+ ret = chip->chip_ctrl(chip, NFI_CTRL_ECC, &value);
+-+ if (ret)
+-+ goto out;
+-+
+-+ mem_free(tmp_buf);
+-+ return status;
+-+
+-+out:
+-+ mem_free(tmp_buf);
+-+ return ret;
+-+}
+-+
+-+static int nand_chip_ctrl(struct nand_chip *chip, int cmd, void *args)
+-+{
+-+ return -EOPNOTSUPP;
+-+}
+-+
+-+static int nand_chip_suspend(struct nand_chip *chip)
+-+{
+-+ return 0;
+-+}
+-+
+-+static int nand_chip_resume(struct nand_chip *chip)
+-+{
+-+ return 0;
+-+}
+-+
+-+struct nand_chip *nand_chip_init(struct nfi_resource *res)
+-+{
+-+ struct nand_chip *chip;
+-+ struct nand_base *nand;
+-+ struct nfi *nfi;
+-+
+-+ chip = mem_alloc(1, sizeof(struct nand_chip));
+-+ if (!chip) {
+-+ pr_info("nand chip alloc fail!\n");
+-+ return NULL;
+-+ }
+-+
+-+ nfi = nfi_init(res);
+-+ if (!nfi) {
+-+ pr_info("nfi init fail!\n");
+-+ goto nfi_err;
+-+ }
+-+
+-+ nand = nand_base_init(NULL, nfi);
+-+ if (!nand) {
+-+ pr_info("nand base init fail!\n");
+-+ goto base_err;
+-+ }
+-+
+-+ chip->nand = (void *)nand;
+-+ chip->read_page = nand_chip_read_page;
+-+ chip->write_page = nand_chip_write_page;
+-+ chip->erase_block = nand_chip_erase_block;
+-+ chip->is_bad_block = nand_chip_is_bad_block;
+-+ chip->chip_ctrl = nand_chip_ctrl;
+-+ chip->suspend = nand_chip_suspend;
+-+ chip->resume = nand_chip_resume;
+-+
+-+ nand = nand_device_init(chip);
+-+ if (!nand)
+-+ goto nand_err;
+-+
+-+ chip->nand = (void *)nand;
+-+ chip->plane_num = nand->dev->plane_num;
+-+ chip->block_num = nand_total_blocks(nand->dev);
+-+ chip->block_size = nand->dev->block_size;
+-+ chip->block_pages = nand_block_pages(nand->dev);
+-+ chip->page_size = nand->dev->page_size;
+-+ chip->oob_size = nfi->fdm_size * div_down(chip->page_size,
+-+ nfi->sector_size);
+-+ chip->sector_size = nfi->sector_size;
+-+ chip->sector_spare_size = nfi->sector_spare_size;
+-+ chip->min_program_pages = nand->dev->min_program_pages;
+-+ chip->ecc_strength = nfi->ecc_strength;
+-+ chip->ecc_parity_size = nfi->ecc_parity_size;
+-+ chip->fdm_ecc_size = nfi->fdm_ecc_size;
+-+ chip->fdm_reg_size = nfi->fdm_size;
+-+
+-+ return chip;
+-+
+-+nand_err:
+-+ mem_free(nand);
+-+base_err:
+-+ nfi_exit(nfi);
+-+nfi_err:
+-+ mem_free(chip);
+-+ return NULL;
+-+}
+-+
+-+void nand_chip_exit(struct nand_chip *chip)
+-+{
+-+ nand_exit(chip->nand);
+-+ mem_free(chip);
+-+}
+-diff --git a/drivers/mtd/nandx/core/nand_chip.h b/drivers/mtd/nandx/core/nand_chip.h
+-new file mode 100644
+-index 0000000000..3e9c8e6ca3
+---- /dev/null
+-+++ b/drivers/mtd/nandx/core/nand_chip.h
+-@@ -0,0 +1,103 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#ifndef __NAND_CHIP_H__
+-+#define __NAND_CHIP_H__
+-+
+-+enum nand_type {
+-+ NAND_SPI,
+-+ NAND_SLC,
+-+ NAND_MLC,
+-+ NAND_TLC
+-+};
+-+
+-+/*
+-+ * nand chip operation unit
+-+ * one nand_ops indicates one row operation
+-+ * @row: nand chip row address, like as nand row
+-+ * @col: nand chip column address, like as nand column
+-+ * @len: operate data length, min is sector_size,
+-+ * max is page_size and sector_size aligned
+-+ * @status: one operation result status
+-+ * @data: data buffer for operation
+-+ * @oob: oob buffer for operation, like as nand spare area
+-+ */
+-+struct nand_ops {
+-+ int row;
+-+ int col;
+-+ int len;
+-+ int status;
+-+ void *data;
+-+ void *oob;
+-+};
+-+
+-+/*
+-+ * nand chip descriptions
+-+ * nand chip includes nand controller and the several same nand devices
+-+ * @nand_type: the nand type on this chip,
+-+ * the chip maybe have several nand device and the type must be same
+-+ * @plane_num: the whole plane number on the chip
+-+ * @block_num: the whole block number on the chip
+-+ * @block_size: nand device block size
+-+ * @block_pages: nand device block has page number
+-+ * @page_size: nand device page size
+-+ * @oob_size: chip out of band size, like as nand spare szie,
+-+ * but restricts this:
+-+ * the size is provied by nand controller(NFI),
+-+ * because NFI would use some nand spare size
+-+ * @min_program_pages: chip needs min pages per program operations
+-+ * one page as one nand_ops
+-+ * @sector_size: chip min read size
+-+ * @sector_spare_size: spare size for sector, is spare_size/page_sectors
+-+ * @ecc_strength: ecc stregth per sector_size, it would be for calculated ecc
+-+ * @ecc_parity_size: ecc parity size for one sector_size data
+-+ * @nand: pointer to inherited struct nand_base
+-+ * @read_page: read %count pages on chip
+-+ * @write_page: write %count pages on chip
+-+ * @erase_block: erase %count blocks on chip, one block is one nand_ops
+-+ * it is better to set nand_ops.row to block start row
+-+ * @is_bad_block: judge the %count blocks on chip if they are bad
+-+ * by vendor specification
+-+ * @chip_ctrl: control the chip features by nandx_ctrl_cmd
+-+ * @suspend: suspend nand chip
+-+ * @resume: resume nand chip
+-+ */
+-+struct nand_chip {
+-+ int nand_type;
+-+ int plane_num;
+-+ int block_num;
+-+ int block_size;
+-+ int block_pages;
+-+ int page_size;
+-+ int oob_size;
+-+
+-+ int min_program_pages;
+-+ int sector_size;
+-+ int sector_spare_size;
+-+ int ecc_strength;
+-+ int ecc_parity_size;
+-+ u32 fdm_ecc_size;
+-+ u32 fdm_reg_size;
+-+
+-+ void *nand;
+-+
+-+ int (*read_page)(struct nand_chip *chip, struct nand_ops *ops,
+-+ int count);
+-+ int (*write_page)(struct nand_chip *chip, struct nand_ops *ops,
+-+ int count);
+-+ int (*erase_block)(struct nand_chip *chip, struct nand_ops *ops,
+-+ int count);
+-+ int (*is_bad_block)(struct nand_chip *chip, struct nand_ops *ops,
+-+ int count);
+-+ int (*chip_ctrl)(struct nand_chip *chip, int cmd, void *args);
+-+ int (*suspend)(struct nand_chip *chip);
+-+ int (*resume)(struct nand_chip *chip);
+-+};
+-+
+-+struct nand_chip *nand_chip_init(struct nfi_resource *res);
+-+void nand_chip_exit(struct nand_chip *chip);
+-+#endif /* __NAND_CHIP_H__ */
+-diff --git a/drivers/mtd/nandx/core/nand_device.c b/drivers/mtd/nandx/core/nand_device.c
+-new file mode 100644
+-index 0000000000..9f6764d1bc
+---- /dev/null
+-+++ b/drivers/mtd/nandx/core/nand_device.c
+-@@ -0,0 +1,285 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#include "nandx_util.h"
+-+#include "nandx_core.h"
+-+#include "nand_chip.h"
+-+#include "nand_device.h"
+-+#include "nand_base.h"
+-+
+-+#define MAX_CHIP_DEVICE 4
+-+#define PARAM_PAGE_LEN 2048
+-+#define ONFI_CRC_BASE 0x4f4e
+-+
+-+static u16 nand_onfi_crc16(u16 crc, u8 const *p, size_t len)
+-+{
+-+ int i;
+-+
+-+ while (len--) {
+-+ crc ^= *p++ << 8;
+-+
+-+ for (i = 0; i < 8; i++)
+-+ crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0);
+-+ }
+-+
+-+ return crc;
+-+}
+-+
+-+static inline void decode_addr_cycle(u8 addr_cycle, u8 *row_cycle,
+-+ u8 *col_cycle)
+-+{
+-+ *row_cycle = addr_cycle & 0xf;
+-+ *col_cycle = (addr_cycle >> 4) & 0xf;
+-+}
+-+
+-+static int detect_onfi(struct nand_device *dev,
+-+ struct nand_onfi_params *onfi)
+-+{
+-+ struct nand_endurance *endurance = dev->endurance;
+-+ u16 size, i, crc16;
+-+ u8 *id;
+-+
+-+ size = sizeof(struct nand_onfi_params) - sizeof(u16);
+-+
+-+ for (i = 0; i < 3; i++) {
+-+ crc16 = nand_onfi_crc16(ONFI_CRC_BASE, (u8 *)&onfi[i], size);
+-+
+-+ if (onfi[i].signature[0] == 'O' &&
+-+ onfi[i].signature[1] == 'N' &&
+-+ onfi[i].signature[2] == 'F' &&
+-+ onfi[i].signature[3] == 'I' &&
+-+ onfi[i].crc16 == crc16)
+-+ break;
+-+
+-+ /* in some spi nand, onfi signature maybe "NAND" */
+-+ if (onfi[i].signature[0] == 'N' &&
+-+ onfi[i].signature[1] == 'A' &&
+-+ onfi[i].signature[2] == 'N' &&
+-+ onfi[i].signature[3] == 'D' &&
+-+ onfi[i].crc16 == crc16)
+-+ break;
+-+ }
+-+
+-+ if (i == 3)
+-+ return -ENODEV;
+-+
+-+ memcpy(dev->name, onfi[i].model, 20);
+-+ id = onfi[i].manufacturer;
+-+ dev->id = NAND_PACK_ID(id[0], id[1], id[2], id[3], id[4], id[5], id[6],
+-+ id[7]);
+-+ dev->id_len = MAX_ID_NUM;
+-+ dev->io_width = (onfi[i].features & 1) ? NAND_IO16 : NAND_IO8;
+-+ decode_addr_cycle(onfi[i].addr_cycle, &dev->row_cycle,
+-+ &dev->col_cycle);
+-+ dev->target_num = 1;
+-+ dev->lun_num = onfi[i].lun_num;
+-+ dev->plane_num = BIT(onfi[i].plane_address_bits);
+-+ dev->block_num = onfi[i].lun_blocks / dev->plane_num;
+-+ dev->block_size = onfi[i].block_pages * onfi[i].page_size;
+-+ dev->page_size = onfi[i].page_size;
+-+ dev->spare_size = onfi[i].spare_size;
+-+
+-+ endurance->ecc_req = onfi[i].ecc_req;
+-+ endurance->pe_cycle = onfi[i].valid_block_endurance;
+-+ endurance->max_bitflips = endurance->ecc_req >> 1;
+-+
+-+ return 0;
+-+}
+-+
+-+static int detect_jedec(struct nand_device *dev,
+-+ struct nand_jedec_params *jedec)
+-+{
+-+ struct nand_endurance *endurance = dev->endurance;
+-+ u16 size, i, crc16;
+-+ u8 *id;
+-+
+-+ size = sizeof(struct nand_jedec_params) - sizeof(u16);
+-+
+-+ for (i = 0; i < 3; i++) {
+-+ crc16 = nand_onfi_crc16(ONFI_CRC_BASE, (u8 *)&jedec[i], size);
+-+
+-+ if (jedec[i].signature[0] == 'J' &&
+-+ jedec[i].signature[1] == 'E' &&
+-+ jedec[i].signature[2] == 'S' &&
+-+ jedec[i].signature[3] == 'D' &&
+-+ jedec[i].crc16 == crc16)
+-+ break;
+-+ }
+-+
+-+ if (i == 3)
+-+ return -ENODEV;
+-+
+-+ memcpy(dev->name, jedec[i].model, 20);
+-+ id = jedec[i].manufacturer;
+-+ dev->id = NAND_PACK_ID(id[0], id[1], id[2], id[3], id[4], id[5], id[6],
+-+ id[7]);
+-+ dev->id_len = MAX_ID_NUM;
+-+ dev->io_width = (jedec[i].features & 1) ? NAND_IO16 : NAND_IO8;
+-+ decode_addr_cycle(jedec[i].addr_cycle, &dev->row_cycle,
+-+ &dev->col_cycle);
+-+ dev->target_num = 1;
+-+ dev->lun_num = jedec[i].lun_num;
+-+ dev->plane_num = BIT(jedec[i].plane_address_bits);
+-+ dev->block_num = jedec[i].lun_blocks / dev->plane_num;
+-+ dev->block_size = jedec[i].block_pages * jedec[i].page_size;
+-+ dev->page_size = jedec[i].page_size;
+-+ dev->spare_size = jedec[i].spare_size;
+-+
+-+ endurance->ecc_req = jedec[i].endurance_block0[0];
+-+ endurance->pe_cycle = jedec[i].valid_block_endurance;
+-+ endurance->max_bitflips = endurance->ecc_req >> 1;
+-+
+-+ return 0;
+-+}
+-+
+-+static struct nand_device *detect_parameters_page(struct nand_base
+-+ *nand)
+-+{
+-+ struct nand_device *dev = nand->dev;
+-+ void *params;
+-+ int ret;
+-+
+-+ params = mem_alloc(1, PARAM_PAGE_LEN);
+-+ if (!params)
+-+ return NULL;
+-+
+-+ memset(params, 0, PARAM_PAGE_LEN);
+-+ ret = nand->read_param_page(nand, params, PARAM_PAGE_LEN);
+-+ if (ret < 0) {
+-+ pr_info("read parameters page fail!\n");
+-+ goto error;
+-+ }
+-+
+-+ ret = detect_onfi(dev, params);
+-+ if (ret) {
+-+ pr_info("detect onfi device fail! try to detect jedec\n");
+-+ ret = detect_jedec(dev, params);
+-+ if (ret) {
+-+ pr_info("detect jedec device fail!\n");
+-+ goto error;
+-+ }
+-+ }
+-+
+-+ mem_free(params);
+-+ return dev;
+-+
+-+error:
+-+ mem_free(params);
+-+ return NULL;
+-+}
+-+
+-+static int read_device_id(struct nand_base *nand, int cs, u8 *id)
+-+{
+-+ int i;
+-+
+-+ nand->select_device(nand, cs);
+-+ nand->reset(nand);
+-+ nand->read_id(nand, id, MAX_ID_NUM);
+-+ pr_info("device %d ID: ", cs);
+-+
+-+ for (i = 0; i < MAX_ID_NUM; i++)
+-+ pr_info("%x ", id[i]);
+-+
+-+ pr_info("\n");
+-+
+-+ return 0;
+-+}
+-+
+-+static int detect_more_device(struct nand_base *nand, u8 *id)
+-+{
+-+ u8 id_ext[MAX_ID_NUM];
+-+ int i, j, target_num = 0;
+-+
+-+ for (i = 1; i < MAX_CHIP_DEVICE; i++) {
+-+ memset(id_ext, 0xff, MAX_ID_NUM);
+-+ read_device_id(nand, i, id_ext);
+-+
+-+ for (j = 0; j < MAX_ID_NUM; j++) {
+-+ if (id_ext[j] != id[j])
+-+ goto out;
+-+ }
+-+
+-+ target_num += 1;
+-+ }
+-+
+-+out:
+-+ return target_num;
+-+}
+-+
+-+static struct nand_device *scan_device_table(const u8 *id, int id_len)
+-+{
+-+ struct nand_device *dev;
+-+ int i = 0, j;
+-+ u8 ids[MAX_ID_NUM] = {0};
+-+
+-+ while (1) {
+-+ dev = nand_get_device(i);
+-+
+-+ if (!strcmp(dev->name, "NO-DEVICE"))
+-+ break;
+-+
+-+ if (id_len < dev->id_len) {
+-+ i += 1;
+-+ continue;
+-+ }
+-+
+-+ NAND_UNPACK_ID(dev->id, ids, MAX_ID_NUM);
+-+ for (j = 0; j < dev->id_len; j++) {
+-+ if (ids[j] != id[j])
+-+ break;
+-+ }
+-+
+-+ if (j == dev->id_len)
+-+ break;
+-+
+-+ i += 1;
+-+ }
+-+
+-+ return dev;
+-+}
+-+
+-+int nand_detect_device(struct nand_base *nand)
+-+{
+-+ struct nand_device *dev;
+-+ u8 id[MAX_ID_NUM] = { 0 };
+-+ int target_num = 0;
+-+
+-+ /* Get nand device default setting for reset/read_id */
+-+ nand->dev = scan_device_table(NULL, -1);
+-+
+-+ read_device_id(nand, 0, id);
+-+ dev = scan_device_table(id, MAX_ID_NUM);
+-+
+-+ if (!strcmp(dev->name, "NO-DEVICE")) {
+-+ pr_info("device scan fail\n");
+-+ return -ENODEV;
+-+ }
+-+
+-+ /* TobeFix: has null pointer issue in this funciton */
+-+ if (!strcmp(dev->name, "NO-DEVICE")) {
+-+ pr_info("device scan fail, detect parameters page\n");
+-+ dev = detect_parameters_page(nand);
+-+ if (!dev) {
+-+ pr_info("detect parameters fail\n");
+-+ return -ENODEV;
+-+ }
+-+ }
+-+
+-+ if (dev->target_num > 1)
+-+ target_num = detect_more_device(nand, id);
+-+
+-+ target_num += 1;
+-+ pr_debug("chip has target device num: %d\n", target_num);
+-+
+-+ if (dev->target_num != target_num)
+-+ dev->target_num = target_num;
+-+
+-+ nand->dev = dev;
+-+
+-+ return 0;
+-+}
+-+
+-diff --git a/drivers/mtd/nandx/core/nand_device.h b/drivers/mtd/nandx/core/nand_device.h
+-new file mode 100644
+-index 0000000000..e142cf529d
+---- /dev/null
+-+++ b/drivers/mtd/nandx/core/nand_device.h
+-@@ -0,0 +1,608 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#ifndef __NAND_DEVICE_H__
+-+#define __NAND_DEVICE_H__
+-+
+-+/* onfi 3.2 */
+-+struct nand_onfi_params {
+-+ /* Revision information and features block. 0 */
+-+ /*
+-+ * Byte 0: 4Fh,
+-+ * Byte 1: 4Eh,
+-+ * Byte 2: 46h,
+-+ * Byte 3: 49h,
+-+ */
+-+ u8 signature[4];
+-+ /*
+-+ * 9-15 Reserved (0)
+-+ * 8 1 = supports ONFI version 3.2
+-+ * 7 1 = supports ONFI version 3.1
+-+ * 6 1 = supports ONFI version 3.0
+-+ * 5 1 = supports ONFI version 2.3
+-+ * 4 1 = supports ONFI version 2.2
+-+ * 3 1 = supports ONFI version 2.1
+-+ * 2 1 = supports ONFI version 2.0
+-+ * 1 1 = supports ONFI version 1.0
+-+ * 0 Reserved (0)
+-+ */
+-+ u16 revision;
+-+ /*
+-+ * 13-15 Reserved (0)
+-+ * 12 1 = supports external Vpp
+-+ * 11 1 = supports Volume addressing
+-+ * 10 1 = supports NV-DDR2
+-+ * 9 1 = supports EZ NAND
+-+ * 8 1 = supports program page register clear enhancement
+-+ * 7 1 = supports extended parameter page
+-+ * 6 1 = supports multi-plane read operations
+-+ * 5 1 = supports NV-DDR
+-+ * 4 1 = supports odd to even page Copyback
+-+ * 3 1 = supports multi-plane program and erase operations
+-+ * 2 1 = supports non-sequential page programming
+-+ * 1 1 = supports multiple LUN operations
+-+ * 0 1 = supports 16-bit data bus width
+-+ */
+-+ u16 features;
+-+ /*
+-+ * 13-15 Reserved (0)
+-+ * 12 1 = supports LUN Get and LUN Set Features
+-+ * 11 1 = supports ODT Configure
+-+ * 10 1 = supports Volume Select
+-+ * 9 1 = supports Reset LUN
+-+ * 8 1 = supports Small Data Move
+-+ * 7 1 = supports Change Row Address
+-+ * 6 1 = supports Change Read Column Enhanced
+-+ * 5 1 = supports Read Unique ID
+-+ * 4 1 = supports Copyback
+-+ * 3 1 = supports Read Status Enhanced
+-+ * 2 1 = supports Get Features and Set Features
+-+ * 1 1 = supports Read Cache commands
+-+ * 0 1 = supports Page Cache Program command
+-+ */
+-+ u16 opt_cmds;
+-+ /*
+-+ * 4-7 Reserved (0)
+-+ * 3 1 = supports Multi-plane Block Erase
+-+ * 2 1 = supports Multi-plane Copyback Program
+-+ * 1 1 = supports Multi-plane Page Program
+-+ * 0 1 = supports Random Data Out
+-+ */
+-+ u8 advance_cmds;
+-+ u8 reserved0[1];
+-+ u16 extend_param_len;
+-+ u8 param_page_num;
+-+ u8 reserved1[17];
+-+
+-+ /* Manufacturer information block. 32 */
+-+ u8 manufacturer[12];
+-+ u8 model[20];
+-+ u8 jedec_id;
+-+ u16 data_code;
+-+ u8 reserved2[13];
+-+
+-+ /* Memory organization block. 80 */
+-+ u32 page_size;
+-+ u16 spare_size;
+-+ u32 partial_page_size; /* obsolete */
+-+ u16 partial_spare_size; /* obsolete */
+-+ u32 block_pages;
+-+ u32 lun_blocks;
+-+ u8 lun_num;
+-+ /*
+-+ * 4-7 Column address cycles
+-+ * 0-3 Row address cycles
+-+ */
+-+ u8 addr_cycle;
+-+ u8 cell_bits;
+-+ u16 lun_max_bad_blocks;
+-+ u16 block_endurance;
+-+ u8 target_begin_valid_blocks;
+-+ u16 valid_block_endurance;
+-+ u8 page_program_num;
+-+ u8 partial_program_attr; /* obsolete */
+-+ u8 ecc_req;
+-+ /*
+-+ * 4-7 Reserved (0)
+-+ * 0-3 Number of plane address bits
+-+ */
+-+ u8 plane_address_bits;
+-+ /*
+-+ * 6-7 Reserved (0)
+-+ * 5 1 = lower bit XNOR block address restriction
+-+ * 4 1 = read cache supported
+-+ * 3 Address restrictions for cache operations
+-+ * 2 1 = program cache supported
+-+ * 1 1 = no block address restrictions
+-+ * 0 Overlapped / concurrent multi-plane support
+-+ */
+-+ u8 multi_plane_attr;
+-+ u8 ez_nand_support;
+-+ u8 reserved3[12];
+-+
+-+ /* Electrical parameters block. 128 */
+-+ u8 io_pin_max_capacitance;
+-+ /*
+-+ * 6-15 Reserved (0)
+-+ * 5 1 = supports timing mode 5
+-+ * 4 1 = supports timing mode 4
+-+ * 3 1 = supports timing mode 3
+-+ * 2 1 = supports timing mode 2
+-+ * 1 1 = supports timing mode 1
+-+ * 0 1 = supports timing mode 0, shall be 1
+-+ */
+-+ u16 sdr_timing_mode;
+-+ u16 sdr_program_cache_timing_mode; /* obsolete */
+-+ u16 tPROG;
+-+ u16 tBERS;
+-+ u16 tR;
+-+ u16 tCCS;
+-+ /*
+-+ * 7 Reserved (0)
+-+ * 6 1 = supports NV-DDR2 timing mode 8
+-+ * 5 1 = supports NV-DDR timing mode 5
+-+ * 4 1 = supports NV-DDR timing mode 4
+-+ * 3 1 = supports NV-DDR timing mode 3
+-+ * 2 1 = supports NV-DDR timing mode 2
+-+ * 1 1 = supports NV-DDR timing mode 1
+-+ * 0 1 = supports NV-DDR timing mode 0
+-+ */
+-+ u8 nvddr_timing_mode;
+-+ /*
+-+ * 7 1 = supports timing mode 7
+-+ * 6 1 = supports timing mode 6
+-+ * 5 1 = supports timing mode 5
+-+ * 4 1 = supports timing mode 4
+-+ * 3 1 = supports timing mode 3
+-+ * 2 1 = supports timing mode 2
+-+ * 1 1 = supports timing mode 1
+-+ * 0 1 = supports timing mode 0
+-+ */
+-+ u8 nvddr2_timing_mode;
+-+ /*
+-+ * 4-7 Reserved (0)
+-+ * 3 1 = device requires Vpp enablement sequence
+-+ * 2 1 = device supports CLK stopped for data input
+-+ * 1 1 = typical capacitance
+-+ * 0 tCAD value to use
+-+ */
+-+ u8 nvddr_fetures;
+-+ u16 clk_pin_capacitance;
+-+ u16 io_pin_capacitance;
+-+ u16 input_pin_capacitance;
+-+ u8 input_pin_max_capacitance;
+-+ /*
+-+ * 3-7 Reserved (0)
+-+ * 2 1 = supports 18 Ohm drive strength
+-+ * 1 1 = supports 25 Ohm drive strength
+-+ * 0 1 = supports driver strength settings
+-+ */
+-+ u8 drive_strength;
+-+ u16 tR_multi_plane;
+-+ u16 tADL;
+-+ u16 tR_ez_nand;
+-+ /*
+-+ * 6-7 Reserved (0)
+-+ * 5 1 = external VREFQ required for >= 200 MT/s
+-+ * 4 1 = supports differential signaling for DQS
+-+ * 3 1 = supports differential signaling for RE_n
+-+ * 2 1 = supports ODT value of 30 Ohms
+-+ * 1 1 = supports matrix termination ODT
+-+ * 0 1 = supports self-termination ODT
+-+ */
+-+ u8 nvddr2_features;
+-+ u8 nvddr2_warmup_cycles;
+-+ u8 reserved4[4];
+-+
+-+ /* vendor block. 164 */
+-+ u16 vendor_revision;
+-+ u8 vendor_spec[88];
+-+
+-+ /* CRC for Parameter Page. 254 */
+-+ u16 crc16;
+-+} __packed;
+-+
+-+/* JESD230-B */
+-+struct nand_jedec_params {
+-+ /* Revision information and features block. 0 */
+-+ /*
+-+ * Byte 0:4Ah
+-+ * Byte 1:45h
+-+ * Byte 2:53h
+-+ * Byte 3:44h
+-+ */
+-+ u8 signature[4];
+-+ /*
+-+ * 3-15: Reserved (0)
+-+ * 2: 1 = supports parameter page revision 1.0 and standard revision 1.0
+-+ * 1: 1 = supports vendor specific parameter page
+-+ * 0: Reserved (0)
+-+ */
+-+ u16 revision;
+-+ /*
+-+ * 9-15 Reserved (0)
+-+ * 8: 1 = supports program page register clear enhancement
+-+ * 7: 1 = supports external Vpp
+-+ * 6: 1 = supports Toggle Mode DDR
+-+ * 5: 1 = supports Synchronous DDR
+-+ * 4: 1 = supports multi-plane read operations
+-+ * 3: 1 = supports multi-plane program and erase operations
+-+ * 2: 1 = supports non-sequential page programming
+-+ * 1: 1 = supports multiple LUN operations
+-+ * 0: 1 = supports 16-bit data bus width
+-+ */
+-+ u16 features;
+-+ /*
+-+ * 11-23: Reserved (0)
+-+ * 10: 1 = supports Synchronous Reset
+-+ * 9: 1 = supports Reset LUN (Primary)
+-+ * 8: 1 = supports Small Data Move
+-+ * 7: 1 = supports Multi-plane Copyback Program (Primary)
+-+ * 6: 1 = supports Random Data Out (Primary)
+-+ * 5: 1 = supports Read Unique ID
+-+ * 4: 1 = supports Copyback
+-+ * 3: 1 = supports Read Status Enhanced (Primary)
+-+ * 2: 1 = supports Get Features and Set Features
+-+ * 1: 1 = supports Read Cache commands
+-+ * 0: 1 = supports Page Cache Program command
+-+ */
+-+ u8 opt_cmds[3];
+-+ /*
+-+ * 8-15: Reserved (0)
+-+ * 7: 1 = supports secondary Read Status Enhanced
+-+ * 6: 1 = supports secondary Multi-plane Block Erase
+-+ * 5: 1 = supports secondary Multi-plane Copyback Program
+-+ * 4: 1 = supports secondary Multi-plane Program
+-+ * 3: 1 = supports secondary Random Data Out
+-+ * 2: 1 = supports secondary Multi-plane Copyback Read
+-+ * 1: 1 = supports secondary Multi-plane Read Cache Random
+-+ * 0: 1 = supports secondary Multi-plane Read
+-+ */
+-+ u16 secondary_cmds;
+-+ u8 param_page_num;
+-+ u8 reserved0[18];
+-+
+-+ /* Manufacturer information block. 32*/
+-+ u8 manufacturer[12];
+-+ u8 model[20];
+-+ u8 jedec_id[6];
+-+ u8 reserved1[10];
+-+
+-+ /* Memory organization block. 80 */
+-+ u32 page_size;
+-+ u16 spare_size;
+-+ u8 reserved2[6];
+-+ u32 block_pages;
+-+ u32 lun_blocks;
+-+ u8 lun_num;
+-+ /*
+-+ * 4-7 Column address cycles
+-+ * 0-3 Row address cycles
+-+ */
+-+ u8 addr_cycle;
+-+ u8 cell_bits;
+-+ u8 page_program_num;
+-+ /*
+-+ * 4-7 Reserved (0)
+-+ * 0-3 Number of plane address bits
+-+ */
+-+ u8 plane_address_bits;
+-+ /*
+-+ * 3-7: Reserved (0)
+-+ * 2: 1= read cache supported
+-+ * 1: 1 = program cache supported
+-+ * 0: 1= No multi-plane block address restrictions
+-+ */
+-+ u8 multi_plane_attr;
+-+ u8 reserved3[38];
+-+
+-+ /* Electrical parameters block. 144 */
+-+ /*
+-+ * 6-15: Reserved (0)
+-+ * 5: 1 = supports 20 ns speed grade (50 MHz)
+-+ * 4: 1 = supports 25 ns speed grade (40 MHz)
+-+ * 3: 1 = supports 30 ns speed grade (~33 MHz)
+-+ * 2: 1 = supports 35 ns speed grade (~28 MHz)
+-+ * 1: 1 = supports 50 ns speed grade (20 MHz)
+-+ * 0: 1 = supports 100 ns speed grade (10 MHz)
+-+ */
+-+ u16 sdr_speed;
+-+ /*
+-+ * 8-15: Reserved (0)
+-+ * 7: 1 = supports 5 ns speed grade (200 MHz)
+-+ * 6: 1 = supports 6 ns speed grade (~166 MHz)
+-+ * 5: 1 = supports 7.5 ns speed grade (~133 MHz)
+-+ * 4: 1 = supports 10 ns speed grade (100 MHz)
+-+ * 3: 1 = supports 12 ns speed grade (~83 MHz)
+-+ * 2: 1 = supports 15 ns speed grade (~66 MHz)
+-+ * 1: 1 = supports 25 ns speed grade (40 MHz)
+-+ * 0: 1 = supports 30 ns speed grade (~33 MHz)
+-+ */
+-+ u16 toggle_ddr_speed;
+-+ /*
+-+ * 6-15: Reserved (0)
+-+ * 5: 1 = supports 10 ns speed grade (100 MHz)
+-+ * 4: 1 = supports 12 ns speed grade (~83 MHz)
+-+ * 3: 1 = supports 15 ns speed grade (~66 MHz)
+-+ * 2: 1 = supports 20 ns speed grade (50 MHz)
+-+ * 1: 1 = supports 30 ns speed grade (~33 MHz)
+-+ * 0: 1 = supports 50 ns speed grade (20 MHz)
+-+ */
+-+ u16 sync_ddr_speed;
+-+ u8 sdr_features;
+-+ u8 toggle_ddr_features;
+-+ /*
+-+ * 2-7: Reserved (0)
+-+ * 1: Device supports CK stopped for data input
+-+ * 0: tCAD value to use
+-+ */
+-+ u8 sync_ddr_features;
+-+ u16 tPROG;
+-+ u16 tBERS;
+-+ u16 tR;
+-+ u16 tR_multi_plane;
+-+ u16 tCCS;
+-+ u16 io_pin_capacitance;
+-+ u16 input_pin_capacitance;
+-+ u16 ck_pin_capacitance;
+-+ /*
+-+ * 3-7: Reserved (0)
+-+ * 2: 1 = supports 18 ohm drive strength
+-+ * 1: 1 = supports 25 ohm drive strength
+-+ * 0: 1 = supports 35ohm/50ohm drive strength
+-+ */
+-+ u8 drive_strength;
+-+ u16 tADL;
+-+ u8 reserved4[36];
+-+
+-+ /* ECC and endurance block. 208 */
+-+ u8 target_begin_valid_blocks;
+-+ u16 valid_block_endurance;
+-+ /*
+-+ * Byte 0: Number of bits ECC correctability
+-+ * Byte 1: Codeword size
+-+ * Byte 2-3: Bad blocks maximum per LUN
+-+ * Byte 4-5: Block endurance
+-+ * Byte 6-7: Reserved (0)
+-+ */
+-+ u8 endurance_block0[8];
+-+ u8 endurance_block1[8];
+-+ u8 endurance_block2[8];
+-+ u8 endurance_block3[8];
+-+ u8 reserved5[29];
+-+
+-+ /* Reserved. 272 */
+-+ u8 reserved6[148];
+-+
+-+ /* Vendor specific block. 420 */
+-+ u16 vendor_revision;
+-+ u8 vendor_spec[88];
+-+
+-+ /* CRC for Parameter Page. 510 */
+-+ u16 crc16;
+-+} __packed;
+-+
+-+/* parallel nand io width */
+-+enum nand_io_width {
+-+ NAND_IO8,
+-+ NAND_IO16
+-+};
+-+
+-+/* all supported nand timming type */
+-+enum nand_timing_type {
+-+ NAND_TIMING_SDR,
+-+ NAND_TIMING_SYNC_DDR,
+-+ NAND_TIMING_TOGGLE_DDR,
+-+ NAND_TIMING_NVDDR2
+-+};
+-+
+-+/* nand basic commands */
+-+struct nand_cmds {
+-+ short reset;
+-+ short read_id;
+-+ short read_status;
+-+ short read_param_page;
+-+ short set_feature;
+-+ short get_feature;
+-+ short read_1st;
+-+ short read_2nd;
+-+ short random_out_1st;
+-+ short random_out_2nd;
+-+ short program_1st;
+-+ short program_2nd;
+-+ short erase_1st;
+-+ short erase_2nd;
+-+ short read_cache;
+-+ short read_cache_last;
+-+ short program_cache;
+-+};
+-+
+-+/*
+-+ * addressing for nand physical address
+-+ * @row_bit_start: row address start bit
+-+ * @block_bit_start: block address start bit
+-+ * @plane_bit_start: plane address start bit
+-+ * @lun_bit_start: lun address start bit
+-+ */
+-+struct nand_addressing {
+-+ u8 row_bit_start;
+-+ u8 block_bit_start;
+-+ u8 plane_bit_start;
+-+ u8 lun_bit_start;
+-+};
+-+
+-+/*
+-+ * nand operations status
+-+ * @array_busy: indicates device array operation busy
+-+ * @write_protect: indicates the device cannot be wrote or erased
+-+ * @erase_fail: indicates erase operation fail
+-+ * @program_fail: indicates program operation fail
+-+ */
+-+struct nand_status {
+-+ u8 array_busy;
+-+ u8 write_protect;
+-+ u8 erase_fail;
+-+ u8 program_fail;
+-+};
+-+
+-+/*
+-+ * nand endurance information
+-+ * @pe_cycle: max program/erase cycle for nand stored data stability
+-+ * @ecc_req: ecc strength required for the nand, measured per 1KB
+-+ * @max_bitflips: bitflips is ecc corrected bits,
+-+ * max_bitflips is the threshold for nand stored data stability
+-+ * if corrected bits is over max_bitflips, stored data must be moved
+-+ * to another good block
+-+ */
+-+struct nand_endurance {
+-+ int pe_cycle;
+-+ int ecc_req;
+-+ int max_bitflips;
+-+};
+-+
+-+/* wait for nand busy type */
+-+enum nand_wait_type {
+-+ NAND_WAIT_IRQ,
+-+ NAND_WAIT_POLLING,
+-+ NAND_WAIT_TWHR2,
+-+};
+-+
+-+/* each nand array operations time */
+-+struct nand_array_timing {
+-+ u16 tRST;
+-+ u16 tWHR;
+-+ u16 tR;
+-+ u16 tRCBSY;
+-+ u16 tFEAT;
+-+ u16 tPROG;
+-+ u16 tPCBSY;
+-+ u16 tBERS;
+-+ u16 tDBSY;
+-+};
+-+
+-+/* nand sdr interface timing required */
+-+struct nand_sdr_timing {
+-+ u16 tREA;
+-+ u16 tREH;
+-+ u16 tCR;
+-+ u16 tRP;
+-+ u16 tWP;
+-+ u16 tWH;
+-+ u16 tWHR;
+-+ u16 tCLS;
+-+ u16 tALS;
+-+ u16 tCLH;
+-+ u16 tALH;
+-+ u16 tWC;
+-+ u16 tRC;
+-+};
+-+
+-+/* nand onfi ddr (nvddr) interface timing required */
+-+struct nand_onfi_timing {
+-+ u16 tCAD;
+-+ u16 tWPRE;
+-+ u16 tWPST;
+-+ u16 tWRCK;
+-+ u16 tDQSCK;
+-+ u16 tWHR;
+-+};
+-+
+-+/* nand toggle ddr (toggle 1.0) interface timing required */
+-+struct nand_toggle_timing {
+-+ u16 tCS;
+-+ u16 tCH;
+-+ u16 tCAS;
+-+ u16 tCAH;
+-+ u16 tCALS;
+-+ u16 tCALH;
+-+ u16 tWP;
+-+ u16 tWPRE;
+-+ u16 tWPST;
+-+ u16 tWPSTH;
+-+ u16 tCR;
+-+ u16 tRPRE;
+-+ u16 tRPST;
+-+ u16 tRPSTH;
+-+ u16 tCDQSS;
+-+ u16 tWHR;
+-+};
+-+
+-+/* nand basic device information */
+-+struct nand_device {
+-+ u8 *name;
+-+ u64 id;
+-+ u8 id_len;
+-+ u8 io_width;
+-+ u8 row_cycle;
+-+ u8 col_cycle;
+-+ u8 target_num;
+-+ u8 lun_num;
+-+ u8 plane_num;
+-+ int block_num;
+-+ int block_size;
+-+ int page_size;
+-+ int spare_size;
+-+ int min_program_pages;
+-+ struct nand_cmds *cmds;
+-+ struct nand_addressing *addressing;
+-+ struct nand_status *status;
+-+ struct nand_endurance *endurance;
+-+ struct nand_array_timing *array_timing;
+-+};
+-+
+-+#define NAND_DEVICE(_name, _id, _id_len, _io_width, _row_cycle, \
+-+ _col_cycle, _target_num, _lun_num, _plane_num, \
+-+ _block_num, _block_size, _page_size, _spare_size, \
+-+ _min_program_pages, _cmds, _addressing, _status, \
+-+ _endurance, _array_timing) \
+-+{ \
+-+ _name, _id, _id_len, _io_width, _row_cycle, \
+-+ _col_cycle, _target_num, _lun_num, _plane_num, \
+-+ _block_num, _block_size, _page_size, _spare_size, \
+-+ _min_program_pages, _cmds, _addressing, _status, \
+-+ _endurance, _array_timing \
+-+}
+-+
+-+#define MAX_ID_NUM sizeof(u64)
+-+
+-+#define NAND_PACK_ID(id0, id1, id2, id3, id4, id5, id6, id7) \
+-+ ( \
+-+ id0 | id1 << 8 | id2 << 16 | id3 << 24 | \
+-+ (u64)id4 << 32 | (u64)id5 << 40 | \
+-+ (u64)id6 << 48 | (u64)id7 << 56 \
+-+ )
+-+
+-+#define NAND_UNPACK_ID(id, ids, len) \
+-+ do { \
+-+ int _i; \
+-+ for (_i = 0; _i < len; _i++) \
+-+ ids[_i] = id >> (_i << 3) & 0xff; \
+-+ } while (0)
+-+
+-+static inline int nand_block_pages(struct nand_device *device)
+-+{
+-+ return div_down(device->block_size, device->page_size);
+-+}
+-+
+-+static inline int nand_lun_blocks(struct nand_device *device)
+-+{
+-+ return device->plane_num * device->block_num;
+-+}
+-+
+-+static inline int nand_target_blocks(struct nand_device *device)
+-+{
+-+ return device->lun_num * device->plane_num * device->block_num;
+-+}
+-+
+-+static inline int nand_total_blocks(struct nand_device *device)
+-+{
+-+ return device->target_num * device->lun_num * device->plane_num *
+-+ device->block_num;
+-+}
+-+
+-+struct nand_device *nand_get_device(int index);
+-+#endif /* __NAND_DEVICE_H__ */
+-diff --git a/drivers/mtd/nandx/core/nfi.h b/drivers/mtd/nandx/core/nfi.h
+-new file mode 100644
+-index 0000000000..ba84e73ccc
+---- /dev/null
+-+++ b/drivers/mtd/nandx/core/nfi.h
+-@@ -0,0 +1,51 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#ifndef __NFI_H__
+-+#define __NFI_H__
+-+
+-+struct nfi_format {
+-+ int page_size;
+-+ int spare_size;
+-+ int ecc_req;
+-+};
+-+
+-+struct nfi {
+-+ int sector_size;
+-+ int sector_spare_size;
+-+ int fdm_size; /*for sector*/
+-+ int fdm_ecc_size;
+-+ int ecc_strength;
+-+ int ecc_parity_size; /*for sector*/
+-+
+-+ int (*select_chip)(struct nfi *nfi, int cs);
+-+ int (*set_format)(struct nfi *nfi, struct nfi_format *format);
+-+ int (*set_timing)(struct nfi *nfi, void *timing, int type);
+-+ int (*nfi_ctrl)(struct nfi *nfi, int cmd, void *args);
+-+
+-+ int (*reset)(struct nfi *nfi);
+-+ int (*send_cmd)(struct nfi *nfi, short cmd);
+-+ int (*send_addr)(struct nfi *nfi, int col, int row,
+-+ int col_cycle, int row_cycle);
+-+ int (*trigger)(struct nfi *nfi);
+-+
+-+ int (*write_page)(struct nfi *nfi, u8 *data, u8 *fdm);
+-+ int (*write_bytes)(struct nfi *nfi, u8 *data, int count);
+-+ int (*read_sectors)(struct nfi *nfi, u8 *data, u8 *fdm,
+-+ int sectors);
+-+ int (*read_bytes)(struct nfi *nfi, u8 *data, int count);
+-+
+-+ int (*wait_ready)(struct nfi *nfi, int type, u32 timeout);
+-+
+-+ int (*enable_randomizer)(struct nfi *nfi, u32 row, bool encode);
+-+ int (*disable_randomizer)(struct nfi *nfi);
+-+};
+-+
+-+struct nfi *nfi_init(struct nfi_resource *res);
+-+void nfi_exit(struct nfi *nfi);
+-+
+-+#endif /* __NFI_H__ */
+-diff --git a/drivers/mtd/nandx/core/nfi/nfi_base.c b/drivers/mtd/nandx/core/nfi/nfi_base.c
+-new file mode 100644
+-index 0000000000..d8679d7aa3
+---- /dev/null
+-+++ b/drivers/mtd/nandx/core/nfi/nfi_base.c
+-@@ -0,0 +1,1357 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+/**
+-+ * nfi_base.c - the base logic for nfi to access nand flash
+-+ *
+-+ * slc/mlc/tlc could use same code to access nand
+-+ * of cause, there still some work need to do
+-+ * even for spi nand, there should be a chance to integrate code together
+-+ */
+-+
+-+#include "nandx_util.h"
+-+#include "nandx_core.h"
+-+#include "../nfi.h"
+-+#include "../nand_device.h"
+-+#include "nfi_regs.h"
+-+#include "nfiecc.h"
+-+#include "nfi_base.h"
+-+
+-+static const int spare_size_mt7622[] = {
+-+ 16, 26, 27, 28
+-+};
+-+
+-+#define RAND_SEED_SHIFT(op) \
+-+ ((op) == RAND_ENCODE ? ENCODE_SEED_SHIFT : DECODE_SEED_SHIFT)
+-+#define RAND_EN(op) \
+-+ ((op) == RAND_ENCODE ? RAN_ENCODE_EN : RAN_DECODE_EN)
+-+
+-+#define SS_SEED_NUM 128
+-+static u16 ss_randomizer_seed[SS_SEED_NUM] = {
+-+ 0x576A, 0x05E8, 0x629D, 0x45A3, 0x649C, 0x4BF0, 0x2342, 0x272E,
+-+ 0x7358, 0x4FF3, 0x73EC, 0x5F70, 0x7A60, 0x1AD8, 0x3472, 0x3612,
+-+ 0x224F, 0x0454, 0x030E, 0x70A5, 0x7809, 0x2521, 0x484F, 0x5A2D,
+-+ 0x492A, 0x043D, 0x7F61, 0x3969, 0x517A, 0x3B42, 0x769D, 0x0647,
+-+ 0x7E2A, 0x1383, 0x49D9, 0x07B8, 0x2578, 0x4EEC, 0x4423, 0x352F,
+-+ 0x5B22, 0x72B9, 0x367B, 0x24B6, 0x7E8E, 0x2318, 0x6BD0, 0x5519,
+-+ 0x1783, 0x18A7, 0x7B6E, 0x7602, 0x4B7F, 0x3648, 0x2C53, 0x6B99,
+-+ 0x0C23, 0x67CF, 0x7E0E, 0x4D8C, 0x5079, 0x209D, 0x244A, 0x747B,
+-+ 0x350B, 0x0E4D, 0x7004, 0x6AC3, 0x7F3E, 0x21F5, 0x7A15, 0x2379,
+-+ 0x1517, 0x1ABA, 0x4E77, 0x15A1, 0x04FA, 0x2D61, 0x253A, 0x1302,
+-+ 0x1F63, 0x5AB3, 0x049A, 0x5AE8, 0x1CD7, 0x4A00, 0x30C8, 0x3247,
+-+ 0x729C, 0x5034, 0x2B0E, 0x57F2, 0x00E4, 0x575B, 0x6192, 0x38F8,
+-+ 0x2F6A, 0x0C14, 0x45FC, 0x41DF, 0x38DA, 0x7AE1, 0x7322, 0x62DF,
+-+ 0x5E39, 0x0E64, 0x6D85, 0x5951, 0x5937, 0x6281, 0x33A1, 0x6A32,
+-+ 0x3A5A, 0x2BAC, 0x743A, 0x5E74, 0x3B2E, 0x7EC7, 0x4FD2, 0x5D28,
+-+ 0x751F, 0x3EF8, 0x39B1, 0x4E49, 0x746B, 0x6EF6, 0x44BE, 0x6DB7
+-+};
+-+
+-+#if 0
+-+static void dump_register(void *regs)
+-+{
+-+ int i;
+-+
+-+ pr_info("registers:\n");
+-+ for (i = 0; i < 0x600; i += 0x10) {
+-+ pr_info(" address 0x%X : %X %X %X %X\n",
+-+ (u32)((unsigned long)regs + i),
+-+ (u32)readl(regs + i),
+-+ (u32)readl(regs + i + 0x4),
+-+ (u32)readl(regs + i + 0x8),
+-+ (u32)readl(regs + i + 0xC));
+-+ }
+-+}
+-+#endif
+-+
+-+static int nfi_enable_randomizer(struct nfi *nfi, u32 row, bool encode)
+-+{
+-+ struct nfi_base *nb = nfi_to_base(nfi);
+-+ enum randomizer_op op = RAND_ENCODE;
+-+ void *regs = nb->res.nfi_regs;
+-+ u32 val;
+-+
+-+ if (!encode)
+-+ op = RAND_DECODE;
+-+
+-+ /* randomizer type and reseed type setup */
+-+ val = readl(regs + NFI_CNFG);
+-+ val |= CNFG_RAND_SEL | CNFG_RESEED_SEC_EN;
+-+ writel(val, regs + NFI_CNFG);
+-+
+-+ /* randomizer seed and type setup */
+-+ val = ss_randomizer_seed[row % SS_SEED_NUM] & RAN_SEED_MASK;
+-+ val <<= RAND_SEED_SHIFT(op);
+-+ val |= RAND_EN(op);
+-+ writel(val, regs + NFI_RANDOM_CNFG);
+-+
+-+ return 0;
+-+}
+-+
+-+static int nfi_disable_randomizer(struct nfi *nfi)
+-+{
+-+ struct nfi_base *nb = nfi_to_base(nfi);
+-+
+-+ writel(0, nb->res.nfi_regs + NFI_RANDOM_CNFG);
+-+
+-+ return 0;
+-+}
+-+
+-+static int nfi_irq_handler(int irq, void *data)
+-+{
+-+ struct nfi_base *nb = (struct nfi_base *) data;
+-+ void *regs = nb->res.nfi_regs;
+-+ u16 status, en;
+-+
+-+ status = readw(regs + NFI_INTR_STA);
+-+ en = readw(regs + NFI_INTR_EN);
+-+
+-+ if (!(status & en))
+-+ return NAND_IRQ_NONE;
+-+
+-+ writew(~status & en, regs + NFI_INTR_EN);
+-+
+-+ nandx_event_complete(nb->done);
+-+
+-+ return NAND_IRQ_HANDLED;
+-+}
+-+
+-+static int nfi_select_chip(struct nfi *nfi, int cs)
+-+{
+-+ struct nfi_base *nb = nfi_to_base(nfi);
+-+
+-+ writel(cs, nb->res.nfi_regs + NFI_CSEL);
+-+
+-+ return 0;
+-+}
+-+
+-+static inline void set_op_mode(void *regs, u32 mode)
+-+{
+-+ u32 val = readl(regs + NFI_CNFG);
+-+
+-+ val &= ~CNFG_OP_MODE_MASK;
+-+ val |= mode;
+-+
+-+ writel(val, regs + NFI_CNFG);
+-+}
+-+
+-+static int nfi_reset(struct nfi *nfi)
+-+{
+-+ struct nfi_base *nb = nfi_to_base(nfi);
+-+ void *regs = nb->res.nfi_regs;
+-+ int ret, val;
+-+
+-+ /* The NFI reset to reset all registers and force the NFI
+-+ * master be early terminated
+-+ */
+-+ writel(CON_FIFO_FLUSH | CON_NFI_RST, regs + NFI_CON);
+-+
+-+ /* check state of NFI internal FSM and NAND interface FSM */
+-+ ret = readl_poll_timeout_atomic(regs + NFI_MASTER_STA, val,
+-+ !(val & MASTER_BUS_BUSY),
+-+ 10, NFI_TIMEOUT);
+-+ if (ret)
+-+ pr_info("nfi reset timeout...\n");
+-+
+-+ writel(CON_FIFO_FLUSH | CON_NFI_RST, regs + NFI_CON);
+-+ writew(STAR_DE, regs + NFI_STRDATA);
+-+
+-+ return ret;
+-+}
+-+
+-+static void bad_mark_swap(struct nfi *nfi, u8 *buf, u8 *fdm)
+-+{
+-+ struct nfi_base *nb = nfi_to_base(nfi);
+-+ u32 start_sector = div_down(nb->col, nfi->sector_size);
+-+ u32 data_mark_pos;
+-+ u8 temp;
+-+
+-+ /* raw access, no need to do swap. */
+-+ if (!nb->ecc_en)
+-+ return;
+-+
+-+ if (!buf || !fdm)
+-+ return;
+-+
+-+ if (nb->bad_mark_ctrl.sector < start_sector ||
+-+ nb->bad_mark_ctrl.sector > start_sector + nb->rw_sectors)
+-+ return;
+-+
+-+ data_mark_pos = nb->bad_mark_ctrl.position +
+-+ (nb->bad_mark_ctrl.sector - start_sector) *
+-+ nfi->sector_size;
+-+
+-+ temp = *fdm;
+-+ *fdm = *(buf + data_mark_pos);
+-+ *(buf + data_mark_pos) = temp;
+-+}
+-+
+-+static u8 *fdm_shift(struct nfi *nfi, u8 *fdm, int sector)
+-+{
+-+ struct nfi_base *nb = nfi_to_base(nfi);
+-+ u8 *pos;
+-+
+-+ if (!fdm)
+-+ return NULL;
+-+
+-+ /* map the sector's FDM data to free oob:
+-+ * the beginning of the oob area stores the FDM data of bad mark sectors
+-+ */
+-+ if (sector < nb->bad_mark_ctrl.sector)
+-+ pos = fdm + (sector + 1) * nfi->fdm_size;
+-+ else if (sector == nb->bad_mark_ctrl.sector)
+-+ pos = fdm;
+-+ else
+-+ pos = fdm + sector * nfi->fdm_size;
+-+
+-+ return pos;
+-+
+-+}
+-+
+-+static void set_bad_mark_ctrl(struct nfi_base *nb)
+-+{
+-+ int temp, page_size = nb->format.page_size;
+-+
+-+ nb->bad_mark_ctrl.bad_mark_swap = bad_mark_swap;
+-+ nb->bad_mark_ctrl.fdm_shift = fdm_shift;
+-+
+-+ temp = nb->nfi.sector_size + nb->nfi.sector_spare_size;
+-+ nb->bad_mark_ctrl.sector = div_down(page_size, temp);
+-+ nb->bad_mark_ctrl.position = reminder(page_size, temp);
+-+}
+-+
+-+/* NOTE: check if page_size valid future */
+-+static int setup_format(struct nfi_base *nb, int spare_idx)
+-+{
+-+ struct nfi *nfi = &nb->nfi;
+-+ u32 page_size = nb->format.page_size;
+-+ u32 val;
+-+
+-+ switch (page_size) {
+-+ case 512:
+-+ val = PAGEFMT_512_2K | PAGEFMT_SEC_SEL_512;
+-+ break;
+-+
+-+ case KB(2):
+-+ if (nfi->sector_size == 512)
+-+ val = PAGEFMT_2K_4K | PAGEFMT_SEC_SEL_512;
+-+ else
+-+ val = PAGEFMT_512_2K;
+-+
+-+ break;
+-+
+-+ case KB(4):
+-+ if (nfi->sector_size == 512)
+-+ val = PAGEFMT_4K_8K | PAGEFMT_SEC_SEL_512;
+-+ else
+-+ val = PAGEFMT_2K_4K;
+-+
+-+ break;
+-+
+-+ case KB(8):
+-+ if (nfi->sector_size == 512)
+-+ val = PAGEFMT_8K_16K | PAGEFMT_SEC_SEL_512;
+-+ else
+-+ val = PAGEFMT_4K_8K;
+-+
+-+ break;
+-+
+-+ case KB(16):
+-+ val = PAGEFMT_8K_16K;
+-+ break;
+-+
+-+ default:
+-+ pr_info("invalid page len: %d\n", page_size);
+-+ return -EINVAL;
+-+ }
+-+
+-+ val |= spare_idx << PAGEFMT_SPARE_SHIFT;
+-+ val |= nfi->fdm_size << PAGEFMT_FDM_SHIFT;
+-+ val |= nfi->fdm_ecc_size << PAGEFMT_FDM_ECC_SHIFT;
+-+ writel(val, nb->res.nfi_regs + NFI_PAGEFMT);
+-+
+-+ if (nb->custom_sector_en) {
+-+ val = nfi->sector_spare_size + nfi->sector_size;
+-+ val |= SECCUS_SIZE_EN;
+-+ writel(val, nb->res.nfi_regs + NFI_SECCUS_SIZE);
+-+ }
+-+
+-+ return 0;
+-+}
+-+
+-+static int adjust_spare(struct nfi_base *nb, int *spare)
+-+{
+-+ int multi = nb->nfi.sector_size == 512 ? 1 : 2;
+-+ int i, count = nb->caps->spare_size_num;
+-+
+-+ if (*spare >= nb->caps->spare_size[count - 1] * multi) {
+-+ *spare = nb->caps->spare_size[count - 1] * multi;
+-+ return count - 1;
+-+ }
+-+
+-+ if (*spare < nb->caps->spare_size[0] * multi)
+-+ return -EINVAL;
+-+
+-+ for (i = 1; i < count; i++) {
+-+ if (*spare < nb->caps->spare_size[i] * multi) {
+-+ *spare = nb->caps->spare_size[i - 1] * multi;
+-+ return i - 1;
+-+ }
+-+ }
+-+
+-+ return -EINVAL;
+-+}
+-+
+-+static int nfi_set_format(struct nfi *nfi, struct nfi_format *format)
+-+{
+-+ struct nfi_base *nb = nfi_to_base(nfi);
+-+ struct nfiecc *ecc = nb->ecc;
+-+ int ecc_strength = format->ecc_req;
+-+ int min_fdm, min_ecc, max_ecc;
+-+ u32 temp, page_sectors;
+-+ int spare_idx = 0;
+-+
+-+ if (!nb->buf) {
+-+#if NANDX_BULK_IO_USE_DRAM
+-+ nb->buf = NANDX_NFI_BUF_ADDR;
+-+#else
+-+ nb->buf = mem_alloc(1, format->page_size + format->spare_size);
+-+#endif
+-+ if (!nb->buf)
+-+ return -ENOMEM;
+-+ }
+-+
+-+ nb->format = *format;
+-+
+-+ /* ToBeFixed: for spi nand, now sector size is 512,
+-+ * it should be same with slc.
+-+ */
+-+ nfi->sector_size = 512;
+-+ /* format->ecc_req is the requirement per 1KB */
+-+ ecc_strength >>= 1;
+-+
+-+ page_sectors = div_down(format->page_size, nfi->sector_size);
+-+ nfi->sector_spare_size = div_down(format->spare_size, page_sectors);
+-+
+-+ if (!nb->custom_sector_en) {
+-+ spare_idx = adjust_spare(nb, &nfi->sector_spare_size);
+-+ if (spare_idx < 0)
+-+ return -EINVAL;
+-+ }
+-+
+-+ /* calculate ecc strength and fdm size */
+-+ temp = (nfi->sector_spare_size - nb->caps->max_fdm_size) * 8;
+-+ min_ecc = div_down(temp, nb->caps->ecc_parity_bits);
+-+ min_ecc = ecc->adjust_strength(ecc, min_ecc);
+-+ if (min_ecc < 0)
+-+ return -EINVAL;
+-+
+-+ temp = div_up(nb->res.min_oob_req, page_sectors);
+-+ temp = (nfi->sector_spare_size - temp) * 8;
+-+ max_ecc = div_down(temp, nb->caps->ecc_parity_bits);
+-+ max_ecc = ecc->adjust_strength(ecc, max_ecc);
+-+ if (max_ecc < 0)
+-+ return -EINVAL;
+-+
+-+ temp = div_up(temp * nb->caps->ecc_parity_bits, 8);
+-+ temp = nfi->sector_spare_size - temp;
+-+ min_fdm = min_t(u32, temp, (u32)nb->caps->max_fdm_size);
+-+
+-+ if (ecc_strength > max_ecc) {
+-+ pr_info("required ecc strength %d, max supported %d\n",
+-+ ecc_strength, max_ecc);
+-+ nfi->ecc_strength = max_ecc;
+-+ nfi->fdm_size = min_fdm;
+-+ } else if (format->ecc_req < min_ecc) {
+-+ nfi->ecc_strength = min_ecc;
+-+ nfi->fdm_size = nb->caps->max_fdm_size;
+-+ } else {
+-+ ecc_strength = ecc->adjust_strength(ecc, ecc_strength);
+-+ if (ecc_strength < 0)
+-+ return -EINVAL;
+-+
+-+ nfi->ecc_strength = ecc_strength;
+-+ temp = div_up(ecc_strength * nb->caps->ecc_parity_bits, 8);
+-+ nfi->fdm_size = nfi->sector_spare_size - temp;
+-+ }
+-+
+-+ nb->page_sectors = div_down(format->page_size, nfi->sector_size);
+-+
+-+ /* some IC has fixed fdm_ecc_size, if not assigend, set to fdm_size */
+-+ nfi->fdm_ecc_size = nb->caps->fdm_ecc_size ? : nfi->fdm_size;
+-+
+-+ nfi->ecc_parity_size = div_up(nfi->ecc_strength *
+-+ nb->caps->ecc_parity_bits,
+-+ 8);
+-+ set_bad_mark_ctrl(nb);
+-+
+-+ pr_debug("sector_size: %d\n", nfi->sector_size);
+-+ pr_debug("sector_spare_size: %d\n", nfi->sector_spare_size);
+-+ pr_debug("fdm_size: %d\n", nfi->fdm_size);
+-+ pr_debug("fdm_ecc_size: %d\n", nfi->fdm_ecc_size);
+-+ pr_debug("ecc_strength: %d\n", nfi->ecc_strength);
+-+ pr_debug("ecc_parity_size: %d\n", nfi->ecc_parity_size);
+-+
+-+ return setup_format(nb, spare_idx);
+-+}
+-+
+-+static int nfi_ctrl(struct nfi *nfi, int cmd, void *args)
+-+{
+-+ struct nfi_base *nb = nfi_to_base(nfi);
+-+ int ret = 0;
+-+
+-+ switch (cmd) {
+-+ case NFI_CTRL_DMA:
+-+ nb->dma_en = *(bool *)args;
+-+ break;
+-+
+-+ case NFI_CTRL_AUTOFORMAT:
+-+ nb->auto_format = *(bool *)args;
+-+ break;
+-+
+-+ case NFI_CTRL_NFI_IRQ:
+-+ nb->nfi_irq_en = *(bool *)args;
+-+ break;
+-+
+-+ case NFI_CTRL_PAGE_IRQ:
+-+ nb->page_irq_en = *(bool *)args;
+-+ break;
+-+
+-+ case NFI_CTRL_BAD_MARK_SWAP:
+-+ nb->bad_mark_swap_en = *(bool *)args;
+-+ break;
+-+
+-+ case NFI_CTRL_ECC:
+-+ nb->ecc_en = *(bool *)args;
+-+ break;
+-+
+-+ case NFI_CTRL_ECC_MODE:
+-+ nb->ecc_mode = *(enum nfiecc_mode *)args;
+-+ break;
+-+
+-+ case NFI_CTRL_ECC_CLOCK:
+-+ /* NOTE: it seems that there's nothing need to do
+-+ * if new IC need, just add tht logic
+-+ */
+-+ nb->ecc_clk_en = *(bool *)args;
+-+ break;
+-+
+-+ case NFI_CTRL_ECC_IRQ:
+-+ nb->ecc_irq_en = *(bool *)args;
+-+ break;
+-+
+-+ case NFI_CTRL_ECC_DECODE_MODE:
+-+ nb->ecc_deccon = *(enum nfiecc_deccon *)args;
+-+ break;
+-+
+-+ default:
+-+ pr_info("invalid arguments.\n");
+-+ ret = -EOPNOTSUPP;
+-+ break;
+-+ }
+-+
+-+ pr_debug("%s: set cmd(%d) to %d\n", __func__, cmd, *(int *)args);
+-+ return ret;
+-+}
+-+
+-+static int nfi_send_cmd(struct nfi *nfi, short cmd)
+-+{
+-+ struct nfi_base *nb = nfi_to_base(nfi);
+-+ void *regs = nb->res.nfi_regs;
+-+ int ret;
+-+ u32 val;
+-+
+-+ pr_debug("%s: cmd 0x%x\n", __func__, cmd);
+-+
+-+ if (cmd < 0)
+-+ return -EINVAL;
+-+
+-+ set_op_mode(regs, nb->op_mode);
+-+
+-+ writel(cmd, regs + NFI_CMD);
+-+
+-+ ret = readl_poll_timeout_atomic(regs + NFI_STA,
+-+ val, !(val & STA_CMD),
+-+ 5, NFI_TIMEOUT);
+-+ if (ret)
+-+ pr_info("send cmd 0x%x timeout\n", cmd);
+-+
+-+ return ret;
+-+}
+-+
+-+static int nfi_send_addr(struct nfi *nfi, int col, int row,
+-+ int col_cycle, int row_cycle)
+-+{
+-+ struct nfi_base *nb = nfi_to_base(nfi);
+-+ void *regs = nb->res.nfi_regs;
+-+ int ret;
+-+ u32 val;
+-+
+-+ pr_debug("%s: col 0x%x, row 0x%x, col_cycle 0x%x, row_cycle 0x%x\n",
+-+ __func__, col, row, col_cycle, row_cycle);
+-+
+-+ nb->col = col;
+-+ nb->row = row;
+-+
+-+ writel(col, regs + NFI_COLADDR);
+-+ writel(row, regs + NFI_ROWADDR);
+-+ writel(col_cycle | (row_cycle << ROW_SHIFT), regs + NFI_ADDRNOB);
+-+
+-+ ret = readl_poll_timeout_atomic(regs + NFI_STA,
+-+ val, !(val & STA_ADDR),
+-+ 5, NFI_TIMEOUT);
+-+ if (ret)
+-+ pr_info("send address timeout\n");
+-+
+-+ return ret;
+-+}
+-+
+-+static int nfi_trigger(struct nfi *nfi)
+-+{
+-+ /* Nothing need to do. */
+-+ return 0;
+-+}
+-+
+-+static inline int wait_io_ready(void *regs)
+-+{
+-+ u32 val;
+-+ int ret;
+-+
+-+ ret = readl_poll_timeout_atomic(regs + NFI_PIO_DIRDY,
+-+ val, val & PIO_DI_RDY,
+-+ 2, NFI_TIMEOUT);
+-+ if (ret)
+-+ pr_info("wait io ready timeout\n");
+-+
+-+ return ret;
+-+}
+-+
+-+static int wait_ready_irq(struct nfi_base *nb, u32 timeout)
+-+{
+-+ void *regs = nb->res.nfi_regs;
+-+ int ret;
+-+ u32 val;
+-+
+-+ writel(0xf1, regs + NFI_CNRNB);
+-+ nandx_event_init(nb->done);
+-+
+-+ writel(INTR_BUSY_RETURN_EN, (void *)(regs + NFI_INTR_EN));
+-+
+-+ /**
+-+ * check if nand already bean ready,
+-+ * avoid issue that casued by missing irq-event.
+-+ */
+-+ val = readl(regs + NFI_STA);
+-+ if (val & STA_BUSY2READY) {
+-+ readl(regs + NFI_INTR_STA);
+-+ writel(0, (void *)(regs + NFI_INTR_EN));
+-+ return 0;
+-+ }
+-+
+-+ ret = nandx_event_wait_complete(nb->done, timeout);
+-+
+-+ writew(0, regs + NFI_CNRNB);
+-+ return ret;
+-+}
+-+
+-+static void wait_ready_twhr2(struct nfi_base *nb, u32 timeout)
+-+{
+-+ /* NOTE: this for tlc */
+-+}
+-+
+-+static int wait_ready_poll(struct nfi_base *nb, u32 timeout)
+-+{
+-+ void *regs = nb->res.nfi_regs;
+-+ int ret;
+-+ u32 val;
+-+
+-+ writel(0x21, regs + NFI_CNRNB);
+-+ ret = readl_poll_timeout_atomic(regs + NFI_STA, val,
+-+ val & STA_BUSY2READY,
+-+ 2, timeout);
+-+ writew(0, regs + NFI_CNRNB);
+-+
+-+ return ret;
+-+}
+-+
+-+static int nfi_wait_ready(struct nfi *nfi, int type, u32 timeout)
+-+{
+-+ struct nfi_base *nb = nfi_to_base(nfi);
+-+ int ret;
+-+
+-+ switch (type) {
+-+ case NAND_WAIT_IRQ:
+-+ if (nb->nfi_irq_en)
+-+ ret = wait_ready_irq(nb, timeout);
+-+ else
+-+ ret = -EINVAL;
+-+
+-+ break;
+-+
+-+ case NAND_WAIT_POLLING:
+-+ ret = wait_ready_poll(nb, timeout);
+-+ break;
+-+
+-+ case NAND_WAIT_TWHR2:
+-+ wait_ready_twhr2(nb, timeout);
+-+ ret = 0;
+-+ break;
+-+
+-+ default:
+-+ ret = -EINVAL;
+-+ break;
+-+ }
+-+
+-+ if (ret)
+-+ pr_info("%s: type 0x%x, timeout 0x%x\n",
+-+ __func__, type, timeout);
+-+
+-+ return ret;
+-+}
+-+
+-+static int enable_ecc_decode(struct nfi_base *nb, int sectors)
+-+{
+-+ struct nfi *nfi = &nb->nfi;
+-+ struct nfiecc *ecc = nb->ecc;
+-+
+-+ ecc->config.op = ECC_DECODE;
+-+ ecc->config.mode = nb->ecc_mode;
+-+ ecc->config.deccon = nb->ecc_deccon;
+-+ ecc->config.sectors = sectors;
+-+ ecc->config.len = nfi->sector_size + nfi->fdm_ecc_size;
+-+ ecc->config.strength = nfi->ecc_strength;
+-+
+-+ return ecc->enable(ecc);
+-+}
+-+
+-+static int enable_ecc_encode(struct nfi_base *nb)
+-+{
+-+ struct nfiecc *ecc = nb->ecc;
+-+ struct nfi *nfi = &nb->nfi;
+-+
+-+ ecc->config.op = ECC_ENCODE;
+-+ ecc->config.mode = nb->ecc_mode;
+-+ ecc->config.len = nfi->sector_size + nfi->fdm_ecc_size;
+-+ ecc->config.strength = nfi->ecc_strength;
+-+
+-+ return ecc->enable(ecc);
+-+}
+-+
+-+static void read_fdm(struct nfi_base *nb, u8 *fdm, int start_sector,
+-+ int sectors)
+-+{
+-+ void *regs = nb->res.nfi_regs;
+-+ int j, i = start_sector;
+-+ u32 vall, valm;
+-+ u8 *buf = fdm;
+-+
+-+ for (; i < start_sector + sectors; i++) {
+-+ if (nb->bad_mark_swap_en)
+-+ buf = nb->bad_mark_ctrl.fdm_shift(&nb->nfi, fdm, i);
+-+
+-+ vall = readl(regs + NFI_FDML(i));
+-+ valm = readl(regs + NFI_FDMM(i));
+-+
+-+ for (j = 0; j < nb->nfi.fdm_size; j++)
+-+ *buf++ = (j >= 4 ? valm : vall) >> ((j & 3) << 3);
+-+ }
+-+}
+-+
+-+static void write_fdm(struct nfi_base *nb, u8 *fdm)
+-+{
+-+ struct nfi *nfi = &nb->nfi;
+-+ void *regs = nb->res.nfi_regs;
+-+ u32 vall, valm;
+-+ int i, j;
+-+ u8 *buf = fdm;
+-+
+-+ for (i = 0; i < nb->page_sectors; i++) {
+-+ if (nb->bad_mark_swap_en)
+-+ buf = nb->bad_mark_ctrl.fdm_shift(nfi, fdm, i);
+-+
+-+ vall = 0;
+-+ for (j = 0; j < 4; j++)
+-+ vall |= (j < nfi->fdm_size ? *buf++ : 0xff) << (j * 8);
+-+ writel(vall, regs + NFI_FDML(i));
+-+
+-+ valm = 0;
+-+ for (j = 0; j < 4; j++)
+-+ valm |= (j < nfi->fdm_size ? *buf++ : 0xff) << (j * 8);
+-+ writel(valm, regs + NFI_FDMM(i));
+-+ }
+-+}
+-+
+-+/* NOTE: pio not use auto format */
+-+static int pio_rx_data(struct nfi_base *nb, u8 *data, u8 *fdm,
+-+ int sectors)
+-+{
+-+ struct nfiecc_status ecc_status;
+-+ struct nfi *nfi = &nb->nfi;
+-+ void *regs = nb->res.nfi_regs;
+-+ u32 val, bitflips = 0;
+-+ int len, ret, i;
+-+ u8 *buf;
+-+
+-+ val = readl(regs + NFI_CNFG) | CNFG_BYTE_RW;
+-+ writel(val, regs + NFI_CNFG);
+-+
+-+ len = nfi->sector_size + nfi->sector_spare_size;
+-+ len *= sectors;
+-+
+-+ for (i = 0; i < len; i++) {
+-+ ret = wait_io_ready(regs);
+-+ if (ret)
+-+ return ret;
+-+
+-+ nb->buf[i] = readb(regs + NFI_DATAR);
+-+ }
+-+
+-+ /* TODO: do error handle for autoformat setting of pio */
+-+ if (nb->ecc_en) {
+-+ for (i = 0; i < sectors; i++) {
+-+ buf = nb->buf + i * (nfi->sector_size +
+-+ nfi->sector_spare_size);
+-+ ret = nb->ecc->correct_data(nb->ecc, &ecc_status,
+-+ buf, i);
+-+ if (data)
+-+ memcpy(data + i * nfi->sector_size,
+-+ buf, nfi->sector_size);
+-+ if (fdm)
+-+ memcpy(fdm + i * nfi->fdm_size,
+-+ buf + nfi->sector_size, nfi->fdm_size);
+-+ if (ret) {
+-+ ret = nb->ecc->decode_status(nb->ecc, i, 1);
+-+ if (ret < 0)
+-+ return ret;
+-+
+-+ bitflips = max_t(int, (int)bitflips, ret);
+-+ }
+-+ }
+-+
+-+ return bitflips;
+-+ }
+-+
+-+ /* raw read, only data not null, and its length should be $len */
+-+ if (data)
+-+ memcpy(data, nb->buf, len);
+-+
+-+ return 0;
+-+}
+-+
+-+static int pio_tx_data(struct nfi_base *nb, u8 *data, u8 *fdm,
+-+ int sectors)
+-+{
+-+ struct nfi *nfi = &nb->nfi;
+-+ void *regs = nb->res.nfi_regs;
+-+ u32 i, val;
+-+ int len, ret;
+-+
+-+ val = readw(regs + NFI_CNFG) | CNFG_BYTE_RW;
+-+ writew(val, regs + NFI_CNFG);
+-+
+-+ len = nb->ecc_en ? nfi->sector_size :
+-+ nfi->sector_size + nfi->sector_spare_size;
+-+ len *= sectors;
+-+
+-+ /* data shouldn't null,
+-+ * and if ecc enable ,fdm been written in prepare process
+-+ */
+-+ for (i = 0; i < len; i++) {
+-+ ret = wait_io_ready(regs);
+-+ if (ret)
+-+ return ret;
+-+ writeb(data[i], regs + NFI_DATAW);
+-+ }
+-+
+-+ return 0;
+-+}
+-+
+-+static bool is_page_empty(struct nfi_base *nb, u8 *data, u8 *fdm,
+-+ int sectors)
+-+{
+-+ u32 empty = readl(nb->res.nfi_regs + NFI_STA) & STA_EMP_PAGE;
+-+
+-+ if (empty) {
+-+ pr_info("empty page!\n");
+-+ return true;
+-+ }
+-+
+-+ return false;
+-+}
+-+
+-+static int rw_prepare(struct nfi_base *nb, int sectors, u8 *data,
+-+ u8 *fdm, bool read)
+-+{
+-+ void *regs = nb->res.nfi_regs;
+-+ u32 len = nb->nfi.sector_size * sectors;
+-+ bool irq_en = nb->dma_en && nb->nfi_irq_en;
+-+ void *dma_addr;
+-+ u32 val;
+-+ int ret;
+-+
+-+ nb->rw_sectors = sectors;
+-+
+-+ if (irq_en) {
+-+ nandx_event_init(nb->done);
+-+ writel(INTR_AHB_DONE_EN, regs + NFI_INTR_EN);
+-+ }
+-+
+-+ val = readw(regs + NFI_CNFG);
+-+ if (read)
+-+ val |= CNFG_READ_EN;
+-+ else
+-+ val &= ~CNFG_READ_EN;
+-+
+-+ /* as design, now, auto format enabled when ecc enabled */
+-+ if (nb->ecc_en) {
+-+ val |= CNFG_HW_ECC_EN | CNFG_AUTO_FMT_EN;
+-+
+-+ if (read)
+-+ ret = enable_ecc_decode(nb, sectors);
+-+ else
+-+ ret = enable_ecc_encode(nb);
+-+
+-+ if (ret) {
+-+ pr_info("%s: ecc enable %s fail!\n", __func__,
+-+ read ? "decode" : "encode");
+-+ return ret;
+-+ }
+-+ } else {
+-+ val &= ~(CNFG_HW_ECC_EN | CNFG_AUTO_FMT_EN);
+-+ }
+-+
+-+ if (!read && nb->bad_mark_swap_en)
+-+ nb->bad_mark_ctrl.bad_mark_swap(&nb->nfi, data, fdm);
+-+
+-+ if (!nb->ecc_en && read)
+-+ len += sectors * nb->nfi.sector_spare_size;
+-+
+-+ if (nb->dma_en) {
+-+ val |= CNFG_DMA_BURST_EN | CNFG_AHB;
+-+
+-+ if (read) {
+-+ dma_addr = (void *)(unsigned long)nandx_dma_map(
+-+ nb->res.dev, nb->buf,
+-+ (u64)len, NDMA_FROM_DEV);
+-+ } else {
+-+ memcpy(nb->buf, data, len);
+-+ dma_addr = (void *)(unsigned long)nandx_dma_map(
+-+ nb->res.dev, nb->buf,
+-+ (u64)len, NDMA_TO_DEV);
+-+ }
+-+
+-+ writel((unsigned long)dma_addr, (void *)regs + NFI_STRADDR);
+-+
+-+ nb->access_len = len;
+-+ nb->dma_addr = dma_addr;
+-+ }
+-+
+-+ if (nb->ecc_en && !read && fdm)
+-+ write_fdm(nb, fdm);
+-+
+-+ writew(val, regs + NFI_CNFG);
+-+ /* setup R/W sector number */
+-+ writel(sectors << CON_SEC_SHIFT, regs + NFI_CON);
+-+
+-+ return 0;
+-+}
+-+
+-+static void rw_trigger(struct nfi_base *nb, bool read)
+-+{
+-+ void *regs = nb->res.nfi_regs;
+-+ u32 val;
+-+
+-+ val = read ? CON_BRD : CON_BWR;
+-+ val |= readl(regs + NFI_CON);
+-+ writel(val, regs + NFI_CON);
+-+
+-+ writel(STAR_EN, regs + NFI_STRDATA);
+-+}
+-+
+-+static int rw_wait_done(struct nfi_base *nb, int sectors, bool read)
+-+{
+-+ void *regs = nb->res.nfi_regs;
+-+ bool irq_en = nb->dma_en && nb->nfi_irq_en;
+-+ int ret;
+-+ u32 val;
+-+
+-+ if (irq_en) {
+-+ ret = nandx_event_wait_complete(nb->done, NFI_TIMEOUT);
+-+ if (!ret) {
+-+ writew(0, regs + NFI_INTR_EN);
+-+ return ret;
+-+ }
+-+ }
+-+
+-+ if (read) {
+-+ ret = readl_poll_timeout_atomic(regs + NFI_BYTELEN, val,
+-+ ADDRCNTR_SEC(val) >=
+-+ (u32)sectors,
+-+ 2, NFI_TIMEOUT);
+-+ /* HW issue: if not wait ahb done, need polling bus busy */
+-+ if (!ret && !irq_en)
+-+ ret = readl_poll_timeout_atomic(regs + NFI_MASTER_STA,
+-+ val,
+-+ !(val &
+-+ MASTER_BUS_BUSY),
+-+ 2, NFI_TIMEOUT);
+-+ } else {
+-+ ret = readl_poll_timeout_atomic(regs + NFI_ADDRCNTR, val,
+-+ ADDRCNTR_SEC(val) >=
+-+ (u32)sectors,
+-+ 2, NFI_TIMEOUT);
+-+ }
+-+
+-+ if (ret) {
+-+ pr_info("do page %s timeout\n", read ? "read" : "write");
+-+ return ret;
+-+ }
+-+
+-+ if (read && nb->ecc_en) {
+-+ ret = nb->ecc->wait_done(nb->ecc);
+-+ if (ret)
+-+ return ret;
+-+
+-+ return nb->ecc->decode_status(nb->ecc, 0, sectors);
+-+ }
+-+
+-+ return 0;
+-+}
+-+
+-+static int rw_data(struct nfi_base *nb, u8 *data, u8 *fdm, int sectors,
+-+ bool read)
+-+{
+-+ if (read && nb->dma_en && nb->ecc_en && fdm)
+-+ read_fdm(nb, fdm, 0, sectors);
+-+
+-+ if (!nb->dma_en) {
+-+ if (read)
+-+ return pio_rx_data(nb, data, fdm, sectors);
+-+
+-+ return pio_tx_data(nb, data, fdm, sectors);
+-+ }
+-+
+-+ return 0;
+-+}
+-+
+-+static void rw_complete(struct nfi_base *nb, u8 *data, u8 *fdm,
+-+ bool read)
+-+{
+-+ int data_len = 0;
+-+ bool is_empty;
+-+
+-+ if (nb->dma_en) {
+-+ if (read) {
+-+ nandx_dma_unmap(nb->res.dev, nb->buf, nb->dma_addr,
+-+ (u64)nb->access_len, NDMA_FROM_DEV);
+-+
+-+ if (data) {
+-+ data_len = nb->rw_sectors * nb->nfi.sector_size;
+-+ memcpy(data, nb->buf, data_len);
+-+ }
+-+
+-+ if (fdm)
+-+ memcpy(fdm, nb->buf + data_len,
+-+ nb->access_len - data_len);
+-+
+-+ if (nb->read_status == -ENANDREAD) {
+-+ is_empty = nb->is_page_empty(nb, data, fdm,
+-+ nb->rw_sectors);
+-+ if (is_empty)
+-+ nb->read_status = 0;
+-+ }
+-+ } else {
+-+ nandx_dma_unmap(nb->res.dev, nb->buf, nb->dma_addr,
+-+ (u64)nb->access_len, NDMA_TO_DEV);
+-+ }
+-+ }
+-+
+-+ /* whether it's reading or writing, we all check if nee swap
+-+ * for write, we need to restore data
+-+ */
+-+ if (nb->bad_mark_swap_en)
+-+ nb->bad_mark_ctrl.bad_mark_swap(&nb->nfi, data, fdm);
+-+
+-+ if (nb->ecc_en)
+-+ nb->ecc->disable(nb->ecc);
+-+
+-+ writel(0, nb->res.nfi_regs + NFI_CNFG);
+-+ writel(0, nb->res.nfi_regs + NFI_CON);
+-+}
+-+
+-+static int nfi_read_sectors(struct nfi *nfi, u8 *data, u8 *fdm,
+-+ int sectors)
+-+{
+-+ struct nfi_base *nb = nfi_to_base(nfi);
+-+ int bitflips = 0, ret;
+-+
+-+ pr_debug("%s: read page#%d\n", __func__, nb->row);
+-+ pr_debug("%s: data address 0x%x, fdm address 0x%x, sectors 0x%x\n",
+-+ __func__, (u32)((unsigned long)data),
+-+ (u32)((unsigned long)fdm), sectors);
+-+
+-+ nb->read_status = 0;
+-+
+-+ ret = nb->rw_prepare(nb, sectors, data, fdm, true);
+-+ if (ret)
+-+ return ret;
+-+
+-+ nb->rw_trigger(nb, true);
+-+
+-+ if (nb->dma_en) {
+-+ ret = nb->rw_wait_done(nb, sectors, true);
+-+ if (ret > 0)
+-+ bitflips = ret;
+-+ else if (ret == -ENANDREAD)
+-+ nb->read_status = -ENANDREAD;
+-+ else if (ret < 0)
+-+ goto complete;
+-+
+-+ }
+-+
+-+ ret = nb->rw_data(nb, data, fdm, sectors, true);
+-+ if (ret > 0)
+-+ ret = max_t(int, ret, bitflips);
+-+
+-+complete:
+-+ nb->rw_complete(nb, data, fdm, true);
+-+
+-+ if (nb->read_status == -ENANDREAD)
+-+ return -ENANDREAD;
+-+
+-+ return ret;
+-+}
+-+
+-+int nfi_write_page(struct nfi *nfi, u8 *data, u8 *fdm)
+-+{
+-+ struct nfi_base *nb = nfi_to_base(nfi);
+-+ u32 sectors = div_down(nb->format.page_size, nfi->sector_size);
+-+ int ret;
+-+
+-+ pr_debug("%s: data address 0x%x, fdm address 0x%x\n",
+-+ __func__, (int)((unsigned long)data),
+-+ (int)((unsigned long)fdm));
+-+
+-+ ret = nb->rw_prepare(nb, sectors, data, fdm, false);
+-+ if (ret)
+-+ return ret;
+-+
+-+ nb->rw_trigger(nb, false);
+-+
+-+ ret = nb->rw_data(nb, data, fdm, sectors, false);
+-+ if (ret)
+-+ return ret;
+-+
+-+ ret = nb->rw_wait_done(nb, sectors, false);
+-+
+-+ nb->rw_complete(nb, data, fdm, false);
+-+
+-+ return ret;
+-+}
+-+
+-+static int nfi_rw_bytes(struct nfi *nfi, u8 *data, int count, bool read)
+-+{
+-+ struct nfi_base *nb = nfi_to_base(nfi);
+-+ void *regs = nb->res.nfi_regs;
+-+ int i, ret;
+-+ u32 val;
+-+
+-+ for (i = 0; i < count; i++) {
+-+ val = readl(regs + NFI_STA) & NFI_FSM_MASK;
+-+ if (val != NFI_FSM_CUSTDATA) {
+-+ val = readw(regs + NFI_CNFG) | CNFG_BYTE_RW;
+-+ if (read)
+-+ val |= CNFG_READ_EN;
+-+ writew(val, regs + NFI_CNFG);
+-+
+-+ val = div_up(count, nfi->sector_size);
+-+ val = (val << CON_SEC_SHIFT) | CON_BRD | CON_BWR;
+-+ writel(val, regs + NFI_CON);
+-+
+-+ writew(STAR_EN, regs + NFI_STRDATA);
+-+ }
+-+
+-+ ret = wait_io_ready(regs);
+-+ if (ret)
+-+ return ret;
+-+
+-+ if (read)
+-+ data[i] = readb(regs + NFI_DATAR);
+-+ else
+-+ writeb(data[i], regs + NFI_DATAW);
+-+ }
+-+
+-+ writel(0, nb->res.nfi_regs + NFI_CNFG);
+-+
+-+ return 0;
+-+}
+-+
+-+static int nfi_read_bytes(struct nfi *nfi, u8 *data, int count)
+-+{
+-+ return nfi_rw_bytes(nfi, data, count, true);
+-+}
+-+
+-+static int nfi_write_bytes(struct nfi *nfi, u8 *data, int count)
+-+{
+-+ return nfi_rw_bytes(nfi, data, count, false);
+-+}
+-+
+-+/* As register map says, only when flash macro is idle,
+-+ * sw reset or nand interface change can be issued
+-+ */
+-+static inline int wait_flash_macro_idle(void *regs)
+-+{
+-+ u32 val;
+-+
+-+ return readl_poll_timeout_atomic(regs + NFI_STA, val,
+-+ val & FLASH_MACRO_IDLE, 2,
+-+ NFI_TIMEOUT);
+-+}
+-+
+-+#define ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt) \
+-+ ((tpoecs) << 28 | (tprecs) << 22 | (tc2r) << 16 | \
+-+ (tw2r) << 12 | (twh) << 8 | (twst) << 4 | (trlt))
+-+
+-+static int nfi_set_sdr_timing(struct nfi *nfi, void *timing, u8 type)
+-+{
+-+ struct nand_sdr_timing *sdr = (struct nand_sdr_timing *) timing;
+-+ struct nfi_base *nb = nfi_to_base(nfi);
+-+ void *regs = nb->res.nfi_regs;
+-+ u32 tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt, tstrobe;
+-+ u32 rate, val;
+-+ int ret;
+-+
+-+ ret = wait_flash_macro_idle(regs);
+-+ if (ret)
+-+ return ret;
+-+
+-+ /* turn clock rate into KHZ */
+-+ rate = nb->res.clock_1x / 1000;
+-+
+-+ tpoecs = max_t(u16, sdr->tALH, sdr->tCLH);
+-+ tpoecs = div_up(tpoecs * rate, 1000000);
+-+ tpoecs &= 0xf;
+-+
+-+ tprecs = max_t(u16, sdr->tCLS, sdr->tALS);
+-+ tprecs = div_up(tprecs * rate, 1000000);
+-+ tprecs &= 0x3f;
+-+
+-+ /* tc2r is in unit of 2T */
+-+ tc2r = div_up(sdr->tCR * rate, 1000000);
+-+ tc2r = div_down(tc2r, 2);
+-+ tc2r &= 0x3f;
+-+
+-+ tw2r = div_up(sdr->tWHR * rate, 1000000);
+-+ tw2r = div_down(tw2r, 2);
+-+ tw2r &= 0xf;
+-+
+-+ twh = max_t(u16, sdr->tREH, sdr->tWH);
+-+ twh = div_up(twh * rate, 1000000) - 1;
+-+ twh &= 0xf;
+-+
+-+ twst = div_up(sdr->tWP * rate, 1000000) - 1;
+-+ twst &= 0xf;
+-+
+-+ trlt = div_up(sdr->tRP * rate, 1000000) - 1;
+-+ trlt &= 0xf;
+-+
+-+ /* If tREA is bigger than tRP, setup strobe sel here */
+-+ if ((trlt + 1) * 1000000 / rate < sdr->tREA) {
+-+ tstrobe = sdr->tREA - (trlt + 1) * 1000000 / rate;
+-+ tstrobe = div_up(tstrobe * rate, 1000000);
+-+ val = readl(regs + NFI_DEBUG_CON1);
+-+ val &= ~STROBE_MASK;
+-+ val |= tstrobe << STROBE_SHIFT;
+-+ writel(val, regs + NFI_DEBUG_CON1);
+-+ }
+-+
+-+ /*
+-+ * ACCON: access timing control register
+-+ * -------------------------------------
+-+ * 31:28: tpoecs, minimum required time for CS post pulling down after
+-+ * accessing the device
+-+ * 27:22: tprecs, minimum required time for CS pre pulling down before
+-+ * accessing the device
+-+ * 21:16: tc2r, minimum required time from NCEB low to NREB low
+-+ * 15:12: tw2r, minimum required time from NWEB high to NREB low.
+-+ * 11:08: twh, write enable hold time
+-+ * 07:04: twst, write wait states
+-+ * 03:00: trlt, read wait states
+-+ */
+-+ val = ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt);
+-+ pr_info("acctiming: 0x%x\n", val);
+-+ writel(val, regs + NFI_ACCCON);
+-+
+-+ /* set NAND type */
+-+ writel(NAND_TYPE_ASYNC, regs + NFI_NAND_TYPE_CNFG);
+-+
+-+ return ret;
+-+}
+-+
+-+static int nfi_set_timing(struct nfi *nfi, void *timing, int type)
+-+{
+-+ switch (type) {
+-+ case NAND_TIMING_SDR:
+-+ return nfi_set_sdr_timing(nfi, timing, type);
+-+
+-+ /* NOTE: for mlc/tlc */
+-+ case NAND_TIMING_SYNC_DDR:
+-+ case NAND_TIMING_TOGGLE_DDR:
+-+ case NAND_TIMING_NVDDR2:
+-+ default:
+-+ return -EINVAL;
+-+ }
+-+
+-+ return 0;
+-+}
+-+
+-+static void set_nfi_funcs(struct nfi *nfi)
+-+{
+-+ nfi->select_chip = nfi_select_chip;
+-+ nfi->set_format = nfi_set_format;
+-+ nfi->nfi_ctrl = nfi_ctrl;
+-+ nfi->set_timing = nfi_set_timing;
+-+
+-+ nfi->reset = nfi_reset;
+-+ nfi->send_cmd = nfi_send_cmd;
+-+ nfi->send_addr = nfi_send_addr;
+-+ nfi->trigger = nfi_trigger;
+-+
+-+ nfi->write_page = nfi_write_page;
+-+ nfi->write_bytes = nfi_write_bytes;
+-+ nfi->read_sectors = nfi_read_sectors;
+-+ nfi->read_bytes = nfi_read_bytes;
+-+
+-+ nfi->wait_ready = nfi_wait_ready;
+-+
+-+ nfi->enable_randomizer = nfi_enable_randomizer;
+-+ nfi->disable_randomizer = nfi_disable_randomizer;
+-+}
+-+
+-+static struct nfi_caps nfi_caps_mt7622 = {
+-+ .max_fdm_size = 8,
+-+ .fdm_ecc_size = 1,
+-+ .ecc_parity_bits = 13,
+-+ .spare_size = spare_size_mt7622,
+-+ .spare_size_num = 4,
+-+};
+-+
+-+static struct nfi_caps *nfi_get_match_data(enum mtk_ic_version ic)
+-+{
+-+ /* NOTE: add other IC's data */
+-+ return &nfi_caps_mt7622;
+-+}
+-+
+-+static void set_nfi_base_params(struct nfi_base *nb)
+-+{
+-+ nb->ecc_en = false;
+-+ nb->dma_en = false;
+-+ nb->nfi_irq_en = false;
+-+ nb->ecc_irq_en = false;
+-+ nb->page_irq_en = false;
+-+ nb->ecc_clk_en = false;
+-+ nb->randomize_en = false;
+-+ nb->custom_sector_en = false;
+-+ nb->bad_mark_swap_en = false;
+-+
+-+ nb->op_mode = CNFG_CUSTOM_MODE;
+-+ nb->ecc_deccon = ECC_DEC_CORRECT;
+-+ nb->ecc_mode = ECC_NFI_MODE;
+-+
+-+ nb->done = nandx_event_create();
+-+ nb->caps = nfi_get_match_data(nb->res.ic_ver);
+-+
+-+ nb->set_op_mode = set_op_mode;
+-+ nb->is_page_empty = is_page_empty;
+-+
+-+ nb->rw_prepare = rw_prepare;
+-+ nb->rw_trigger = rw_trigger;
+-+ nb->rw_wait_done = rw_wait_done;
+-+ nb->rw_data = rw_data;
+-+ nb->rw_complete = rw_complete;
+-+}
+-+
+-+struct nfi *__weak nfi_extend_init(struct nfi_base *nb)
+-+{
+-+ return &nb->nfi;
+-+}
+-+
+-+void __weak nfi_extend_exit(struct nfi_base *nb)
+-+{
+-+ mem_free(nb);
+-+}
+-+
+-+struct nfi *nfi_init(struct nfi_resource *res)
+-+{
+-+ struct nfiecc_resource ecc_res;
+-+ struct nfi_base *nb;
+-+ struct nfiecc *ecc;
+-+ struct nfi *nfi;
+-+ int ret;
+-+
+-+ nb = mem_alloc(1, sizeof(struct nfi_base));
+-+ if (!nb) {
+-+ pr_info("nfi alloc memory fail @%s.\n", __func__);
+-+ return NULL;
+-+ }
+-+
+-+ nb->res = *res;
+-+
+-+ ret = nandx_irq_register(res->dev, res->nfi_irq_id, nfi_irq_handler,
+-+ "mtk_nand", nb);
+-+ if (ret) {
+-+ pr_info("nfi irq register failed!\n");
+-+ goto error;
+-+ }
+-+
+-+ /* fill ecc paras and init ecc */
+-+ ecc_res.ic_ver = nb->res.ic_ver;
+-+ ecc_res.dev = nb->res.dev;
+-+ ecc_res.irq_id = nb->res.ecc_irq_id;
+-+ ecc_res.regs = nb->res.ecc_regs;
+-+ ecc = nfiecc_init(&ecc_res);
+-+ if (!ecc) {
+-+ pr_info("nfiecc init fail.\n");
+-+ return NULL;
+-+ }
+-+
+-+ nb->ecc = ecc;
+-+
+-+ set_nfi_base_params(nb);
+-+ set_nfi_funcs(&nb->nfi);
+-+
+-+ /* Assign a temp sector size for reading ID & para page.
+-+ * We may assign new value later.
+-+ */
+-+ nb->nfi.sector_size = 512;
+-+
+-+ /* give a default timing, and as discuss
+-+ * this is the only thing what we need do for nfi init
+-+ * if need do more, then we can add a function
+-+ */
+-+ writel(0x30C77FFF, nb->res.nfi_regs + NFI_ACCCON);
+-+
+-+ nfi = nfi_extend_init(nb);
+-+ if (nfi)
+-+ return nfi;
+-+
+-+error:
+-+ mem_free(nb);
+-+ return NULL;
+-+}
+-+
+-+void nfi_exit(struct nfi *nfi)
+-+{
+-+ struct nfi_base *nb = nfi_to_base(nfi);
+-+
+-+ nandx_event_destroy(nb->done);
+-+ nfiecc_exit(nb->ecc);
+-+#if !NANDX_BULK_IO_USE_DRAM
+-+ mem_free(nb->buf);
+-+#endif
+-+ nfi_extend_exit(nb);
+-+}
+-+
+-diff --git a/drivers/mtd/nandx/core/nfi/nfi_base.h b/drivers/mtd/nandx/core/nfi/nfi_base.h
+-new file mode 100644
+-index 0000000000..ae894eaa31
+---- /dev/null
+-+++ b/drivers/mtd/nandx/core/nfi/nfi_base.h
+-@@ -0,0 +1,95 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#ifndef __NFI_BASE_H__
+-+#define __NFI_BASE_H__
+-+
+-+#define NFI_TIMEOUT 1000000
+-+
+-+enum randomizer_op {
+-+ RAND_ENCODE,
+-+ RAND_DECODE
+-+};
+-+
+-+struct bad_mark_ctrl {
+-+ void (*bad_mark_swap)(struct nfi *nfi, u8 *buf, u8 *fdm);
+-+ u8 *(*fdm_shift)(struct nfi *nfi, u8 *fdm, int sector);
+-+ u32 sector;
+-+ u32 position;
+-+};
+-+
+-+struct nfi_caps {
+-+ u8 max_fdm_size;
+-+ u8 fdm_ecc_size;
+-+ u8 ecc_parity_bits;
+-+ const int *spare_size;
+-+ u32 spare_size_num;
+-+};
+-+
+-+struct nfi_base {
+-+ struct nfi nfi;
+-+ struct nfi_resource res;
+-+ struct nfiecc *ecc;
+-+ struct nfi_format format;
+-+ struct nfi_caps *caps;
+-+ struct bad_mark_ctrl bad_mark_ctrl;
+-+
+-+ /* page_size + spare_size */
+-+ u8 *buf;
+-+
+-+ /* used for spi nand */
+-+ u8 cmd_mode;
+-+ u32 op_mode;
+-+
+-+ int page_sectors;
+-+
+-+ void *done;
+-+
+-+ /* for read/write */
+-+ int col;
+-+ int row;
+-+ int access_len;
+-+ int rw_sectors;
+-+ void *dma_addr;
+-+ int read_status;
+-+
+-+ bool dma_en;
+-+ bool nfi_irq_en;
+-+ bool page_irq_en;
+-+ bool auto_format;
+-+ bool ecc_en;
+-+ bool ecc_irq_en;
+-+ bool ecc_clk_en;
+-+ bool randomize_en;
+-+ bool custom_sector_en;
+-+ bool bad_mark_swap_en;
+-+
+-+ enum nfiecc_deccon ecc_deccon;
+-+ enum nfiecc_mode ecc_mode;
+-+
+-+ void (*set_op_mode)(void *regs, u32 mode);
+-+ bool (*is_page_empty)(struct nfi_base *nb, u8 *data, u8 *fdm,
+-+ int sectors);
+-+
+-+ int (*rw_prepare)(struct nfi_base *nb, int sectors, u8 *data, u8 *fdm,
+-+ bool read);
+-+ void (*rw_trigger)(struct nfi_base *nb, bool read);
+-+ int (*rw_wait_done)(struct nfi_base *nb, int sectors, bool read);
+-+ int (*rw_data)(struct nfi_base *nb, u8 *data, u8 *fdm, int sectors,
+-+ bool read);
+-+ void (*rw_complete)(struct nfi_base *nb, u8 *data, u8 *fdm, bool read);
+-+};
+-+
+-+static inline struct nfi_base *nfi_to_base(struct nfi *nfi)
+-+{
+-+ return container_of(nfi, struct nfi_base, nfi);
+-+}
+-+
+-+struct nfi *nfi_extend_init(struct nfi_base *nb);
+-+void nfi_extend_exit(struct nfi_base *nb);
+-+
+-+#endif /* __NFI_BASE_H__ */
+-diff --git a/drivers/mtd/nandx/core/nfi/nfi_regs.h b/drivers/mtd/nandx/core/nfi/nfi_regs.h
+-new file mode 100644
+-index 0000000000..ba4868acc8
+---- /dev/null
+-+++ b/drivers/mtd/nandx/core/nfi/nfi_regs.h
+-@@ -0,0 +1,114 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#ifndef __NFI_REGS_H__
+-+#define __NFI_REGS_H__
+-+
+-+#define NFI_CNFG 0x000
+-+#define CNFG_AHB BIT(0)
+-+#define CNFG_READ_EN BIT(1)
+-+#define CNFG_DMA_BURST_EN BIT(2)
+-+#define CNFG_RESEED_SEC_EN BIT(4)
+-+#define CNFG_RAND_SEL BIT(5)
+-+#define CNFG_BYTE_RW BIT(6)
+-+#define CNFG_HW_ECC_EN BIT(8)
+-+#define CNFG_AUTO_FMT_EN BIT(9)
+-+#define CNFG_RAND_MASK GENMASK(5, 4)
+-+#define CNFG_OP_MODE_MASK GENMASK(14, 12)
+-+#define CNFG_IDLE_MOD 0
+-+#define CNFG_READ_MODE (1 << 12)
+-+#define CNFG_SINGLE_READ_MODE (2 << 12)
+-+#define CNFG_PROGRAM_MODE (3 << 12)
+-+#define CNFG_ERASE_MODE (4 << 12)
+-+#define CNFG_RESET_MODE (5 << 12)
+-+#define CNFG_CUSTOM_MODE (6 << 12)
+-+#define NFI_PAGEFMT 0x004
+-+#define PAGEFMT_SPARE_SHIFT 4
+-+#define PAGEFMT_FDM_ECC_SHIFT 12
+-+#define PAGEFMT_FDM_SHIFT 8
+-+#define PAGEFMT_SEC_SEL_512 BIT(2)
+-+#define PAGEFMT_512_2K 0
+-+#define PAGEFMT_2K_4K 1
+-+#define PAGEFMT_4K_8K 2
+-+#define PAGEFMT_8K_16K 3
+-+#define NFI_CON 0x008
+-+#define CON_FIFO_FLUSH BIT(0)
+-+#define CON_NFI_RST BIT(1)
+-+#define CON_BRD BIT(8)
+-+#define CON_BWR BIT(9)
+-+#define CON_SEC_SHIFT 12
+-+#define NFI_ACCCON 0x00c
+-+#define NFI_INTR_EN 0x010
+-+#define INTR_BUSY_RETURN_EN BIT(4)
+-+#define INTR_AHB_DONE_EN BIT(6)
+-+#define NFI_INTR_STA 0x014
+-+#define NFI_CMD 0x020
+-+#define NFI_ADDRNOB 0x030
+-+#define ROW_SHIFT 4
+-+#define NFI_COLADDR 0x034
+-+#define NFI_ROWADDR 0x038
+-+#define NFI_STRDATA 0x040
+-+#define STAR_EN 1
+-+#define STAR_DE 0
+-+#define NFI_CNRNB 0x044
+-+#define NFI_DATAW 0x050
+-+#define NFI_DATAR 0x054
+-+#define NFI_PIO_DIRDY 0x058
+-+#define PIO_DI_RDY 1
+-+#define NFI_STA 0x060
+-+#define STA_CMD BIT(0)
+-+#define STA_ADDR BIT(1)
+-+#define FLASH_MACRO_IDLE BIT(5)
+-+#define STA_BUSY BIT(8)
+-+#define STA_BUSY2READY BIT(9)
+-+#define STA_EMP_PAGE BIT(12)
+-+#define NFI_FSM_CUSTDATA (0xe << 16)
+-+#define NFI_FSM_MASK GENMASK(19, 16)
+-+#define NAND_FSM_MASK GENMASK(29, 23)
+-+#define NFI_ADDRCNTR 0x070
+-+#define CNTR_VALID_MASK GENMASK(16, 0)
+-+#define CNTR_MASK GENMASK(15, 12)
+-+#define ADDRCNTR_SEC_SHIFT 12
+-+#define ADDRCNTR_SEC(val) \
+-+ (((val) & CNTR_MASK) >> ADDRCNTR_SEC_SHIFT)
+-+#define NFI_STRADDR 0x080
+-+#define NFI_BYTELEN 0x084
+-+#define NFI_CSEL 0x090
+-+#define NFI_FDML(x) (0x0a0 + (x) * 8)
+-+#define NFI_FDMM(x) (0x0a4 + (x) * 8)
+-+#define NFI_DEBUG_CON1 0x220
+-+#define STROBE_MASK GENMASK(4, 3)
+-+#define STROBE_SHIFT 3
+-+#define ECC_CLK_EN BIT(11)
+-+#define AUTOC_SRAM_MODE BIT(12)
+-+#define BYPASS_MASTER_EN BIT(15)
+-+#define NFI_MASTER_STA 0x224
+-+#define MASTER_BUS_BUSY 0x3
+-+#define NFI_SECCUS_SIZE 0x22c
+-+#define SECCUS_SIZE_EN BIT(17)
+-+#define NFI_RANDOM_CNFG 0x238
+-+#define RAN_ENCODE_EN BIT(0)
+-+#define ENCODE_SEED_SHIFT 1
+-+#define RAN_DECODE_EN BIT(16)
+-+#define DECODE_SEED_SHIFT 17
+-+#define RAN_SEED_MASK 0x7fff
+-+#define NFI_EMPTY_THRESH 0x23c
+-+#define NFI_NAND_TYPE_CNFG 0x240
+-+#define NAND_TYPE_ASYNC 0
+-+#define NAND_TYPE_TOGGLE 1
+-+#define NAND_TYPE_SYNC 2
+-+#define NFI_ACCCON1 0x244
+-+#define NFI_DELAY_CTRL 0x248
+-+#define NFI_TLC_RD_WHR2 0x300
+-+#define TLC_RD_WHR2_EN BIT(12)
+-+#define TLC_RD_WHR2_MASK GENMASK(11, 0)
+-+#define SNF_SNF_CNFG 0x55c
+-+#define SPI_MODE_EN 1
+-+#define SPI_MODE_DIS 0
+-+
+-+#endif /* __NFI_REGS_H__ */
+-+
+-diff --git a/drivers/mtd/nandx/core/nfi/nfi_spi.c b/drivers/mtd/nandx/core/nfi/nfi_spi.c
+-new file mode 100644
+-index 0000000000..67cd0aaad9
+---- /dev/null
+-+++ b/drivers/mtd/nandx/core/nfi/nfi_spi.c
+-@@ -0,0 +1,689 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#include "nandx_util.h"
+-+#include "nandx_core.h"
+-+#include "../nfi.h"
+-+#include "nfiecc.h"
+-+#include "nfi_regs.h"
+-+#include "nfi_base.h"
+-+#include "nfi_spi_regs.h"
+-+#include "nfi_spi.h"
+-+
+-+#define NFI_CMD_DUMMY_RD 0x00
+-+#define NFI_CMD_DUMMY_WR 0x80
+-+
+-+static struct nfi_spi_delay spi_delay[SPI_NAND_MAX_DELAY] = {
+-+ /*
+-+ * tCLK_SAM_DLY, tCLK_OUT_DLY, tCS_DLY, tWR_EN_DLY,
+-+ * tIO_IN_DLY[4], tIO_OUT_DLY[4], tREAD_LATCH_LATENCY
+-+ */
+-+ {0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0}, 0},
+-+ {21, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0}, 0},
+-+ {63, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0}, 0},
+-+ {0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0}, 1},
+-+ {21, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0}, 1},
+-+ {63, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0}, 1}
+-+};
+-+
+-+static inline struct nfi_spi *base_to_snfi(struct nfi_base *nb)
+-+{
+-+ return container_of(nb, struct nfi_spi, base);
+-+}
+-+
+-+static void snfi_mac_enable(struct nfi_base *nb)
+-+{
+-+ void *regs = nb->res.nfi_regs;
+-+ u32 val;
+-+
+-+ val = readl(regs + SNF_MAC_CTL);
+-+ val &= ~MAC_XIO_SEL;
+-+ val |= SF_MAC_EN;
+-+
+-+ writel(val, regs + SNF_MAC_CTL);
+-+}
+-+
+-+static void snfi_mac_disable(struct nfi_base *nb)
+-+{
+-+ void *regs = nb->res.nfi_regs;
+-+ u32 val;
+-+
+-+ val = readl(regs + SNF_MAC_CTL);
+-+ val &= ~(SF_TRIG | SF_MAC_EN);
+-+ writel(val, regs + SNF_MAC_CTL);
+-+}
+-+
+-+static int snfi_mac_trigger(struct nfi_base *nb)
+-+{
+-+ void *regs = nb->res.nfi_regs;
+-+ int ret;
+-+ u32 val;
+-+
+-+ val = readl(regs + SNF_MAC_CTL);
+-+ val |= SF_TRIG;
+-+ writel(val, regs + SNF_MAC_CTL);
+-+
+-+ ret = readl_poll_timeout_atomic(regs + SNF_MAC_CTL, val,
+-+ val & WIP_READY, 10,
+-+ NFI_TIMEOUT);
+-+ if (ret) {
+-+ pr_info("polling wip ready for read timeout\n");
+-+ return ret;
+-+ }
+-+
+-+ return readl_poll_timeout_atomic(regs + SNF_MAC_CTL, val,
+-+ !(val & WIP), 10,
+-+ NFI_TIMEOUT);
+-+}
+-+
+-+static int snfi_mac_op(struct nfi_base *nb)
+-+{
+-+ int ret;
+-+
+-+ snfi_mac_enable(nb);
+-+ ret = snfi_mac_trigger(nb);
+-+ snfi_mac_disable(nb);
+-+
+-+ return ret;
+-+}
+-+
+-+static void snfi_write_mac(struct nfi_spi *nfi_spi, u8 *data, int count)
+-+{
+-+ struct nandx_split32 split = {0};
+-+ u32 reg_offset = round_down(nfi_spi->tx_count, 4);
+-+ void *regs = nfi_spi->base.res.nfi_regs;
+-+ u32 data_offset = 0, i, val;
+-+ u8 *p_val = (u8 *)(&val);
+-+
+-+ nandx_split(&split, nfi_spi->tx_count, count, val, 4);
+-+
+-+ if (split.head_len) {
+-+ val = readl(regs + SPI_GPRAM_ADDR + reg_offset);
+-+
+-+ for (i = 0; i < split.head_len; i++)
+-+ p_val[split.head + i] = data[i];
+-+
+-+ writel(val, regs + SPI_GPRAM_ADDR + reg_offset);
+-+ }
+-+
+-+ if (split.body_len) {
+-+ reg_offset = split.body;
+-+ data_offset = split.head_len;
+-+
+-+ for (i = 0; i < split.body_len; i++) {
+-+ p_val[i & 3] = data[data_offset + i];
+-+
+-+ if ((i & 3) == 3) {
+-+ writel(val, regs + SPI_GPRAM_ADDR + reg_offset);
+-+ reg_offset += 4;
+-+ }
+-+ }
+-+ }
+-+
+-+ if (split.tail_len) {
+-+ reg_offset = split.tail;
+-+ data_offset += split.body_len;
+-+
+-+ for (i = 0; i < split.tail_len; i++) {
+-+ p_val[i] = data[data_offset + i];
+-+
+-+ if (i == split.tail_len - 1)
+-+ writel(val, regs + SPI_GPRAM_ADDR + reg_offset);
+-+ }
+-+ }
+-+}
+-+
+-+static void snfi_read_mac(struct nfi_spi *nfi_spi, u8 *data, int count)
+-+{
+-+ void *regs = nfi_spi->base.res.nfi_regs;
+-+ u32 reg_offset = round_down(nfi_spi->tx_count, 4);
+-+ struct nandx_split32 split = {0};
+-+ u32 data_offset = 0, i, val;
+-+ u8 *p_val = (u8 *)&val;
+-+
+-+ nandx_split(&split, nfi_spi->tx_count, count, val, 4);
+-+
+-+ if (split.head_len) {
+-+ val = readl(regs + SPI_GPRAM_ADDR + reg_offset);
+-+
+-+ for (i = 0; i < split.head_len; i++)
+-+ data[data_offset + i] = p_val[split.head + i];
+-+ }
+-+
+-+ if (split.body_len) {
+-+ reg_offset = split.body;
+-+ data_offset = split.head_len;
+-+
+-+ for (i = 0; i < split.body_len; i++) {
+-+ if ((i & 3) == 0) {
+-+ val = readl(regs + SPI_GPRAM_ADDR + reg_offset);
+-+ reg_offset += 4;
+-+ }
+-+
+-+ data[data_offset + i] = p_val[i % 4];
+-+ }
+-+ }
+-+
+-+ if (split.tail_len) {
+-+ reg_offset = split.tail;
+-+ data_offset += split.body_len;
+-+ val = readl(regs + SPI_GPRAM_ADDR + reg_offset);
+-+
+-+ for (i = 0; i < split.tail_len; i++)
+-+ data[data_offset + i] = p_val[i];
+-+ }
+-+}
+-+
+-+static int snfi_send_command(struct nfi *nfi, short cmd)
+-+{
+-+ struct nfi_base *nb = nfi_to_base(nfi);
+-+ struct nfi_spi *nfi_spi = base_to_snfi(nb);
+-+
+-+ if (cmd == -1)
+-+ return 0;
+-+
+-+ if (nfi_spi->snfi_mode == SNFI_MAC_MODE) {
+-+ snfi_write_mac(nfi_spi, (u8 *)&cmd, 1);
+-+ nfi_spi->tx_count++;
+-+ return 0;
+-+ }
+-+
+-+ nfi_spi->cmd[nfi_spi->cur_cmd_idx++] = cmd;
+-+ return 0;
+-+}
+-+
+-+static int snfi_send_address(struct nfi *nfi, int col, int row,
+-+ int col_cycle,
+-+ int row_cycle)
+-+{
+-+ struct nfi_base *nb = nfi_to_base(nfi);
+-+ struct nfi_spi *nfi_spi = base_to_snfi(nb);
+-+ u32 addr, cycle, temp;
+-+
+-+ nb->col = col;
+-+ nb->row = row;
+-+
+-+ if (nfi_spi->snfi_mode == SNFI_MAC_MODE) {
+-+ addr = row;
+-+ cycle = row_cycle;
+-+
+-+ if (!row_cycle) {
+-+ addr = col;
+-+ cycle = col_cycle;
+-+ }
+-+
+-+ temp = nandx_cpu_to_be32(addr) >> ((4 - cycle) << 3);
+-+ snfi_write_mac(nfi_spi, (u8 *)&temp, cycle);
+-+ nfi_spi->tx_count += cycle;
+-+ } else {
+-+ nfi_spi->row_addr[nfi_spi->cur_addr_idx++] = row;
+-+ nfi_spi->col_addr[nfi_spi->cur_addr_idx++] = col;
+-+ }
+-+
+-+ return 0;
+-+}
+-+
+-+static int snfi_trigger(struct nfi *nfi)
+-+{
+-+ struct nfi_base *nb = nfi_to_base(nfi);
+-+ struct nfi_spi *nfi_spi = base_to_snfi(nb);
+-+ void *regs = nb->res.nfi_regs;
+-+
+-+ writel(nfi_spi->tx_count, regs + SNF_MAC_OUTL);
+-+ writel(0, regs + SNF_MAC_INL);
+-+
+-+ nfi_spi->tx_count = 0;
+-+ nfi_spi->cur_cmd_idx = 0;
+-+ nfi_spi->cur_addr_idx = 0;
+-+
+-+ return snfi_mac_op(nb);
+-+}
+-+
+-+static int snfi_select_chip(struct nfi *nfi, int cs)
+-+{
+-+ struct nfi_base *nb = nfi_to_base(nfi);
+-+ void *regs = nb->res.nfi_regs;
+-+ u32 val;
+-+
+-+ val = readl(regs + SNF_MISC_CTL);
+-+
+-+ if (cs == 0) {
+-+ val &= ~SF2CS_SEL;
+-+ val &= ~SF2CS_EN;
+-+ } else if (cs == 1) {
+-+ val |= SF2CS_SEL;
+-+ val |= SF2CS_EN;
+-+ } else {
+-+ return -EIO;
+-+ }
+-+
+-+ writel(val, regs + SNF_MISC_CTL);
+-+
+-+ return 0;
+-+}
+-+
+-+static int snfi_set_delay(struct nfi_base *nb, u8 delay_mode)
+-+{
+-+ void *regs = nb->res.nfi_regs;
+-+ struct nfi_spi_delay *delay;
+-+ u32 val;
+-+
+-+ if (delay_mode < 0 || delay_mode > SPI_NAND_MAX_DELAY)
+-+ return -EINVAL;
+-+
+-+ delay = &spi_delay[delay_mode];
+-+
+-+ val = delay->tIO_OUT_DLY[0] | delay->tIO_OUT_DLY[1] << 8 |
+-+ delay->tIO_OUT_DLY[2] << 16 |
+-+ delay->tIO_OUT_DLY[3] << 24;
+-+ writel(val, regs + SNF_DLY_CTL1);
+-+
+-+ val = delay->tIO_IN_DLY[0] | (delay->tIO_IN_DLY[1] << 8) |
+-+ delay->tIO_IN_DLY[2] << 16 |
+-+ delay->tIO_IN_DLY[3] << 24;
+-+ writel(val, regs + SNF_DLY_CTL2);
+-+
+-+ val = delay->tCLK_SAM_DLY | delay->tCLK_OUT_DLY << 8 |
+-+ delay->tCS_DLY << 16 |
+-+ delay->tWR_EN_DLY << 24;
+-+ writel(val, regs + SNF_DLY_CTL3);
+-+
+-+ writel(delay->tCS_DLY, regs + SNF_DLY_CTL4);
+-+
+-+ val = readl(regs + SNF_MISC_CTL);
+-+ val |= (delay->tREAD_LATCH_LATENCY) <<
+-+ LATCH_LAT_SHIFT;
+-+ writel(val, regs + SNF_MISC_CTL);
+-+
+-+ return 0;
+-+}
+-+
+-+static int snfi_set_timing(struct nfi *nfi, void *timing, int type)
+-+{
+-+ /* Nothing need to do. */
+-+ return 0;
+-+}
+-+
+-+static int snfi_wait_ready(struct nfi *nfi, int type, u32 timeout)
+-+{
+-+ /* Nothing need to do. */
+-+ return 0;
+-+}
+-+
+-+static int snfi_ctrl(struct nfi *nfi, int cmd, void *args)
+-+{
+-+ struct nfi_base *nb = nfi_to_base(nfi);
+-+ struct nfi_spi *nfi_spi = base_to_snfi(nb);
+-+ int ret = 0;
+-+
+-+ if (!args)
+-+ return -EINVAL;
+-+
+-+ switch (cmd) {
+-+ case NFI_CTRL_DMA:
+-+ nb->dma_en = *(bool *)args;
+-+ break;
+-+
+-+ case NFI_CTRL_NFI_IRQ:
+-+ nb->nfi_irq_en = *(bool *)args;
+-+ break;
+-+
+-+ case NFI_CTRL_ECC_IRQ:
+-+ nb->ecc_irq_en = *(bool *)args;
+-+ break;
+-+
+-+ case NFI_CTRL_PAGE_IRQ:
+-+ nb->page_irq_en = *(bool *)args;
+-+ break;
+-+
+-+ case NFI_CTRL_ECC:
+-+ nb->ecc_en = *(bool *)args;
+-+ break;
+-+
+-+ case NFI_CTRL_BAD_MARK_SWAP:
+-+ nb->bad_mark_swap_en = *(bool *)args;
+-+ break;
+-+
+-+ case NFI_CTRL_ECC_CLOCK:
+-+ nb->ecc_clk_en = *(bool *)args;
+-+ break;
+-+
+-+ case SNFI_CTRL_OP_MODE:
+-+ nfi_spi->snfi_mode = *(u8 *)args;
+-+ break;
+-+
+-+ case SNFI_CTRL_RX_MODE:
+-+ nfi_spi->read_cache_mode = *(u8 *)args;
+-+ break;
+-+
+-+ case SNFI_CTRL_TX_MODE:
+-+ nfi_spi->write_cache_mode = *(u8 *)args;
+-+ break;
+-+
+-+ case SNFI_CTRL_DELAY_MODE:
+-+ ret = snfi_set_delay(nb, *(u8 *)args);
+-+ break;
+-+
+-+ default:
+-+ pr_info("operation not support.\n");
+-+ ret = -EOPNOTSUPP;
+-+ break;
+-+ }
+-+
+-+ return ret;
+-+}
+-+
+-+static int snfi_read_bytes(struct nfi *nfi, u8 *data, int count)
+-+{
+-+ struct nfi_base *nb = nfi_to_base(nfi);
+-+ struct nfi_spi *nfi_spi = base_to_snfi(nb);
+-+ void *regs = nb->res.nfi_regs;
+-+ int ret;
+-+
+-+ writel(nfi_spi->tx_count, regs + SNF_MAC_OUTL);
+-+ writel(count, regs + SNF_MAC_INL);
+-+
+-+ ret = snfi_mac_op(nb);
+-+ if (ret)
+-+ return ret;
+-+
+-+ snfi_read_mac(nfi_spi, data, count);
+-+
+-+ nfi_spi->tx_count = 0;
+-+
+-+ return 0;
+-+}
+-+
+-+static int snfi_write_bytes(struct nfi *nfi, u8 *data, int count)
+-+{
+-+ struct nfi_base *nb = nfi_to_base(nfi);
+-+ struct nfi_spi *nfi_spi = base_to_snfi(nb);
+-+ void *regs = nb->res.nfi_regs;
+-+
+-+ snfi_write_mac(nfi_spi, data, count);
+-+ nfi_spi->tx_count += count;
+-+
+-+ writel(0, regs + SNF_MAC_INL);
+-+ writel(nfi_spi->tx_count, regs + SNF_MAC_OUTL);
+-+
+-+ nfi_spi->tx_count = 0;
+-+
+-+ return snfi_mac_op(nb);
+-+}
+-+
+-+static int snfi_reset(struct nfi *nfi)
+-+{
+-+ struct nfi_base *nb = nfi_to_base(nfi);
+-+ struct nfi_spi *nfi_spi = base_to_snfi(nb);
+-+ void *regs = nb->res.nfi_regs;
+-+ u32 val;
+-+ int ret;
+-+
+-+ ret = nfi_spi->parent->nfi.reset(nfi);
+-+ if (ret)
+-+ return ret;
+-+
+-+ val = readl(regs + SNF_MISC_CTL);
+-+ val |= SW_RST;
+-+ writel(val, regs + SNF_MISC_CTL);
+-+
+-+ ret = readx_poll_timeout_atomic(readw, regs + SNF_STA_CTL1, val,
+-+ !(val & SPI_STATE), 50,
+-+ NFI_TIMEOUT);
+-+ if (ret) {
+-+ pr_info("spi state active in reset [0x%x] = 0x%x\n",
+-+ SNF_STA_CTL1, val);
+-+ return ret;
+-+ }
+-+
+-+ val = readl(regs + SNF_MISC_CTL);
+-+ val &= ~SW_RST;
+-+ writel(val, regs + SNF_MISC_CTL);
+-+
+-+ return 0;
+-+}
+-+
+-+static int snfi_config_for_write(struct nfi_base *nb, int count)
+-+{
+-+ struct nfi_spi *nfi_spi = base_to_snfi(nb);
+-+ void *regs = nb->res.nfi_regs;
+-+ u32 val;
+-+
+-+ nb->set_op_mode(regs, CNFG_CUSTOM_MODE);
+-+
+-+ val = readl(regs + SNF_MISC_CTL);
+-+
+-+ if (nfi_spi->write_cache_mode == SNFI_TX_114)
+-+ val |= PG_LOAD_X4_EN;
+-+
+-+ if (nfi_spi->snfi_mode == SNFI_CUSTOM_MODE)
+-+ val |= PG_LOAD_CUSTOM_EN;
+-+
+-+ writel(val, regs + SNF_MISC_CTL);
+-+
+-+ val = count * (nb->nfi.sector_size + nb->nfi.sector_spare_size);
+-+ writel(val << PG_LOAD_SHIFT, regs + SNF_MISC_CTL2);
+-+
+-+ val = readl(regs + SNF_PG_CTL1);
+-+
+-+ if (nfi_spi->snfi_mode == SNFI_CUSTOM_MODE)
+-+ val |= nfi_spi->cmd[0] << PG_LOAD_CMD_SHIFT;
+-+ else {
+-+ val |= nfi_spi->cmd[0] | nfi_spi->cmd[1] << PG_LOAD_CMD_SHIFT |
+-+ nfi_spi->cmd[2] << PG_EXE_CMD_SHIFT;
+-+
+-+ writel(nfi_spi->row_addr[1], regs + SNF_PG_CTL3);
+-+ writel(nfi_spi->cmd[3] << GF_CMD_SHIFT | nfi_spi->col_addr[2] <<
+-+ GF_ADDR_SHIFT, regs + SNF_GF_CTL1);
+-+ }
+-+
+-+ writel(val, regs + SNF_PG_CTL1);
+-+ writel(nfi_spi->col_addr[1], regs + SNF_PG_CTL2);
+-+
+-+ writel(NFI_CMD_DUMMY_WR, regs + NFI_CMD);
+-+
+-+ return 0;
+-+}
+-+
+-+static int snfi_config_for_read(struct nfi_base *nb, int count)
+-+{
+-+ struct nfi_spi *nfi_spi = base_to_snfi(nb);
+-+ void *regs = nb->res.nfi_regs;
+-+ u32 val;
+-+ int ret = 0;
+-+
+-+ nb->set_op_mode(regs, CNFG_CUSTOM_MODE);
+-+
+-+ val = readl(regs + SNF_MISC_CTL);
+-+ val &= ~DARA_READ_MODE_MASK;
+-+
+-+ switch (nfi_spi->read_cache_mode) {
+-+
+-+ case SNFI_RX_111:
+-+ break;
+-+
+-+ case SNFI_RX_112:
+-+ val |= X2_DATA_MODE << READ_MODE_SHIFT;
+-+ break;
+-+
+-+ case SNFI_RX_114:
+-+ val |= X4_DATA_MODE << READ_MODE_SHIFT;
+-+ break;
+-+
+-+ case SNFI_RX_122:
+-+ val |= DUAL_IO_MODE << READ_MODE_SHIFT;
+-+ break;
+-+
+-+ case SNFI_RX_144:
+-+ val |= QUAD_IO_MODE << READ_MODE_SHIFT;
+-+ break;
+-+
+-+ default:
+-+ pr_info("Not support this read operarion: %d!\n",
+-+ nfi_spi->read_cache_mode);
+-+ ret = -EINVAL;
+-+ break;
+-+ }
+-+
+-+ if (nfi_spi->snfi_mode == SNFI_CUSTOM_MODE)
+-+ val |= DATARD_CUSTOM_EN;
+-+
+-+ writel(val, regs + SNF_MISC_CTL);
+-+
+-+ val = count * (nb->nfi.sector_size + nb->nfi.sector_spare_size);
+-+ writel(val, regs + SNF_MISC_CTL2);
+-+
+-+ val = readl(regs + SNF_RD_CTL2);
+-+
+-+ if (nfi_spi->snfi_mode == SNFI_CUSTOM_MODE) {
+-+ val |= nfi_spi->cmd[0];
+-+ writel(nfi_spi->col_addr[1], regs + SNF_RD_CTL3);
+-+ } else {
+-+ val |= nfi_spi->cmd[2];
+-+ writel(nfi_spi->cmd[0] << PAGE_READ_CMD_SHIFT |
+-+ nfi_spi->row_addr[0], regs + SNF_RD_CTL1);
+-+ writel(nfi_spi->cmd[1] << GF_CMD_SHIFT |
+-+ nfi_spi->col_addr[1] << GF_ADDR_SHIFT,
+-+ regs + SNF_GF_CTL1);
+-+ writel(nfi_spi->col_addr[2], regs + SNF_RD_CTL3);
+-+ }
+-+
+-+ writel(val, regs + SNF_RD_CTL2);
+-+
+-+ writel(NFI_CMD_DUMMY_RD, regs + NFI_CMD);
+-+
+-+ return ret;
+-+}
+-+
+-+static bool is_page_empty(struct nfi_base *nb, u8 *data, u8 *fdm,
+-+ int sectors)
+-+{
+-+ u32 *data32 = (u32 *)data;
+-+ u32 *fdm32 = (u32 *)fdm;
+-+ u32 i, count = 0;
+-+
+-+ for (i = 0; i < nb->format.page_size >> 2; i++) {
+-+ if (data32[i] != 0xffff) {
+-+ count += zero_popcount(data32[i]);
+-+ if (count > 10) {
+-+ pr_info("%s %d %d count:%d\n",
+-+ __func__, __LINE__, i, count);
+-+ return false;
+-+ }
+-+ }
+-+ }
+-+
+-+ if (fdm) {
+-+ for (i = 0; i < (nb->nfi.fdm_size * sectors >> 2); i++)
+-+ if (fdm32[i] != 0xffff) {
+-+ count += zero_popcount(fdm32[i]);
+-+ if (count > 10) {
+-+ pr_info("%s %d %d count:%d\n",
+-+ __func__, __LINE__, i, count);
+-+ return false;
+-+ }
+-+ }
+-+ }
+-+
+-+ return true;
+-+}
+-+
+-+static int rw_prepare(struct nfi_base *nb, int sectors, u8 *data,
+-+ u8 *fdm,
+-+ bool read)
+-+{
+-+ struct nfi_spi *nfi_spi = base_to_snfi(nb);
+-+ int ret;
+-+
+-+ ret = nfi_spi->parent->rw_prepare(nb, sectors, data, fdm, read);
+-+ if (ret)
+-+ return ret;
+-+
+-+ if (read)
+-+ ret = snfi_config_for_read(nb, sectors);
+-+ else
+-+ ret = snfi_config_for_write(nb, sectors);
+-+
+-+ return ret;
+-+}
+-+
+-+static void rw_complete(struct nfi_base *nb, u8 *data, u8 *fdm,
+-+ bool read)
+-+{
+-+ struct nfi_spi *nfi_spi = base_to_snfi(nb);
+-+ void *regs = nb->res.nfi_regs;
+-+ u32 val;
+-+
+-+ nfi_spi->parent->rw_complete(nb, data, fdm, read);
+-+
+-+ val = readl(regs + SNF_MISC_CTL);
+-+
+-+ if (read)
+-+ val &= ~DATARD_CUSTOM_EN;
+-+ else
+-+ val &= ~PG_LOAD_CUSTOM_EN;
+-+
+-+ writel(val, regs + SNF_MISC_CTL);
+-+
+-+ nfi_spi->tx_count = 0;
+-+ nfi_spi->cur_cmd_idx = 0;
+-+ nfi_spi->cur_addr_idx = 0;
+-+}
+-+
+-+static void set_nfi_base_funcs(struct nfi_base *nb)
+-+{
+-+ nb->nfi.reset = snfi_reset;
+-+ nb->nfi.set_timing = snfi_set_timing;
+-+ nb->nfi.wait_ready = snfi_wait_ready;
+-+
+-+ nb->nfi.send_cmd = snfi_send_command;
+-+ nb->nfi.send_addr = snfi_send_address;
+-+ nb->nfi.trigger = snfi_trigger;
+-+ nb->nfi.nfi_ctrl = snfi_ctrl;
+-+ nb->nfi.select_chip = snfi_select_chip;
+-+
+-+ nb->nfi.read_bytes = snfi_read_bytes;
+-+ nb->nfi.write_bytes = snfi_write_bytes;
+-+
+-+ nb->rw_prepare = rw_prepare;
+-+ nb->rw_complete = rw_complete;
+-+ nb->is_page_empty = is_page_empty;
+-+
+-+}
+-+
+-+struct nfi *nfi_extend_init(struct nfi_base *nb)
+-+{
+-+ struct nfi_spi *nfi_spi;
+-+
+-+ nfi_spi = mem_alloc(1, sizeof(struct nfi_spi));
+-+ if (!nfi_spi) {
+-+ pr_info("snfi alloc memory fail @%s.\n", __func__);
+-+ return NULL;
+-+ }
+-+
+-+ memcpy(&nfi_spi->base, nb, sizeof(struct nfi_base));
+-+ nfi_spi->parent = nb;
+-+
+-+ nfi_spi->read_cache_mode = SNFI_RX_114;
+-+ nfi_spi->write_cache_mode = SNFI_TX_114;
+-+
+-+ set_nfi_base_funcs(&nfi_spi->base);
+-+
+-+ /* Change nfi to spi mode */
+-+ writel(SPI_MODE, nb->res.nfi_regs + SNF_SNF_CNFG);
+-+
+-+ return &(nfi_spi->base.nfi);
+-+}
+-+
+-+void nfi_extend_exit(struct nfi_base *nb)
+-+{
+-+ struct nfi_spi *nfi_spi = base_to_snfi(nb);
+-+
+-+ mem_free(nfi_spi->parent);
+-+ mem_free(nfi_spi);
+-+}
+-+
+-diff --git a/drivers/mtd/nandx/core/nfi/nfi_spi.h b/drivers/mtd/nandx/core/nfi/nfi_spi.h
+-new file mode 100644
+-index 0000000000..a52255663a
+---- /dev/null
+-+++ b/drivers/mtd/nandx/core/nfi/nfi_spi.h
+-@@ -0,0 +1,44 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#ifndef __NFI_SPI_H__
+-+#define __NFI_SPI_H__
+-+
+-+#define SPI_NAND_MAX_DELAY 6
+-+#define SPI_NAND_MAX_OP 4
+-+
+-+/*TODO - add comments */
+-+struct nfi_spi_delay {
+-+ u8 tCLK_SAM_DLY;
+-+ u8 tCLK_OUT_DLY;
+-+ u8 tCS_DLY;
+-+ u8 tWR_EN_DLY;
+-+ u8 tIO_IN_DLY[4];
+-+ u8 tIO_OUT_DLY[4];
+-+ u8 tREAD_LATCH_LATENCY;
+-+};
+-+
+-+/* SPI Nand structure */
+-+struct nfi_spi {
+-+ struct nfi_base base;
+-+ struct nfi_base *parent;
+-+
+-+ u8 snfi_mode;
+-+ u8 tx_count;
+-+
+-+ u8 cmd[SPI_NAND_MAX_OP];
+-+ u8 cur_cmd_idx;
+-+
+-+ u32 row_addr[SPI_NAND_MAX_OP];
+-+ u32 col_addr[SPI_NAND_MAX_OP];
+-+ u8 cur_addr_idx;
+-+
+-+ u8 read_cache_mode;
+-+ u8 write_cache_mode;
+-+};
+-+
+-+#endif /* __NFI_SPI_H__ */
+-diff --git a/drivers/mtd/nandx/core/nfi/nfi_spi_regs.h b/drivers/mtd/nandx/core/nfi/nfi_spi_regs.h
+-new file mode 100644
+-index 0000000000..77adf46782
+---- /dev/null
+-+++ b/drivers/mtd/nandx/core/nfi/nfi_spi_regs.h
+-@@ -0,0 +1,64 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#ifndef __NFI_SPI_REGS_H__
+-+#define __NFI_SPI_REGS_H__
+-+
+-+#define SNF_MAC_CTL 0x500
+-+#define WIP BIT(0)
+-+#define WIP_READY BIT(1)
+-+#define SF_TRIG BIT(2)
+-+#define SF_MAC_EN BIT(3)
+-+#define MAC_XIO_SEL BIT(4)
+-+#define SNF_MAC_OUTL 0x504
+-+#define SNF_MAC_INL 0x508
+-+#define SNF_RD_CTL1 0x50c
+-+#define PAGE_READ_CMD_SHIFT 24
+-+#define SNF_RD_CTL2 0x510
+-+#define SNF_RD_CTL3 0x514
+-+#define SNF_GF_CTL1 0x518
+-+#define GF_ADDR_SHIFT 16
+-+#define GF_CMD_SHIFT 24
+-+#define SNF_GF_CTL3 0x520
+-+#define SNF_PG_CTL1 0x524
+-+#define PG_EXE_CMD_SHIFT 16
+-+#define PG_LOAD_CMD_SHIFT 8
+-+#define SNF_PG_CTL2 0x528
+-+#define SNF_PG_CTL3 0x52c
+-+#define SNF_ER_CTL 0x530
+-+#define SNF_ER_CTL2 0x534
+-+#define SNF_MISC_CTL 0x538
+-+#define SW_RST BIT(28)
+-+#define PG_LOAD_X4_EN BIT(20)
+-+#define X2_DATA_MODE 1
+-+#define X4_DATA_MODE 2
+-+#define DUAL_IO_MODE 5
+-+#define QUAD_IO_MODE 6
+-+#define READ_MODE_SHIFT 16
+-+#define LATCH_LAT_SHIFT 8
+-+#define LATCH_LAT_MASK GENMASK(9, 8)
+-+#define DARA_READ_MODE_MASK GENMASK(18, 16)
+-+#define SF2CS_SEL BIT(13)
+-+#define SF2CS_EN BIT(12)
+-+#define PG_LOAD_CUSTOM_EN BIT(7)
+-+#define DATARD_CUSTOM_EN BIT(6)
+-+#define SNF_MISC_CTL2 0x53c
+-+#define PG_LOAD_SHIFT 16
+-+#define SNF_DLY_CTL1 0x540
+-+#define SNF_DLY_CTL2 0x544
+-+#define SNF_DLY_CTL3 0x548
+-+#define SNF_DLY_CTL4 0x54c
+-+#define SNF_STA_CTL1 0x550
+-+#define SPI_STATE GENMASK(3, 0)
+-+#define SNF_STA_CTL2 0x554
+-+#define SNF_STA_CTL3 0x558
+-+#define SNF_SNF_CNFG 0x55c
+-+#define SPI_MODE BIT(0)
+-+#define SNF_DEBUG_SEL 0x560
+-+#define SPI_GPRAM_ADDR 0x800
+-+
+-+#endif /* __NFI_SPI_REGS_H__ */
+-diff --git a/drivers/mtd/nandx/core/nfi/nfiecc.c b/drivers/mtd/nandx/core/nfi/nfiecc.c
+-new file mode 100644
+-index 0000000000..14246fbc3e
+---- /dev/null
+-+++ b/drivers/mtd/nandx/core/nfi/nfiecc.c
+-@@ -0,0 +1,510 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#include "nandx_util.h"
+-+#include "nandx_core.h"
+-+#include "nfiecc_regs.h"
+-+#include "nfiecc.h"
+-+
+-+#define NFIECC_IDLE_REG(op) \
+-+ ((op) == ECC_ENCODE ? NFIECC_ENCIDLE : NFIECC_DECIDLE)
+-+#define IDLE_MASK 1
+-+#define NFIECC_CTL_REG(op) \
+-+ ((op) == ECC_ENCODE ? NFIECC_ENCCON : NFIECC_DECCON)
+-+#define NFIECC_IRQ_REG(op) \
+-+ ((op) == ECC_ENCODE ? NFIECC_ENCIRQEN : NFIECC_DECIRQEN)
+-+#define NFIECC_ADDR(op) \
+-+ ((op) == ECC_ENCODE ? NFIECC_ENCDIADDR : NFIECC_DECDIADDR)
+-+
+-+#define ECC_TIMEOUT 500000
+-+
+-+/* ecc strength that each IP supports */
+-+static const int ecc_strength_mt7622[] = {
+-+ 4, 6, 8, 10, 12, 14, 16
+-+};
+-+
+-+static int nfiecc_irq_handler(void *data)
+-+{
+-+ struct nfiecc *ecc = data;
+-+ void *regs = ecc->res.regs;
+-+ u32 status;
+-+
+-+ status = readl(regs + NFIECC_DECIRQSTA) & DEC_IRQSTA_GEN;
+-+ if (status) {
+-+ status = readl(regs + NFIECC_DECDONE);
+-+ if (!(status & ecc->config.sectors))
+-+ return NAND_IRQ_NONE;
+-+
+-+ /*
+-+ * Clear decode IRQ status once again to ensure that
+-+ * there will be no extra IRQ.
+-+ */
+-+ readl(regs + NFIECC_DECIRQSTA);
+-+ ecc->config.sectors = 0;
+-+ nandx_event_complete(ecc->done);
+-+ } else {
+-+ status = readl(regs + NFIECC_ENCIRQSTA) & ENC_IRQSTA_GEN;
+-+ if (!status)
+-+ return NAND_IRQ_NONE;
+-+
+-+ nandx_event_complete(ecc->done);
+-+ }
+-+
+-+ return NAND_IRQ_HANDLED;
+-+}
+-+
+-+static inline int nfiecc_wait_idle(struct nfiecc *ecc)
+-+{
+-+ int op = ecc->config.op;
+-+ int ret, val;
+-+
+-+ ret = readl_poll_timeout_atomic(ecc->res.regs + NFIECC_IDLE_REG(op),
+-+ val, val & IDLE_MASK,
+-+ 10, ECC_TIMEOUT);
+-+ if (ret)
+-+ pr_info("%s not idle\n",
+-+ op == ECC_ENCODE ? "encoder" : "decoder");
+-+
+-+ return ret;
+-+}
+-+
+-+static int nfiecc_wait_encode_done(struct nfiecc *ecc)
+-+{
+-+ int ret, val;
+-+
+-+ if (ecc->ecc_irq_en) {
+-+ /* poll one time to avoid missing irq event */
+-+ ret = readl_poll_timeout_atomic(ecc->res.regs + NFIECC_ENCSTA,
+-+ val, val & ENC_FSM_IDLE, 1, 1);
+-+ if (!ret)
+-+ return 0;
+-+
+-+ /* irq done, if not, we can go on to poll status for a while */
+-+ ret = nandx_event_wait_complete(ecc->done, ECC_TIMEOUT);
+-+ if (ret)
+-+ return 0;
+-+ }
+-+
+-+ ret = readl_poll_timeout_atomic(ecc->res.regs + NFIECC_ENCSTA,
+-+ val, val & ENC_FSM_IDLE,
+-+ 10, ECC_TIMEOUT);
+-+ if (ret)
+-+ pr_info("encode timeout\n");
+-+
+-+ return ret;
+-+
+-+}
+-+
+-+static int nfiecc_wait_decode_done(struct nfiecc *ecc)
+-+{
+-+ u32 secbit = BIT(ecc->config.sectors - 1);
+-+ void *regs = ecc->res.regs;
+-+ int ret, val;
+-+
+-+ if (ecc->ecc_irq_en) {
+-+ ret = readl_poll_timeout_atomic(regs + NFIECC_DECDONE,
+-+ val, val & secbit, 1, 1);
+-+ if (!ret)
+-+ return 0;
+-+
+-+ ret = nandx_event_wait_complete(ecc->done, ECC_TIMEOUT);
+-+ if (ret)
+-+ return 0;
+-+ }
+-+
+-+ ret = readl_poll_timeout_atomic(regs + NFIECC_DECDONE,
+-+ val, val & secbit,
+-+ 10, ECC_TIMEOUT);
+-+ if (ret) {
+-+ pr_info("decode timeout\n");
+-+ return ret;
+-+ }
+-+
+-+ /* decode done does not stands for ecc all work done.
+-+ * we need check syn, bma, chien, autoc all idle.
+-+ * just check it when ECC_DECCNFG[13:12] is 3,
+-+ * which means auto correct.
+-+ */
+-+ ret = readl_poll_timeout_atomic(regs + NFIECC_DECFSM,
+-+ val, (val & FSM_MASK) == FSM_IDLE,
+-+ 10, ECC_TIMEOUT);
+-+ if (ret)
+-+ pr_info("decode fsm(0x%x) is not idle\n",
+-+ readl(regs + NFIECC_DECFSM));
+-+
+-+ return ret;
+-+}
+-+
+-+static int nfiecc_wait_done(struct nfiecc *ecc)
+-+{
+-+ if (ecc->config.op == ECC_ENCODE)
+-+ return nfiecc_wait_encode_done(ecc);
+-+
+-+ return nfiecc_wait_decode_done(ecc);
+-+}
+-+
+-+static void nfiecc_encode_config(struct nfiecc *ecc, u32 ecc_idx)
+-+{
+-+ struct nfiecc_config *config = &ecc->config;
+-+ u32 val;
+-+
+-+ val = ecc_idx | (config->mode << ecc->caps->ecc_mode_shift);
+-+
+-+ if (config->mode == ECC_DMA_MODE)
+-+ val |= ENC_BURST_EN;
+-+
+-+ val |= (config->len << 3) << ENCCNFG_MS_SHIFT;
+-+ writel(val, ecc->res.regs + NFIECC_ENCCNFG);
+-+}
+-+
+-+static void nfiecc_decode_config(struct nfiecc *ecc, u32 ecc_idx)
+-+{
+-+ struct nfiecc_config *config = &ecc->config;
+-+ u32 dec_sz = (config->len << 3) +
+-+ config->strength * ecc->caps->parity_bits;
+-+ u32 val;
+-+
+-+ val = ecc_idx | (config->mode << ecc->caps->ecc_mode_shift);
+-+
+-+ if (config->mode == ECC_DMA_MODE)
+-+ val |= DEC_BURST_EN;
+-+
+-+ val |= (dec_sz << DECCNFG_MS_SHIFT) |
+-+ (config->deccon << DEC_CON_SHIFT);
+-+ val |= DEC_EMPTY_EN;
+-+ writel(val, ecc->res.regs + NFIECC_DECCNFG);
+-+}
+-+
+-+static void nfiecc_config(struct nfiecc *ecc)
+-+{
+-+ u32 idx;
+-+
+-+ for (idx = 0; idx < ecc->caps->ecc_strength_num; idx++) {
+-+ if (ecc->config.strength == ecc->caps->ecc_strength[idx])
+-+ break;
+-+ }
+-+
+-+ if (ecc->config.op == ECC_ENCODE)
+-+ nfiecc_encode_config(ecc, idx);
+-+ else
+-+ nfiecc_decode_config(ecc, idx);
+-+}
+-+
+-+static int nfiecc_enable(struct nfiecc *ecc)
+-+{
+-+ enum nfiecc_operation op = ecc->config.op;
+-+ void *regs = ecc->res.regs;
+-+
+-+ nfiecc_config(ecc);
+-+
+-+ writel(ECC_OP_EN, regs + NFIECC_CTL_REG(op));
+-+
+-+ if (ecc->ecc_irq_en) {
+-+ writel(ECC_IRQEN, regs + NFIECC_IRQ_REG(op));
+-+
+-+ if (ecc->page_irq_en)
+-+ writel(ECC_IRQEN | ECC_PG_IRQ_SEL,
+-+ regs + NFIECC_IRQ_REG(op));
+-+
+-+ nandx_event_init(ecc->done);
+-+ }
+-+
+-+ return 0;
+-+}
+-+
+-+static int nfiecc_disable(struct nfiecc *ecc)
+-+{
+-+ enum nfiecc_operation op = ecc->config.op;
+-+ void *regs = ecc->res.regs;
+-+
+-+ nfiecc_wait_idle(ecc);
+-+
+-+ writel(0, regs + NFIECC_IRQ_REG(op));
+-+ writel(~ECC_OP_EN, regs + NFIECC_CTL_REG(op));
+-+
+-+ return 0;
+-+}
+-+
+-+static int nfiecc_correct_data(struct nfiecc *ecc,
+-+ struct nfiecc_status *status,
+-+ u8 *data, u32 sector)
+-+{
+-+ u32 err, offset, i;
+-+ u32 loc, byteloc, bitloc;
+-+
+-+ status->corrected = 0;
+-+ status->failed = 0;
+-+
+-+ offset = (sector >> 2);
+-+ err = readl(ecc->res.regs + NFIECC_DECENUM(offset));
+-+ err >>= (sector % 4) * 8;
+-+ err &= ecc->caps->err_mask;
+-+
+-+ if (err == ecc->caps->err_mask) {
+-+ status->failed++;
+-+ return -ENANDREAD;
+-+ }
+-+
+-+ status->corrected += err;
+-+ status->bitflips = max_t(u32, status->bitflips, err);
+-+
+-+ for (i = 0; i < err; i++) {
+-+ loc = readl(ecc->res.regs + NFIECC_DECEL(i >> 1));
+-+ loc >>= ((i & 0x1) << 4);
+-+ byteloc = loc >> 3;
+-+ bitloc = loc & 0x7;
+-+ data[byteloc] ^= (1 << bitloc);
+-+ }
+-+
+-+ return 0;
+-+}
+-+
+-+static int nfiecc_fill_data(struct nfiecc *ecc, u8 *data)
+-+{
+-+ struct nfiecc_config *config = &ecc->config;
+-+ void *regs = ecc->res.regs;
+-+ int size, ret, i;
+-+ u32 val;
+-+
+-+ if (config->mode == ECC_DMA_MODE) {
+-+ if ((unsigned long)config->dma_addr & 0x3)
+-+ pr_info("encode address is not 4B aligned: 0x%x\n",
+-+ (u32)(unsigned long)config->dma_addr);
+-+
+-+ writel((unsigned long)config->dma_addr,
+-+ regs + NFIECC_ADDR(config->op));
+-+ } else if (config->mode == ECC_PIO_MODE) {
+-+ if (config->op == ECC_ENCODE) {
+-+ size = (config->len + 3) >> 2;
+-+ } else {
+-+ size = config->strength * ecc->caps->parity_bits;
+-+ size = (size + 7) >> 3;
+-+ size += config->len;
+-+ size >>= 2;
+-+ }
+-+
+-+ for (i = 0; i < size; i++) {
+-+ ret = readl_poll_timeout_atomic(regs + NFIECC_PIO_DIRDY,
+-+ val, val & PIO_DI_RDY,
+-+ 10, ECC_TIMEOUT);
+-+ if (ret)
+-+ return ret;
+-+
+-+ writel(*((u32 *)data + i), regs + NFIECC_PIO_DI);
+-+ }
+-+ }
+-+
+-+ return 0;
+-+}
+-+
+-+static int nfiecc_encode(struct nfiecc *ecc, u8 *data)
+-+{
+-+ struct nfiecc_config *config = &ecc->config;
+-+ u32 len, i, val = 0;
+-+ u8 *p;
+-+ int ret;
+-+
+-+ /* Under NFI mode, nothing need to do */
+-+ if (config->mode == ECC_NFI_MODE)
+-+ return 0;
+-+
+-+ ret = nfiecc_fill_data(ecc, data);
+-+ if (ret)
+-+ return ret;
+-+
+-+ ret = nfiecc_wait_encode_done(ecc);
+-+ if (ret)
+-+ return ret;
+-+
+-+ ret = nfiecc_wait_idle(ecc);
+-+ if (ret)
+-+ return ret;
+-+
+-+ /* Program ECC bytes to OOB: per sector oob = FDM + ECC + SPARE */
+-+ len = (config->strength * ecc->caps->parity_bits + 7) >> 3;
+-+ p = data + config->len;
+-+
+-+ /* Write the parity bytes generated by the ECC back to the OOB region */
+-+ for (i = 0; i < len; i++) {
+-+ if ((i % 4) == 0)
+-+ val = readl(ecc->res.regs + NFIECC_ENCPAR(i / 4));
+-+
+-+ p[i] = (val >> ((i % 4) * 8)) & 0xff;
+-+ }
+-+
+-+ return 0;
+-+}
+-+
+-+static int nfiecc_decode(struct nfiecc *ecc, u8 *data)
+-+{
+-+ int ret;
+-+
+-+ /* Under NFI mode, nothing need to do */
+-+ if (ecc->config.mode == ECC_NFI_MODE)
+-+ return 0;
+-+
+-+ ret = nfiecc_fill_data(ecc, data);
+-+ if (ret)
+-+ return ret;
+-+
+-+ return nfiecc_wait_decode_done(ecc);
+-+}
+-+
+-+static int nfiecc_decode_status(struct nfiecc *ecc, u32 start_sector,
+-+ u32 sectors)
+-+{
+-+ void *regs = ecc->res.regs;
+-+ u32 i, val = 0, err;
+-+ u32 bitflips = 0;
+-+
+-+ for (i = start_sector; i < start_sector + sectors; i++) {
+-+ if ((i % 4) == 0)
+-+ val = readl(regs + NFIECC_DECENUM(i / 4));
+-+
+-+ err = val >> ((i % 4) * 5);
+-+ err &= ecc->caps->err_mask;
+-+
+-+ if (err == ecc->caps->err_mask)
+-+ pr_err("sector %d is uncorrect\n", i);
+-+
+-+ bitflips = max_t(u32, bitflips, err);
+-+ }
+-+
+-+ if (bitflips == ecc->caps->err_mask)
+-+ return -ENANDREAD;
+-+
+-+ if (bitflips)
+-+ pr_info("bitflips %d is corrected\n", bitflips);
+-+
+-+ return bitflips;
+-+}
+-+
+-+static int nfiecc_adjust_strength(struct nfiecc *ecc, int strength)
+-+{
+-+ struct nfiecc_caps *caps = ecc->caps;
+-+ int i, count = caps->ecc_strength_num;
+-+
+-+ if (strength >= caps->ecc_strength[count - 1])
+-+ return caps->ecc_strength[count - 1];
+-+
+-+ if (strength < caps->ecc_strength[0])
+-+ return -EINVAL;
+-+
+-+ for (i = 1; i < count; i++) {
+-+ if (strength < caps->ecc_strength[i])
+-+ return caps->ecc_strength[i - 1];
+-+ }
+-+
+-+ return -EINVAL;
+-+}
+-+
+-+static int nfiecc_ctrl(struct nfiecc *ecc, int cmd, void *args)
+-+{
+-+ int ret = 0;
+-+
+-+ switch (cmd) {
+-+ case NFI_CTRL_ECC_IRQ:
+-+ ecc->ecc_irq_en = *(bool *)args;
+-+ break;
+-+
+-+ case NFI_CTRL_ECC_PAGE_IRQ:
+-+ ecc->page_irq_en = *(bool *)args;
+-+ break;
+-+
+-+ default:
+-+ pr_info("invalid arguments.\n");
+-+ ret = -EINVAL;
+-+ break;
+-+ }
+-+
+-+ return ret;
+-+}
+-+
+-+static int nfiecc_hw_init(struct nfiecc *ecc)
+-+{
+-+ int ret;
+-+
+-+ ret = nfiecc_wait_idle(ecc);
+-+ if (ret)
+-+ return ret;
+-+
+-+ writel(~ECC_OP_EN, ecc->res.regs + NFIECC_ENCCON);
+-+
+-+ ret = nfiecc_wait_idle(ecc);
+-+ if (ret)
+-+ return ret;
+-+
+-+ writel(~ECC_OP_EN, ecc->res.regs + NFIECC_DECCON);
+-+
+-+ return 0;
+-+}
+-+
+-+static struct nfiecc_caps nfiecc_caps_mt7622 = {
+-+ .err_mask = 0x1f,
+-+ .ecc_mode_shift = 4,
+-+ .parity_bits = 13,
+-+ .ecc_strength = ecc_strength_mt7622,
+-+ .ecc_strength_num = 7,
+-+};
+-+
+-+static struct nfiecc_caps *nfiecc_get_match_data(enum mtk_ic_version ic)
+-+{
+-+ /* NOTE: add other IC's data */
+-+ return &nfiecc_caps_mt7622;
+-+}
+-+
+-+struct nfiecc *nfiecc_init(struct nfiecc_resource *res)
+-+{
+-+ struct nfiecc *ecc;
+-+ int ret;
+-+
+-+ ecc = mem_alloc(1, sizeof(struct nfiecc));
+-+ if (!ecc)
+-+ return NULL;
+-+
+-+ ecc->res = *res;
+-+
+-+ ret = nandx_irq_register(res->dev, res->irq_id, nfiecc_irq_handler,
+-+ "mtk-ecc", ecc);
+-+ if (ret) {
+-+ pr_info("ecc irq register failed!\n");
+-+ goto error;
+-+ }
+-+
+-+ ecc->ecc_irq_en = false;
+-+ ecc->page_irq_en = false;
+-+ ecc->done = nandx_event_create();
+-+ ecc->caps = nfiecc_get_match_data(res->ic_ver);
+-+
+-+ ecc->adjust_strength = nfiecc_adjust_strength;
+-+ ecc->enable = nfiecc_enable;
+-+ ecc->disable = nfiecc_disable;
+-+ ecc->decode = nfiecc_decode;
+-+ ecc->encode = nfiecc_encode;
+-+ ecc->wait_done = nfiecc_wait_done;
+-+ ecc->decode_status = nfiecc_decode_status;
+-+ ecc->correct_data = nfiecc_correct_data;
+-+ ecc->nfiecc_ctrl = nfiecc_ctrl;
+-+
+-+ ret = nfiecc_hw_init(ecc);
+-+ if (ret)
+-+ return NULL;
+-+
+-+ return ecc;
+-+
+-+error:
+-+ mem_free(ecc);
+-+
+-+ return NULL;
+-+}
+-+
+-+void nfiecc_exit(struct nfiecc *ecc)
+-+{
+-+ nandx_event_destroy(ecc->done);
+-+ mem_free(ecc);
+-+}
+-+
+-diff --git a/drivers/mtd/nandx/core/nfi/nfiecc.h b/drivers/mtd/nandx/core/nfi/nfiecc.h
+-new file mode 100644
+-index 0000000000..b02a5c3534
+---- /dev/null
+-+++ b/drivers/mtd/nandx/core/nfi/nfiecc.h
+-@@ -0,0 +1,90 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#ifndef __NFIECC_H__
+-+#define __NFIECC_H__
+-+
+-+enum nfiecc_mode {
+-+ ECC_DMA_MODE,
+-+ ECC_NFI_MODE,
+-+ ECC_PIO_MODE
+-+};
+-+
+-+enum nfiecc_operation {
+-+ ECC_ENCODE,
+-+ ECC_DECODE
+-+};
+-+
+-+enum nfiecc_deccon {
+-+ ECC_DEC_FER = 1,
+-+ ECC_DEC_LOCATE = 2,
+-+ ECC_DEC_CORRECT = 3
+-+};
+-+
+-+struct nfiecc_resource {
+-+ int ic_ver;
+-+ void *dev;
+-+ void *regs;
+-+ int irq_id;
+-+
+-+};
+-+
+-+struct nfiecc_status {
+-+ u32 corrected;
+-+ u32 failed;
+-+ u32 bitflips;
+-+};
+-+
+-+struct nfiecc_caps {
+-+ u32 err_mask;
+-+ u32 ecc_mode_shift;
+-+ u32 parity_bits;
+-+ const int *ecc_strength;
+-+ u32 ecc_strength_num;
+-+};
+-+
+-+struct nfiecc_config {
+-+ enum nfiecc_operation op;
+-+ enum nfiecc_mode mode;
+-+ enum nfiecc_deccon deccon;
+-+
+-+ void *dma_addr; /* DMA use only */
+-+ u32 strength;
+-+ u32 sectors;
+-+ u32 len;
+-+};
+-+
+-+struct nfiecc {
+-+ struct nfiecc_resource res;
+-+ struct nfiecc_config config;
+-+ struct nfiecc_caps *caps;
+-+
+-+ bool ecc_irq_en;
+-+ bool page_irq_en;
+-+
+-+ void *done;
+-+
+-+ int (*adjust_strength)(struct nfiecc *ecc, int strength);
+-+ int (*enable)(struct nfiecc *ecc);
+-+ int (*disable)(struct nfiecc *ecc);
+-+
+-+ int (*decode)(struct nfiecc *ecc, u8 *data);
+-+ int (*encode)(struct nfiecc *ecc, u8 *data);
+-+
+-+ int (*decode_status)(struct nfiecc *ecc, u32 start_sector, u32 sectors);
+-+ int (*correct_data)(struct nfiecc *ecc,
+-+ struct nfiecc_status *status,
+-+ u8 *data, u32 sector);
+-+ int (*wait_done)(struct nfiecc *ecc);
+-+
+-+ int (*nfiecc_ctrl)(struct nfiecc *ecc, int cmd, void *args);
+-+};
+-+
+-+struct nfiecc *nfiecc_init(struct nfiecc_resource *res);
+-+void nfiecc_exit(struct nfiecc *ecc);
+-+
+-+#endif /* __NFIECC_H__ */
+-diff --git a/drivers/mtd/nandx/core/nfi/nfiecc_regs.h b/drivers/mtd/nandx/core/nfi/nfiecc_regs.h
+-new file mode 100644
+-index 0000000000..96564cf872
+---- /dev/null
+-+++ b/drivers/mtd/nandx/core/nfi/nfiecc_regs.h
+-@@ -0,0 +1,51 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#ifndef __NFIECC_REGS_H__
+-+#define __NFIECC_REGS_H__
+-+
+-+#define NFIECC_ENCCON 0x000
+-+/* NFIECC_DECCON has same bit define */
+-+#define ECC_OP_EN BIT(0)
+-+#define NFIECC_ENCCNFG 0x004
+-+#define ENCCNFG_MS_SHIFT 16
+-+#define ENC_BURST_EN BIT(8)
+-+#define NFIECC_ENCDIADDR 0x008
+-+#define NFIECC_ENCIDLE 0x00c
+-+#define NFIECC_ENCSTA 0x02c
+-+#define ENC_FSM_IDLE 1
+-+#define NFIECC_ENCIRQEN 0x030
+-+/* NFIECC_DECIRQEN has same bit define */
+-+#define ECC_IRQEN BIT(0)
+-+#define ECC_PG_IRQ_SEL BIT(1)
+-+#define NFIECC_ENCIRQSTA 0x034
+-+#define ENC_IRQSTA_GEN BIT(0)
+-+#define NFIECC_PIO_DIRDY 0x080
+-+#define PIO_DI_RDY BIT(0)
+-+#define NFIECC_PIO_DI 0x084
+-+#define NFIECC_DECCON 0x100
+-+#define NFIECC_DECCNFG 0x104
+-+#define DEC_BURST_EN BIT(8)
+-+#define DEC_EMPTY_EN BIT(31)
+-+#define DEC_CON_SHIFT 12
+-+#define DECCNFG_MS_SHIFT 16
+-+#define NFIECC_DECDIADDR 0x108
+-+#define NFIECC_DECIDLE 0x10c
+-+#define NFIECC_DECENUM(x) (0x114 + (x) * 4)
+-+#define NFIECC_DECDONE 0x11c
+-+#define NFIECC_DECIRQEN 0x140
+-+#define NFIECC_DECIRQSTA 0x144
+-+#define DEC_IRQSTA_GEN BIT(0)
+-+#define NFIECC_DECFSM 0x14c
+-+#define FSM_MASK 0x7f0f0f0f
+-+#define FSM_IDLE 0x01010101
+-+#define NFIECC_BYPASS 0x20c
+-+#define NFIECC_BYPASS_EN BIT(0)
+-+#define NFIECC_ENCPAR(x) (0x010 + (x) * 4)
+-+#define NFIECC_DECEL(x) (0x120 + (x) * 4)
+-+
+-+#endif /* __NFIECC_REGS_H__ */
+-diff --git a/drivers/mtd/nandx/driver/Nandx.mk b/drivers/mtd/nandx/driver/Nandx.mk
+-new file mode 100644
+-index 0000000000..3fb93d37c5
+---- /dev/null
+-+++ b/drivers/mtd/nandx/driver/Nandx.mk
+-@@ -0,0 +1,18 @@
+-+#
+-+# Copyright (C) 2017 MediaTek Inc.
+-+# Licensed under either
+-+# BSD Licence, (see NOTICE for more details)
+-+# GNU General Public License, version 2.0, (see NOTICE for more details)
+-+#
+-+
+-+nandx-$(NANDX_SIMULATOR_SUPPORT) += simulator/driver.c
+-+
+-+nandx-$(NANDX_CTP_SUPPORT) += ctp/ts_nand.c
+-+nandx-$(NANDX_CTP_SUPPORT) += ctp/nand_test.c
+-+nandx-header-$(NANDX_CTP_SUPPORT) += ctp/nand_test.h
+-+
+-+nandx-$(NANDX_BBT_SUPPORT) += bbt/bbt.c
+-+nandx-$(NANDX_BROM_SUPPORT) += brom/driver.c
+-+nandx-$(NANDX_KERNEL_SUPPORT) += kernel/driver.c
+-+nandx-$(NANDX_LK_SUPPORT) += lk/driver.c
+-+nandx-$(NANDX_UBOOT_SUPPORT) += uboot/driver.c
+-diff --git a/drivers/mtd/nandx/driver/bbt/bbt.c b/drivers/mtd/nandx/driver/bbt/bbt.c
+-new file mode 100644
+-index 0000000000..c9d4823e09
+---- /dev/null
+-+++ b/drivers/mtd/nandx/driver/bbt/bbt.c
+-@@ -0,0 +1,408 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#include "nandx_util.h"
+-+#include "nandx_core.h"
+-+#include "bbt.h"
+-+
+-+/* Not support: multi-chip */
+-+static u8 main_bbt_pattern[] = {'B', 'b', 't', '0' };
+-+static u8 mirror_bbt_pattern[] = {'1', 't', 'b', 'B' };
+-+
+-+static struct bbt_manager g_bbt_manager = {
+-+ { {{main_bbt_pattern, 4}, 0, BBT_INVALID_ADDR},
+-+ {{mirror_bbt_pattern, 4}, 0, BBT_INVALID_ADDR}
+-+ },
+-+ NAND_BBT_SCAN_MAXBLOCKS, NULL
+-+};
+-+
+-+static inline void set_bbt_mark(u8 *bbt, int block, u8 mark)
+-+{
+-+ int index, offset;
+-+
+-+ index = GET_ENTRY(block);
+-+ offset = GET_POSITION(block);
+-+
+-+ bbt[index] &= ~(BBT_ENTRY_MASK << offset);
+-+ bbt[index] |= (mark & BBT_ENTRY_MASK) << offset;
+-+ pr_info("%s %d block:%d, bbt[%d]:0x%x, offset:%d, mark:%d\n",
+-+ __func__, __LINE__, block, index, bbt[index], offset, mark);
+-+}
+-+
+-+static inline u8 get_bbt_mark(u8 *bbt, int block)
+-+{
+-+ int offset = GET_POSITION(block);
+-+ int index = GET_ENTRY(block);
+-+ u8 value = bbt[index];
+-+
+-+ return (value >> offset) & BBT_ENTRY_MASK;
+-+}
+-+
+-+static void mark_nand_bad(struct nandx_info *nand, int block)
+-+{
+-+ u8 *buf;
+-+
+-+ buf = mem_alloc(1, nand->page_size + nand->oob_size);
+-+ if (!buf) {
+-+ pr_info("%s, %d, memory alloc fail, pagesize:%d, oobsize:%d\n",
+-+ __func__, __LINE__, nand->page_size, nand->oob_size);
+-+ return;
+-+ }
+-+ memset(buf, 0, nand->page_size + nand->oob_size);
+-+ nandx_erase(block * nand->block_size, nand->block_size);
+-+ nandx_write(buf, buf + nand->page_size, block * nand->block_size,
+-+ nand->page_size);
+-+ mem_free(buf);
+-+}
+-+
+-+static inline bool is_bbt_data(u8 *buf, struct bbt_pattern *pattern)
+-+{
+-+ int i;
+-+
+-+ for (i = 0; i < pattern->len; i++) {
+-+ if (buf[i] != pattern->data[i])
+-+ return false;
+-+ }
+-+
+-+ return true;
+-+}
+-+
+-+static u64 get_bbt_address(struct nandx_info *nand, u8 *bbt,
+-+ u64 mirror_addr,
+-+ int max_blocks)
+-+{
+-+ u64 addr, end_addr;
+-+ u8 mark;
+-+
+-+ addr = nand->total_size;
+-+ end_addr = nand->total_size - nand->block_size * max_blocks;
+-+
+-+ while (addr > end_addr) {
+-+ addr -= nand->block_size;
+-+ mark = get_bbt_mark(bbt, div_down(addr, nand->block_size));
+-+
+-+ if (mark == BBT_BLOCK_WORN || mark == BBT_BLOCK_FACTORY_BAD)
+-+ continue;
+-+ if (addr != mirror_addr)
+-+ return addr;
+-+ }
+-+
+-+ return BBT_INVALID_ADDR;
+-+}
+-+
+-+static int read_bbt(struct bbt_desc *desc, u8 *bbt, u32 len)
+-+{
+-+ int ret;
+-+
+-+ ret = nandx_read(bbt, NULL, desc->bbt_addr + desc->pattern.len + 1,
+-+ len);
+-+ if (ret < 0)
+-+ pr_info("nand_bbt: error reading BBT page, ret:-%x\n", ret);
+-+
+-+ return ret;
+-+}
+-+
+-+static void create_bbt(struct nandx_info *nand, u8 *bbt)
+-+{
+-+ u32 offset = 0, block = 0;
+-+
+-+ do {
+-+ if (nandx_is_bad_block(offset)) {
+-+ pr_info("Create bbt at bad block:%d\n", block);
+-+ set_bbt_mark(bbt, block, BBT_BLOCK_FACTORY_BAD);
+-+ }
+-+ block++;
+-+ offset += nand->block_size;
+-+ } while (offset < nand->total_size);
+-+}
+-+
+-+static int search_bbt(struct nandx_info *nand, struct bbt_desc *desc,
+-+ int max_blocks)
+-+{
+-+ u64 addr, end_addr;
+-+ u8 *buf;
+-+ int ret;
+-+
+-+ buf = mem_alloc(1, nand->page_size);
+-+ if (!buf) {
+-+ pr_info("%s, %d, mem alloc fail!!! len:%d\n",
+-+ __func__, __LINE__, nand->page_size);
+-+ return -ENOMEM;
+-+ }
+-+
+-+ addr = nand->total_size;
+-+ end_addr = nand->total_size - max_blocks * nand->block_size;
+-+ while (addr > end_addr) {
+-+ addr -= nand->block_size;
+-+
+-+ nandx_read(buf, NULL, addr, nand->page_size);
+-+
+-+ if (is_bbt_data(buf, &desc->pattern)) {
+-+ desc->bbt_addr = addr;
+-+ desc->version = buf[desc->pattern.len];
+-+ pr_info("BBT is found at addr 0x%llx, version %d\n",
+-+ desc->bbt_addr, desc->version);
+-+ ret = 0;
+-+ break;
+-+ }
+-+ ret = -EFAULT;
+-+ }
+-+
+-+ mem_free(buf);
+-+ return ret;
+-+}
+-+
+-+static int save_bbt(struct nandx_info *nand, struct bbt_desc *desc,
+-+ u8 *bbt)
+-+{
+-+ u32 page_size_mask, total_block;
+-+ int write_len;
+-+ u8 *buf;
+-+ int ret;
+-+
+-+ ret = nandx_erase(desc->bbt_addr, nand->block_size);
+-+ if (ret) {
+-+ pr_info("erase addr 0x%llx fail !!!, ret %d\n",
+-+ desc->bbt_addr, ret);
+-+ return ret;
+-+ }
+-+
+-+ total_block = div_down(nand->total_size, nand->block_size);
+-+ write_len = GET_BBT_LENGTH(total_block) + desc->pattern.len + 1;
+-+ page_size_mask = nand->page_size - 1;
+-+ write_len = (write_len + page_size_mask) & (~page_size_mask);
+-+
+-+ buf = (u8 *)mem_alloc(1, write_len);
+-+ if (!buf) {
+-+ pr_info("%s, %d, mem alloc fail!!! len:%d\n",
+-+ __func__, __LINE__, write_len);
+-+ return -ENOMEM;
+-+ }
+-+ memset(buf, 0xFF, write_len);
+-+
+-+ memcpy(buf, desc->pattern.data, desc->pattern.len);
+-+ buf[desc->pattern.len] = desc->version;
+-+
+-+ memcpy(buf + desc->pattern.len + 1, bbt, GET_BBT_LENGTH(total_block));
+-+
+-+ ret = nandx_write(buf, NULL, desc->bbt_addr, write_len);
+-+
+-+ if (ret)
+-+ pr_info("nandx_write fail(%d), offset:0x%llx, len(%d)\n",
+-+ ret, desc->bbt_addr, write_len);
+-+ mem_free(buf);
+-+
+-+ return ret;
+-+}
+-+
+-+static int write_bbt(struct nandx_info *nand, struct bbt_desc *main,
+-+ struct bbt_desc *mirror, u8 *bbt, int max_blocks)
+-+{
+-+ int block;
+-+ int ret;
+-+
+-+ do {
+-+ if (main->bbt_addr == BBT_INVALID_ADDR) {
+-+ main->bbt_addr = get_bbt_address(nand, bbt,
+-+ mirror->bbt_addr, max_blocks);
+-+ if (main->bbt_addr == BBT_INVALID_ADDR)
+-+ return -ENOSPC;
+-+ }
+-+
+-+ ret = save_bbt(nand, main, bbt);
+-+ if (!ret)
+-+ break;
+-+
+-+ block = div_down(main->bbt_addr, nand->block_size);
+-+ set_bbt_mark(bbt, block, BBT_BLOCK_WORN);
+-+ main->version++;
+-+ mark_nand_bad(nand, block);
+-+ main->bbt_addr = BBT_INVALID_ADDR;
+-+ } while (1);
+-+
+-+ return 0;
+-+}
+-+
+-+static void mark_bbt_region(struct nandx_info *nand, u8 *bbt, int bbt_blocks)
+-+{
+-+ int total_block;
+-+ int block;
+-+ u8 mark;
+-+
+-+ total_block = div_down(nand->total_size, nand->block_size);
+-+ block = total_block - bbt_blocks;
+-+
+-+ while (bbt_blocks) {
+-+ mark = get_bbt_mark(bbt, block);
+-+ if (mark == BBT_BLOCK_GOOD)
+-+ set_bbt_mark(bbt, block, BBT_BLOCK_RESERVED);
+-+ block++;
+-+ bbt_blocks--;
+-+ }
+-+}
+-+
+-+static void unmark_bbt_region(struct nandx_info *nand, u8 *bbt, int bbt_blocks)
+-+{
+-+ int total_block;
+-+ int block;
+-+ u8 mark;
+-+
+-+ total_block = div_down(nand->total_size, nand->block_size);
+-+ block = total_block - bbt_blocks;
+-+
+-+ while (bbt_blocks) {
+-+ mark = get_bbt_mark(bbt, block);
+-+ if (mark == BBT_BLOCK_RESERVED)
+-+ set_bbt_mark(bbt, block, BBT_BLOCK_GOOD);
+-+ block++;
+-+ bbt_blocks--;
+-+ }
+-+}
+-+
+-+static int update_bbt(struct nandx_info *nand, struct bbt_desc *desc,
+-+ u8 *bbt,
+-+ int max_blocks)
+-+{
+-+ int ret = 0, i;
+-+
+-+ /* The reserved info is not stored in NAND*/
+-+ unmark_bbt_region(nand, bbt, max_blocks);
+-+
+-+ desc[0].version++;
+-+ for (i = 0; i < 2; i++) {
+-+ if (i > 0)
+-+ desc[i].version = desc[i - 1].version;
+-+
+-+ ret = write_bbt(nand, &desc[i], &desc[1 - i], bbt, max_blocks);
+-+ if (ret)
+-+ break;
+-+ }
+-+ mark_bbt_region(nand, bbt, max_blocks);
+-+
+-+ return ret;
+-+}
+-+
+-+int scan_bbt(struct nandx_info *nand)
+-+{
+-+ struct bbt_manager *manager = &g_bbt_manager;
+-+ struct bbt_desc *pdesc;
+-+ int total_block, len, i;
+-+ int valid_desc = 0;
+-+ int ret = 0;
+-+ u8 *bbt;
+-+
+-+ total_block = div_down(nand->total_size, nand->block_size);
+-+ len = GET_BBT_LENGTH(total_block);
+-+
+-+ if (!manager->bbt) {
+-+ manager->bbt = (u8 *)mem_alloc(1, len);
+-+ if (!manager->bbt) {
+-+ pr_info("%s, %d, mem alloc fail!!! len:%d\n",
+-+ __func__, __LINE__, len);
+-+ return -ENOMEM;
+-+ }
+-+ }
+-+ bbt = manager->bbt;
+-+ memset(bbt, 0xFF, len);
+-+
+-+ /* scan bbt */
+-+ for (i = 0; i < 2; i++) {
+-+ pdesc = &manager->desc[i];
+-+ pdesc->bbt_addr = BBT_INVALID_ADDR;
+-+ pdesc->version = 0;
+-+ ret = search_bbt(nand, pdesc, manager->max_blocks);
+-+ if (!ret && (pdesc->bbt_addr != BBT_INVALID_ADDR))
+-+ valid_desc += 1 << i;
+-+ }
+-+
+-+ pdesc = &manager->desc[0];
+-+ if ((valid_desc == 0x3) && (pdesc[0].version != pdesc[1].version))
+-+ valid_desc = (pdesc[0].version > pdesc[1].version) ? 1 : 2;
+-+
+-+ /* read bbt */
+-+ for (i = 0; i < 2; i++) {
+-+ if (!(valid_desc & (1 << i)))
+-+ continue;
+-+ ret = read_bbt(&pdesc[i], bbt, len);
+-+ if (ret) {
+-+ pdesc->bbt_addr = BBT_INVALID_ADDR;
+-+ pdesc->version = 0;
+-+ valid_desc &= ~(1 << i);
+-+ }
+-+ /* If two BBT version is same, only need to read the first bbt*/
+-+ if ((valid_desc == 0x3) &&
+-+ (pdesc[0].version == pdesc[1].version))
+-+ break;
+-+ }
+-+
+-+ if (!valid_desc) {
+-+ create_bbt(nand, bbt);
+-+ pdesc[0].version = 1;
+-+ pdesc[1].version = 1;
+-+ }
+-+
+-+ pdesc[0].version = max_t(u8, pdesc[0].version, pdesc[1].version);
+-+ pdesc[1].version = pdesc[0].version;
+-+
+-+ for (i = 0; i < 2; i++) {
+-+ if (valid_desc & (1 << i))
+-+ continue;
+-+
+-+ ret = write_bbt(nand, &pdesc[i], &pdesc[1 - i], bbt,
+-+ manager->max_blocks);
+-+ if (ret) {
+-+ pr_info("write bbt(%d) fail, ret:%d\n", i, ret);
+-+ manager->bbt = NULL;
+-+ return ret;
+-+ }
+-+ }
+-+
+-+ /* Prevent the bbt regions from erasing / writing */
+-+ mark_bbt_region(nand, manager->bbt, manager->max_blocks);
+-+
+-+ for (i = 0; i < total_block; i++) {
+-+ if (get_bbt_mark(manager->bbt, i) == BBT_BLOCK_WORN)
+-+ pr_info("Checked WORN bad blk: %d\n", i);
+-+ else if (get_bbt_mark(manager->bbt, i) == BBT_BLOCK_FACTORY_BAD)
+-+ pr_info("Checked Factory bad blk: %d\n", i);
+-+ else if (get_bbt_mark(manager->bbt, i) == BBT_BLOCK_RESERVED)
+-+ pr_info("Checked Reserved blk: %d\n", i);
+-+ else if (get_bbt_mark(manager->bbt, i) != BBT_BLOCK_GOOD)
+-+ pr_info("Checked unknown blk: %d\n", i);
+-+ }
+-+
+-+ return 0;
+-+}
+-+
+-+int bbt_mark_bad(struct nandx_info *nand, off_t offset)
+-+{
+-+ struct bbt_manager *manager = &g_bbt_manager;
+-+ int block = div_down(offset, nand->block_size);
+-+ int ret = 0;
+-+
+-+ mark_nand_bad(nand, block);
+-+
+-+#if 0
+-+ set_bbt_mark(manager->bbt, block, BBT_BLOCK_WORN);
+-+
+-+ /* Update flash-based bad block table */
+-+ ret = update_bbt(nand, manager->desc, manager->bbt,
+-+ manager->max_blocks);
+-+#endif
+-+ pr_info("block %d, update result %d.\n", block, ret);
+-+
+-+ return ret;
+-+}
+-+
+-+int bbt_is_bad(struct nandx_info *nand, off_t offset)
+-+{
+-+ int block;
+-+
+-+ block = div_down(offset, nand->block_size);
+-+
+-+ return get_bbt_mark(g_bbt_manager.bbt, block) != BBT_BLOCK_GOOD;
+-+}
+-diff --git a/drivers/mtd/nandx/driver/uboot/driver.c b/drivers/mtd/nandx/driver/uboot/driver.c
+-new file mode 100644
+-index 0000000000..7bd3342452
+---- /dev/null
+-+++ b/drivers/mtd/nandx/driver/uboot/driver.c
+-@@ -0,0 +1,574 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#include <common.h>
+-+#include <linux/io.h>
+-+#include <dm.h>
+-+#include <clk.h>
+-+#include <nand.h>
+-+#include <linux/iopoll.h>
+-+#include <linux/delay.h>
+-+#include <linux/mtd/nand.h>
+-+#include <linux/mtd/mtd.h>
+-+#include <linux/mtd/partitions.h>
+-+#include "nandx_core.h"
+-+#include "nandx_util.h"
+-+#include "bbt.h"
+-+
+-+typedef int (*func_nandx_operation)(u8 *, u8 *, u64, size_t);
+-+
+-+struct nandx_clk {
+-+ struct clk *nfi_clk;
+-+ struct clk *ecc_clk;
+-+ struct clk *snfi_clk;
+-+ struct clk *snfi_clk_sel;
+-+ struct clk *snfi_parent_50m;
+-+};
+-+
+-+struct nandx_nfc {
+-+ struct nandx_info info;
+-+ struct nandx_clk clk;
+-+ struct nfi_resource *res;
+-+
+-+ struct nand_chip *nand;
+-+ spinlock_t lock;
+-+};
+-+
+-+/* Default flash layout for MTK nand controller
+-+ * 64Bytes oob format.
+-+ */
+-+static struct nand_ecclayout eccoob = {
+-+ .eccbytes = 42,
+-+ .eccpos = {
+-+ 17, 18, 19, 20, 21, 22, 23, 24, 25,
+-+ 26, 27, 28, 29, 30, 31, 32, 33, 34,
+-+ 35, 36, 37, 38, 39, 40, 41
+-+ },
+-+ .oobavail = 16,
+-+ .oobfree = {
+-+ {
+-+ .offset = 0,
+-+ .length = 16,
+-+ },
+-+ }
+-+};
+-+
+-+static struct nandx_nfc *mtd_to_nfc(struct mtd_info *mtd)
+-+{
+-+ struct nand_chip *nand = mtd_to_nand(mtd);
+-+
+-+ return (struct nandx_nfc *)nand_get_controller_data(nand);
+-+}
+-+
+-+static int nandx_enable_clk(struct nandx_clk *clk)
+-+{
+-+ int ret;
+-+
+-+ ret = clk_enable(clk->nfi_clk);
+-+ if (ret) {
+-+ pr_info("failed to enable nfi clk\n");
+-+ return ret;
+-+ }
+-+
+-+ ret = clk_enable(clk->ecc_clk);
+-+ if (ret) {
+-+ pr_info("failed to enable ecc clk\n");
+-+ goto disable_nfi_clk;
+-+ }
+-+
+-+ ret = clk_enable(clk->snfi_clk);
+-+ if (ret) {
+-+ pr_info("failed to enable snfi clk\n");
+-+ goto disable_ecc_clk;
+-+ }
+-+
+-+ ret = clk_enable(clk->snfi_clk_sel);
+-+ if (ret) {
+-+ pr_info("failed to enable snfi clk sel\n");
+-+ goto disable_snfi_clk;
+-+ }
+-+
+-+ ret = clk_set_parent(clk->snfi_clk_sel, clk->snfi_parent_50m);
+-+ if (ret) {
+-+ pr_info("failed to set snfi parent 50MHz\n");
+-+ goto disable_snfi_clk;
+-+ }
+-+
+-+ return 0;
+-+
+-+disable_snfi_clk:
+-+ clk_disable(clk->snfi_clk);
+-+disable_ecc_clk:
+-+ clk_disable(clk->ecc_clk);
+-+disable_nfi_clk:
+-+ clk_disable(clk->nfi_clk);
+-+
+-+ return ret;
+-+}
+-+
+-+static void nandx_disable_clk(struct nandx_clk *clk)
+-+{
+-+ clk_disable(clk->ecc_clk);
+-+ clk_disable(clk->nfi_clk);
+-+ clk_disable(clk->snfi_clk);
+-+}
+-+
+-+static int mtk_nfc_ooblayout_free(struct mtd_info *mtd, int section,
+-+ struct mtd_oob_region *oob_region)
+-+{
+-+ struct nandx_nfc *nfc = (struct nandx_nfc *)mtd_to_nfc(mtd);
+-+ u32 eccsteps;
+-+
+-+ eccsteps = div_down(mtd->writesize, mtd->ecc_step_size);
+-+
+-+ if (section >= eccsteps)
+-+ return -EINVAL;
+-+
+-+ oob_region->length = nfc->info.fdm_reg_size - nfc->info.fdm_ecc_size;
+-+ oob_region->offset = section * nfc->info.fdm_reg_size
+-+ + nfc->info.fdm_ecc_size;
+-+
+-+ return 0;
+-+}
+-+
+-+static int mtk_nfc_ooblayout_ecc(struct mtd_info *mtd, int section,
+-+ struct mtd_oob_region *oob_region)
+-+{
+-+ struct nandx_nfc *nfc = (struct nandx_nfc *)mtd_to_nfc(mtd);
+-+ u32 eccsteps;
+-+
+-+ if (section)
+-+ return -EINVAL;
+-+
+-+ eccsteps = div_down(mtd->writesize, mtd->ecc_step_size);
+-+ oob_region->offset = nfc->info.fdm_reg_size * eccsteps;
+-+ oob_region->length = mtd->oobsize - oob_region->offset;
+-+
+-+ return 0;
+-+}
+-+
+-+static const struct mtd_ooblayout_ops mtk_nfc_ooblayout_ops = {
+-+ .rfree = mtk_nfc_ooblayout_free,
+-+ .ecc = mtk_nfc_ooblayout_ecc,
+-+};
+-+
+-+struct nfc_compatible {
+-+ enum mtk_ic_version ic_ver;
+-+
+-+ u32 clock_1x;
+-+ u32 *clock_2x;
+-+ int clock_2x_num;
+-+
+-+ int min_oob_req;
+-+};
+-+
+-+static const struct nfc_compatible nfc_compats_mt7622 = {
+-+ .ic_ver = NANDX_MT7622,
+-+ .clock_1x = 26000000,
+-+ .clock_2x = NULL,
+-+ .clock_2x_num = 8,
+-+ .min_oob_req = 1,
+-+};
+-+
+-+static const struct udevice_id ic_of_match[] = {
+-+ {.compatible = "mediatek,mt7622-nfc", .data = &nfc_compats_mt7622},
+-+ {}
+-+};
+-+
+-+static int nand_operation(struct mtd_info *mtd, loff_t addr, size_t len,
+-+ size_t *retlen, uint8_t *data, uint8_t *oob, bool read)
+-+{
+-+ struct nandx_split64 split = {0};
+-+ func_nandx_operation operation;
+-+ u64 block_oobs, val, align;
+-+ uint8_t *databuf, *oobbuf;
+-+ struct nandx_nfc *nfc;
+-+ bool readoob;
+-+ int ret = 0;
+-+
+-+ nfc = (struct nandx_nfc *)nand_get_controller_data;
+-+ spin_lock(&nfc->lock);
+-+
+-+ databuf = data;
+-+ oobbuf = oob;
+-+
+-+ readoob = data ? false : true;
+-+ block_oobs = div_up(mtd->erasesize, mtd->writesize) * mtd->oobavail;
+-+ align = readoob ? block_oobs : mtd->erasesize;
+-+
+-+ operation = read ? nandx_read : nandx_write;
+-+
+-+ nandx_split(&split, addr, len, val, align);
+-+
+-+ if (split.head_len) {
+-+ ret = operation((u8 *) databuf, oobbuf, addr, split.head_len);
+-+
+-+ if (databuf)
+-+ databuf += split.head_len;
+-+
+-+ if (oobbuf)
+-+ oobbuf += split.head_len;
+-+
+-+ addr += split.head_len;
+-+ *retlen += split.head_len;
+-+ }
+-+
+-+ if (split.body_len) {
+-+ while (div_up(split.body_len, align)) {
+-+ ret = operation((u8 *) databuf, oobbuf, addr, align);
+-+
+-+ if (databuf) {
+-+ databuf += mtd->erasesize;
+-+ split.body_len -= mtd->erasesize;
+-+ *retlen += mtd->erasesize;
+-+ }
+-+
+-+ if (oobbuf) {
+-+ oobbuf += block_oobs;
+-+ split.body_len -= block_oobs;
+-+ *retlen += block_oobs;
+-+ }
+-+
+-+ addr += mtd->erasesize;
+-+ }
+-+
+-+ }
+-+
+-+ if (split.tail_len) {
+-+ ret = operation((u8 *) databuf, oobbuf, addr, split.tail_len);
+-+ *retlen += split.tail_len;
+-+ }
+-+
+-+ spin_unlock(&nfc->lock);
+-+
+-+ return ret;
+-+}
+-+
+-+static int mtk_nand_read(struct mtd_info *mtd, loff_t from, size_t len,
+-+ size_t *retlen, u_char *buf)
+-+{
+-+ return nand_operation(mtd, from, len, retlen, buf, NULL, true);
+-+}
+-+
+-+static int mtk_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
+-+ size_t *retlen, const u_char *buf)
+-+{
+-+ return nand_operation(mtd, to, len, retlen, (uint8_t *)buf,
+-+ NULL, false);
+-+}
+-+
+-+int mtk_nand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
+-+{
+-+ size_t retlen;
+-+
+-+ return nand_operation(mtd, from, ops->ooblen, &retlen, NULL,
+-+ ops->oobbuf, true);
+-+}
+-+
+-+int mtk_nand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
+-+{
+-+ size_t retlen;
+-+
+-+ return nand_operation(mtd, to, ops->ooblen, &retlen, NULL,
+-+ ops->oobbuf, false);
+-+}
+-+
+-+static int mtk_nand_erase(struct mtd_info *mtd, struct erase_info *instr)
+-+{
+-+ struct nandx_nfc *nfc;
+-+ u64 erase_len, erase_addr;
+-+ u32 block_size;
+-+ int ret = 0;
+-+
+-+ nfc = (struct nandx_nfc *)mtd_to_nfc(mtd);
+-+ block_size = nfc->info.block_size;
+-+ erase_len = instr->len;
+-+ erase_addr = instr->addr;
+-+ spin_lock(&nfc->lock);
+-+ instr->state = MTD_ERASING;
+-+
+-+ while (erase_len) {
+-+ if (mtk_nand_is_bad(mtd, erase_addr)) {
+-+ pr_info("block(0x%llx) is bad, not erase\n",
+-+ erase_addr);
+-+ instr->state = MTD_ERASE_FAILED;
+-+ goto erase_exit;
+-+ } else {
+-+ ret = nandx_erase(erase_addr, block_size);
+-+ if (ret < 0) {
+-+ instr->state = MTD_ERASE_FAILED;
+-+ goto erase_exit;
+-+ pr_info("erase fail at blk %llu, ret:%d\n",
+-+ erase_addr, ret);
+-+ }
+-+ }
+-+ erase_addr += block_size;
+-+ erase_len -= block_size;
+-+ }
+-+
+-+ instr->state = MTD_ERASE_DONE;
+-+
+-+erase_exit:
+-+ ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
+-+
+-+ spin_unlock(&nfc->lock);
+-+ /* Do mtd call back function */
+-+ if (!ret)
+-+ mtd_erase_callback(instr);
+-+
+-+ return ret;
+-+}
+-+
+-+int mtk_nand_is_bad(struct mtd_info *mtd, loff_t ofs)
+-+{
+-+ struct nandx_nfc *nfc;
+-+ int ret;
+-+
+-+ nfc = (struct nandx_nfc *)mtd_to_nfc(mtd);
+-+ spin_lock(&nfc->lock);
+-+
+-+ /*ret = bbt_is_bad(&nfc->info, ofs);*/
+-+ ret = nandx_is_bad_block(ofs);
+-+ spin_unlock(&nfc->lock);
+-+
+-+ if (ret) {
+-+ pr_info("nand block 0x%x is bad, ret %d!\n", ofs, ret);
+-+ return 1;
+-+ } else {
+-+ return 0;
+-+ }
+-+}
+-+
+-+int mtk_nand_mark_bad(struct mtd_info *mtd, loff_t ofs)
+-+{
+-+ struct nandx_nfc *nfc;
+-+ int ret;
+-+
+-+ nfc = (struct nandx_nfc *)mtd_to_nfc(mtd);
+-+ spin_lock(&nfc->lock);
+-+ pr_info("%s, %d\n", __func__, __LINE__);
+-+ ret = bbt_mark_bad(&nfc->info, ofs);
+-+
+-+ spin_unlock(&nfc->lock);
+-+
+-+ return ret;
+-+}
+-+
+-+void mtk_nand_sync(struct mtd_info *mtd)
+-+{
+-+ nandx_sync();
+-+}
+-+
+-+static struct mtd_info *mtd_info_create(struct udevice *pdev,
+-+ struct nandx_nfc *nfc, struct nand_chip *nand)
+-+{
+-+ struct mtd_info *mtd = nand_to_mtd(nand);
+-+ int ret;
+-+
+-+ nand_set_controller_data(nand, nfc);
+-+
+-+ nand->flash_node = dev_of_offset(pdev);
+-+ nand->ecc.layout = &eccoob;
+-+
+-+ ret = nandx_ioctl(CORE_CTRL_NAND_INFO, &nfc->info);
+-+ if (ret) {
+-+ pr_info("fail to get nand info (%d)!\n", ret);
+-+ mem_free(mtd);
+-+ return NULL;
+-+ }
+-+
+-+ mtd->owner = THIS_MODULE;
+-+
+-+ mtd->name = "MTK-SNand";
+-+ mtd->writesize = nfc->info.page_size;
+-+ mtd->erasesize = nfc->info.block_size;
+-+ mtd->oobsize = nfc->info.oob_size;
+-+ mtd->size = nfc->info.total_size;
+-+ mtd->type = MTD_NANDFLASH;
+-+ mtd->flags = MTD_CAP_NANDFLASH;
+-+ mtd->_erase = mtk_nand_erase;
+-+ mtd->_read = mtk_nand_read;
+-+ mtd->_write = mtk_nand_write;
+-+ mtd->_read_oob = mtk_nand_read_oob;
+-+ mtd->_write_oob = mtk_nand_write_oob;
+-+ mtd->_sync = mtk_nand_sync;
+-+ mtd->_lock = NULL;
+-+ mtd->_unlock = NULL;
+-+ mtd->_block_isbad = mtk_nand_is_bad;
+-+ mtd->_block_markbad = mtk_nand_mark_bad;
+-+ mtd->writebufsize = mtd->writesize;
+-+
+-+ mtd_set_ooblayout(mtd, &mtk_nfc_ooblayout_ops);
+-+
+-+ mtd->ecc_strength = nfc->info.ecc_strength;
+-+ mtd->ecc_step_size = nfc->info.sector_size;
+-+
+-+ if (!mtd->bitflip_threshold)
+-+ mtd->bitflip_threshold = mtd->ecc_strength;
+-+
+-+ return mtd;
+-+}
+-+
+-+int board_nand_init(struct nand_chip *nand)
+-+{
+-+ struct udevice *dev;
+-+ struct mtd_info *mtd;
+-+ struct nandx_nfc *nfc;
+-+ int arg = 1;
+-+ int ret;
+-+
+-+ ret = uclass_get_device_by_driver(UCLASS_MTD,
+-+ DM_GET_DRIVER(mtk_snand_drv),
+-+ &dev);
+-+ if (ret) {
+-+ pr_err("Failed to get mtk_nand_drv. (error %d)\n", ret);
+-+ return ret;
+-+ }
+-+
+-+ nfc = dev_get_priv(dev);
+-+
+-+ ret = nandx_enable_clk(&nfc->clk);
+-+ if (ret) {
+-+ pr_err("failed to enable nfi clk (error %d)\n", ret);
+-+ return ret;
+-+ }
+-+
+-+ ret = nandx_init(nfc->res);
+-+ if (ret) {
+-+ pr_err("nandx init error (%d)!\n", ret);
+-+ goto disable_clk;
+-+ }
+-+
+-+ arg = 1;
+-+ nandx_ioctl(NFI_CTRL_DMA, &arg);
+-+ nandx_ioctl(NFI_CTRL_ECC, &arg);
+-+
+-+#ifdef NANDX_UNIT_TEST
+-+ nandx_unit_test(0x780000, 0x800);
+-+#endif
+-+
+-+ mtd = mtd_info_create(dev, nfc, nand);
+-+ if (!mtd) {
+-+ ret = -ENOMEM;
+-+ goto disable_clk;
+-+ }
+-+
+-+ spin_lock_init(&nfc->lock);
+-+#if 0
+-+ ret = scan_bbt(&nfc->info);
+-+ if (ret) {
+-+ pr_info("bbt init error (%d)!\n", ret);
+-+ goto disable_clk;
+-+ }
+-+#endif
+-+ return ret;
+-+
+-+disable_clk:
+-+ nandx_disable_clk(&nfc->clk);
+-+
+-+ return ret;
+-+}
+-+
+-+static int mtk_snand_ofdata_to_platdata(struct udevice *dev)
+-+{
+-+ struct nandx_nfc *nfc = dev_get_priv(dev);
+-+ struct nfc_compatible *compat;
+-+ struct nfi_resource *res;
+-+
+-+ int ret = 0;
+-+
+-+ res = mem_alloc(1, sizeof(struct nfi_resource));
+-+ if (!res)
+-+ return -ENOMEM;
+-+
+-+ nfc->res = res;
+-+
+-+ res->nfi_regs = (void *)dev_read_addr_index(dev, 0);
+-+ res->ecc_regs = (void *)dev_read_addr_index(dev, 1);
+-+ pr_debug("mtk snand nfi_regs:0x%x ecc_regs:0x%x\n",
+-+ res->nfi_regs, res->ecc_regs);
+-+
+-+ compat = (struct nfc_compatible *)dev_get_driver_data(dev);
+-+
+-+ res->ic_ver = (enum mtk_ic_version)(compat->ic_ver);
+-+ res->clock_1x = compat->clock_1x;
+-+ res->clock_2x = compat->clock_2x;
+-+ res->clock_2x_num = compat->clock_2x_num;
+-+
+-+ memset(&nfc->clk, 0, sizeof(struct nandx_clk));
+-+ nfc->clk.nfi_clk =
+-+ kmalloc(sizeof(*nfc->clk.nfi_clk), GFP_KERNEL);
+-+ nfc->clk.ecc_clk =
+-+ kmalloc(sizeof(*nfc->clk.ecc_clk), GFP_KERNEL);
+-+ nfc->clk.snfi_clk=
+-+ kmalloc(sizeof(*nfc->clk.snfi_clk), GFP_KERNEL);
+-+ nfc->clk.snfi_clk_sel =
+-+ kmalloc(sizeof(*nfc->clk.snfi_clk_sel), GFP_KERNEL);
+-+ nfc->clk.snfi_parent_50m =
+-+ kmalloc(sizeof(*nfc->clk.snfi_parent_50m), GFP_KERNEL);
+-+
+-+ if (!nfc->clk.nfi_clk || !nfc->clk.ecc_clk || !nfc->clk.snfi_clk ||
+-+ !nfc->clk.snfi_clk_sel || !nfc->clk.snfi_parent_50m) {
+-+ ret = -ENOMEM;
+-+ goto err;
+-+ }
+-+
+-+ ret = clk_get_by_name(dev, "nfi_clk", nfc->clk.nfi_clk);
+-+ if (IS_ERR(nfc->clk.nfi_clk)) {
+-+ ret = PTR_ERR(nfc->clk.nfi_clk);
+-+ goto err;
+-+ }
+-+
+-+ ret = clk_get_by_name(dev, "ecc_clk", nfc->clk.ecc_clk);
+-+ if (IS_ERR(nfc->clk.ecc_clk)) {
+-+ ret = PTR_ERR(nfc->clk.ecc_clk);
+-+ goto err;
+-+ }
+-+
+-+ ret = clk_get_by_name(dev, "snfi_clk", nfc->clk.snfi_clk);
+-+ if (IS_ERR(nfc->clk.snfi_clk)) {
+-+ ret = PTR_ERR(nfc->clk.snfi_clk);
+-+ goto err;
+-+ }
+-+
+-+ ret = clk_get_by_name(dev, "spinfi_sel", nfc->clk.snfi_clk_sel);
+-+ if (IS_ERR(nfc->clk.snfi_clk_sel)) {
+-+ ret = PTR_ERR(nfc->clk.snfi_clk_sel);
+-+ goto err;
+-+ }
+-+
+-+ ret = clk_get_by_name(dev, "spinfi_parent_50m", nfc->clk.snfi_parent_50m);
+-+ if (IS_ERR(nfc->clk.snfi_parent_50m))
+-+ pr_info("spinfi parent 50MHz is not configed\n");
+-+
+-+ return 0;
+-+err:
+-+ if (nfc->clk.nfi_clk)
+-+ kfree(nfc->clk.nfi_clk);
+-+ if (nfc->clk.snfi_clk)
+-+ kfree(nfc->clk.snfi_clk);
+-+ if (nfc->clk.ecc_clk)
+-+ kfree(nfc->clk.ecc_clk);
+-+ if (nfc->clk.snfi_clk_sel)
+-+ kfree(nfc->clk.snfi_clk_sel);
+-+ if (nfc->clk.snfi_parent_50m)
+-+ kfree(nfc->clk.snfi_parent_50m);
+-+
+-+ return ret;
+-+}
+-+
+-+U_BOOT_DRIVER(mtk_snand_drv) = {
+-+ .name = "mtk_snand",
+-+ .id = UCLASS_MTD,
+-+ .of_match = ic_of_match,
+-+ .ofdata_to_platdata = mtk_snand_ofdata_to_platdata,
+-+ .priv_auto_alloc_size = sizeof(struct nandx_nfc),
+-+};
+-+
+-+MODULE_LICENSE("GPL v2");
+-+MODULE_DESCRIPTION("MTK Nand Flash Controller Driver");
+-+MODULE_AUTHOR("MediaTek");
+-diff --git a/drivers/mtd/nandx/include/Nandx.mk b/drivers/mtd/nandx/include/Nandx.mk
+-new file mode 100644
+-index 0000000000..667402790e
+---- /dev/null
+-+++ b/drivers/mtd/nandx/include/Nandx.mk
+-@@ -0,0 +1,16 @@
+-+#
+-+# Copyright (C) 2017 MediaTek Inc.
+-+# Licensed under either
+-+# BSD Licence, (see NOTICE for more details)
+-+# GNU General Public License, version 2.0, (see NOTICE for more details)
+-+#
+-+
+-+nandx-header-y += internal/nandx_core.h
+-+nandx-header-y += internal/nandx_errno.h
+-+nandx-header-y += internal/nandx_util.h
+-+nandx-header-$(NANDX_BBT_SUPPORT) += internal/bbt.h
+-+nandx-header-$(NANDX_SIMULATOR_SUPPORT) += simulator/nandx_os.h
+-+nandx-header-$(NANDX_CTP_SUPPORT) += ctp/nandx_os.h
+-+nandx-header-$(NANDX_LK_SUPPORT) += lk/nandx_os.h
+-+nandx-header-$(NANDX_KERNEL_SUPPORT) += kernel/nandx_os.h
+-+nandx-header-$(NANDX_UBOOT_SUPPORT) += uboot/nandx_os.h
+-diff --git a/drivers/mtd/nandx/include/internal/bbt.h b/drivers/mtd/nandx/include/internal/bbt.h
+-new file mode 100644
+-index 0000000000..4676def1f5
+---- /dev/null
+-+++ b/drivers/mtd/nandx/include/internal/bbt.h
+-@@ -0,0 +1,62 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#ifndef __BBT_H__
+-+#define __BBT_H__
+-+
+-+#define BBT_BLOCK_GOOD 0x03
+-+#define BBT_BLOCK_WORN 0x02
+-+#define BBT_BLOCK_RESERVED 0x01
+-+#define BBT_BLOCK_FACTORY_BAD 0x00
+-+
+-+#define BBT_INVALID_ADDR 0
+-+/* The maximum number of blocks to scan for a bbt */
+-+#define NAND_BBT_SCAN_MAXBLOCKS 4
+-+#define NAND_BBT_USE_FLASH 0x00020000
+-+#define NAND_BBT_NO_OOB 0x00040000
+-+
+-+/* Search good / bad pattern on the first and the second page */
+-+#define NAND_BBT_SCAN2NDPAGE 0x00008000
+-+/* Search good / bad pattern on the last page of the eraseblock */
+-+#define NAND_BBT_SCANLASTPAGE 0x00010000
+-+
+-+#define NAND_DRAM_BUF_DATABUF_ADDR (NAND_BUF_ADDR)
+-+
+-+struct bbt_pattern {
+-+ u8 *data;
+-+ int len;
+-+};
+-+
+-+struct bbt_desc {
+-+ struct bbt_pattern pattern;
+-+ u8 version;
+-+ u64 bbt_addr;/*0: invalid value; otherwise, valid value*/
+-+};
+-+
+-+struct bbt_manager {
+-+ /* main bbt descriptor and mirror descriptor */
+-+ struct bbt_desc desc[2];/* 0: main bbt; 1: mirror bbt */
+-+ int max_blocks;
+-+ u8 *bbt;
+-+};
+-+
+-+#define BBT_ENTRY_MASK 0x03
+-+#define BBT_ENTRY_SHIFT 2
+-+
+-+#define GET_BBT_LENGTH(blocks) (blocks >> 2)
+-+#define GET_ENTRY(block) ((block) >> BBT_ENTRY_SHIFT)
+-+#define GET_POSITION(block) (((block) & BBT_ENTRY_MASK) * 2)
+-+#define GET_MARK_VALUE(block, mark) \
+-+ (((mark) & BBT_ENTRY_MASK) << GET_POSITION(block))
+-+
+-+int scan_bbt(struct nandx_info *nand);
+-+
+-+int bbt_mark_bad(struct nandx_info *nand, off_t offset);
+-+
+-+int bbt_is_bad(struct nandx_info *nand, off_t offset);
+-+
+-+#endif /*__BBT_H__*/
+-diff --git a/drivers/mtd/nandx/include/internal/nandx_core.h b/drivers/mtd/nandx/include/internal/nandx_core.h
+-new file mode 100644
+-index 0000000000..09aff72224
+---- /dev/null
+-+++ b/drivers/mtd/nandx/include/internal/nandx_core.h
+-@@ -0,0 +1,250 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#ifndef __NANDX_CORE_H__
+-+#define __NANDX_CORE_H__
+-+
+-+/**
+-+ * mtk_ic_version - indicates specifical IC, IP need this to load some info
+-+ */
+-+enum mtk_ic_version {
+-+ NANDX_MT7622,
+-+};
+-+
+-+/**
+-+ * nandx_ioctl_cmd - operations supported by nandx
+-+ *
+-+ * @NFI_CTRL_DMA dma enable or not
+-+ * @NFI_CTRL_NFI_MODE customer/read/program/erase...
+-+ * @NFI_CTRL_ECC ecc enable or not
+-+ * @NFI_CTRL_ECC_MODE nfi/dma/pio
+-+ * @CHIP_CTRL_DRIVE_STRENGTH enum chip_ctrl_drive_strength
+-+ */
+-+enum nandx_ctrl_cmd {
+-+ CORE_CTRL_NAND_INFO,
+-+
+-+ NFI_CTRL_DMA,
+-+ NFI_CTRL_NFI_MODE,
+-+ NFI_CTRL_AUTOFORMAT,
+-+ NFI_CTRL_NFI_IRQ,
+-+ NFI_CTRL_PAGE_IRQ,
+-+ NFI_CTRL_RANDOMIZE,
+-+ NFI_CTRL_BAD_MARK_SWAP,
+-+
+-+ NFI_CTRL_ECC,
+-+ NFI_CTRL_ECC_MODE,
+-+ NFI_CTRL_ECC_CLOCK,
+-+ NFI_CTRL_ECC_IRQ,
+-+ NFI_CTRL_ECC_PAGE_IRQ,
+-+ NFI_CTRL_ECC_DECODE_MODE,
+-+
+-+ SNFI_CTRL_OP_MODE,
+-+ SNFI_CTRL_RX_MODE,
+-+ SNFI_CTRL_TX_MODE,
+-+ SNFI_CTRL_DELAY_MODE,
+-+
+-+ CHIP_CTRL_OPS_CACHE,
+-+ CHIP_CTRL_OPS_MULTI,
+-+ CHIP_CTRL_PSLC_MODE,
+-+ CHIP_CTRL_DRIVE_STRENGTH,
+-+ CHIP_CTRL_DDR_MODE,
+-+ CHIP_CTRL_ONDIE_ECC,
+-+ CHIP_CTRL_TIMING_MODE
+-+};
+-+
+-+enum snfi_ctrl_op_mode {
+-+ SNFI_CUSTOM_MODE,
+-+ SNFI_AUTO_MODE,
+-+ SNFI_MAC_MODE
+-+};
+-+
+-+enum snfi_ctrl_rx_mode {
+-+ SNFI_RX_111,
+-+ SNFI_RX_112,
+-+ SNFI_RX_114,
+-+ SNFI_RX_122,
+-+ SNFI_RX_144
+-+};
+-+
+-+enum snfi_ctrl_tx_mode {
+-+ SNFI_TX_111,
+-+ SNFI_TX_114,
+-+};
+-+
+-+enum chip_ctrl_drive_strength {
+-+ CHIP_DRIVE_NORMAL,
+-+ CHIP_DRIVE_HIGH,
+-+ CHIP_DRIVE_MIDDLE,
+-+ CHIP_DRIVE_LOW
+-+};
+-+
+-+enum chip_ctrl_timing_mode {
+-+ CHIP_TIMING_MODE0,
+-+ CHIP_TIMING_MODE1,
+-+ CHIP_TIMING_MODE2,
+-+ CHIP_TIMING_MODE3,
+-+ CHIP_TIMING_MODE4,
+-+ CHIP_TIMING_MODE5,
+-+};
+-+
+-+/**
+-+ * nandx_info - basic information
+-+ */
+-+struct nandx_info {
+-+ u32 max_io_count;
+-+ u32 min_write_pages;
+-+ u32 plane_num;
+-+ u32 oob_size;
+-+ u32 page_parity_size;
+-+ u32 page_size;
+-+ u32 block_size;
+-+ u64 total_size;
+-+ u32 fdm_reg_size;
+-+ u32 fdm_ecc_size;
+-+ u32 ecc_strength;
+-+ u32 sector_size;
+-+};
+-+
+-+/**
+-+ * nfi_resource - the resource needed by nfi & ecc to do initialization
+-+ */
+-+struct nfi_resource {
+-+ int ic_ver;
+-+ void *dev;
+-+
+-+ void *ecc_regs;
+-+ int ecc_irq_id;
+-+
+-+ void *nfi_regs;
+-+ int nfi_irq_id;
+-+
+-+ u32 clock_1x;
+-+ u32 *clock_2x;
+-+ int clock_2x_num;
+-+
+-+ int min_oob_req;
+-+};
+-+
+-+/**
+-+ * nandx_init - init all related modules below
+-+ *
+-+ * @res: basic resource of the project
+-+ *
+-+ * return 0 if init success, otherwise return negative error code
+-+ */
+-+int nandx_init(struct nfi_resource *res);
+-+
+-+/**
+-+ * nandx_exit - release resource those that obtained in init flow
+-+ */
+-+void nandx_exit(void);
+-+
+-+/**
+-+ * nandx_read - read data from nand this function can read data and related
+-+ * oob from specifical address
+-+ * if do multi_ops, set one operation per time, and call nandx_sync at last
+-+ * in multi mode, not support page partial read
+-+ * oob not support partial read
+-+ *
+-+ * @data: buf to receive data from nand
+-+ * @oob: buf to receive oob data from nand which related to data page
+-+ * length of @oob should oob size aligned, oob not support partial read
+-+ * @offset: offset address on the whole flash
+-+ * @len: the length of @data that need to read
+-+ *
+-+ * if read success return 0, otherwise return negative error code
+-+ */
+-+int nandx_read(u8 *data, u8 *oob, u64 offset, size_t len);
+-+
+-+/**
+-+ * nandx_write - write data to nand
+-+ * this function can write data and related oob to specifical address
+-+ * if do multi_ops, set one operation per time, and call nandx_sync at last
+-+ *
+-+ * @data: source data to be written to nand,
+-+ * for multi operation, the length of @data should be page size aliged
+-+ * @oob: source oob which related to data page to be written to nand,
+-+ * length of @oob should oob size aligned
+-+ * @offset: offset address on the whole flash, the value should be start address
+-+ * of a page
+-+ * @len: the length of @data that need to write,
+-+ * for multi operation, the len should be page size aliged
+-+ *
+-+ * if write success return 0, otherwise return negative error code
+-+ * if return value > 0, it indicates that how many pages still need to write,
+-+ * and data has not been written to nand
+-+ * please call nandx_sync after pages alligned $nandx_info.min_write_pages
+-+ */
+-+int nandx_write(u8 *data, u8 *oob, u64 offset, size_t len);
+-+
+-+/**
+-+ * nandx_erase - erase an area of nand
+-+ * if do multi_ops, set one operation per time, and call nandx_sync at last
+-+ *
+-+ * @offset: offset address on the flash
+-+ * @len: erase length which should be block size aligned
+-+ *
+-+ * if erase success return 0, otherwise return negative error code
+-+ */
+-+int nandx_erase(u64 offset, size_t len);
+-+
+-+/**
+-+ * nandx_sync - sync all operations to nand
+-+ * when do multi_ops, this function will be called at last operation
+-+ * when write data, if number of pages not alligned
+-+ * by $nandx_info.min_write_pages, this interface could be called to do
+-+ * force write, 0xff will be padded to blanked pages.
+-+ */
+-+int nandx_sync(void);
+-+
+-+/**
+-+ * nandx_is_bad_block - check if the block is bad
+-+ * only check the flag that marked by the flash vendor
+-+ *
+-+ * @offset: offset address on the whole flash
+-+ *
+-+ * return true if the block is bad, otherwise return false
+-+ */
+-+bool nandx_is_bad_block(u64 offset);
+-+
+-+/**
+-+ * nandx_ioctl - set/get property of nand chip
+-+ *
+-+ * @cmd: parameter that defined in enum nandx_ioctl_cmd
+-+ * @arg: operate parameter
+-+ *
+-+ * return 0 if operate success, otherwise return negative error code
+-+ */
+-+int nandx_ioctl(int cmd, void *arg);
+-+
+-+/**
+-+ * nandx_suspend - suspend nand, and store some data
+-+ *
+-+ * return 0 if suspend success, otherwise return negative error code
+-+ */
+-+int nandx_suspend(void);
+-+
+-+/**
+-+ * nandx_resume - resume nand, and replay some data
+-+ *
+-+ * return 0 if resume success, otherwise return negative error code
+-+ */
+-+int nandx_resume(void);
+-+
+-+#ifdef NANDX_UNIT_TEST
+-+/**
+-+ * nandx_unit_test - unit test
+-+ *
+-+ * @offset: offset address on the whole flash
+-+ * @len: should be not larger than a block size, we only test a block per time
+-+ *
+-+ * return 0 if test success, otherwise return negative error code
+-+ */
+-+int nandx_unit_test(u64 offset, size_t len);
+-+#endif
+-+
+-+#endif /* __NANDX_CORE_H__ */
+-diff --git a/drivers/mtd/nandx/include/internal/nandx_errno.h b/drivers/mtd/nandx/include/internal/nandx_errno.h
+-new file mode 100644
+-index 0000000000..51fb299c03
+---- /dev/null
+-+++ b/drivers/mtd/nandx/include/internal/nandx_errno.h
+-@@ -0,0 +1,40 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#ifndef __NANDX_ERRNO_H__
+-+#define __NANDX_ERRNO_H__
+-+
+-+#ifndef EIO
+-+#define EIO 5 /* I/O error */
+-+#define ENOMEM 12 /* Out of memory */
+-+#define EFAULT 14 /* Bad address */
+-+#define EBUSY 16 /* Device or resource busy */
+-+#define ENODEV 19 /* No such device */
+-+#define EINVAL 22 /* Invalid argument */
+-+#define ENOSPC 28 /* No space left on device */
+-+/* Operation not supported on transport endpoint */
+-+#define EOPNOTSUPP 95
+-+#define ETIMEDOUT 110 /* Connection timed out */
+-+#endif
+-+
+-+#define ENANDFLIPS 1024 /* Too many bitflips, uncorrected */
+-+#define ENANDREAD 1025 /* Read fail, can't correct */
+-+#define ENANDWRITE 1026 /* Write fail */
+-+#define ENANDERASE 1027 /* Erase fail */
+-+#define ENANDBAD 1028 /* Bad block */
+-+#define ENANDWP 1029
+-+
+-+#define IS_NAND_ERR(err) ((err) >= -ENANDBAD && (err) <= -ENANDFLIPS)
+-+
+-+#ifndef MAX_ERRNO
+-+#define MAX_ERRNO 4096
+-+#define ERR_PTR(errno) ((void *)((long)errno))
+-+#define PTR_ERR(ptr) ((long)(ptr))
+-+#define IS_ERR(ptr) ((unsigned long)(ptr) > (unsigned long)-MAX_ERRNO)
+-+#endif
+-+
+-+#endif /* __NANDX_ERRNO_H__ */
+-diff --git a/drivers/mtd/nandx/include/internal/nandx_util.h b/drivers/mtd/nandx/include/internal/nandx_util.h
+-new file mode 100644
+-index 0000000000..1990b000ee
+---- /dev/null
+-+++ b/drivers/mtd/nandx/include/internal/nandx_util.h
+-@@ -0,0 +1,221 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#ifndef __NANDX_UTIL_H__
+-+#define __NANDX_UTIL_H__
+-+
+-+typedef unsigned char u8;
+-+typedef unsigned short u16;
+-+typedef unsigned int u32;
+-+typedef unsigned long long u64;
+-+
+-+enum nand_irq_return {
+-+ NAND_IRQ_NONE,
+-+ NAND_IRQ_HANDLED,
+-+};
+-+
+-+enum nand_dma_operation {
+-+ NDMA_FROM_DEV,
+-+ NDMA_TO_DEV,
+-+};
+-+
+-+
+-+/*
+-+ * Compatible function
+-+ * used for preloader/lk/kernel environment
+-+ */
+-+#include "nandx_os.h"
+-+#include "nandx_errno.h"
+-+
+-+#ifndef BIT
+-+#define BIT(a) (1 << (a))
+-+#endif
+-+
+-+#ifndef min_t
+-+#define min_t(type, x, y) ({ \
+-+ type __min1 = (x); \
+-+ type __min2 = (y); \
+-+ __min1 < __min2 ? __min1 : __min2; })
+-+
+-+#define max_t(type, x, y) ({ \
+-+ type __max1 = (x); \
+-+ type __max2 = (y); \
+-+ __max1 > __max2 ? __max1 : __max2; })
+-+#endif
+-+
+-+#ifndef GENMASK
+-+#define GENMASK(h, l) \
+-+ (((~0UL) << (l)) & (~0UL >> ((sizeof(unsigned long) * 8) - 1 - (h))))
+-+#endif
+-+
+-+#ifndef __weak
+-+#define __weak __attribute__((__weak__))
+-+#endif
+-+
+-+#ifndef __packed
+-+#define __packed __attribute__((__packed__))
+-+#endif
+-+
+-+#ifndef KB
+-+#define KB(x) ((x) << 10)
+-+#define MB(x) (KB(x) << 10)
+-+#define GB(x) (MB(x) << 10)
+-+#endif
+-+
+-+#ifndef offsetof
+-+#define offsetof(type, member) ((size_t)&((type *)0)->member)
+-+#endif
+-+
+-+#ifndef NULL
+-+#define NULL (void *)0
+-+#endif
+-+static inline u32 nandx_popcount(u32 x)
+-+{
+-+ x = (x & 0x55555555) + ((x >> 1) & 0x55555555);
+-+ x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
+-+ x = (x & 0x0F0F0F0F) + ((x >> 4) & 0x0F0F0F0F);
+-+ x = (x & 0x00FF00FF) + ((x >> 8) & 0x00FF00FF);
+-+ x = (x & 0x0000FFFF) + ((x >> 16) & 0x0000FFFF);
+-+
+-+ return x;
+-+}
+-+
+-+#ifndef zero_popcount
+-+#define zero_popcount(x) (32 - nandx_popcount(x))
+-+#endif
+-+
+-+#ifndef do_div
+-+#define do_div(n, base) \
+-+ ({ \
+-+ u32 __base = (base); \
+-+ u32 __rem; \
+-+ __rem = ((u64)(n)) % __base; \
+-+ (n) = ((u64)(n)) / __base; \
+-+ __rem; \
+-+ })
+-+#endif
+-+
+-+#define div_up(x, y) \
+-+ ({ \
+-+ u64 __temp = ((x) + (y) - 1); \
+-+ do_div(__temp, (y)); \
+-+ __temp; \
+-+ })
+-+
+-+#define div_down(x, y) \
+-+ ({ \
+-+ u64 __temp = (x); \
+-+ do_div(__temp, (y)); \
+-+ __temp; \
+-+ })
+-+
+-+#define div_round_up(x, y) (div_up(x, y) * (y))
+-+#define div_round_down(x, y) (div_down(x, y) * (y))
+-+
+-+#define reminder(x, y) \
+-+ ({ \
+-+ u64 __temp = (x); \
+-+ do_div(__temp, (y)); \
+-+ })
+-+
+-+#ifndef round_up
+-+#define round_up(x, y) ((((x) - 1) | ((y) - 1)) + 1)
+-+#define round_down(x, y) ((x) & ~((y) - 1))
+-+#endif
+-+
+-+#ifndef readx_poll_timeout_atomic
+-+#define readx_poll_timeout_atomic(op, addr, val, cond, delay_us, timeout_us) \
+-+ ({ \
+-+ u64 end = get_current_time_us() + timeout_us; \
+-+ for (;;) { \
+-+ u64 now = get_current_time_us(); \
+-+ (val) = op(addr); \
+-+ if (cond) \
+-+ break; \
+-+ if (now > end) { \
+-+ (val) = op(addr); \
+-+ break; \
+-+ } \
+-+ } \
+-+ (cond) ? 0 : -ETIMEDOUT; \
+-+ })
+-+
+-+#define readl_poll_timeout_atomic(addr, val, cond, delay_us, timeout_us) \
+-+ readx_poll_timeout_atomic(readl, addr, val, cond, delay_us, timeout_us)
+-+#define readw_poll_timeout_atomic(addr, val, cond, delay_us, timeout_us) \
+-+ readx_poll_timeout_atomic(readw, addr, val, cond, delay_us, timeout_us)
+-+#define readb_poll_timeout_atomic(addr, val, cond, delay_us, timeout_us) \
+-+ readx_poll_timeout_atomic(readb, addr, val, cond, delay_us, timeout_us)
+-+#endif
+-+
+-+struct nandx_split64 {
+-+ u64 head;
+-+ size_t head_len;
+-+ u64 body;
+-+ size_t body_len;
+-+ u64 tail;
+-+ size_t tail_len;
+-+};
+-+
+-+struct nandx_split32 {
+-+ u32 head;
+-+ u32 head_len;
+-+ u32 body;
+-+ u32 body_len;
+-+ u32 tail;
+-+ u32 tail_len;
+-+};
+-+
+-+#define nandx_split(split, offset, len, val, align) \
+-+ do { \
+-+ (split)->head = (offset); \
+-+ (val) = div_round_down((offset), (align)); \
+-+ (val) = (align) - ((offset) - (val)); \
+-+ if ((val) == (align)) \
+-+ (split)->head_len = 0; \
+-+ else if ((val) > (len)) \
+-+ (split)->head_len = len; \
+-+ else \
+-+ (split)->head_len = val; \
+-+ (split)->body = (offset) + (split)->head_len; \
+-+ (split)->body_len = div_round_down((len) - \
+-+ (split)->head_len,\
+-+ (align)); \
+-+ (split)->tail = (split)->body + (split)->body_len; \
+-+ (split)->tail_len = (len) - (split)->head_len - \
+-+ (split)->body_len; \
+-+ } while (0)
+-+
+-+#ifndef container_of
+-+#define container_of(ptr, type, member) \
+-+ ({const __typeof__(((type *)0)->member) * __mptr = (ptr); \
+-+ (type *)((char *)__mptr - offsetof(type, member)); })
+-+#endif
+-+
+-+static inline u32 nandx_cpu_to_be32(u32 val)
+-+{
+-+ u32 temp = 1;
+-+ u8 *p_temp = (u8 *)&temp;
+-+
+-+ if (*p_temp)
+-+ return ((val & 0xff) << 24) | ((val & 0xff00) << 8) |
+-+ ((val >> 8) & 0xff00) | ((val >> 24) & 0xff);
+-+
+-+ return val;
+-+}
+-+
+-+static inline void nandx_set_bits32(unsigned long addr, u32 mask,
+-+ u32 val)
+-+{
+-+ u32 temp = readl((void *)addr);
+-+
+-+ temp &= ~(mask);
+-+ temp |= val;
+-+ writel(temp, (void *)addr);
+-+}
+-+
+-+#endif /* __NANDX_UTIL_H__ */
+-diff --git a/drivers/mtd/nandx/include/uboot/nandx_os.h b/drivers/mtd/nandx/include/uboot/nandx_os.h
+-new file mode 100644
+-index 0000000000..8ea53378bf
+---- /dev/null
+-+++ b/drivers/mtd/nandx/include/uboot/nandx_os.h
+-@@ -0,0 +1,78 @@
+-+/*
+-+ * Copyright (C) 2017 MediaTek Inc.
+-+ * Licensed under either
+-+ * BSD Licence, (see NOTICE for more details)
+-+ * GNU General Public License, version 2.0, (see NOTICE for more details)
+-+ */
+-+
+-+#ifndef __NANDX_OS_H__
+-+#define __NANDX_OS_H__
+-+
+-+#include <common.h>
+-+#include <dm.h>
+-+#include <clk.h>
+-+#include <asm/dma-mapping.h>
+-+#include <linux/io.h>
+-+#include <linux/err.h>
+-+#include <linux/errno.h>
+-+#include <linux/bitops.h>
+-+#include <linux/kernel.h>
+-+#include <linux/compiler-gcc.h>
+-+
+-+#define NANDX_BULK_IO_USE_DRAM 0
+-+
+-+#define nandx_event_create() NULL
+-+#define nandx_event_destroy(event)
+-+#define nandx_event_complete(event)
+-+#define nandx_event_init(event)
+-+#define nandx_event_wait_complete(event, timeout) true
+-+
+-+#define nandx_irq_register(dev, irq, irq_handler, name, data) NULL
+-+
+-+static inline void *mem_alloc(u32 count, u32 size)
+-+{
+-+ return kmalloc(count * size, GFP_KERNEL | __GFP_ZERO);
+-+}
+-+
+-+static inline void mem_free(void *mem)
+-+{
+-+ kfree(mem);
+-+}
+-+
+-+static inline u64 get_current_time_us(void)
+-+{
+-+ return timer_get_us();
+-+}
+-+
+-+static inline u32 nandx_dma_map(void *dev, void *buf, u64 len,
+-+ enum nand_dma_operation op)
+-+{
+-+ unsigned long addr = (unsigned long)buf;
+-+ u64 size;
+-+
+-+ size = ALIGN(len, ARCH_DMA_MINALIGN);
+-+
+-+ if (op == NDMA_FROM_DEV)
+-+ invalidate_dcache_range(addr, addr + size);
+-+ else
+-+ flush_dcache_range(addr, addr + size);
+-+
+-+ return addr;
+-+}
+-+
+-+static inline void nandx_dma_unmap(void *dev, void *buf, void *addr,
+-+ u64 len, enum nand_dma_operation op)
+-+{
+-+ u64 size;
+-+
+-+ size = ALIGN(len, ARCH_DMA_MINALIGN);
+-+
+-+ if (op != NDMA_FROM_DEV)
+-+ invalidate_dcache_range((unsigned long)addr, addr + size);
+-+ else
+-+ flush_dcache_range((unsigned long)addr, addr + size);
+-+
+-+ return addr;
+-+}
+-+
+-+#endif /* __NANDX_OS_H__ */
+-diff --git a/include/configs/mt7622.h b/include/configs/mt7622.h
+-index dfd506ed24..6d0c956484 100644
+---- a/include/configs/mt7622.h
+-+++ b/include/configs/mt7622.h
+-@@ -11,6 +11,31 @@
+-
+- #include <linux/sizes.h>
+-
+-+/* SPI Nand */
+-+#if defined(CONFIG_MTD_RAW_NAND)
+-+#define CONFIG_SYS_MAX_NAND_DEVICE 1
+-+#define CONFIG_SYS_NAND_BASE 0x1100d000
+-+
+-+#define ENV_BOOT_READ_IMAGE \
+-+ "boot_rd_img=" \
+-+ "nand read 0x4007ff28 0x380000 0x1400000" \
+-+ ";iminfo 0x4007ff28 \0"
+-+
+-+#define ENV_BOOT_WRITE_IMAGE \
+-+ "boot_wr_img=" \
+-+ "nand write 0x4007ff28 0x380000 0x1400000" \
+-+ ";iminfo 0x4007ff28 \0"
+-+
+-+#define ENV_BOOT_CMD \
+-+ "mtk_boot=run boot_rd_img;bootm;\0"
+-+
+-+#define CONFIG_EXTRA_ENV_SETTINGS \
+-+ ENV_BOOT_READ_IMAGE \
+-+ ENV_BOOT_CMD \
+-+ "bootcmd=run mtk_boot;\0"
+-+
+-+#endif
+-+
+- #define CONFIG_SYS_MAXARGS 8
+- #define CONFIG_SYS_BOOTM_LEN SZ_64M
+- #define CONFIG_SYS_CBSIZE SZ_1K
+---
+-2.17.1
+-
+diff --git a/package/boot/uboot-mediatek/patches/003-mt7622-uboot-add-dts-and-config-for-spi-nand.patch b/package/boot/uboot-mediatek/patches/003-mt7622-uboot-add-dts-and-config-for-spi-nand.patch
+deleted file mode 100644
+index 2c021e1..0000000
+--- a/package/boot/uboot-mediatek/patches/003-mt7622-uboot-add-dts-and-config-for-spi-nand.patch
++++ /dev/null
+@@ -1,64 +0,0 @@
+-From b1b3c3d2ce62872c8dec4a7d645af6b3c565e094 Mon Sep 17 00:00:00 2001
+-From: Sam Shih <sam.shih@mediatek.com>
+-Date: Mon, 20 Apr 2020 17:11:32 +0800
+-Subject: [PATCH 2/3] mt7622 uboot: add dts and config for spi nand
+-
+-This patch add dts and config for mt7622 spi nand
+-
+-Signed-off-by: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
+----
+- arch/arm/dts/mt7622-rfb.dts | 6 ++++++
+- arch/arm/dts/mt7622.dtsi | 20 ++++++++++++++++++++
+- 2 files changed, 26 insertions(+)
+-
+-diff --git a/arch/arm/dts/mt7622-rfb.dts b/arch/arm/dts/mt7622-rfb.dts
+-index f05c3fe14d..05502bddec 100644
+---- a/arch/arm/dts/mt7622-rfb.dts
+-+++ b/arch/arm/dts/mt7622-rfb.dts
+-@@ -143,6 +143,12 @@
+- };
+- };
+-
+-+&nandc {
+-+ pinctrl-names = "default";
+-+ pinctrl-0 = <&snfi_pins>;
+-+ status = "okay";
+-+};
+-+
+- &uart0 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&uart0_pins>;
+-diff --git a/arch/arm/dts/mt7622.dtsi b/arch/arm/dts/mt7622.dtsi
+-index 1e8ec9b48b..63fdb63d4a 100644
+---- a/arch/arm/dts/mt7622.dtsi
+-+++ b/arch/arm/dts/mt7622.dtsi
+-@@ -52,6 +52,26 @@
+- #size-cells = <0>;
+- };
+-
+-+ nandc: nfi@1100d000 {
+-+ compatible = "mediatek,mt7622-nfc";
+-+ reg = <0x1100d000 0x1000>,
+-+ <0x1100e000 0x1000>;
+-+ interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>,
+-+ <GIC_SPI 95 IRQ_TYPE_LEVEL_LOW>;
+-+ clocks = <&pericfg CLK_PERI_NFI_PD>,
+-+ <&pericfg CLK_PERI_NFIECC_PD>,
+-+ <&pericfg CLK_PERI_SNFI_PD>,
+-+ <&topckgen CLK_TOP_NFI_INFRA_SEL>,
+-+ <&topckgen CLK_TOP_UNIVPLL2_D8>;
+-+ clock-names = "nfi_clk",
+-+ "ecc_clk",
+-+ "snfi_clk",
+-+ "spinfi_sel",
+-+ "spinfi_parent_50m";
+-+ nand-ecc-mode = "hw";
+-+ status = "disabled";
+-+ };
+-+
+- timer {
+- compatible = "arm,armv8-timer";
+- interrupt-parent = <&gic>;
+---
+-2.17.1
+-
+diff --git a/package/boot/uboot-mediatek/patches/004-configs-enable-mtd-and-mtk_spi_nand-in-defconfig.patch b/package/boot/uboot-mediatek/patches/004-configs-enable-mtd-and-mtk_spi_nand-in-defconfig.patch
+deleted file mode 100644
+index cb56496..0000000
+--- a/package/boot/uboot-mediatek/patches/004-configs-enable-mtd-and-mtk_spi_nand-in-defconfig.patch
++++ /dev/null
+@@ -1,39 +0,0 @@
+-From e5745143a2984cf44fbfc0b3aedb49e57873f109 Mon Sep 17 00:00:00 2001
+-From: Sam Shih <sam.shih@mediatek.com>
+-Date: Mon, 20 Apr 2020 17:17:04 +0800
+-Subject: [PATCH 3/3] configs: enable mtd and mtk_spi_nand in defconfig
+-
+-This patch enable mtk and mtk_spi_nand in mt7622_rfb defconfig
+-
+-Signed-off-by: Sam Shih <sam.shih@mediatek.com>
+----
+- configs/mt7622_rfb_defconfig | 5 +++++
+- 1 file changed, 5 insertions(+)
+-
+-diff --git a/configs/mt7622_rfb_defconfig b/configs/mt7622_rfb_defconfig
+-index 1ce6ebdfeb..816126267b 100644
+---- a/configs/mt7622_rfb_defconfig
+-+++ b/configs/mt7622_rfb_defconfig
+-@@ -13,6 +13,7 @@ CONFIG_DEFAULT_FDT_FILE="mt7622-rfb"
+- CONFIG_SYS_PROMPT="MT7622> "
+- CONFIG_CMD_BOOTMENU=y
+- CONFIG_CMD_MMC=y
+-+CONFIG_CMD_NAND=y
+- CONFIG_CMD_PCI=y
+- CONFIG_CMD_SF_TEST=y
+- CONFIG_CMD_PING=y
+- CONFIG_CMD_SMC=y
+-@@ -25,6 +26,10 @@ CONFIG_CLK=y
+- CONFIG_DM_MMC=y
+- CONFIG_MMC_HS200_SUPPORT=y
+- CONFIG_MMC_MTK=y
+-+CONFIG_MTD=y
+-+CONFIG_DM_MTD=y
+-+CONFIG_MTK_SPI_NAND=y
+-+CONFIG_MTD_RAW_NAND=y
+- CONFIG_DM_SPI_FLASH=y
+- CONFIG_SPI_FLASH_EON=y
+- CONFIG_SPI_FLASH_GIGADEVICE=y
+---
+-2.17.1
+-
+diff --git a/package/boot/uboot-mediatek/patches/010-no-binman.patch b/package/boot/uboot-mediatek/patches/010-no-binman.patch
+deleted file mode 100644
+index a2680e5..0000000
+--- a/package/boot/uboot-mediatek/patches/010-no-binman.patch
++++ /dev/null
+@@ -1,23 +0,0 @@
+---- a/Makefile 2020-10-13 13:39:06.471438591 +0800
+-+++ b/Makefile 2020-10-13 13:39:39.190798462 +0800
+-@@ -1725,6 +1725,10 @@
+-
+- ifeq ($(CONFIG_SPL),y)
+- spl/u-boot-spl-mtk.bin: spl/u-boot-spl
+-+OBJCOPYFLAGS_u-boot-mtk.bin = -I binary -O binary \
+-+ --pad-to=$(CONFIG_SPL_PAD_TO) --gap-fill=0xff
+-+u-boot-mtk.bin: u-boot.img spl/u-boot-spl-mtk.bin FORCE
+-+ $(call if_changed,pad_cat)
+- else
+- MKIMAGEFLAGS_u-boot-mtk.bin = -T mtk_image \
+- -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE) \
+---- a/arch/arm/mach-mediatek/Kconfig
+-+++ b/arch/arm/mach-mediatek/Kconfig
+-@@ -36,7 +36,6 @@ config TARGET_MT7629
+- bool "MediaTek MT7629 SoC"
+- select CPU_V7A
+- select SPL
+-- select BINMAN
+- help
+- The MediaTek MT7629 is a ARM-based SoC with a dual-core Cortex-A7
+- including DDR3, crypto engine, 3x3 11n/ac Wi-Fi, Gigabit Ethernet,
diff --git a/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/8500-arm-trusted-firmware-mediatek-add-internal-build.patch b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/8500-arm-trusted-firmware-mediatek-add-internal-build.patch
new file mode 100644
index 0000000..265b335
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches-21.02/mtk_soc/8500-arm-trusted-firmware-mediatek-add-internal-build.patch
@@ -0,0 +1,102 @@
+diff --git a/package/boot/arm-trusted-firmware-mediatek/Makefile b/package/boot/arm-trusted-firmware-mediatek/Makefile
+index 98d421e..e128122 100644
+--- a/package/boot/arm-trusted-firmware-mediatek/Makefile
++++ b/package/boot/arm-trusted-firmware-mediatek/Makefile
+@@ -8,14 +8,21 @@
+
+ include $(TOPDIR)/rules.mk
+
++INTERNAL_BUILD:=1
++
+ PKG_NAME:=arm-trusted-firmware-mediatek
+ PKG_RELEASE:=$(AUTORELEASE)
+
+ PKG_SOURCE_PROTO:=git
++ifneq ($(INTERNAL_BUILD),)
++PKG_SOURCE_URL=https://gerrit.mediatek.inc/gateway/security/atf
++PKG_SOURCE_VERSION:=icb_rebb-main
++else
+ PKG_SOURCE_URL=https://github.com/mtk-openwrt/arm-trusted-firmware.git
+ PKG_SOURCE_DATE:=2020-11-09
+ PKG_SOURCE_VERSION:=03017334ccd8c0fac12e7db36749b95b9a7d745f
+ PKG_MIRROR_HASH:=b211b2f9143d4debc7ad8dc959cb606888af20af790855dd66c87e451b6a1bc7
++endif
+
+ PKG_MAINTAINER:=Daniel Golle <daniel@makrotopia.org>
+
+@@ -55,10 +62,31 @@ define Trusted-Firmware-A/Default
+ BUILD_SUBTARGET:=mt7622
+ PLAT:=mt7622
+ TFA_IMAGE:=bl2.img bl31.bin
++ TFA_PLAT_MAKE_FLAGS:=
+ BOOT_DEVICE:=
+ DDR_BLOB:=
+ endef
+
++define Trusted-Firmware-A/mt7986-snand
++ NAME:=MediaTek MT7986 (SPI-NAND)
++ DEPENDS:=+u-boot-mt7986 +libmbedtls
++ BUILD_SUBTARGET:=mt7986
++ PLAT:=mt7986
++ TFA_IMAGE:=bl2.img fip.bin
++ TFA_PLAT_MAKE_FLAGS:=NAND_TYPE=hsm:4k+256 FPGA=1
++ BOOT_DEVICE:=snand
++endef
++
++define Trusted-Firmware-A/mt7622-snand
++ NAME:=MediaTek MT7622 (SPI-NAND)
++ DEPENDS:=+u-boot-mt7622 +libmbedtls
++ BUILD_SUBTARGET:=mt7622
++ PLAT:=mt7622
++ TFA_IMAGE:=bl2.img fip.bin
++ TFA_PLAT_MAKE_FLAGS:=NAND_TYPE=2k+64
++ BOOT_DEVICE:=snand
++endef
++
+ define Trusted-Firmware-A/mt7622-nor-1ddr
+ NAME:=MediaTek MT7622 (SPI-NOR, 1x DDR3)
+ BOOT_DEVICE:=nor
+@@ -107,6 +135,36 @@ define Trusted-Firmware-A/mt7622-sdmmc-2ddr
+ DDR_BLOB:=2
+ endef
+
++ifneq ($(INTERNAL_BUILD),)
++TFA_TARGETS:= \
++ mt7986-snand \
++ mt7622-snand
++
++TFA_MAKE_FLAGS += \
++ BOOT_DEVICE=$(BOOT_DEVICE) \
++ $(TFA_PLAT_MAKE_FLAGS) \
++ BL33=$(BIN_DIR)/u-boot-$(PLAT)/u-boot.bin \
++ all \
++ fip
++
++define Build/Clean
++ rm -rf $(BIN_DIR)/atf-$(VARIANT)
++ $(call Build/Clean/Default)
++endef
++
++define Build/Compile/Trusted-Firmware-A
++ +$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
++ CROSS_COMPILE=$(TARGET_CROSS) \
++ PLAT=$(PLAT) \
++ $(TFA_MAKE_FLAGS)
++endef
++
++define Package/trusted-firmware-a/install/default
++ $(INSTALL_DIR) $(BIN_DIR)/atf-$(VARIANT)
++ $(CP) $(patsubst %,$(PKG_BUILD_DIR)/build/$(PLAT)/release/%,$(TFA_IMAGE)) $(BIN_DIR)/atf-$(VARIANT)/
++endef
++
++else
+ TFA_TARGETS:= \
+ mt7622-nor-1ddr \
+ mt7622-nor-2ddr \
+@@ -158,4 +216,6 @@ ifeq ($(BOOT_DEVICE),sdmmc)
+ endif
+ endef
+
++endif
++
+ $(eval $(call BuildPackage/Trusted-Firmware-A))
diff --git a/autobuild_mac80211_release/openwrt_patches/mtk_soc/0001-prefligt-add-cmd-to-speedup-build-image.patch b/autobuild_mac80211_release/openwrt_patches/mtk_soc/0001-prefligt-add-cmd-to-speedup-build-image.patch
new file mode 100755
index 0000000..3689bd5
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches/mtk_soc/0001-prefligt-add-cmd-to-speedup-build-image.patch
@@ -0,0 +1,39 @@
+diff --git a/include/kernel-build.mk b/include/kernel-build.mk
+index 9dfb19c..e2d97da 100644
+--- a/include/kernel-build.mk
++++ b/include/kernel-build.mk
+@@ -184,4 +184,10 @@ define BuildKernel
+
+ prereq: image-prereq
+
++ install-image:
++ @echo Only install image........
++ +$(MAKE) -C image compile install TARGET_BUILD=
++
++ clean-linux: FORCE
++ rm -rf $(LINUX_DIR)
+ endef
+diff --git a/rules.mk b/rules.mk
+index 8b2424f..1787d75 100644
+--- a/rules.mk
++++ b/rules.mk
+@@ -103,7 +103,7 @@ ifdef CONFIG_MIPS64_ABI
+ endif
+ endif
+
+-DEFAULT_SUBDIR_TARGETS:=clean download prepare compile update refresh prereq dist distcheck configure check check-depends
++DEFAULT_SUBDIR_TARGETS:=clean download prepare compile update refresh prereq dist distcheck configure check check-depends install-image clean-linux
+
+ define DefaultTargets
+ $(foreach t,$(DEFAULT_SUBDIR_TARGETS) $(1),
+diff --git a/target/linux/Makefile b/target/linux/Makefile
+index 3a70b80..e3fe1ca 100644
+--- a/target/linux/Makefile
++++ b/target/linux/Makefile
+@@ -9,5 +9,5 @@ include $(INCLUDE_DIR)/target.mk
+
+ export TARGET_BUILD=1
+
+-prereq clean download prepare compile install oldconfig menuconfig nconfig xconfig update refresh: FORCE
++prereq clean download prepare compile install oldconfig menuconfig nconfig xconfig update refresh install-image clean-linux: FORCE
+ @+$(NO_TRACE_MAKE) -C $(firstword $(wildcard feeds/$(BOARD) $(BOARD))) $@
diff --git a/autobuild_mac80211_release/openwrt_patches/mtk_soc/0002-busybox-mtk-defconfig.patch b/autobuild_mac80211_release/openwrt_patches/mtk_soc/0002-busybox-mtk-defconfig.patch
new file mode 100644
index 0000000..54cdda6
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches/mtk_soc/0002-busybox-mtk-defconfig.patch
@@ -0,0 +1,85 @@
+diff --git a/package/utils/busybox/Config-defaults.in b/package/utils/busybox/Config-defaults.in
+index abe6d54..707bf10 100644
+--- a/package/utils/busybox/Config-defaults.in
++++ b/package/utils/busybox/Config-defaults.in
+@@ -1627,10 +1627,10 @@ config BUSYBOX_DEFAULT_LOSETUP
+ default n
+ config BUSYBOX_DEFAULT_LSPCI
+ bool
+- default n
++ default y
+ config BUSYBOX_DEFAULT_LSUSB
+ bool
+- default n
++ default y
+ config BUSYBOX_DEFAULT_MDEV
+ bool
+ default n
+@@ -2552,22 +2552,22 @@ config BUSYBOX_DEFAULT_UDPSVD
+ default n
+ config BUSYBOX_DEFAULT_TELNET
+ bool
+- default n
++ default y
+ config BUSYBOX_DEFAULT_FEATURE_TELNET_TTYPE
+ bool
+- default n
++ default y
+ config BUSYBOX_DEFAULT_FEATURE_TELNET_AUTOLOGIN
+ bool
+- default n
++ default y
+ config BUSYBOX_DEFAULT_FEATURE_TELNET_WIDTH
+ bool
+ default n
+ config BUSYBOX_DEFAULT_TELNETD
+ bool
+- default n
++ default y
+ config BUSYBOX_DEFAULT_FEATURE_TELNETD_STANDALONE
+ bool
+- default n
++ default y
+ config BUSYBOX_DEFAULT_FEATURE_TELNETD_PORT_DEFAULT
+ int
+ default 23
+@@ -2576,7 +2576,7 @@ config BUSYBOX_DEFAULT_FEATURE_TELNETD_INETD_WAIT
+ default n
+ config BUSYBOX_DEFAULT_TFTP
+ bool
+- default n
++ default y
+ config BUSYBOX_DEFAULT_FEATURE_TFTP_PROGRESS_BAR
+ bool
+ default n
+@@ -2588,10 +2588,10 @@ config BUSYBOX_DEFAULT_TFTPD
+ default n
+ config BUSYBOX_DEFAULT_FEATURE_TFTP_GET
+ bool
+- default n
++ default y
+ config BUSYBOX_DEFAULT_FEATURE_TFTP_PUT
+ bool
+- default n
++ default y
+ config BUSYBOX_DEFAULT_FEATURE_TFTP_BLOCKSIZE
+ bool
+ default n
+@@ -2621,7 +2621,7 @@ config BUSYBOX_DEFAULT_FEATURE_TUNCTL_UG
+ default n
+ config BUSYBOX_DEFAULT_VCONFIG
+ bool
+- default n
++ default y
+ config BUSYBOX_DEFAULT_WGET
+ bool
+ default n
+@@ -2777,7 +2777,7 @@ config BUSYBOX_DEFAULT_LSOF
+ default n
+ config BUSYBOX_DEFAULT_MPSTAT
+ bool
+- default n
++ default y
+ config BUSYBOX_DEFAULT_NMETER
+ bool
+ default n
diff --git a/autobuild_mac80211_release/openwrt_patches/mtk_soc/0003-fstool-mtk-samba-test.patch b/autobuild_mac80211_release/openwrt_patches/mtk_soc/0003-fstool-mtk-samba-test.patch
new file mode 100644
index 0000000..7e1eba0
--- /dev/null
+++ b/autobuild_mac80211_release/openwrt_patches/mtk_soc/0003-fstool-mtk-samba-test.patch
@@ -0,0 +1,65 @@
+diff -urN a/package/system/fstools/patches/0100-automount.patch b/package/system/fstools/patches/0100-automount.patch
+--- a/package/system/fstools/patches/0100-automount.patch 1970-01-01 08:00:00.000000000 +0800
++++ b/package/system/fstools/patches/0100-automount.patch 2020-07-30 18:16:13.122072146 +0800
+@@ -0,0 +1,22 @@
++Index: fstools-2016-12-04-84b530a7/block.c
++===================================================================
++--- fstools-2016-12-04-84b530a7.orig/block.c 2017-08-17 16:10:43.236274000 +0800
+++++ fstools-2016-12-04-84b530a7/block.c 2017-08-17 16:11:02.423958000 +0800
++@@ -530,7 +530,7 @@
++ printf("\toption\tuuid\t'%s'\n", pr->uuid);
++ else
++ printf("\toption\tdevice\t'%s'\n", pr->dev);
++- printf("\toption\tenabled\t'0'\n\n");
+++ printf("\toption\tenabled\t'1'\n\n");
++
++ return 0;
++ }
++@@ -1454,7 +1454,7 @@
++ cache_load(0);
++ printf("config 'global'\n");
++ printf("\toption\tanon_swap\t'0'\n");
++- printf("\toption\tanon_mount\t'0'\n");
+++ printf("\toption\tanon_mount\t'1'\n");
++ printf("\toption\tauto_swap\t'1'\n");
++ printf("\toption\tauto_mount\t'1'\n");
++ printf("\toption\tdelay_root\t'5'\n");
+diff -urN a/package/system/fstools/patches/0102-mount-options.patch b/package/system/fstools/patches/0102-mount-options.patch
+--- a/package/system/fstools/patches/0102-mount-options.patch 1970-01-01 08:00:00.000000000 +0800
++++ b/package/system/fstools/patches/0102-mount-options.patch 2020-07-30 18:16:13.190070353 +0800
+@@ -0,0 +1,19 @@
++Index: fstools-2016-12-04-84b530a7/block.c
++===================================================================
++--- fstools-2016-12-04-84b530a7.orig/block.c 2017-10-31 18:34:40.867026783 +0800
+++++ fstools-2016-12-04-84b530a7/block.c 2017-10-31 18:39:16.417175783 +0800
++@@ -854,9 +854,13 @@
++ int i, err;
++ size_t mount_opts_len;
++ char *mount_opts = NULL, *ptr;
+++ char _data[128] = {0};
+++ if (strstr(fstype, "fat") || strstr(fstype, "ntfs")) {
+++ snprintf(_data, sizeof(_data), "%s", "iocharset=utf8,uid=65534,gid=65534");
+++ }
++
++ err = mount(source, target, fstype, m ? m->flags : 0,
++- (m && m->options) ? m->options : "");
+++ (m && m->options) ? m->options : _data);
++
++ /* Requested file system type is not available in kernel,
++ attempt to call mount helper. */
+diff -urN a/package/system/fstools/patches/0103-mtk-ntfs-mount-by-ufsd.patch b/package/system/fstools/patches/0103-mtk-ntfs-mount-by-ufsd.patch
+--- a/package/system/fstools/patches/0103-mtk-ntfs-mount-by-ufsd.patch 1970-01-01 08:00:00.000000000 +0800
++++ b/package/system/fstools/patches/0103-mtk-ntfs-mount-by-ufsd.patch 2021-01-26 14:21:31.235330174 +0800
+@@ -0,0 +1,12 @@
++--- a/block.c 2017-11-07 11:13:11.502259230 +0800
+++++ b/block.c 2017-11-07 11:16:43.484684786 +0800
++@@ -859,6 +859,9 @@
++ snprintf(_data, sizeof(_data), "%s", "iocharset=utf8,uid=65534,gid=65534");
++ }
++
+++ if (strstr(fstype, "ntfs"))
+++ fstype= "ufsd";
+++
++ err = mount(source, target, fstype, m ? m->flags : 0,
++ (m && m->options) ? m->options : _data);
++
diff --git a/autobuild_mac80211_release/package/kernel/mt76/src/firmware/mt7996/mt7996_rom_patch.bin b/autobuild_mac80211_release/package/kernel/mt76/src/firmware/mt7996/mt7996_rom_patch.bin
index 5b5e33b..d0f8122 100644
--- a/autobuild_mac80211_release/package/kernel/mt76/src/firmware/mt7996/mt7996_rom_patch.bin
+++ b/autobuild_mac80211_release/package/kernel/mt76/src/firmware/mt7996/mt7996_rom_patch.bin
Binary files differ
diff --git a/autobuild_mac80211_release/package/kernel/mt76/src/firmware/mt7996/mt7996_wa.bin b/autobuild_mac80211_release/package/kernel/mt76/src/firmware/mt7996/mt7996_wa.bin
index 854c01c..4251e6c 100644
--- a/autobuild_mac80211_release/package/kernel/mt76/src/firmware/mt7996/mt7996_wa.bin
+++ b/autobuild_mac80211_release/package/kernel/mt76/src/firmware/mt7996/mt7996_wa.bin
Binary files differ
diff --git a/autobuild_mac80211_release/package/kernel/mt76/src/firmware/mt7996/mt7996_wm.bin b/autobuild_mac80211_release/package/kernel/mt76/src/firmware/mt7996/mt7996_wm.bin
index 4a60cc8..717ce1e 100644
--- a/autobuild_mac80211_release/package/kernel/mt76/src/firmware/mt7996/mt7996_wm.bin
+++ b/autobuild_mac80211_release/package/kernel/mt76/src/firmware/mt7996/mt7996_wm.bin
Binary files differ
diff --git a/autobuild_mac80211_release/package/kernel/mt76/src/firmware/mt7996/mt7996_wm_tm.bin b/autobuild_mac80211_release/package/kernel/mt76/src/firmware/mt7996/mt7996_wm_tm.bin
index 11bbd95..c8868e6 100644
--- a/autobuild_mac80211_release/package/kernel/mt76/src/firmware/mt7996/mt7996_wm_tm.bin
+++ b/autobuild_mac80211_release/package/kernel/mt76/src/firmware/mt7996/mt7996_wm_tm.bin
Binary files differ