mediatek: more v5.4 mtd fixes
authorJohn Crispin <john@phrozen.org>
Fri, 27 Mar 2020 14:34:33 +0000 (15:34 +0100)
committerJohn Crispin <john@phrozen.org>
Fri, 27 Mar 2020 15:18:57 +0000 (16:18 +0100)
Signed-off-by: John Crispin <john@phrozen.org>
target/linux/mediatek/mt7622/config-5.4
target/linux/mediatek/mt7629/config-5.4
target/linux/mediatek/patches-5.4/0301-mtd-mtk-ecc-move-mtk-ecc-header-file-to-include-mtd.patch [new file with mode: 0644]
target/linux/mediatek/patches-5.4/0303-mtd-spinand-disable-on-die-ECC.patch [new file with mode: 0644]
target/linux/mediatek/patches-5.4/0306-spi-spi-mem-MediaTek-Add-SPI-NAND-Flash-interface-dr.patch [new file with mode: 0644]
target/linux/mediatek/patches-5.4/0307-dts-mt7629-add-snand-support.patch [new file with mode: 0644]
target/linux/mediatek/patches-5.4/0308-dts-mt7622-add-snand-support.patch [new file with mode: 0644]
target/linux/mediatek/patches-5.4/0310-dts-add-wmac-support-for-mt7622-rfb1.patch [new file with mode: 0644]

index f867844885bbdff6c5dc030fc5109b44b4b77bfe..f8bb25ee0bb03102c93607944cc4fe4cafbd46fe 100755 (executable)
@@ -1,7 +1,5 @@
 CONFIG_64BIT=y
 CONFIG_AHCI_MTK=y
-# CONFIG_ARCH_AGILEX is not set
-# CONFIG_ARCH_BITMAIN is not set
 CONFIG_ARCH_CLOCKSOURCE_DATA=y
 CONFIG_ARCH_DMA_ADDR_T_64BIT=y
 CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
@@ -83,27 +81,18 @@ CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y
 CONFIG_ARCH_WANT_FRAME_POINTERS=y
 CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y
 CONFIG_ARM64=y
-# CONFIG_ARM64_16K_PAGES is not set
 CONFIG_ARM64_4K_PAGES=y
-# CONFIG_ARM64_64K_PAGES is not set
 CONFIG_ARM64_CNP=y
 CONFIG_ARM64_CONT_SHIFT=4
-# CONFIG_ARM64_CRYPTO is not set
 CONFIG_ARM64_ERRATUM_1165522=y
 CONFIG_ARM64_ERRATUM_1286807=y
 CONFIG_ARM64_ERRATUM_1418040=y
 CONFIG_ARM64_HW_AFDBM=y
-# CONFIG_ARM64_LSE_ATOMICS is not set
-# CONFIG_ARM64_MODULE_PLTS is not set
 CONFIG_ARM64_PAGE_SHIFT=12
 CONFIG_ARM64_PAN=y
 CONFIG_ARM64_PA_BITS=48
 CONFIG_ARM64_PA_BITS_48=y
-# CONFIG_ARM64_PMEM is not set
-# CONFIG_ARM64_PSEUDO_NMI is not set
-# CONFIG_ARM64_PTDUMP_DEBUGFS is not set
 CONFIG_ARM64_PTR_AUTH=y
-# CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET is not set
 CONFIG_ARM64_SSBD=y
 CONFIG_ARM64_SVE=y
 # CONFIG_ARM64_SW_TTBR0_PAN is not set
@@ -111,7 +100,6 @@ CONFIG_ARM64_TAGGED_ADDR_ABI=y
 CONFIG_ARM64_UAO=y
 CONFIG_ARM64_VA_BITS=39
 CONFIG_ARM64_VA_BITS_39=y
-# CONFIG_ARM64_VA_BITS_48 is not set
 CONFIG_ARM64_VHE=y
 CONFIG_ARM64_WORKAROUND_REPEAT_TLBI=y
 # CONFIG_ARMV8_DEPRECATED is not set
@@ -126,10 +114,8 @@ CONFIG_ARM_GIC_V3_ITS_PCI=y
 CONFIG_ARM_MEDIATEK_CPUFREQ=y
 CONFIG_ARM_PMU=y
 CONFIG_ARM_PSCI_FW=y
-# CONFIG_ARM_SP805_WATCHDOG is not set
 CONFIG_ATA=y
 CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
-# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_MQ_PCI=y
 CONFIG_BLK_PM=y
@@ -153,10 +139,7 @@ CONFIG_BT_LE=y
 CONFIG_BT_MTKUART=y
 CONFIG_BT_QCA=y
 CONFIG_CAVIUM_TX2_ERRATUM_219=y
-CONFIG_CC_CAN_LINK=y
-CONFIG_CC_HAS_ASM_INLINE=y
 CONFIG_CC_HAS_KASAN_GENERIC=y
-CONFIG_CC_HAS_WARN_MAYBE_UNINITIALIZED=y
 CONFIG_CLKDEV_LOOKUP=y
 CONFIG_CLKSRC_MMIO=y
 CONFIG_CLOCK_THERMAL=y
@@ -195,10 +178,10 @@ CONFIG_COMMON_CLK_MT8516=y
 CONFIG_COMPAT=y
 CONFIG_COMPAT_32BIT_TIME=y
 CONFIG_COMPAT_BINFMT_ELF=y
+CONFIG_COMPAT_NETLINK_MESSAGES=y
 CONFIG_COMPAT_OLD_SIGACTION=y
 CONFIG_CONSOLE_LOGLEVEL_DEFAULT=15
 # CONFIG_CPUFREQ_DT is not set
-# CONFIG_CPU_BIG_ENDIAN is not set
 CONFIG_CPU_FREQ=y
 # CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
 CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
@@ -214,10 +197,8 @@ CONFIG_CPU_FREQ_STAT=y
 CONFIG_CPU_RMAP=y
 CONFIG_CPU_THERMAL=y
 CONFIG_CRC16=y
-CONFIG_CRYPTO_ACOMP2=y
 CONFIG_CRYPTO_AEAD=y
 CONFIG_CRYPTO_AEAD2=y
-CONFIG_CRYPTO_AKCIPHER2=y
 CONFIG_CRYPTO_CMAC=y
 CONFIG_CRYPTO_DRBG=y
 CONFIG_CRYPTO_DRBG_HMAC=y
@@ -231,7 +212,6 @@ CONFIG_CRYPTO_HMAC=y
 CONFIG_CRYPTO_JITTERENTROPY=y
 CONFIG_CRYPTO_KPP=y
 CONFIG_CRYPTO_KPP2=y
-CONFIG_CRYPTO_LIB_AES=y
 CONFIG_CRYPTO_LIB_SHA256=y
 CONFIG_CRYPTO_MANAGER=y
 CONFIG_CRYPTO_MANAGER2=y
@@ -258,7 +238,6 @@ CONFIG_DYNAMIC_DEBUG=y
 CONFIG_EDAC_SUPPORT=y
 CONFIG_EFI_EARLYCON=y
 CONFIG_EINT_MTK=y
-# CONFIG_ENERGY_MODEL is not set
 CONFIG_FIXED_PHY=y
 CONFIG_FIX_EARLYCON_MEM=y
 # CONFIG_FLATMEM_MANUAL is not set
@@ -266,7 +245,6 @@ CONFIG_FONT_8x16=y
 CONFIG_FONT_AUTOSELECT=y
 CONFIG_FONT_SUPPORT=y
 CONFIG_FRAME_POINTER=y
-# CONFIG_FSL_QDMA is not set
 CONFIG_FUJITSU_ERRATUM_010001=y
 CONFIG_FW_LOADER_PAGED_BUF=y
 CONFIG_GENERIC_ALLOCATOR=y
@@ -299,7 +277,6 @@ CONFIG_GENERIC_STRNLEN_USER=y
 CONFIG_GENERIC_TIME_VSYSCALL=y
 CONFIG_GLOB=y
 CONFIG_GPIOLIB=y
-# CONFIG_HABANA_AI is not set
 CONFIG_HANDLE_DOMAIN_IRQ=y
 CONFIG_HARDEN_BRANCH_PREDICTOR=y
 CONFIG_HARDIRQS_SW_RESEND=y
@@ -331,6 +308,7 @@ CONFIG_HAVE_CLK_PREPARE=y
 CONFIG_HAVE_CMPXCHG_DOUBLE=y
 CONFIG_HAVE_CMPXCHG_LOCAL=y
 CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_COPY_THREAD_TLS=y
 CONFIG_HAVE_C_RECORDMCOUNT=y
 CONFIG_HAVE_DEBUG_BUGVERBOSE=y
 CONFIG_HAVE_DEBUG_KMEMLEAK=y
@@ -362,17 +340,12 @@ CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
 CONFIG_HAVE_UID16=y
 CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
 CONFIG_HOLES_IN_ZONE=y
-# CONFIG_HUGETLBFS is not set
 CONFIG_ICPLUS_PHY=y
-# CONFIG_IGC is not set
 CONFIG_IIO=y
-# CONFIG_IIO_BUFFER is not set
-# CONFIG_IIO_TRIGGER is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
 CONFIG_INITRAMFS_SOURCE=""
-CONFIG_INIT_STACK_NONE=y
 CONFIG_INLINE_READ_LOCK=y
 CONFIG_INLINE_READ_LOCK_BH=y
 CONFIG_INLINE_READ_LOCK_IRQ=y
@@ -412,11 +385,9 @@ CONFIG_MEDIATEK_MT6577_AUXADC=y
 CONFIG_MEDIATEK_WATCHDOG=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_MEMFD_CREATE=y
-# CONFIG_MEMORY_HOTPLUG is not set
 CONFIG_MESSAGE_LOGLEVEL_DEFAULT=7
 CONFIG_MFD_SYSCON=y
 CONFIG_MIGRATION=y
-# CONFIG_MISC_ALCOR_PCI is not set
 CONFIG_MMC=y
 CONFIG_MMC_MTK=y
 # CONFIG_MMC_TIFM_SD is not set
