blob: 86421597b703abf057e5d8f0beae5cc26b491984 [file] [log] [blame]
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, &param, 1);
-+ param |= die_sel;
-+ nand->set_feature(nand, dev->feature.character.addr, &param, 1);
-+ param = 0;
-+ nand->get_feature(nand, dev->feature.character.addr, &param, 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, &param, 1);
-+ param |= BIT(dev->feature.config.otp_en_bit);
-+ nand->set_feature(nand, dev->feature.config.addr, &param, 1);
-+
-+ param = 0;
-+ nand->get_feature(nand, dev->feature.config.addr, &param, 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, &param, 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,