@@ -424,8 +395,13 @@ CONFIG_MODULES_TREE_LOOKUP=y
 CONFIG_MODULES_USE_ELF_RELA=y
 CONFIG_MT753X_GSW=y
 CONFIG_MTD_NAND_CORE=y
+CONFIG_MTD_NAND_ECC_SW_HAMMING=y
+CONFIG_MTD_NAND_MTK=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_SPI_NAND=y
 CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_SPLIT_FIRMWARE=y
+CONFIG_MTD_SPLIT_FIT_FW=y
 # CONFIG_MTK_CMDQ is not set
 # CONFIG_MTK_CQDMA is not set
 CONFIG_MTK_EFUSE=y
@@ -446,9 +422,7 @@ CONFIG_NLS=y
 CONFIG_NO_HZ_COMMON=y
 CONFIG_NO_HZ_IDLE=y
 CONFIG_NR_CPUS=2
-# CONFIG_NUMA is not set
 CONFIG_NVMEM=y
-# CONFIG_NVMEM_REBOOT_MODE is not set
 CONFIG_NVMEM_SYSFS=y
 # CONFIG_OCTEONTX2_AF is not set
 CONFIG_OF=y
@@ -469,7 +443,6 @@ CONFIG_PCIE_MEDIATEK=y
 CONFIG_PCI_DEBUG=y
 CONFIG_PCI_DOMAINS=y
 CONFIG_PCI_DOMAINS_GENERIC=y
-# CONFIG_PCI_MESON is not set
 CONFIG_PCI_MSI=y
 CONFIG_PCI_MSI_IRQ_DOMAIN=y
 CONFIG_PERF_EVENTS=y
@@ -491,9 +464,7 @@ CONFIG_PINCTRL_MT8516=y
 CONFIG_PINCTRL_MTK=y
 CONFIG_PINCTRL_MTK_MOORE=y
 CONFIG_PM=y
-# CONFIG_PMS7003 is not set
 CONFIG_PM_CLK=y
-# CONFIG_PM_DEBUG is not set
 CONFIG_PM_GENERIC_DOMAINS=y
 CONFIG_PM_GENERIC_DOMAINS_OF=y
 CONFIG_PM_OPP=y
@@ -507,7 +478,6 @@ CONFIG_PWM_MEDIATEK=y
 CONFIG_PWM_SYSFS=y
 CONFIG_QUEUED_RWLOCKS=y
 CONFIG_QUEUED_SPINLOCKS=y
-# CONFIG_RANDOMIZE_BASE is not set
 CONFIG_RAS=y
 CONFIG_RATIONAL=y
 # CONFIG_RAVE_SP_CORE is not set
@@ -517,12 +487,10 @@ CONFIG_REALTEK_PHY=y
 CONFIG_REFCOUNT_FULL=y
 CONFIG_REGMAP=y
 CONFIG_REGMAP_MMIO=y
-CONFIG_REGMAP_SPI=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_MT6380=y
 CONFIG_RESET_CONTROLLER=y
-CONFIG_RFKILL_LEDS=y
 CONFIG_RFS_ACCEL=y
 CONFIG_RODATA_FULL_DEFAULT_ENABLED=y
 CONFIG_RPS=y
@@ -532,18 +500,15 @@ CONFIG_RTC_I2C_AND_SPI=y
 CONFIG_RWSEM_SPIN_ON_OWNER=y
 CONFIG_SCHED_MC=y
 CONFIG_SCSI=y
-# CONFIG_SCSI_MYRS is not set
 # CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
 CONFIG_SERIAL_8250_FSL=y
 CONFIG_SERIAL_8250_MT6577=y
 CONFIG_SERIAL_8250_NR_UARTS=3
 CONFIG_SERIAL_8250_RUNTIME_UARTS=3
-# CONFIG_SERIAL_AMBA_PL011 is not set
 CONFIG_SERIAL_DEV_BUS=y
 CONFIG_SERIAL_DEV_CTRL_TTYPORT=y
 CONFIG_SERIAL_MCTRL_GPIO=y
 CONFIG_SERIAL_OF_PLATFORM=y
-CONFIG_SGL_ALLOC=y
 CONFIG_SG_POOL=y
 CONFIG_SMP=y
 CONFIG_SPARSEMEM=y
@@ -556,6 +521,8 @@ CONFIG_SPI=y
 CONFIG_SPI_MASTER=y
 CONFIG_SPI_MEM=y
 CONFIG_SPI_MT65XX=y
+# CONFIG_SPI_MTK_NOR is not set
+CONFIG_SPI_MTK_SNFI=y
 CONFIG_SRCU=y
 CONFIG_SWIOTLB=y
 CONFIG_SWPHY=y
@@ -577,7 +544,6 @@ CONFIG_THREAD_INFO_IN_TASK=y
 CONFIG_TICK_CPU_ACCOUNTING=y
 CONFIG_TIMER_OF=y
 CONFIG_TIMER_PROBE=y
-# CONFIG_TI_CPSW_PHY_SEL is not set
 CONFIG_TREE_RCU=y
 CONFIG_TREE_SRCU=y
 # CONFIG_UCLAMP_TASK is not set
index 44cb3a17528ccb30d77aacf659c3d89611f0a281..3805eba40e115aeddccc1d1d9700f6735b8cfc27 100644 (file)
@@ -238,6 +238,9 @@ CONFIG_MODULES_TREE_LOOKUP=y
 CONFIG_MODULES_USE_ELF_REL=y
 CONFIG_MT753X_GSW=y
 CONFIG_MTD_NAND_CORE=y
+CONFIG_MTD_NAND_ECC_SW_HAMMING=y
+CONFIG_MTD_NAND_MTK=y
+CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_SPI_NAND=y
 CONFIG_MTD_SPI_NOR=y
 CONFIG_MTD_SPLIT_FIRMWARE=y
@@ -335,8 +338,9 @@ CONFIG_SPARSE_IRQ=y
 CONFIG_SPI=y
 CONFIG_SPI_MASTER=y
 CONFIG_SPI_MEM=y
-# CONFIG_SPI_MT65XX is not set
-CONFIG_SPI_MTK_NOR=y
+CONFIG_SPI_MT65XX=y
+# CONFIG_SPI_MTK_NOR is not set
+CONFIG_SPI_MTK_SNFI=y
 CONFIG_SRCU=y
 CONFIG_STACKTRACE=y
 # CONFIG_SWAP is not set
diff --git a/target/linux/mediatek/patches-5.4/0301-mtd-mtk-ecc-move-mtk-ecc-header-file-to-include-mtd.patch b/target/linux/mediatek/patches-5.4/0301-mtd-mtk-ecc-move-mtk-ecc-header-file-to-include-mtd.patch
new file mode 100644 (file)
index 0000000..fd30355
--- /dev/null
@@ -0,0 +1,139 @@
+From a2479dc254ebe31c84fbcfda73f35e2321576494 Mon Sep 17 00:00:00 2001
+From: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
+Date: Tue, 19 Mar 2019 13:57:38 +0800
+Subject: [PATCH 1/6] mtd: mtk ecc: move mtk ecc header file to include/mtd
+
+Change-Id: I8dc1d30e21b40d68ef5efd9587012f82970156a5
+Signed-off-by: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
+---
+ drivers/mtd/nand/raw/mtk_ecc.c                        | 3 +--
+ drivers/mtd/nand/raw/mtk_nand.c                       | 2 +-
+ {drivers/mtd/nand/raw => include/linux/mtd}/mtk_ecc.h | 0
+ 3 files changed, 2 insertions(+), 3 deletions(-)
+ rename {drivers/mtd/nand/raw => include/linux/mtd}/mtk_ecc.h (100%)
+
+--- a/drivers/mtd/nand/raw/mtk_ecc.c
++++ b/drivers/mtd/nand/raw/mtk_ecc.c
+@@ -23,8 +23,7 @@
+ #include <linux/of.h>
+ #include <linux/of_platform.h>
+ #include <linux/mutex.h>
+-
+-#include "mtk_ecc.h"
++#include <linux/mtd/mtk_ecc.h>
+ #define ECC_IDLE_MASK         BIT(0)
+ #define ECC_IRQ_EN            BIT(0)
+--- a/drivers/mtd/nand/raw/mtk_nand.c
++++ b/drivers/mtd/nand/raw/mtk_nand.c
+@@ -25,7 +25,7 @@
+ #include <linux/iopoll.h>
+ #include <linux/of.h>
+ #include <linux/of_device.h>
+-#include "mtk_ecc.h"
++#include <linux/mtd/mtk_ecc.h>
+ /* NAND controller register definition */
+ #define NFI_CNFG              (0x00)
+--- /dev/null
++++ b/include/linux/mtd/mtk_ecc.h
+@@ -0,0 +1,49 @@
++/*
++ * MTK SDG1 ECC controller
++ *
++ * Copyright (c) 2016 Mediatek
++ * Authors:   Xiaolei Li              <xiaolei.li@mediatek.com>
++ *            Jorge Ramirez-Ortiz     <jorge.ramirez-ortiz@linaro.org>
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef __DRIVERS_MTD_NAND_MTK_ECC_H__
++#define __DRIVERS_MTD_NAND_MTK_ECC_H__
++
++#include <linux/types.h>
++
++enum mtk_ecc_mode {ECC_DMA_MODE = 0, ECC_NFI_MODE = 1};
++enum mtk_ecc_operation {ECC_ENCODE, ECC_DECODE};
++
++struct device_node;
++struct mtk_ecc;
++
++struct mtk_ecc_stats {
++      u32 corrected;
++      u32 bitflips;
++      u32 failed;
++};
++
++struct mtk_ecc_config {
++      enum mtk_ecc_operation op;
++      enum mtk_ecc_mode mode;
++      dma_addr_t addr;
++      u32 strength;
++      u32 sectors;
++      u32 len;
++};
++
++int mtk_ecc_encode(struct mtk_ecc *, struct mtk_ecc_config *, u8 *, u32);
++void mtk_ecc_get_stats(struct mtk_ecc *, struct mtk_ecc_stats *, int);
++int mtk_ecc_wait_done(struct mtk_ecc *, enum mtk_ecc_operation);
++int mtk_ecc_enable(struct mtk_ecc *, struct mtk_ecc_config *);
++void mtk_ecc_disable(struct mtk_ecc *);
++void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p);
++unsigned int mtk_ecc_get_parity_bits(struct mtk_ecc *ecc);
++
++struct mtk_ecc *of_mtk_ecc_get(struct device_node *);
++void mtk_ecc_release(struct mtk_ecc *);
++
++#endif
+--- a/drivers/mtd/nand/raw/mtk_ecc.h
++++ /dev/null
+@@ -1,47 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0 OR MIT */
+-/*
+- * MTK SDG1 ECC controller
+- *
+- * Copyright (c) 2016 Mediatek
+- * Authors:   Xiaolei Li              <xiaolei.li@mediatek.com>
+- *            Jorge Ramirez-Ortiz     <jorge.ramirez-ortiz@linaro.org>
+- */
+-
+-#ifndef __DRIVERS_MTD_NAND_MTK_ECC_H__
+-#define __DRIVERS_MTD_NAND_MTK_ECC_H__
+-
+-#include <linux/types.h>
+-
+-enum mtk_ecc_mode {ECC_DMA_MODE = 0, ECC_NFI_MODE = 1};
+-enum mtk_ecc_operation {ECC_ENCODE, ECC_DECODE};
+-
+-struct device_node;
+-struct mtk_ecc;
+-
+-struct mtk_ecc_stats {
+-      u32 corrected;
+-      u32 bitflips;
+-      u32 failed;
+-};
+-
+-struct mtk_ecc_config {
+-      enum mtk_ecc_operation op;
+-      enum mtk_ecc_mode mode;
+-      dma_addr_t addr;
+-      u32 strength;
+-      u32 sectors;
+-      u32 len;
+-};
+-
+-int mtk_ecc_encode(struct mtk_ecc *, struct mtk_ecc_config *, u8 *, u32);
+-void mtk_ecc_get_stats(struct mtk_ecc *, struct mtk_ecc_stats *, int);
+-int mtk_ecc_wait_done(struct mtk_ecc *, enum mtk_ecc_operation);
+-int mtk_ecc_enable(struct mtk_ecc *, struct mtk_ecc_config *);
+-void mtk_ecc_disable(struct mtk_ecc *);
+-void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p);
+-unsigned int mtk_ecc_get_parity_bits(struct mtk_ecc *ecc);
+-
+-struct mtk_ecc *of_mtk_ecc_get(struct device_node *);
+-void mtk_ecc_release(struct mtk_ecc *);
+-
+-#endif
diff --git a/target/linux/mediatek/patches-5.4/0303-mtd-spinand-disable-on-die-ECC.patch b/target/linux/mediatek/patches-5.4/0303-mtd-spinand-disable-on-die-ECC.patch
new file mode 100644 (file)
index 0000000..cdf2146
--- /dev/null
@@ -0,0 +1,31 @@
+From b341f120cfc9ca1dfd48364b7f36ac2c1fbdea43 Mon Sep 17 00:00:00 2001
+From: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
+Date: Wed, 3 Apr 2019 16:30:01 +0800
+Subject: [PATCH 3/6] mtd: spinand: disable on-die ECC
+
+Change-Id: I9745adaed5295202fabbe8ab8947885c57a5b847
+Signed-off-by: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
+---
+ drivers/mtd/nand/spi/core.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/mtd/nand/spi/core.c
++++ b/drivers/mtd/nand/spi/core.c
+@@ -552,7 +552,7 @@ static int spinand_mtd_read(struct mtd_i
+       int ret = 0;
+       if (ops->mode != MTD_OPS_RAW && spinand->eccinfo.ooblayout)
+-              enable_ecc = true;
++              enable_ecc = false;
+       mutex_lock(&spinand->lock);
+@@ -600,7 +600,7 @@ static int spinand_mtd_write(struct mtd_
+       int ret = 0;
+       if (ops->mode != MTD_OPS_RAW && mtd->ooblayout)
+-              enable_ecc = true;
++              enable_ecc = false;
+       mutex_lock(&spinand->lock);
diff --git a/target/linux/mediatek/patches-5.4/0306-spi-spi-mem-MediaTek-Add-SPI-NAND-Flash-interface-dr.patch b/target/linux/mediatek/patches-5.4/0306-spi-spi-mem-MediaTek-Add-SPI-NAND-Flash-interface-dr.patch
new file mode 100644 (file)
index 0000000..4e266bf
--- /dev/null
@@ -0,0 +1,1246 @@
+From 1ecb38eabd90efe93957d0a822a167560c39308a Mon Sep 17 00:00:00 2001
+From: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
+Date: Wed, 20 Mar 2019 16:19:51 +0800
+Subject: [PATCH 6/6] spi: spi-mem: MediaTek: Add SPI NAND Flash interface
+ driver for MediaTek MT7622
+
+Change-Id: I3e78406bb9b46b0049d3988a5c71c7069e4f809c
+Signed-off-by: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
+---
+ drivers/spi/Kconfig        |    9 +
+ drivers/spi/Makefile       |    1 +
+ drivers/spi/spi-mtk-snfi.c | 1183 ++++++++++++++++++++++++++++++++++++
+ 3 files changed, 1193 insertions(+)
+ create mode 100644 drivers/spi/spi-mtk-snfi.c
+
+--- a/drivers/spi/Makefile     2020-03-02 15:33:05.223669793 +0800
++++ b/drivers/spi/Makefile     2020-03-02 15:33:44.146364315 +0800
+@@ -60,6 +60,7 @@
+ obj-$(CONFIG_SPI_MPC52xx_PSC)         += spi-mpc52xx-psc.o
+ obj-$(CONFIG_SPI_MPC52xx)             += spi-mpc52xx.o
+ obj-$(CONFIG_SPI_MT65XX)                += spi-mt65xx.o
++obj-$(CONFIG_SPI_MTK_SNFI)              += spi-mtk-snfi.o
+ obj-$(CONFIG_SPI_MT7621)              += spi-mt7621.o
+ obj-$(CONFIG_SPI_MXIC)                        += spi-mxic.o
+ obj-$(CONFIG_SPI_MXS)                 += spi-mxs.o
+--- a/drivers/spi/Kconfig      2020-03-02 15:33:11.183468935 +0800
++++ b/drivers/spi/Kconfig      2020-03-02 15:34:53.304079101 +0800
+@@ -427,6 +427,15 @@
+         say Y or M here.If you are not sure, say N.
+         SPI drivers for Mediatek MT65XX and MT81XX series ARM SoCs.
++config SPI_MTK_SNFI
++      tristate "MediaTek SPI NAND interface"
++      select MTD_SPI_NAND
++      help
++        This selects the SPI NAND FLASH interface(SNFI),
++        which could be found on MediaTek Soc.
++        Say Y or M here.If you are not sure, say N.
++        Note Parallel Nand and SPI NAND is alternative on MediaTek SoCs.
++
+ config SPI_MT7621
+       tristate "MediaTek MT7621 SPI Controller"
+       depends on RALINK || COMPILE_TEST
+--- /dev/null
++++ b/drivers/spi/spi-mtk-snfi.c
+@@ -0,0 +1,1200 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Driver for MediaTek SPI Nand interface
++ *
++ * Copyright (C) 2018 MediaTek Inc.
++ * Authors:   Xiangsheng Hou  <xiangsheng.hou@mediatek.com>
++ *
++ */
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/dma-mapping.h>
++#include <linux/interrupt.h>
++#include <linux/iopoll.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/mtk_ecc.h>
++#include <linux/mtd/spinand.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi-mem.h>
++
++/* NAND controller register definition */
++/* NFI control */
++#define NFI_CNFG              0x00
++#define               CNFG_DMA                BIT(0)
++#define               CNFG_READ_EN            BIT(1)
++#define               CNFG_DMA_BURST_EN       BIT(2)
++#define               CNFG_BYTE_RW            BIT(6)
++#define               CNFG_HW_ECC_EN          BIT(8)
++#define               CNFG_AUTO_FMT_EN        BIT(9)
++#define               CNFG_OP_PROGRAM         (3UL << 12)
++#define               CNFG_OP_CUST            (6UL << 12)
++#define NFI_PAGEFMT           0x04
++#define               PAGEFMT_512             0
++#define               PAGEFMT_2K              1
++#define               PAGEFMT_4K              2
++#define               PAGEFMT_FDM_SHIFT       8
++#define               PAGEFMT_FDM_ECC_SHIFT   12
++#define NFI_CON                       0x08
++#define               CON_FIFO_FLUSH          BIT(0)
++#define               CON_NFI_RST             BIT(1)
++#define               CON_BRD                 BIT(8)
++#define               CON_BWR                 BIT(9)
++#define               CON_SEC_SHIFT           12
++#define NFI_INTR_EN           0x10
++#define               INTR_AHB_DONE_EN        BIT(6)
++#define NFI_INTR_STA          0x14
++#define NFI_CMD                       0x20
++#define NFI_STA                       0x60
++#define               STA_EMP_PAGE            BIT(12)
++#define               NAND_FSM_MASK           (0x1f << 24)
++#define               NFI_FSM_MASK            (0xf << 16)
++#define NFI_ADDRCNTR          0x70
++#define               CNTR_MASK               GENMASK(16, 12)
++#define               ADDRCNTR_SEC_SHIFT      12
++#define               ADDRCNTR_SEC(val) \
++              (((val) & CNTR_MASK) >> ADDRCNTR_SEC_SHIFT)
++#define NFI_STRADDR           0x80
++#define NFI_BYTELEN           0x84
++#define NFI_CSEL              0x90
++#define NFI_FDML(x)           (0xa0 + (x) * sizeof(u32) * 2)
++#define NFI_FDMM(x)           (0xa4 + (x) * sizeof(u32) * 2)
++#define NFI_MASTER_STA                0x224
++#define               MASTER_STA_MASK         0x0fff
++/* NFI_SPI control */
++#define SNFI_MAC_OUTL         0x504
++#define SNFI_MAC_INL          0x508
++#define SNFI_RD_CTL2          0x510
++#define               RD_CMD_MASK             0x00ff
++#define               RD_DUMMY_SHIFT          8
++#define SNFI_RD_CTL3          0x514
++#define               RD_ADDR_MASK            0xffff
++#define SNFI_MISC_CTL         0x538
++#define               RD_MODE_X2              BIT(16)
++#define               RD_MODE_X4              (2UL << 16)
++#define               RD_QDUAL_IO             (4UL << 16)
++#define               RD_MODE_MASK            (7UL << 16)
++#define               RD_CUSTOM_EN            BIT(6)
++#define               WR_CUSTOM_EN            BIT(7)
++#define               WR_X4_EN                BIT(20)
++#define               SW_RST                  BIT(28)
++#define SNFI_MISC_CTL2                0x53c
++#define               WR_LEN_SHIFT            16
++#define SNFI_PG_CTL1          0x524
++#define               WR_LOAD_CMD_SHIFT       8
++#define SNFI_PG_CTL2          0x528
++#define               WR_LOAD_ADDR_MASK       0xffff
++#define SNFI_MAC_CTL          0x500
++#define               MAC_WIP                 BIT(0)
++#define               MAC_WIP_READY           BIT(1)
++#define               MAC_TRIG                BIT(2)
++#define               MAC_EN                  BIT(3)
++#define               MAC_SIO_SEL             BIT(4)
++#define SNFI_STA_CTL1         0x550
++#define               SPI_STATE_IDLE          0xf
++#define SNFI_CNFG             0x55c
++#define               SNFI_MODE_EN            BIT(0)
++#define SNFI_GPRAM_DATA               0x800
++#define               SNFI_GPRAM_MAX_LEN      16
++
++/* Dummy command trigger NFI to spi mode */
++#define NAND_CMD_DUMMYREAD    0x00
++#define NAND_CMD_DUMMYPROG    0x80
++
++#define MTK_TIMEOUT           500000
++#define MTK_RESET_TIMEOUT     1000000
++#define MTK_SNFC_MIN_SPARE    16
++#define KB(x)                 ((x) * 1024UL)
++
++/*
++ * supported spare size of each IP.
++ * order should be the same with the spare size bitfiled defination of
++ * register NFI_PAGEFMT.
++ */
++static const u8 spare_size_mt7622[] = {
++      16, 26, 27, 28
++};
++
++struct mtk_snfi_caps {
++      const u8 *spare_size;
++      u8 num_spare_size;
++      u32 nand_sec_size;
++      u8 nand_fdm_size;
++      u8 nand_fdm_ecc_size;
++      u8 ecc_parity_bits;
++      u8 pageformat_spare_shift;
++      u8 bad_mark_swap;
++};
++
++struct mtk_snfi_bad_mark_ctl {
++      void (*bm_swap)(struct spi_mem *mem, u8 *buf, int raw);
++      u32 sec;
++      u32 pos;
++};
++
++struct mtk_snfi_nand_chip {
++      struct mtk_snfi_bad_mark_ctl bad_mark;
++      u32 spare_per_sector;
++};
++
++struct mtk_snfi_clk {
++      struct clk *nfi_clk;
++      struct clk *spi_clk;
++};
++
++struct mtk_snfi {
++      const struct mtk_snfi_caps *caps;
++      struct mtk_snfi_nand_chip snfi_nand;
++      struct mtk_snfi_clk clk;
++      struct mtk_ecc_config ecc_cfg;
++      struct mtk_ecc *ecc;
++      struct completion done;
++      struct device *dev;
++
++      void __iomem *regs;
++
++      u8 *buffer;
++};
++
++static inline u8 *oob_ptr(struct spi_mem *mem, int i)
++{
++      struct spinand_device *spinand = spi_mem_get_drvdata(mem);
++      struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++      struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand;
++      u8 *poi;
++
++      /* map the sector's FDM data to free oob:
++       * the beginning of the oob area stores the FDM data of bad mark
++       */
++
++      if (i < snfi_nand->bad_mark.sec)
++              poi = spinand->oobbuf + (i + 1) * snfi->caps->nand_fdm_size;
++      else if (i == snfi_nand->bad_mark.sec)
++              poi = spinand->oobbuf;
++      else
++              poi = spinand->oobbuf + i * snfi->caps->nand_fdm_size;
++
++      return poi;
++}
++
++static inline int mtk_data_len(struct spi_mem *mem)
++{
++      struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++      struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand;
++
++      return snfi->caps->nand_sec_size + snfi_nand->spare_per_sector;
++}
++
++static inline u8 *mtk_oob_ptr(struct spi_mem *mem,
++                            const u8 *p, int i)
++{
++      struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++
++      return (u8 *)p + i * mtk_data_len(mem) + snfi->caps->nand_sec_size;
++}
++
++static void mtk_snfi_bad_mark_swap(struct spi_mem *mem,
++                                 u8 *buf, int raw)
++{
++      struct spinand_device *spinand = spi_mem_get_drvdata(mem);
++      struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++      struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand;
++      u32 bad_pos = snfi_nand->bad_mark.pos;
++
++      if (raw)
++              bad_pos += snfi_nand->bad_mark.sec * mtk_data_len(mem);
++      else
++              bad_pos += snfi_nand->bad_mark.sec * snfi->caps->nand_sec_size;
++
++      swap(spinand->oobbuf[0], buf[bad_pos]);
++}
++
++static void mtk_snfi_set_bad_mark_ctl(struct mtk_snfi_bad_mark_ctl *bm_ctl,
++                                    struct spi_mem *mem)
++{
++      struct spinand_device *spinand = spi_mem_get_drvdata(mem);
++      struct mtd_info *mtd = spinand_to_mtd(spinand);
++
++      bm_ctl->bm_swap = mtk_snfi_bad_mark_swap;
++      bm_ctl->sec = mtd->writesize / mtk_data_len(mem);
++      bm_ctl->pos = mtd->writesize % mtk_data_len(mem);
++}
++
++static void mtk_snfi_mac_enable(struct mtk_snfi *snfi)
++{
++      u32 mac;
++
++      mac = readl(snfi->regs + SNFI_MAC_CTL);
++      mac &= ~MAC_SIO_SEL;
++      mac |= MAC_EN;
++
++      writel(mac, snfi->regs + SNFI_MAC_CTL);
++}
++
++static int mtk_snfi_mac_trigger(struct mtk_snfi *snfi)
++{
++      u32 mac, reg;
++      int ret = 0;
++
++      mac = readl(snfi->regs + SNFI_MAC_CTL);
++      mac |= MAC_TRIG;
++      writel(mac, snfi->regs + SNFI_MAC_CTL);
++
++      ret = readl_poll_timeout_atomic(snfi->regs + SNFI_MAC_CTL, reg,
++                                      reg & MAC_WIP_READY, 10,
++                                      MTK_TIMEOUT);
++      if (ret < 0) {
++              dev_err(snfi->dev, "polling wip ready for read timeout\n");
++              return -EIO;
++      }
++
++      ret = readl_poll_timeout_atomic(snfi->regs + SNFI_MAC_CTL, reg,
++                                      !(reg & MAC_WIP), 10,
++                                      MTK_TIMEOUT);
++      if (ret < 0) {
++              dev_err(snfi->dev, "polling flash update timeout\n");
++              return -EIO;
++      }
++
++      return ret;
++}
++
++static void mtk_snfi_mac_leave(struct mtk_snfi *snfi)
++{
++      u32 mac;
++
++      mac = readl(snfi->regs + SNFI_MAC_CTL);
++      mac &= ~(MAC_TRIG | MAC_EN | MAC_SIO_SEL);
++      writel(mac, snfi->regs + SNFI_MAC_CTL);
++}
++
++static int mtk_snfi_mac_op(struct mtk_snfi *snfi)
++{
++      int ret = 0;
++
++      mtk_snfi_mac_enable(snfi);
++
++      ret = mtk_snfi_mac_trigger(snfi);
++      if (ret)
++              return ret;
++
++      mtk_snfi_mac_leave(snfi);
++
++      return ret;
++}
++
++static irqreturn_t mtk_snfi_irq(int irq, void *id)
++{
++      struct mtk_snfi *snfi = id;
++      u16 sta, ien;
++
++      sta = readw(snfi->regs + NFI_INTR_STA);
++      ien = readw(snfi->regs + NFI_INTR_EN);
++
++      if (!(sta & ien))
++              return IRQ_NONE;
++
++      writew(~sta & ien, snfi->regs + NFI_INTR_EN);
++      complete(&snfi->done);
++
++      return IRQ_HANDLED;
++}
++
++static int mtk_snfi_enable_clk(struct device *dev, struct mtk_snfi_clk *clk)
++{
++      int ret;
++
++      ret = clk_prepare_enable(clk->nfi_clk);
++      if (ret) {
++              dev_err(dev, "failed to enable nfi clk\n");
++              return ret;
++      }
++
++      ret = clk_prepare_enable(clk->spi_clk);
++      if (ret) {
++              dev_err(dev, "failed to enable spi clk\n");
++              clk_disable_unprepare(clk->nfi_clk);
++              return ret;
++      }
++
++      return 0;
++}
++
++static void mtk_snfi_disable_clk(struct mtk_snfi_clk *clk)
++{
++      clk_disable_unprepare(clk->nfi_clk);
++      clk_disable_unprepare(clk->spi_clk);
++}
++
++static int mtk_snfi_reset(struct mtk_snfi *snfi)
++{
++      u32 val;
++      int ret;
++
++      /* SW reset controller */
++      val = readl(snfi->regs + SNFI_MISC_CTL) | SW_RST;
++      writel(val, snfi->regs + SNFI_MISC_CTL);
++
++      ret = readw_poll_timeout(snfi->regs + SNFI_STA_CTL1, val,
++                               !(val & SPI_STATE_IDLE), 50,
++                               MTK_RESET_TIMEOUT);
++      if (ret) {
++              dev_warn(snfi->dev, "spi state active in reset [0x%x] = 0x%x\n",
++                       SNFI_STA_CTL1, val);
++              return ret;
++      }
++
++      val = readl(snfi->regs + SNFI_MISC_CTL);
++      val &= ~SW_RST;
++      writel(val, snfi->regs + SNFI_MISC_CTL);
++
++      /* reset all registers and force the NFI master to terminate */
++      writew(CON_FIFO_FLUSH | CON_NFI_RST, snfi->regs + NFI_CON);
++      ret = readw_poll_timeout(snfi->regs + NFI_STA, val,
++                               !(val & (NFI_FSM_MASK | NAND_FSM_MASK)), 50,
++                               MTK_RESET_TIMEOUT);
++      if (ret) {
++              dev_warn(snfi->dev, "nfi active in reset [0x%x] = 0x%x\n",
++                       NFI_STA, val);
++              return ret;
++      }
++
++      return 0;
++}
++
++static int mtk_snfi_set_spare_per_sector(struct spinand_device *spinand,
++                                       const struct mtk_snfi_caps *caps,
++                                       u32 *sps)
++{
++      struct mtd_info *mtd = spinand_to_mtd(spinand);
++      const u8 *spare = caps->spare_size;
++      u32 sectors, i, closest_spare = 0;
++
++      sectors = mtd->writesize / caps->nand_sec_size;
++      *sps = mtd->oobsize / sectors;
++
++      if (*sps < MTK_SNFC_MIN_SPARE)
++              return -EINVAL;
++
++      for (i = 0; i < caps->num_spare_size; i++) {
++              if (*sps >= spare[i] && spare[i] >= spare[closest_spare]) {
++                      closest_spare = i;
++                      if (*sps == spare[i])
++                              break;
++              }
++      }
++
++      *sps = spare[closest_spare];
++
++      return 0;
++}
++
++static void mtk_snfi_read_fdm_data(struct spi_mem *mem,
++                                 u32 sectors)
++{
++      struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++      const struct mtk_snfi_caps *caps = snfi->caps;
++      u32 vall, valm;
++      int i, j;
++      u8 *oobptr;
++
++      for (i = 0; i < sectors; i++) {
++              oobptr = oob_ptr(mem, i);
++              vall = readl(snfi->regs + NFI_FDML(i));
++              valm = readl(snfi->regs + NFI_FDMM(i));
++
++              for (j = 0; j < caps->nand_fdm_size; j++)
++                      oobptr[j] = (j >= 4 ? valm : vall) >> ((j % 4) * 8);
++      }
++}
++
++static void mtk_snfi_write_fdm_data(struct spi_mem *mem,
++                                  u32 sectors)
++{
++      struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++      const struct mtk_snfi_caps *caps = snfi->caps;
++      u32 vall, valm;
++      int i, j;
++      u8 *oobptr;
++
++      for (i = 0; i < sectors; i++) {
++              oobptr = oob_ptr(mem, i);
++              vall = 0;
++              valm = 0;
++              for (j = 0; j < 8; j++) {
++                      if (j < 4)
++                              vall |= (j < caps->nand_fdm_size ? oobptr[j] :
++                                       0xff) << (j * 8);
++                      else
++                              valm |= (j < caps->nand_fdm_size ? oobptr[j] :
++                                       0xff) << ((j - 4) * 8);
++              }
++              writel(vall, snfi->regs + NFI_FDML(i));
++              writel(valm, snfi->regs + NFI_FDMM(i));
++      }
++}
++
++static int mtk_snfi_update_ecc_stats(struct spi_mem *mem,
++                                   u8 *buf, u32 sectors)
++{
++      struct spinand_device *spinand = spi_mem_get_drvdata(mem);
++      struct mtd_info *mtd = spinand_to_mtd(spinand);
++      struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++      struct mtk_ecc_stats stats;
++      int rc, i;
++
++      rc = readl(snfi->regs + NFI_STA) & STA_EMP_PAGE;
++      if (rc) {
++              memset(buf, 0xff, sectors * snfi->caps->nand_sec_size);
++              for (i = 0; i < sectors; i++)
++                      memset(spinand->oobbuf, 0xff,
++                             snfi->caps->nand_fdm_size);
++              return 0;
++      }
++
++      mtk_ecc_get_stats(snfi->ecc, &stats, sectors);
++      mtd->ecc_stats.corrected += stats.corrected;
++      mtd->ecc_stats.failed += stats.failed;
++
++      return 0;
++}
++
++static int mtk_snfi_hw_runtime_config(struct spi_mem *mem)
++{
++      struct spinand_device *spinand = spi_mem_get_drvdata(mem);
++      struct mtd_info *mtd = spinand_to_mtd(spinand);
++      struct nand_device *nand = mtd_to_nanddev(mtd);
++      struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++      const struct mtk_snfi_caps *caps = snfi->caps;
++      struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand;
++      u32 fmt, spare, i = 0;
++      int ret;
++
++      ret = mtk_snfi_set_spare_per_sector(spinand, caps, &spare);
++      if (ret)
++              return ret;
++
++      /* calculate usable oob bytes for ecc parity data */
++      snfi_nand->spare_per_sector = spare;
++      spare -= caps->nand_fdm_size;
++
++      nand->memorg.oobsize = snfi_nand->spare_per_sector
++              * (mtd->writesize / caps->nand_sec_size);
++      mtd->oobsize = nanddev_per_page_oobsize(nand);
++
++      snfi->ecc_cfg.strength = (spare << 3) / caps->ecc_parity_bits;
++      mtk_ecc_adjust_strength(snfi->ecc, &snfi->ecc_cfg.strength);
++
++      switch (mtd->writesize) {
++      case 512:
++              fmt = PAGEFMT_512;
++              break;
++      case KB(2):
++              fmt = PAGEFMT_2K;
++              break;
++      case KB(4):
++              fmt = PAGEFMT_4K;
++              break;
++      default:
++              dev_err(snfi->dev, "invalid page len: %d\n", mtd->writesize);
++              return -EINVAL;
++      }
++
++      /* Setup PageFormat */
++      while (caps->spare_size[i] != snfi_nand->spare_per_sector) {
++              i++;
++              if (i == (caps->num_spare_size - 1)) {
++                      dev_err(snfi->dev, "invalid spare size %d\n",
++                              snfi_nand->spare_per_sector);
++                      return -EINVAL;
++              }
++      }
++
++      fmt |= i << caps->pageformat_spare_shift;
++      fmt |= caps->nand_fdm_size << PAGEFMT_FDM_SHIFT;
++      fmt |= caps->nand_fdm_ecc_size << PAGEFMT_FDM_ECC_SHIFT;
++      writel(fmt, snfi->regs + NFI_PAGEFMT);
++
++      snfi->ecc_cfg.len = caps->nand_sec_size + caps->nand_fdm_ecc_size;
++
++      mtk_snfi_set_bad_mark_ctl(&snfi_nand->bad_mark, mem);
++
++      return 0;
++}
++
++static int mtk_snfi_read_from_cache(struct spi_mem *mem,
++                                  const struct spi_mem_op *op, int oob_on)
++{
++      struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++      struct spinand_device *spinand = spi_mem_get_drvdata(mem);
++      struct mtd_info *mtd = spinand_to_mtd(spinand);
++      u32 sectors = mtd->writesize / snfi->caps->nand_sec_size;
++      struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand;
++      u32 reg, len, col_addr = 0;
++      int dummy_cycle, ret;
++      dma_addr_t dma_addr;
++
++      len = sectors * (snfi->caps->nand_sec_size
++            + snfi_nand->spare_per_sector);
++
++      dma_addr = dma_map_single(snfi->dev, snfi->buffer,
++                                len, DMA_FROM_DEVICE);
++      ret = dma_mapping_error(snfi->dev, dma_addr);
++      if (ret) {
++              dev_err(snfi->dev, "dma mapping error\n");
++              return -EINVAL;
++      }
++
++      /* set Read cache command and dummy cycle */
++      dummy_cycle = (op->dummy.nbytes << 3) >> (ffs(op->dummy.buswidth) - 1);
++      reg = ((op->cmd.opcode & RD_CMD_MASK) |
++             (dummy_cycle << RD_DUMMY_SHIFT));
++      writel(reg, snfi->regs + SNFI_RD_CTL2);
++
++      writel((col_addr & RD_ADDR_MASK), snfi->regs + SNFI_RD_CTL3);
++
++      reg = readl(snfi->regs + SNFI_MISC_CTL);
++      reg |= RD_CUSTOM_EN;
++      reg &= ~(RD_MODE_MASK | WR_X4_EN);
++
++      /* set data and addr buswidth */
++      if (op->data.buswidth == 4)
++              reg |= RD_MODE_X4;
++      else if (op->data.buswidth == 2)
++              reg |= RD_MODE_X2;
++
++      if (op->addr.buswidth == 4 || op->addr.buswidth == 2)
++              reg |= RD_QDUAL_IO;
++      writel(reg, snfi->regs + SNFI_MISC_CTL);
++
++      writel(len, snfi->regs + SNFI_MISC_CTL2);
++      writew(sectors << CON_SEC_SHIFT, snfi->regs + NFI_CON);
++      reg = readw(snfi->regs + NFI_CNFG);
++      reg |= CNFG_READ_EN | CNFG_DMA_BURST_EN | CNFG_DMA | CNFG_OP_CUST;
++
++      if (!oob_on) {
++              reg |= CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN;
++              writew(reg, snfi->regs + NFI_CNFG);
++
++              snfi->ecc_cfg.mode = ECC_NFI_MODE;
++              snfi->ecc_cfg.sectors = sectors;
++              snfi->ecc_cfg.op = ECC_DECODE;
++              ret = mtk_ecc_enable(snfi->ecc, &snfi->ecc_cfg);
++              if (ret) {
++                      dev_err(snfi->dev, "ecc enable failed\n");
++                      /* clear NFI_CNFG */
++                      reg &= ~(CNFG_READ_EN | CNFG_DMA_BURST_EN | CNFG_DMA |
++                              CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
++                      writew(reg, snfi->regs + NFI_CNFG);
++                      goto out;
++              }
++      } else {
++              writew(reg, snfi->regs + NFI_CNFG);
++      }
++
++      writel(lower_32_bits(dma_addr), snfi->regs + NFI_STRADDR);
++      readw(snfi->regs + NFI_INTR_STA);
++      writew(INTR_AHB_DONE_EN, snfi->regs + NFI_INTR_EN);
++
++      init_completion(&snfi->done);
++
++      /* set dummy command to trigger NFI enter SPI mode */
++      writew(NAND_CMD_DUMMYREAD, snfi->regs + NFI_CMD);
++      reg = readl(snfi->regs + NFI_CON) | CON_BRD;
++      writew(reg, snfi->regs + NFI_CON);
++
++      ret = wait_for_completion_timeout(&snfi->done, msecs_to_jiffies(500));
++      if (!ret) {
++              dev_err(snfi->dev, "read ahb done timeout\n");
++              writew(0, snfi->regs + NFI_INTR_EN);
++              ret = -ETIMEDOUT;
++              goto out;
++      }
++
++      ret = readl_poll_timeout_atomic(snfi->regs + NFI_BYTELEN, reg,
++                                      ADDRCNTR_SEC(reg) >= sectors, 10,
++                                      MTK_TIMEOUT);
++      if (ret < 0) {
++              dev_err(snfi->dev, "polling read byte len timeout\n");
++              ret = -EIO;
++      } else {
++              if (!oob_on) {
++                      ret = mtk_ecc_wait_done(snfi->ecc, ECC_DECODE);
++                      if (ret) {
++                              dev_warn(snfi->dev, "wait ecc done timeout\n");
++                      } else {
++                              mtk_snfi_update_ecc_stats(mem, snfi->buffer,
++                                                        sectors);
++                              mtk_snfi_read_fdm_data(mem, sectors);
++                      }
++              }
++      }
++
++      if (oob_on)
++              goto out;
++
++      mtk_ecc_disable(snfi->ecc);
++out:
++      dma_unmap_single(snfi->dev, dma_addr, len, DMA_FROM_DEVICE);
++      writel(0, snfi->regs + NFI_CON);
++      writel(0, snfi->regs + NFI_CNFG);
++      reg = readl(snfi->regs + SNFI_MISC_CTL);
++      reg &= ~RD_CUSTOM_EN;
++      writel(reg, snfi->regs + SNFI_MISC_CTL);
++
++      return ret;
++}
++
++static int mtk_snfi_write_to_cache(struct spi_mem *mem,
++                                 const struct spi_mem_op *op,
++                                 int oob_on)
++{
++      struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++      struct spinand_device *spinand = spi_mem_get_drvdata(mem);
++      struct mtd_info *mtd = spinand_to_mtd(spinand);
++      u32 sectors = mtd->writesize / snfi->caps->nand_sec_size;
++      struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand;
++      u32 reg, len, col_addr = 0;
++      dma_addr_t dma_addr;
++      int ret;
++
++      len = sectors * (snfi->caps->nand_sec_size
++            + snfi_nand->spare_per_sector);
++
++      dma_addr = dma_map_single(snfi->dev, snfi->buffer, len,
++                                DMA_TO_DEVICE);
++      ret = dma_mapping_error(snfi->dev, dma_addr);
++      if (ret) {
++              dev_err(snfi->dev, "dma mapping error\n");
++              return -EINVAL;
++      }
++
++      /* set program load cmd and address */
++      reg = (op->cmd.opcode << WR_LOAD_CMD_SHIFT);
++      writel(reg, snfi->regs + SNFI_PG_CTL1);
++      writel(col_addr & WR_LOAD_ADDR_MASK, snfi->regs + SNFI_PG_CTL2);
++
++      reg = readl(snfi->regs + SNFI_MISC_CTL);
++      reg |= WR_CUSTOM_EN;
++      reg &= ~(RD_MODE_MASK | WR_X4_EN);
++
++      if (op->data.buswidth == 4)
++              reg |= WR_X4_EN;
++      writel(reg, snfi->regs + SNFI_MISC_CTL);
++
++      writel(len << WR_LEN_SHIFT, snfi->regs + SNFI_MISC_CTL2);
++      writew(sectors << CON_SEC_SHIFT, snfi->regs + NFI_CON);
++
++      reg = readw(snfi->regs + NFI_CNFG);
++      reg &= ~(CNFG_READ_EN | CNFG_BYTE_RW);
++      reg |= CNFG_DMA | CNFG_DMA_BURST_EN | CNFG_OP_PROGRAM;
++
++      if (!oob_on) {
++              reg |= CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN;
++              writew(reg, snfi->regs + NFI_CNFG);
++
++              snfi->ecc_cfg.mode = ECC_NFI_MODE;
++              snfi->ecc_cfg.op = ECC_ENCODE;
++              ret = mtk_ecc_enable(snfi->ecc, &snfi->ecc_cfg);
++              if (ret) {
++                      dev_err(snfi->dev, "ecc enable failed\n");
++                      /* clear NFI_CNFG */
++                      reg &= ~(CNFG_DMA_BURST_EN | CNFG_DMA |
++                                      CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
++                      writew(reg, snfi->regs + NFI_CNFG);
++                      dma_unmap_single(snfi->dev, dma_addr, len,
++                                       DMA_FROM_DEVICE);
++                      goto out;
++              }
++              /* write OOB into the FDM registers (OOB area in MTK NAND) */
++              mtk_snfi_write_fdm_data(mem, sectors);
++      } else {
++              writew(reg, snfi->regs + NFI_CNFG);
++      }
++      writel(lower_32_bits(dma_addr), snfi->regs + NFI_STRADDR);
++      readw(snfi->regs + NFI_INTR_STA);
++      writew(INTR_AHB_DONE_EN, snfi->regs + NFI_INTR_EN);
++
++      init_completion(&snfi->done);
++
++      /* set dummy command to trigger NFI enter SPI mode */
++      writew(NAND_CMD_DUMMYPROG, snfi->regs + NFI_CMD);
++      reg = readl(snfi->regs + NFI_CON) | CON_BWR;
++      writew(reg, snfi->regs + NFI_CON);
++
++      ret = wait_for_completion_timeout(&snfi->done, msecs_to_jiffies(500));
++      if (!ret) {
++              dev_err(snfi->dev, "custom program done timeout\n");
++              writew(0, snfi->regs + NFI_INTR_EN);
++              ret = -ETIMEDOUT;
++              goto ecc_disable;
++      }
++
++      ret = readl_poll_timeout_atomic(snfi->regs + NFI_ADDRCNTR, reg,
++                                      ADDRCNTR_SEC(reg) >= sectors,
++                                      10, MTK_TIMEOUT);
++      if (ret)
++              dev_err(snfi->dev, "hwecc write timeout\n");
++
++ecc_disable:
++      mtk_ecc_disable(snfi->ecc);
++
++out:
++      dma_unmap_single(snfi->dev, dma_addr, len, DMA_TO_DEVICE);
++      writel(0, snfi->regs + NFI_CON);
++      writel(0, snfi->regs + NFI_CNFG);
++      reg = readl(snfi->regs + SNFI_MISC_CTL);
++      reg &= ~WR_CUSTOM_EN;
++      writel(reg, snfi->regs + SNFI_MISC_CTL);
++
++      return ret;
++}
++
++static int mtk_snfi_read(struct spi_mem *mem,
++                       const struct spi_mem_op *op)
++{
++      struct spinand_device *spinand = spi_mem_get_drvdata(mem);
++      struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++      struct mtd_info *mtd = spinand_to_mtd(spinand);
++      struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand;
++      u32 col_addr = op->addr.val;
++      int i, ret, sectors, oob_on = false;
++
++      if (col_addr == mtd->writesize)
++              oob_on = true;
++
++      ret = mtk_snfi_read_from_cache(mem, op, oob_on);
++      if (ret) {
++              dev_warn(snfi->dev, "read from cache fail\n");
++              return ret;
++      }
++
++      sectors = mtd->writesize / snfi->caps->nand_sec_size;
++      for (i = 0; i < sectors; i++) {
++              if (oob_on)
++                      memcpy(oob_ptr(mem, i),
++                             mtk_oob_ptr(mem, snfi->buffer, i),
++                             snfi->caps->nand_fdm_size);
++
++              if (i == snfi_nand->bad_mark.sec && snfi->caps->bad_mark_swap)
++                      snfi_nand->bad_mark.bm_swap(mem, snfi->buffer,
++                                                      oob_on);
++      }
++
++      if (!oob_on)
++              memcpy(spinand->databuf, snfi->buffer, mtd->writesize);
++
++      return ret;
++}
++
++static int mtk_snfi_write(struct spi_mem *mem,
++                        const struct spi_mem_op *op)
++{
++      struct spinand_device *spinand = spi_mem_get_drvdata(mem);
++      struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++      struct mtd_info *mtd = spinand_to_mtd(spinand);
++      struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand;
++      u32 ret, i, sectors, col_addr = op->addr.val;
++      int oob_on = false;
++
++      if (col_addr == mtd->writesize)
++              oob_on = true;
++
++      sectors = mtd->writesize / snfi->caps->nand_sec_size;
++      memset(snfi->buffer, 0xff, mtd->writesize + mtd->oobsize);
++
++      if (!oob_on)
++              memcpy(snfi->buffer, spinand->databuf, mtd->writesize);
++
++      for (i = 0; i < sectors; i++) {
++              if (i == snfi_nand->bad_mark.sec && snfi->caps->bad_mark_swap)
++                      snfi_nand->bad_mark.bm_swap(mem, snfi->buffer, oob_on);
++
++              if (oob_on)
++                      memcpy(mtk_oob_ptr(mem, snfi->buffer, i),
++                             oob_ptr(mem, i),
++                             snfi->caps->nand_fdm_size);
++      }
++
++      ret = mtk_snfi_write_to_cache(mem, op, oob_on);
++      if (ret)
++              dev_warn(snfi->dev, "write to cache fail\n");
++
++      return ret;
++}
++
++static int mtk_snfi_command_exec(struct mtk_snfi *snfi,
++                               const u8 *txbuf, u8 *rxbuf,
++                               const u32 txlen, const u32 rxlen)
++{
++      u32 tmp, i, j, reg, m;
++      u8 *p_tmp = (u8 *)(&tmp);
++      int ret = 0;
++
++      /* Moving tx data to NFI_SPI GPRAM */
++      for (i = 0, m = 0; i < txlen; ) {
++              for (j = 0, tmp = 0; i < txlen && j < 4; i++, j++)
++                      p_tmp[j] = txbuf[i];
++
++              writel(tmp, snfi->regs + SNFI_GPRAM_DATA + m);
++              m += 4;
++      }
++
++      writel(txlen, snfi->regs + SNFI_MAC_OUTL);
++      writel(rxlen, snfi->regs + SNFI_MAC_INL);
++      ret = mtk_snfi_mac_op(snfi);
++      if (ret)
++              return ret;
++
++      /* For NULL input data, this loop will be skipped */
++      if (rxlen)
++              for (i = 0, m = 0; i < rxlen; ) {
++                      reg = readl(snfi->regs +
++                                          SNFI_GPRAM_DATA + m);
++                      for (j = 0; i < rxlen && j < 4; i++, j++, rxbuf++) {
++                              if (m == 0 && i == 0)
++                                      j = i + txlen;
++                              *rxbuf = (reg >> (j * 8)) & 0xFF;
++                      }
++                      m += 4;
++              }
++
++      return ret;
++}
++
++/*
++ * mtk_snfi_exec_op - to process command/data to send to the
++ * SPI NAND by mtk controller
++ */
++static int mtk_snfi_exec_op(struct spi_mem *mem,
++                          const struct spi_mem_op *op)
++
++{
++      struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++      struct spinand_device *spinand = spi_mem_get_drvdata(mem);
++      struct mtd_info *mtd = spinand_to_mtd(spinand);
++      struct nand_device *nand = mtd_to_nanddev(mtd);
++      const struct spi_mem_op *read_cache;
++      const struct spi_mem_op *write_cache;
++      const struct spi_mem_op *update_cache;
++      u32 tmpbufsize, txlen = 0, rxlen = 0;
++      u8 *txbuf, *rxbuf = NULL, *buf;
++      int i, ret = 0;
++      
++      ret = mtk_snfi_reset(snfi);
++      if (ret) {
++              dev_warn(snfi->dev, "reset spi memory controller fail\n");
++              return ret;
++      }
++
++      /*if bbt initial, framework have detect nand information */
++      if (nand->bbt.cache) {
++              read_cache = spinand->op_templates.read_cache;
++              write_cache = spinand->op_templates.write_cache;
++              update_cache = spinand->op_templates.update_cache;
++
++              ret = mtk_snfi_hw_runtime_config(mem);
++              if (ret)
++                      return ret;
++
++              /* For Read/Write with cache, Erase use framework flow */
++              if (op->cmd.opcode == read_cache->cmd.opcode) {
++                      ret = mtk_snfi_read(mem, op);
++                      if (ret)
++                              dev_warn(snfi->dev, "snfi read fail\n");
++                      
++                      return ret;
++              } else if ((op->cmd.opcode == write_cache->cmd.opcode)
++                              || (op->cmd.opcode == update_cache->cmd.opcode)) {
++                      ret = mtk_snfi_write(mem, op);
++                      if (ret)
++                              dev_warn(snfi->dev, "snfi write fail\n");
++                      
++                      return ret;
++              }
++      }
++
++      tmpbufsize = sizeof(op->cmd.opcode) + op->addr.nbytes +
++                   op->dummy.nbytes + op->data.nbytes;
++
++      txbuf = kzalloc(tmpbufsize, GFP_KERNEL);
++      if (!txbuf)
++              return -ENOMEM;
++
++      txbuf[txlen++] = op->cmd.opcode;
++
++      if (op->addr.nbytes)
++              for (i = 0; i < op->addr.nbytes; i++)
++                      txbuf[txlen++] = op->addr.val >>
++                                      (8 * (op->addr.nbytes - i - 1));
++
++      txlen += op->dummy.nbytes;
++
++      if (op->data.dir == SPI_MEM_DATA_OUT)
++              for (i = 0; i < op->data.nbytes; i++) {
++                      buf = (u8 *)op->data.buf.out;
++                      txbuf[txlen++] = buf[i];
++              }
++
++      if (op->data.dir == SPI_MEM_DATA_IN) {
++              rxbuf = (u8 *)op->data.buf.in;
++              rxlen += op->data.nbytes;
++      }
++
++      ret = mtk_snfi_command_exec(snfi, txbuf, rxbuf, txlen, rxlen);
++      kfree(txbuf);
++
++      return ret;
++}
++
++static int mtk_snfi_init(struct mtk_snfi *snfi)
++{
++      int ret;
++
++      /* Reset the state machine and data FIFO */
++      ret = mtk_snfi_reset(snfi);
++      if (ret) {
++              dev_warn(snfi->dev, "MTK reset controller fail\n");
++              return ret;
++      }
++
++      snfi->buffer = devm_kzalloc(snfi->dev, 4096 + 256, GFP_KERNEL);
++      if (!snfi->buffer)
++              return  -ENOMEM;
++
++      /* Clear interrupt, read clear. */
++      readw(snfi->regs + NFI_INTR_STA);
++      writew(0, snfi->regs + NFI_INTR_EN);
++
++      writel(0, snfi->regs + NFI_CON);
++      writel(0, snfi->regs + NFI_CNFG);
++
++      /* Change to NFI_SPI mode. */
++      writel(SNFI_MODE_EN, snfi->regs + SNFI_CNFG);
++
++      return 0;
++}
++
++static int mtk_snfi_check_buswidth(u8 width)
++{
++      switch (width) {
++      case 1:
++      case 2:
++      case 4:
++              return 0;
++
++      default:
++              break;
++      }
++
++      return -ENOTSUPP;
++}
++
++static bool mtk_snfi_supports_op(struct spi_mem *mem,
++                               const struct spi_mem_op *op)
++{
++      int ret = 0;
++
++      /* For MTK Spi Nand controller, cmd buswidth just support 1 bit*/
++      if (op->cmd.buswidth != 1)
++              ret = -ENOTSUPP;
++
++      if (op->addr.nbytes)
++              ret |= mtk_snfi_check_buswidth(op->addr.buswidth);
++
++      if (op->dummy.nbytes)
++              ret |= mtk_snfi_check_buswidth(op->dummy.buswidth);
++
++      if (op->data.nbytes)
++              ret |= mtk_snfi_check_buswidth(op->data.buswidth);
++
++      if (ret)
++              return false;
++
++      return true;
++}
++
++static const struct spi_controller_mem_ops mtk_snfi_ops = {
++      .supports_op = mtk_snfi_supports_op,
++      .exec_op = mtk_snfi_exec_op,
++};
++
++static const struct mtk_snfi_caps snfi_mt7622 = {
++      .spare_size = spare_size_mt7622,
++      .num_spare_size = 4,
++      .nand_sec_size = 512,
++      .nand_fdm_size = 8,
++      .nand_fdm_ecc_size = 1,
++      .ecc_parity_bits = 13,
++      .pageformat_spare_shift = 4,
++      .bad_mark_swap = 0,
++};
++
++static const struct mtk_snfi_caps snfi_mt7629 = {
++      .spare_size = spare_size_mt7622,
++      .num_spare_size = 4,
++      .nand_sec_size = 512,
++      .nand_fdm_size = 8,
++      .nand_fdm_ecc_size = 1,
++      .ecc_parity_bits = 13,
++      .pageformat_spare_shift = 4,
++      .bad_mark_swap = 1,
++};
++
++static const struct of_device_id mtk_snfi_id_table[] = {
++      { .compatible = "mediatek,mt7622-snfi", .data = &snfi_mt7622, },
++      { .compatible = "mediatek,mt7629-snfi", .data = &snfi_mt7629, },
++      {  /* sentinel */ }
++};
++
++static int mtk_snfi_probe(struct platform_device *pdev)
++{
++      struct device *dev = &pdev->dev;
++      struct device_node *np = dev->of_node;
++      struct spi_controller *ctlr;
++      struct mtk_snfi *snfi;
++      struct resource *res;
++      int ret = 0, irq;
++
++      ctlr = spi_alloc_master(&pdev->dev, sizeof(*snfi));
++      if (!ctlr)
++              return -ENOMEM;
++
++      snfi = spi_controller_get_devdata(ctlr);
++      snfi->caps = of_device_get_match_data(dev);
++      snfi->dev = dev;
++
++      snfi->ecc = of_mtk_ecc_get(np);
++      if (IS_ERR_OR_NULL(snfi->ecc))
++              goto err_put_master;
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      snfi->regs = devm_ioremap_resource(dev, res);
++      if (IS_ERR(snfi->regs)) {
++              ret = PTR_ERR(snfi->regs);
++              goto release_ecc;
++      }
++
++      /* find the clocks */
++      snfi->clk.nfi_clk = devm_clk_get(dev, "nfi_clk");
++      if (IS_ERR(snfi->clk.nfi_clk)) {
++              dev_err(dev, "no nfi clk\n");
++              ret = PTR_ERR(snfi->clk.nfi_clk);
++              goto release_ecc;
++      }
++
++      snfi->clk.spi_clk = devm_clk_get(dev, "spi_clk");
++      if (IS_ERR(snfi->clk.spi_clk)) {
++              dev_err(dev, "no spi clk\n");
++              ret = PTR_ERR(snfi->clk.spi_clk);
++              goto release_ecc;
++      }
++
++      ret = mtk_snfi_enable_clk(dev, &snfi->clk);
++      if (ret)
++              goto release_ecc;
++
++      /* find the irq */
++      irq = platform_get_irq(pdev, 0);
++      if (irq < 0) {
++              dev_err(dev, "no snfi irq resource\n");
++              ret = -EINVAL;
++              goto clk_disable;
++      }
++
++      ret = devm_request_irq(dev, irq, mtk_snfi_irq, 0, "mtk-snfi", snfi);
++      if (ret) {
++              dev_err(dev, "failed to request snfi irq\n");
++              goto clk_disable;
++      }
++
++      ret = dma_set_mask(dev, DMA_BIT_MASK(32));
++      if (ret) {
++              dev_err(dev, "failed to set dma mask\n");
++              goto clk_disable;
++      }
++
++      ctlr->dev.of_node = np;
++      ctlr->mem_ops = &mtk_snfi_ops;
++
++      platform_set_drvdata(pdev, snfi);
++      ret = mtk_snfi_init(snfi);
++      if (ret) {
++              dev_err(dev, "failed to init snfi\n");
++              goto clk_disable;
++      }
++
++      ret = devm_spi_register_master(dev, ctlr);
++      if (ret)
++              goto clk_disable;
++
++      return 0;
++
++clk_disable:
++      mtk_snfi_disable_clk(&snfi->clk);
++
++release_ecc:
++      mtk_ecc_release(snfi->ecc);
++
++err_put_master:
++      spi_master_put(ctlr);
++
++      dev_err(dev, "MediaTek SPI NAND interface probe failed %d\n", ret);
++      return ret;
++}
++
++static int mtk_snfi_remove(struct platform_device *pdev)
++{
++      struct mtk_snfi *snfi = platform_get_drvdata(pdev);
++
++      mtk_snfi_disable_clk(&snfi->clk);
++
++      return 0;
++}
++
++static int mtk_snfi_suspend(struct platform_device *pdev, pm_message_t state)
++{
++      struct mtk_snfi *snfi = platform_get_drvdata(pdev);
++
++      mtk_snfi_disable_clk(&snfi->clk);
++
++      return 0;
++}
++
++static int mtk_snfi_resume(struct platform_device *pdev)
++{
++      struct device *dev = &pdev->dev;
++      struct mtk_snfi *snfi = dev_get_drvdata(dev);
++      int ret;
++
++      ret = mtk_snfi_enable_clk(dev, &snfi->clk);
++      if (ret)
++              return ret;
++
++      ret = mtk_snfi_init(snfi);
++      if (ret)
++              dev_err(dev, "failed to init snfi controller\n");
++
++      return ret;
++}
++
++static struct platform_driver mtk_snfi_driver = {
++      .driver = {
++              .name   = "mtk-snfi",
++              .of_match_table = mtk_snfi_id_table,
++      },
++      .probe          = mtk_snfi_probe,
++      .remove         = mtk_snfi_remove,
++      .suspend        = mtk_snfi_suspend,
++      .resume         = mtk_snfi_resume,
++};
++
++module_platform_driver(mtk_snfi_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Xiangsheng Hou <xiangsheng.hou@mediatek.com>");
++MODULE_DESCRIPTION("Mediatek SPI Memory Interface Driver");
diff --git a/target/linux/mediatek/patches-5.4/0307-dts-mt7629-add-snand-support.patch b/target/linux/mediatek/patches-5.4/0307-dts-mt7629-add-snand-support.patch
new file mode 100644 (file)
index 0000000..2775563
--- /dev/null
@@ -0,0 +1,97 @@
+From c813fbe806257c574240770ef716fbee19f7dbfa Mon Sep 17 00:00:00 2001
+From: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
+Date: Thu, 6 Jun 2019 16:29:04 +0800
+Subject: [PATCH] spi: spi-mem: Mediatek: Add SPI Nand support for MT7629
+
+Signed-off-by: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
+---
+ arch/arm/boot/dts/mt7629-rfb.dts | 45 ++++++++++++++++++++++++++++++++
+ arch/arm/boot/dts/mt7629.dtsi    | 22 ++++++++++++++++
+ 3 files changed, 79 insertions(+)
+
+--- a/arch/arm/boot/dts/mt7629.dtsi
++++ b/arch/arm/boot/dts/mt7629.dtsi
+@@ -259,6 +259,28 @@
+                       status = "disabled";
+               };
++              bch: ecc@1100e000 {
++                      compatible = "mediatek,mt7622-ecc";
++                      reg = <0x1100e000 0x1000>;
++                      interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_LOW>;
++                      clocks = <&pericfg CLK_PERI_NFIECC_PD>;
++                      clock-names = "nfiecc_clk";
++                      status = "disabled";
++              };
++
++              snfi: spi@1100d000 {
++                      compatible = "mediatek,mt7629-snfi";
++                      reg = <0x1100d000 0x1000>;
++                      interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>;
++                      clocks = <&pericfg CLK_PERI_NFI_PD>,
++                               <&pericfg CLK_PERI_SNFI_PD>;
++                      clock-names = "nfi_clk", "spi_clk";
++                      ecc-engine = <&bch>;
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      status = "disabled";
++              };
++
+               spi: spi@1100a000 {
+                       compatible = "mediatek,mt7629-spi",
+                                    "mediatek,mt7622-spi";
+--- a/arch/arm/boot/dts/mt7629-rfb.dts
++++ b/arch/arm/boot/dts/mt7629-rfb.dts
+@@ -281,6 +281,52 @@
+       };
+ };
++&bch {
++      status = "okay";
++};
++
++&snfi {
++      pinctrl-names = "default";
++      pinctrl-0 = <&serial_nand_pins>;
++      status = "okay";
++
++      spi_nand@0 {
++              #address-cells = <1>;
++              #size-cells = <1>;
++              compatible = "spi-nand";
++              spi-max-frequency = <104000000>;
++              reg = <0>;
++
++              partitions {
++              compatible = "fixed-partitions";
++              #address-cells = <1>;
++              #size-cells = <1>;
++
++              partition@0 {
++                      label = "Bootloader";
++                      reg = <0x00000 0x0100000>;
++                      read-only;
++              };
++
++              partition@100000 {
++                      label = "Config";
++                      reg = <0x100000 0x0040000>;
++              };
++
++              partition@140000 {
++                      label = "factory";
++                      reg = <0x140000 0x0080000>;
++              };
++
++              partition@1c0000 {
++                      label = "firmware";
++                      reg = <0x1c0000 0x1000000>;
++              };
++
++              };
++      };
++};
++
+ &spi {
+       pinctrl-names = "default";
+       pinctrl-0 = <&spi_pins>;
diff --git a/target/linux/mediatek/patches-5.4/0308-dts-mt7622-add-snand-support.patch b/target/linux/mediatek/patches-5.4/0308-dts-mt7622-add-snand-support.patch
new file mode 100644 (file)
index 0000000..7c135cf
--- /dev/null
@@ -0,0 +1,98 @@
+diff -urN a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
+--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi 2020-03-02 17:16:13.700464470 +0800
++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi 2020-03-02 17:15:55.276885406 +0800
+@@ -554,6 +554,19 @@
+               status = "disabled";
+       };
++      snfi: spi@1100d000 {
++              compatible = "mediatek,mt7622-snfi";
++              reg = <0 0x1100d000 0 0x1000>;
++              interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>;
++              clocks = <&pericfg CLK_PERI_NFI_PD>,
++                       <&pericfg CLK_PERI_SNFI_PD>;
++              clock-names = "nfi_clk", "spi_clk";
++              ecc-engine = <&bch>;
++              #address-cells = <1>;
++              #size-cells = <0>;
++              status = "disabled";
++      };
++
+       nor_flash: spi@11014000 {
+               compatible = "mediatek,mt7622-nor",
+                            "mediatek,mt8173-nor";
+diff -urN a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
+--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts     2020-03-02 17:16:25.492193459 +0800
++++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts     2020-03-02 17:16:35.243968416 +0800
+@@ -108,7 +108,7 @@
+ };
+ &bch {
+-      status = "disabled";
++      status = "okay";
+ };
+ &btif {
+@@ -541,6 +541,62 @@
+       status = "disable";
+ };
++&snfi {
++      pinctrl-names = "default";
++      pinctrl-0 = <&serial_nand_pins>;
++      status = "okay";
++
++      spi_nand@0 {
++              #address-cells = <1>;
++              #size-cells = <1>;
++              compatible = "spi-nand";
++              spi-max-frequency = <104000000>;
++              reg = <0>;
++
++              partitions {
++                      compatible = "fixed-partitions";
++                      #address-cells = <1>;
++                      #size-cells = <1>;
++
++                      partition@0 {
++                              label = "Preloader";
++                              reg = <0x00000 0x0080000>;
++                              read-only;
++                      };
++
++                      partition@80000 {
++                              label = "ATF";
++                              reg = <0x80000 0x0040000>;
++                      };
++
++                      partition@c0000 {
++                              label = "Bootloader";
++                              reg = <0xc0000 0x0080000>;
++                      };
++
++                      partition@140000 {
++                              label = "Config";
++                              reg = <0x140000 0x0080000>;
++                      };
++
++                      partition@1c0000 {
++                              label = "Factory";
++                              reg = <0x1c0000 0x0040000>;
++                      };
++
++                      partition@200000 {
++                              label = "firmware";
++                              reg = <0x200000 0x2000000>;
++                      };
++
++                      partition@2200000 {
++                              label = "User_data";
++                              reg = <0x2200000 0x4000000>;
++                      };
++              };
++      };
++};
++
+ &spi0 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&spic0_pins>;
diff --git a/target/linux/mediatek/patches-5.4/0310-dts-add-wmac-support-for-mt7622-rfb1.patch b/target/linux/mediatek/patches-5.4/0310-dts-add-wmac-support-for-mt7622-rfb1.patch
new file mode 100644 (file)
index 0000000..463602e
--- /dev/null
@@ -0,0 +1,32 @@
+diff --git a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
+index 1ec68de..44cc80c 100644
+--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
+@@ -105,6 +105,18 @@
+               regulator-boot-on;
+               regulator-always-on;
+       };
++
++      wmac: wmac@18000000 {
++              compatible = "mediatek,mt7622-wmac";
++              reg = <0 0x18000000 0 0x100000>;
++              interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_LOW>;
++
++              mediatek,infracfg = <&infracfg>;
++              status = "okay";
++
++              power-domains = <&scpsys MT7622_POWER_DOMAIN_WB>;
++              mediatek,mtd-eeprom = <&factory 0x0000>;
++      };
+ };
+ &bch {
+@@ -579,7 +591,7 @@
+                               reg = <0x140000 0x0080000>;
+                       };
+-                      partition@1c0000 {
++                      factory: partition@1c0000 {
+                               label = "Factory";
+                               reg = <0x1c0000 0x0040000>;
+                       };