mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 0/4] NXP IFC nand driver
@ 2021-07-28 12:47 Renaud Barbier
  2021-07-28 12:47 ` [PATCH 1/4] ARM: atomic.h: add 64-bit counter support Renaud Barbier
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Renaud Barbier @ 2021-07-28 12:47 UTC (permalink / raw)
  To: barebox; +Cc: Renaud Barbier

These patches add the NXP IFC nand driver and enables it for the
Layescape SOC. Tested on the ls1046ardb evaluation board with UBI/UBIFS.

The driver makes use of the ls10146ardb DTS to probe the device.
Originally, adapted for our NXP P1014 based platforms(not upstream), it
allows to pass the chip select number using platform data.

Additional I/O operations and atomic 64-bit counters are added to support
the 64-bit platform, driver and UBIFS.

Renaud Barbier (4):
  ARM: atomic.h: add 64-bit counter support
  arm: 64-bit device specific operation
  nand: add NXP IFC nand driver
  ls1046ardb: enable IFC NAND.

 arch/arm/boards/ls1046ardb/board.c            |   26 +
 arch/arm/configs/layerscape_defconfig         |   12 +
 arch/arm/lib64/Makefile                       |    2 +-
 arch/arm/lib64/io.c                           |   98 ++
 .../mach-layerscape/include/mach/fsl_ifc.h    |   16 +
 .../mach-layerscape/include/mach/layerscape.h |    3 +
 drivers/mtd/nand/Kconfig                      |    6 +
 drivers/mtd/nand/Makefile                     |    1 +
 drivers/mtd/nand/fsl_ifc.h                    |  116 ++
 drivers/mtd/nand/nand_fsl_ifc.c               | 1037 +++++++++++++++++
 include/asm-generic/atomic-long.h             |    3 +-
 include/asm-generic/atomic.h                  |   49 +
 include/linux/fsl_ifc.h                       |  306 +++++
 13 files changed, 1673 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm/lib64/io.c
 create mode 100644 arch/arm/mach-layerscape/include/mach/fsl_ifc.h
 create mode 100644 drivers/mtd/nand/fsl_ifc.h
 create mode 100644 drivers/mtd/nand/nand_fsl_ifc.c
 create mode 100644 include/linux/fsl_ifc.h

-- 
2.27.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/4] ARM: atomic.h: add 64-bit counter support
  2021-07-28 12:47 [PATCH 0/4] NXP IFC nand driver Renaud Barbier
@ 2021-07-28 12:47 ` Renaud Barbier
  2021-07-29  9:58   ` Ahmad Fatoum
  2021-07-28 12:47 ` [PATCH 2/4] arm: 64-bit device specific operation Renaud Barbier
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 10+ messages in thread
From: Renaud Barbier @ 2021-07-28 12:47 UTC (permalink / raw)
  To: barebox; +Cc: Renaud Barbier

In preparation for the introduction of the FSL IFC nand driver
for the layerscape CPU, add 64-bit counter support.

Signed-off-by: Renaud Barbier <renaud.barbier@abaco.com>
---
 include/asm-generic/atomic-long.h |  3 +-
 include/asm-generic/atomic.h      | 49 +++++++++++++++++++++++++++++++
 2 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/include/asm-generic/atomic-long.h b/include/asm-generic/atomic-long.h
index 322d510f38..dbb503e758 100644
--- a/include/asm-generic/atomic-long.h
+++ b/include/asm-generic/atomic-long.h
@@ -65,7 +65,7 @@ static inline void atomic_long_sub(long i, atomic_long_t *l)
 
 	atomic64_sub(i, v);
 }
-
+#if 0
 static inline int atomic_long_sub_and_test(long i, atomic_long_t *l)
 {
 	atomic64_t *v = (atomic64_t *)l;
@@ -128,6 +128,7 @@ static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u)
 
 	return (long)atomic64_add_unless(v, a, u);
 }
+#endif
 
 #define atomic_long_inc_not_zero(l) atomic64_inc_not_zero((atomic64_t *)(l))
 
diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h
index 449cecaabc..6e63b8e8e7 100644
--- a/include/asm-generic/atomic.h
+++ b/include/asm-generic/atomic.h
@@ -11,7 +11,55 @@
 #ifdef CONFIG_SMP
 #error SMP not supported
 #endif
+#define ATOMIC_INIT(i)	{ (i) }
+
+#ifdef CONFIG_64BIT
+typedef struct { s64 counter; } atomic64_t;
+
+#define atomic64_read(v)	((v)->counter)
+#define atomic64_set(v, i)	(((v)->counter) = (i))
+
+static inline void atomic64_add(s64 i, volatile atomic64_t *v)
+{
+	v->counter += i;
+}
+
+static inline void atomic64_sub(s64 i, volatile atomic64_t *v)
+{
+	v->counter -= i;
+}
+
+static inline void atomic64_inc(volatile atomic64_t *v)
+{
+	v->counter += 1;
+}
+
+static inline void atomic64_dec(volatile atomic64_t *v)
+{
+	v->counter -= 1;
+}
+
+static inline int atomic64_dec_and_test(volatile atomic64_t *v)
+{
+	s64 val;
+
+	val = v->counter;
+	v->counter = val -= 1;
+
+	return val == 0;
+}
 
+static inline int atomic64_add_negative(s64 i, volatile atomic64_t *v)
+{
+	s64 val;
+
+	val = v->counter;
+	v->counter = val += i;
+
+	return val < 0;
+}
+
+#else
 typedef struct { volatile int counter; } atomic_t;
 
 #define ATOMIC_INIT(i)	{ (i) }
@@ -63,6 +111,7 @@ static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
 {
 	*addr &= ~mask;
 }
+#endif
 
 /* Atomic operations are already serializing on ARM */
 #define smp_mb__before_atomic_dec()	barrier()
-- 
2.27.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 2/4] arm: 64-bit device specific operation
  2021-07-28 12:47 [PATCH 0/4] NXP IFC nand driver Renaud Barbier
  2021-07-28 12:47 ` [PATCH 1/4] ARM: atomic.h: add 64-bit counter support Renaud Barbier
@ 2021-07-28 12:47 ` Renaud Barbier
  2021-07-29 10:00   ` Ahmad Fatoum
  2021-07-28 12:47 ` [PATCH 3/4] nand: add NXP IFC nand driver Renaud Barbier
  2021-07-28 12:47 ` [PATCH 4/4] ls1046ardb: enable IFC NAND Renaud Barbier
  3 siblings, 1 reply; 10+ messages in thread
From: Renaud Barbier @ 2021-07-28 12:47 UTC (permalink / raw)
  To: barebox; +Cc: Renaud Barbier

In preparation for the introduction of the NXP FSL IFC
nand driver, add memcpy_ directional I/O operation.

Code based on NXP Linux support:
git://source.codeaurora.org/external/qoriq/qoriq-components/linux

Signed-off-by: Renaud Barbier <renaud.barbier@abaco.com>
---
 arch/arm/lib64/Makefile |  2 +-
 arch/arm/lib64/io.c     | 98 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 99 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/lib64/io.c

diff --git a/arch/arm/lib64/Makefile b/arch/arm/lib64/Makefile
index 69cb3d8ea1..591727c160 100644
--- a/arch/arm/lib64/Makefile
+++ b/arch/arm/lib64/Makefile
@@ -1,4 +1,4 @@
-obj-y += stacktrace.o
+obj-y += stacktrace.o io.o
 obj-$(CONFIG_ARM_LINUX)	+= armlinux.o
 obj-y	+= div0.o
 obj-$(CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS)	+= memcpy.o
diff --git a/arch/arm/lib64/io.c b/arch/arm/lib64/io.c
new file mode 100644
index 0000000000..693cda42b0
--- /dev/null
+++ b/arch/arm/lib64/io.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Based on arch/arm/kernel/io.c
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ */
+
+#include <module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <io.h>
+
+/*
+ * Copy data from IO memory space to "real" memory space.
+ */
+void memcpy_fromio(void *to, const volatile void __iomem *from, size_t count)
+{
+	while (count && !IS_ALIGNED((unsigned long)from, 8)) {
+		*(u8 *)to = __raw_readb(from);
+		from++;
+		to++;
+		count--;
+	}
+
+	while (count >= 8) {
+		*(u64 *)to = __raw_readq(from);
+		from += 8;
+		to += 8;
+		count -= 8;
+	}
+
+	while (count) {
+		*(u8 *)to = __raw_readb(from);
+		from++;
+		to++;
+		count--;
+	}
+}
+EXPORT_SYMBOL(memcpy_fromio);
+
+/*
+ * Copy data from "real" memory space to IO memory space.
+ */
+void memcpy_toio(volatile void __iomem *to, const void *from, size_t count)
+{
+	while (count && !IS_ALIGNED((unsigned long)to, 8)) {
+		__raw_writeb(*(u8 *)from, to);
+		from++;
+		to++;
+		count--;
+	}
+
+	while (count >= 8) {
+		__raw_writeq(*(u64 *)from, to);
+		from += 8;
+		to += 8;
+		count -= 8;
+	}
+
+	while (count) {
+		__raw_writeb(*(u8 *)from, to);
+		from++;
+		to++;
+		count--;
+	}
+}
+EXPORT_SYMBOL(memcpy_toio);
+
+/*
+ * "memset" on IO memory space.
+ */
+void memset_io(volatile void __iomem *dst, int c, size_t count)
+{
+	u64 qc = (u8)c;
+
+	qc |= qc << 8;
+	qc |= qc << 16;
+	qc |= qc << 32;
+
+	while (count && !IS_ALIGNED((unsigned long)dst, 8)) {
+		__raw_writeb(c, dst);
+		dst++;
+		count--;
+	}
+
+	while (count >= 8) {
+		__raw_writeq(qc, dst);
+		dst += 8;
+		count -= 8;
+	}
+
+	while (count) {
+		__raw_writeb(c, dst);
+		dst++;
+		count--;
+	}
+}
+EXPORT_SYMBOL(memset_io);
-- 
2.27.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 3/4] nand: add NXP IFC nand driver
  2021-07-28 12:47 [PATCH 0/4] NXP IFC nand driver Renaud Barbier
  2021-07-28 12:47 ` [PATCH 1/4] ARM: atomic.h: add 64-bit counter support Renaud Barbier
  2021-07-28 12:47 ` [PATCH 2/4] arm: 64-bit device specific operation Renaud Barbier
@ 2021-07-28 12:47 ` Renaud Barbier
  2021-07-29 10:11   ` Ahmad Fatoum
  2021-07-28 12:47 ` [PATCH 4/4] ls1046ardb: enable IFC NAND Renaud Barbier
  3 siblings, 1 reply; 10+ messages in thread
From: Renaud Barbier @ 2021-07-28 12:47 UTC (permalink / raw)
  To: barebox; +Cc: Renaud Barbier

Add the NXP IFC nand driver support. This driver
can be used with the NXP QorIQ cores.

Signed-off-by: Renaud Barbier <renaud.barbier@abaco.com>
---
 .../mach-layerscape/include/mach/fsl_ifc.h    |   16 +
 .../mach-layerscape/include/mach/layerscape.h |    3 +
 drivers/mtd/nand/Kconfig                      |    6 +
 drivers/mtd/nand/Makefile                     |    1 +
 drivers/mtd/nand/fsl_ifc.h                    |  116 ++
 drivers/mtd/nand/nand_fsl_ifc.c               | 1037 +++++++++++++++++
 include/linux/fsl_ifc.h                       |  306 +++++
 7 files changed, 1485 insertions(+)
 create mode 100644 arch/arm/mach-layerscape/include/mach/fsl_ifc.h
 create mode 100644 drivers/mtd/nand/fsl_ifc.h
 create mode 100644 drivers/mtd/nand/nand_fsl_ifc.c
 create mode 100644 include/linux/fsl_ifc.h

diff --git a/arch/arm/mach-layerscape/include/mach/fsl_ifc.h b/arch/arm/mach-layerscape/include/mach/fsl_ifc.h
new file mode 100644
index 0000000000..385d07cb1f
--- /dev/null
+++ b/arch/arm/mach-layerscape/include/mach/fsl_ifc.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier:     GPL-2.0+ */
+/*
+ * Copyright 2021 Abaco Systems, Inc
+ */
+
+#ifndef __MACH_MTD_FSL_IFC
+#define __MACH_MTD_FSL_IFC
+
+#include <mach/layerscape.h>
+#include <linux/fsl_ifc.h>
+
+
+struct fsl_ifc_data {
+	uint32_t cs;
+};
+#endif
diff --git a/arch/arm/mach-layerscape/include/mach/layerscape.h b/arch/arm/mach-layerscape/include/mach/layerscape.h
index 1f1da0f66e..cb7bbc56b0 100644
--- a/arch/arm/mach-layerscape/include/mach/layerscape.h
+++ b/arch/arm/mach-layerscape/include/mach/layerscape.h
@@ -3,6 +3,9 @@
 
 #define LS1046A_DDR_SDRAM_BASE	0x80000000
 #define LS1046A_DDR_FREQ	2100000000
+#define LS10146A_IFC_ADDR	0x01530000
+
+#define IFC_ADDR	LS10146A_IFC_ADDR
 
 enum bootsource ls1046_bootsource_get(void);
 
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index c69e5ce4e1..046b4f9e8f 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -42,6 +42,12 @@ config NAND_IMX
 	  and later, which use the GPMI NAND controller from the MXS series. 
 	  See the i.MX 'mxs' driver for those chips.
 
+config NAND_FSL_IFC
+    bool
+    select MTD_NAND_ECC_SOFT if ARCH_MPC85XX
+    prompt "FSL IFC NAND driver"
+    depends on ARCH_MPC85XX || ARCH_LAYERSCAPE
+
 config NAND_MXS
 	bool
 	select STMP_DEVICE
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index f6e5b41e94..4fd14ddd63 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -22,3 +22,4 @@ pbl-$(CONFIG_NAND_S3C24XX)		+= nand_s3c24xx.o
 obj-$(CONFIG_NAND_MXS)			+= nand_mxs.o
 obj-$(CONFIG_MTD_NAND_DENALI)		+= nand_denali.o
 obj-$(CONFIG_MTD_NAND_DENALI_DT)	+= nand_denali_dt.o
+obj-$(CONFIG_NAND_FSL_IFC)		+= nand_fsl_ifc.o
diff --git a/drivers/mtd/nand/fsl_ifc.h b/drivers/mtd/nand/fsl_ifc.h
new file mode 100644
index 0000000000..4c89f569f5
--- /dev/null
+++ b/drivers/mtd/nand/fsl_ifc.h
@@ -0,0 +1,116 @@
+/* SPDX-License-Identifier:     GPL-2.0+ */
+/*
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ *
+ */
+
+/*
+ * The actual number of banks implemented depends on the IFC version
+ *    - IFC version 1.0 implements 4 banks.
+ *    - IFC version 1.1 onward implements 8 banks.
+ */
+#define FSL_IFC_BANK_COUNT 8
+
+#define FSL_IFC_REV		0x0000
+#define		FSL_IFC_V1_1_0	0x01010000
+#define		FSL_IFC_V2_0_0	0x02000000
+
+/*
+ * Version 1.1.0 adds offset 0x1000
+ * Version 2.0.0 adds offset 0x10000
+ */
+#define FSL_IFC_NCFGR		0x000
+
+#define		IFC_NAND_SRAM_INIT_EN           0x20000000
+
+/*
+ * NAND Flash Command Registers (NAND_FCR0/NAND_FCR1)
+ */
+#define FSL_IFC_FCR0		0x014
+/* General purpose FCM flash command bytes CMD0-CMD7 */
+#define		IFC_NAND_FCR0_CMD0_SHIFT	24
+#define		IFC_NAND_FCR0_CMD1_SHIFT	16
+#define		IFC_NAND_FCR0_CMD2_SHIFT	8
+#define		IFC_NAND_FCR0_CMD3_SHIFT	0
+#define FSL_IFC_ROW0		0x03c
+#define		IFC_NAND_COL_MS			0x80000000
+#define FSL_IFC_COL0		0x044
+#define FSL_IFC_ROW3		0x06c
+#define FSL_IFC_NAND_BC		0x108
+/*
+ * NAND Flash Instruction Registers (NAND_FIR0/NAND_FIR1/NAND_FIR2)
+ */
+#define FSL_IFC_FIR0		0x110
+/* NAND Machine specific opcodes OP0-OP14*/
+#define		IFC_NAND_FIR0_OP0_SHIFT		26
+#define		IFC_NAND_FIR0_OP1_SHIFT		20
+#define		IFC_NAND_FIR0_OP2_SHIFT		14
+#define		IFC_NAND_FIR0_OP3_SHIFT		8
+#define		IFC_NAND_FIR0_OP4_SHIFT		2
+#define FSL_IFC_FIR1		0x114
+#define		IFC_NAND_FIR1_OP5_SHIFT		26
+#define		IFC_NAND_FIR1_OP6_SHIFT		20
+#define		IFC_NAND_FIR1_OP7_SHIFT		14
+#define		IFC_NAND_FIR1_OP8_SHIFT		8
+#define FSL_IFC_NAND_CSEL	0x15c
+#define		IFC_NAND_CSEL_SHIFT		26
+#define FSL_IFC_NANDSEQ_STRT	0x164
+#define		IFC_NAND_SEQ_STRT_FIR_STRT	0x80000000
+/* NAND Event and Error Status Register */
+#define FSL_IFC_NAND_EVTER_STAT	0x16c
+#define		IFC_NAND_EVTER_STAT_OPC		0x80000000
+#define		IFC_NAND_EVTER_STAT_FTOER	0x08000000
+#define		IFC_NAND_EVTER_STAT_WPER	0x04000000
+/* NAND Flash Page Read Completion Event Status Register */
+#define FSL_IFC_PGRDCMPL_EVT_STAT 0x174
+/* NAND Event and Error Enable Register (NAND_EVTER_EN) */
+#define FSL_IFC_EVTER_EN	0x180
+#define		IFC_NAND_EVTER_EN_OPC_EN	0x80000000
+#define		IFC_NAND_EVTER_EN_PGRDCMPL_EN	0x20000000
+#define		IFC_NAND_EVTER_EN_FTOER_EN	0x08000000
+#define		IFC_NAND_EVTER_EN_WPER_EN	0x04000000
+
+#define FSL_IFC_NAND_FSR	0x1e0
+#define FSL_IFC_ECCSTAT(v)	(0x1e8 + (4 * v))
+#define		IFC_NAND_EVTER_STAT_ECCER	0x02000000
+
+/*
+ * Instruction opcodes to be programmed
+ * in FIR registers- 6bits
+ */
+enum ifc_nand_fir_opcodes {
+	IFC_FIR_OP_NOP,
+	IFC_FIR_OP_CA0,
+	IFC_FIR_OP_CA1,
+	IFC_FIR_OP_CA2,
+	IFC_FIR_OP_CA3,
+	IFC_FIR_OP_RA0,
+	IFC_FIR_OP_RA1,
+	IFC_FIR_OP_RA2,
+	IFC_FIR_OP_RA3,
+	IFC_FIR_OP_CMD0,
+	IFC_FIR_OP_CMD1,
+	IFC_FIR_OP_CMD2,
+	IFC_FIR_OP_CMD3,
+	IFC_FIR_OP_CMD4,
+	IFC_FIR_OP_CMD5,
+	IFC_FIR_OP_CMD6,
+	IFC_FIR_OP_CMD7,
+	IFC_FIR_OP_CW0,
+	IFC_FIR_OP_CW1,
+	IFC_FIR_OP_CW2,
+	IFC_FIR_OP_CW3,
+	IFC_FIR_OP_CW4,
+	IFC_FIR_OP_CW5,
+	IFC_FIR_OP_CW6,
+	IFC_FIR_OP_CW7,
+	IFC_FIR_OP_WBCD,
+	IFC_FIR_OP_RBCD,
+	IFC_FIR_OP_BTRD,
+	IFC_FIR_OP_RDSTAT,
+	IFC_FIR_OP_NWAIT,
+	IFC_FIR_OP_WFR,
+	IFC_FIR_OP_SBRD,
+	IFC_FIR_OP_UA,
+	IFC_FIR_OP_RB,
+};
diff --git a/drivers/mtd/nand/nand_fsl_ifc.c b/drivers/mtd/nand/nand_fsl_ifc.c
new file mode 100644
index 0000000000..c29fd919e7
--- /dev/null
+++ b/drivers/mtd/nand/nand_fsl_ifc.c
@@ -0,0 +1,1037 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Integrated Flash Controller NAND Machine Driver
+ *
+ * Copyright (c) 2012 Freescale Semiconductor, Inc
+ *
+ * Authors: Dipen Dudhat <Dipen.Dudhat@freescale.com>
+ *
+ */
+
+#include <config.h>
+#include <common.h>
+#include <driver.h>
+#include <init.h>
+#include <malloc.h>
+#include <nand.h>
+#include <errno.h>
+#include <clock.h>
+#include <io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <mach/fsl_ifc.h>
+#include <asm-generic/io.h>
+#include "fsl_ifc.h"
+
+#define ERR_BYTE	0xFF
+#define IFC_TIMEOUT_MS	500
+/* overview of the fsl ifc controller */
+struct fsl_ifc_ctrl {
+	struct nand_controller controller;
+	/* device info */
+	void __iomem *rregs;  /* Run-time register		      */
+	void __iomem *gregs;  /* Global registers		      */
+	uint32_t version;
+	uint32_t page;       /* Last page written to / read from      */
+	uint32_t read_bytes; /* Number of bytes read during command   */
+	uint32_t column;     /* Saved column from SEQIN               */
+	uint32_t index;      /* Pointer to next byte to 'read'        */
+	uint32_t nand_stat;  /* status read from NEESR after last op  */
+	uint32_t oob;        /* Non zero if operating on OOB data     */
+	uint32_t eccread;    /* Non zero for a full-page ECC read     */
+	uint32_t max_bitflips; /* Saved during READ0 cmd              */
+	void __iomem *addr;  /* Address of assigned IFC buffer        */
+};
+
+/* mtd information per set */
+struct fsl_ifc_mtd {
+	struct device_d *dev;
+	struct nand_chip chip;
+	struct fsl_ifc_ctrl *ctrl;
+	uint32_t cs;		/* On which chipsel NAND is connected    */
+	uint32_t bufnum_mask;	/* bufnum = page & bufnum_mask */
+	void __iomem *vbase;    /* Chip select base virtual address     */
+	phys_addr_t pbase;	/* Chip select physical address		*/
+};
+
+static struct fsl_ifc_ctrl *ifc_ctrl;
+
+/* Generic flash bbt descriptors */
+static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
+static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
+
+static struct nand_bbt_descr bbt_main_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
+		   NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.offs =	2, /* 0 on 8-bit small page */
+	.len = 4,
+	.veroffs = 6,
+	.maxblocks = 4,
+	.pattern = bbt_pattern,
+};
+
+static struct nand_bbt_descr bbt_mirror_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
+		   NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.offs =	2, /* 0 on 8-bit small page */
+	.len = 4,
+	.veroffs = 6,
+	.maxblocks = 4,
+	.pattern = mirror_pattern,
+};
+
+static int fsl_ifc_ooblayout_ecc(struct mtd_info *mtd, int section,
+		struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = 8;
+	oobregion->length = chip->ecc.total;
+
+	return 0;
+}
+
+static int fsl_ifc_ooblayout_free(struct mtd_info *mtd, int section,
+		struct mtd_oob_region *oobregion)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section > 1)
+		return -ERANGE;
+
+	if (mtd->writesize == 512 && !(chip->options & NAND_BUSWIDTH_16)) {
+		if (!section) {
+			oobregion->offset = 0;
+			oobregion->length = 5;
+		} else {
+			oobregion->offset = 6;
+			oobregion->length = 2;
+		}
+
+		return 0;
+	}
+
+	if (!section) {
+		oobregion->offset = 2;
+		oobregion->length = 6;
+	} else {
+		oobregion->offset = chip->ecc.total + 8;
+		oobregion->length = mtd->oobsize - oobregion->offset;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops fsl_ifc_ooblayout_ops = {
+	.ecc = fsl_ifc_ooblayout_ecc,
+	.free = fsl_ifc_ooblayout_free,
+};
+
+/*
+ * Set up the IFC hardware block and page address fields, and the ifc nand
+ * structure addr field to point to the correct IFC buffer in memory
+ */
+static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct fsl_ifc_mtd *priv = chip->priv;
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	int buf_num;
+
+	if (page_addr != -1) {
+		ctrl->page = page_addr;
+		/* Program ROW0/COL0 */
+		ifc_out32(ctrl->rregs + FSL_IFC_ROW0, page_addr);
+		buf_num = page_addr & priv->bufnum_mask;
+		ctrl->addr = priv->vbase + buf_num * (mtd->writesize * 2);
+	}
+
+	ifc_out32(ctrl->rregs + FSL_IFC_COL0, (oob ? IFC_NAND_COL_MS : 0) |
+						column);
+	ctrl->index = column;
+
+	/* for OOB data point to the second half of the buffer */
+	if (oob)
+		ctrl->index += mtd->writesize;
+}
+
+/* returns nonzero if entire page is blank */
+static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl,
+			  uint32_t eccstat, uint32_t bufnum)
+{
+	return (eccstat >> ((3 - bufnum % 4) * 8)) & 15;
+}
+
+/* execute IFC NAND command and wait for it to complete */
+static void fsl_ifc_run_command(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct fsl_ifc_mtd *priv = chip->priv;
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	uint64_t time_start;
+	uint32_t eccstat;
+	int i;
+
+	/* set the chip select for NAND Transaction */
+	ifc_out32(ctrl->rregs + FSL_IFC_NAND_CSEL,
+			priv->cs << IFC_NAND_CSEL_SHIFT);
+
+	/* start read/write seq */
+	ifc_out32(ctrl->rregs + FSL_IFC_NANDSEQ_STRT,
+			IFC_NAND_SEQ_STRT_FIR_STRT);
+
+	ctrl->nand_stat = 0;
+
+	/* wait for NAND Machine complete flag or timeout */
+	time_start = get_time_ns();
+	while (!is_timeout(time_start, IFC_TIMEOUT_MS * MSECOND)) {
+		ctrl->nand_stat = ifc_in32(ctrl->rregs + FSL_IFC_NAND_EVTER_STAT);
+
+		if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_OPC)
+			break;
+	}
+
+	ifc_out32(ctrl->rregs + FSL_IFC_NAND_EVTER_STAT, ctrl->nand_stat);
+
+	if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_FTOER)
+		pr_err("%s: Flash Time Out Error\n", __func__);
+	if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_WPER)
+		pr_err("%s: Write Protect Error\n", __func__);
+
+	ctrl->max_bitflips = 0;
+
+	if (ctrl->eccread) {
+		int errors;
+		int bufnum = ctrl->page & priv->bufnum_mask;
+		int sector_start = bufnum * chip->ecc.steps;
+		int sector_end = sector_start + chip->ecc.steps - 1;
+
+		eccstat = ifc_in32(ctrl->rregs +
+				FSL_IFC_ECCSTAT(sector_start / 4));
+
+		for (i = sector_start; i <= sector_end; i++) {
+			if ((i != sector_start) && !(i % 4)) {
+				eccstat = ifc_in32(ctrl->rregs +
+						FSL_IFC_ECCSTAT(i / 4));
+			}
+			errors = check_read_ecc(mtd, ctrl, eccstat, i);
+
+			if (errors == 15) {
+				/*
+				 * Uncorrectable error.
+				 * We'll check for blank pages later.
+				 *
+				 * We disable ECCER reporting due to erratum
+				 * IFC-A002770 -- so report it now if we
+				 * see an uncorrectable error in ECCSTAT.
+				 */
+				ctrl->nand_stat |= IFC_NAND_EVTER_STAT_ECCER;
+				continue;
+			}
+
+			mtd->ecc_stats.corrected += errors;
+			ctrl->max_bitflips = max_t(unsigned int,
+					ctrl->max_bitflips, errors);
+		}
+
+		ctrl->eccread = 0;
+	}
+}
+
+static void
+fsl_ifc_do_read(struct nand_chip *chip, int oob, struct mtd_info *mtd)
+{
+	struct fsl_ifc_mtd *priv = chip->priv;
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+
+	/* Program FIR/IFC_NAND_FCR0 for Small/Large page */
+	if (mtd->writesize > 512) {
+		ifc_out32(ctrl->rregs + FSL_IFC_FIR0,
+			  (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+			  (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+			  (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+			  (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) |
+			  (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP4_SHIFT));
+		ifc_out32(ctrl->rregs + FSL_IFC_FIR1, 0x0);
+
+		ifc_out32(ctrl->rregs + FSL_IFC_FCR0,
+			  (NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) |
+			  (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT));
+	} else {
+		ifc_out32(ctrl->rregs + FSL_IFC_FIR0,
+			  (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+			  (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+			  (IFC_FIR_OP_RA0  << IFC_NAND_FIR0_OP2_SHIFT) |
+			  (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP3_SHIFT));
+		ifc_out32(ctrl->rregs + FSL_IFC_FIR1, 0);
+
+		if (oob)
+			ifc_out32(ctrl->rregs + FSL_IFC_FCR0,
+				  NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT);
+		else
+			ifc_out32(ctrl->rregs + FSL_IFC_FCR0,
+				  NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT);
+	}
+}
+
+/* cmdfunc send commands to the IFC NAND Machine */
+static void fsl_ifc_cmdfunc(struct nand_chip *chip, uint32_t command,
+			     int column, int page_addr)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct fsl_ifc_mtd *priv = chip->priv;
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+
+	/* clear the read buffer */
+	ctrl->read_bytes = 0;
+	if (command != NAND_CMD_PAGEPROG)
+		ctrl->index = 0;
+
+	switch (command) {
+	/* READ0 read the entire buffer to use hardware ECC. */
+	case NAND_CMD_READ0: {
+		ifc_out32(ctrl->rregs + FSL_IFC_NAND_BC, 0);
+		set_addr(mtd, 0, page_addr, 0);
+
+		ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+		ctrl->index += column;
+
+		if (chip->ecc.mode == NAND_ECC_HW)
+			ctrl->eccread = 1;
+
+		fsl_ifc_do_read(chip, 0, mtd);
+		fsl_ifc_run_command(mtd);
+		return;
+	}
+
+	/* READOOB reads only the OOB because no ECC is performed. */
+	case NAND_CMD_READOOB:
+		ifc_out32(ctrl->rregs + FSL_IFC_NAND_BC, mtd->oobsize - column);
+
+		set_addr(mtd, column, page_addr, 1);
+
+		ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+
+		fsl_ifc_do_read(chip, 1, mtd);
+		fsl_ifc_run_command(mtd);
+
+		return;
+
+	case NAND_CMD_RNDOUT:
+		if (chip->ecc.mode == NAND_ECC_HW)
+			break;
+		ifc_out32(ctrl->rregs + FSL_IFC_NAND_BC, 0);
+		set_addr(mtd, column, -1, 0);
+		ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+
+		/* For write size greater than 512 */
+		ifc_out32(ctrl->rregs + FSL_IFC_FIR0,
+			(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+			(IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+			(IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP3_SHIFT));
+		ifc_out32(ctrl->rregs + FSL_IFC_FIR1, 0x0);
+
+		ifc_out32(ctrl->rregs + FSL_IFC_FCR0,
+			(NAND_CMD_RNDOUT << IFC_NAND_FCR0_CMD0_SHIFT) |
+			(NAND_CMD_RNDOUTSTART << IFC_NAND_FCR0_CMD1_SHIFT));
+
+		fsl_ifc_run_command(mtd);
+		return;
+
+	case NAND_CMD_READID:
+	case NAND_CMD_PARAM: {
+		int timing = IFC_FIR_OP_RB;
+		int len = 8;
+
+		if (command == NAND_CMD_PARAM) {
+			timing = IFC_FIR_OP_RBCD;
+			len = 256 * 3;
+		}
+
+		ifc_out32(ctrl->rregs + FSL_IFC_FIR0,
+			  (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+			  (IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
+			  (timing << IFC_NAND_FIR0_OP2_SHIFT));
+		ifc_out32(ctrl->rregs + FSL_IFC_FCR0,
+			  command << IFC_NAND_FCR0_CMD0_SHIFT);
+		ifc_out32(ctrl->rregs + FSL_IFC_ROW3, column);
+
+		/*
+		 * although currently it's 8 bytes for READID, we always read
+		 * the maximum 256 bytes(for PARAM)
+		 */
+		ifc_out32(ctrl->rregs + FSL_IFC_NAND_BC, len);
+		ctrl->read_bytes = len;
+
+		set_addr(mtd, 0, 0, 0);
+		fsl_ifc_run_command(mtd);
+		return;
+	}
+
+	/* ERASE1 stores the block and page address */
+	case NAND_CMD_ERASE1:
+		set_addr(mtd, 0, page_addr, 0);
+		return;
+
+	/* ERASE2 uses the block and page address from ERASE1 */
+	case NAND_CMD_ERASE2:
+		ifc_out32(ctrl->rregs + FSL_IFC_FIR0,
+			  (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+			  (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+			  (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP2_SHIFT));
+
+		ifc_out32(ctrl->rregs + FSL_IFC_FCR0,
+			  (NAND_CMD_ERASE1 << IFC_NAND_FCR0_CMD0_SHIFT) |
+			  (NAND_CMD_ERASE2 << IFC_NAND_FCR0_CMD1_SHIFT));
+
+		ifc_out32(ctrl->rregs + FSL_IFC_NAND_BC, 0);
+		ctrl->read_bytes = 0;
+		fsl_ifc_run_command(mtd);
+		return;
+
+	/* SEQIN sets up the addr buffer and all registers except the length */
+	case NAND_CMD_SEQIN: {
+		uint32_t nand_fcr0;
+
+		ctrl->column = column;
+		ctrl->oob = 0;
+
+		if (mtd->writesize > 512) {
+			nand_fcr0 =
+				(NAND_CMD_SEQIN << IFC_NAND_FCR0_CMD0_SHIFT) |
+				(NAND_CMD_STATUS << IFC_NAND_FCR0_CMD1_SHIFT) |
+				(NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD2_SHIFT);
+
+			ifc_out32(ctrl->rregs + FSL_IFC_FIR0,
+				  (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+				  (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+				  (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+				  (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP3_SHIFT) |
+				  (IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP4_SHIFT));
+			ifc_out32(ctrl->rregs + FSL_IFC_FIR1,
+				  (IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT) |
+				  (IFC_FIR_OP_RDSTAT <<
+					IFC_NAND_FIR1_OP6_SHIFT) |
+				  (IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP7_SHIFT));
+		} else {
+			nand_fcr0 = ((NAND_CMD_PAGEPROG <<
+					IFC_NAND_FCR0_CMD1_SHIFT) |
+				    (NAND_CMD_SEQIN <<
+					IFC_NAND_FCR0_CMD2_SHIFT) |
+				    (NAND_CMD_STATUS <<
+					IFC_NAND_FCR0_CMD3_SHIFT));
+
+			ifc_out32(ctrl->rregs + FSL_IFC_FIR0,
+				  (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+				  (IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP1_SHIFT) |
+				  (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+				  (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP3_SHIFT) |
+				  (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP4_SHIFT));
+			ifc_out32(ctrl->rregs + FSL_IFC_FIR1,
+				  (IFC_FIR_OP_CMD1 << IFC_NAND_FIR1_OP5_SHIFT) |
+				  (IFC_FIR_OP_CW3 << IFC_NAND_FIR1_OP6_SHIFT) |
+				  (IFC_FIR_OP_RDSTAT <<
+					IFC_NAND_FIR1_OP7_SHIFT) |
+				  (IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP8_SHIFT));
+
+			if (column >= mtd->writesize)
+				nand_fcr0 |=
+				NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT;
+			else
+				nand_fcr0 |=
+				NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT;
+		}
+
+		if (column >= mtd->writesize) {
+			/* OOB area --> READOOB */
+			column -= mtd->writesize;
+			ctrl->oob = 1;
+		}
+		ifc_out32(ctrl->rregs + FSL_IFC_FCR0, nand_fcr0);
+		set_addr(mtd, column, page_addr, ctrl->oob);
+		return;
+	}
+
+	/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
+	case NAND_CMD_PAGEPROG:
+		if (ctrl->oob)
+			ifc_out32(ctrl->rregs + FSL_IFC_NAND_BC,
+				  ctrl->index - ctrl->column);
+		else
+			ifc_out32(ctrl->rregs + FSL_IFC_NAND_BC, 0);
+
+		fsl_ifc_run_command(mtd);
+		return;
+
+	case NAND_CMD_STATUS:
+		ifc_out32(ctrl->rregs + FSL_IFC_FIR0,
+			  (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+			  (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP1_SHIFT));
+		ifc_out32(ctrl->rregs + FSL_IFC_FCR0,
+			  NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT);
+		ifc_out32(ctrl->rregs + FSL_IFC_NAND_BC, 1);
+		set_addr(mtd, 0, 0, 0);
+		ctrl->read_bytes = 1;
+
+		fsl_ifc_run_command(mtd);
+
+		/*
+		 * The chip always seems to report that it is
+		 * write-protected, even when it is not.
+		 */
+		if (chip->options & NAND_BUSWIDTH_16)
+			out_be16(ctrl->addr, in_be16(ctrl->addr) |
+					NAND_STATUS_WP);
+		else
+			out_8(ctrl->addr, in_8(ctrl->addr) | NAND_STATUS_WP);
+		return;
+
+	case NAND_CMD_RESET:
+		ifc_out32(ctrl->rregs + FSL_IFC_FIR0,
+			  IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT);
+		ifc_out32(ctrl->rregs + FSL_IFC_FCR0,
+			  NAND_CMD_RESET << IFC_NAND_FCR0_CMD0_SHIFT);
+		fsl_ifc_run_command(mtd);
+		return;
+
+	default:
+		pr_err("%s: error, unsupported command 0x%x.\n",
+			__func__, command);
+	}
+}
+
+/* Write buf to the IFC NAND Controller Data Buffer */
+static void fsl_ifc_write_buf(struct nand_chip *chip, const uint8_t *buf, int len)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct fsl_ifc_mtd *priv = chip->priv;
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	uint32_t bufsize = mtd->writesize + mtd->oobsize;
+
+	if (len <= 0) {
+		pr_info("%s of %d bytes", __func__, len);
+		ctrl->nand_stat = 0;
+		return;
+	}
+
+	if ((uint32_t)len > bufsize - ctrl->index) {
+		pr_err("%s beyond end of buffer (%d requested, %u available)\n",
+			__func__, len, bufsize - ctrl->index);
+		len = bufsize - ctrl->index;
+	}
+
+	memcpy_toio(ctrl->addr + ctrl->index, buf, len);
+	ctrl->index += len;
+}
+
+/*
+ * read a byte from either the IFC hardware buffer if it has any data left
+ * otherwise issue a command to read a single byte.
+ */
+static uint8_t fsl_ifc_read_byte(struct nand_chip *chip)
+{
+	struct fsl_ifc_mtd *priv = chip->priv;
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	uint32_t offset;
+
+	/*
+	 * If there are still bytes in the IFC buffer, then use the
+	 * next byte.
+	 */
+	if (ctrl->index < ctrl->read_bytes) {
+		offset = ctrl->index++;
+		return in_8(ctrl->addr + offset);
+	}
+
+	return ERR_BYTE;
+}
+
+/*
+ * Read two bytes from the IFC hardware buffer
+ * read function for 16-bit buswith
+ */
+static uint8_t fsl_ifc_read_byte16(struct nand_chip *chip)
+{
+	struct fsl_ifc_mtd *priv = chip->priv;
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	uint16_t data;
+
+	/*
+	 * If there are still bytes in the IFC buffer, then use the
+	 * next byte.
+	 */
+	if (ctrl->index < ctrl->read_bytes) {
+		data = ifc_in16(ctrl->addr + ctrl->index);
+		ctrl->index += 2;
+		return (uint8_t)data;
+	}
+
+	return ERR_BYTE;
+}
+
+/* Read from the IFC Controller Data Buffer */
+static void fsl_ifc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
+{
+	struct fsl_ifc_mtd *priv = chip->priv;
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	int avail;
+
+	if (len < 0)
+		return;
+
+	avail = min((uint32_t)len, ctrl->read_bytes - ctrl->index);
+	memcpy_fromio(buf, ctrl->addr + ctrl->index, avail);
+
+	ctrl->index += avail;
+
+	if (len > avail)
+		pr_err("%s beyond end of buffer (%d requested, %d available)\n",
+		       __func__, len, avail);
+}
+
+/* This function is called after Program and Erase Operations to
+ * check for success or failure.
+ */
+static int fsl_ifc_wait(struct nand_chip *chip)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct fsl_ifc_mtd *priv = chip->priv;
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	uint32_t nand_fsr;
+	int status;
+
+	/* Use READ_STATUS command, but wait for the device to be ready */
+	ifc_out32(ctrl->rregs + FSL_IFC_FIR0,
+		  (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+		  (IFC_FIR_OP_RDSTAT << IFC_NAND_FIR0_OP1_SHIFT));
+	ifc_out32(ctrl->rregs + FSL_IFC_FCR0, NAND_CMD_STATUS <<
+		  IFC_NAND_FCR0_CMD0_SHIFT);
+	ifc_out32(ctrl->rregs + FSL_IFC_NAND_BC, 1);
+	set_addr(mtd, 0, 0, 0);
+	ctrl->read_bytes = 1;
+
+	fsl_ifc_run_command(mtd);
+
+	nand_fsr = ifc_in32(ctrl->rregs + FSL_IFC_NAND_FSR);
+	status = nand_fsr >> 24;
+
+	/* Chip sometimes reporting write protect even when it's not */
+	return status | NAND_STATUS_WP;
+}
+
+/*
+ * The controller does not check for bitflips in erased pages,
+ * therefore software must check instead.
+ */
+static int
+check_erased_page(struct nand_chip *chip, u8 *buf, struct mtd_info *mtd)
+{
+	u8 *ecc = chip->oob_poi;
+	const int ecc_size = chip->ecc.bytes;
+	const int pkt_size = chip->ecc.size;
+	int i, res, bitflips = 0;
+	struct mtd_oob_region oobregion = { };
+
+
+	mtd_ooblayout_ecc(mtd, 0, &oobregion);
+	ecc += oobregion.offset;
+	for (i = 0; i < chip->ecc.steps; i++) {
+		res = nand_check_erased_ecc_chunk(buf, pkt_size, ecc, ecc_size,
+		NULL, 0, chip->ecc.strength);
+
+		if (res < 0) {
+			pr_err("fsl-ifc: NAND Flash ECC Uncorrectable Error\n");
+			mtd->ecc_stats.failed++;
+		} else if (res > 0) {
+			mtd->ecc_stats.corrected += res;
+		}
+		bitflips = max(res, bitflips);
+		buf += pkt_size;
+		ecc += ecc_size;
+	}
+
+	return bitflips;
+}
+
+static int fsl_ifc_read_page(struct nand_chip *chip, uint8_t *buf,
+		int oob_required, int page)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct fsl_ifc_mtd *priv = chip->priv;
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+
+	nand_read_page_op(chip, page, 0, buf, mtd->writesize);
+	/*fsl_ifc_read_buf(chip, buf, mtd->writesize); */
+	if (oob_required)
+		fsl_ifc_read_buf(chip, chip->oob_poi, mtd->oobsize);
+
+	if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_ECCER) {
+		if (!oob_required)
+			fsl_ifc_read_buf(chip, chip->oob_poi, mtd->oobsize);
+
+		return check_erased_page(chip, buf, mtd);
+	}
+
+	if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
+		mtd->ecc_stats.failed++;
+
+	return ctrl->max_bitflips;
+}
+
+/*
+ * ECC will be calculated automatically, and errors will be detected in
+ * waitfunc.
+ */
+static int fsl_ifc_write_page(struct nand_chip *chip, const uint8_t *buf,
+		int oob_required, int page)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	nand_prog_page_begin_op(chip, page, 0, buf, mtd->writesize);
+	fsl_ifc_write_buf(chip, chip->oob_poi, mtd->oobsize);
+
+	return nand_prog_page_end_op(chip);
+}
+
+static int match_bank(int bank, phys_addr_t addr)
+{
+	u32 cspr = get_ifc_cspr(bank);
+
+	if (!(cspr & CSPR_V))
+		return 0;
+	if ((cspr & CSPR_MSEL) != CSPR_MSEL_NAND)
+		return 0;
+
+	return (cspr & CSPR_BA) == (addr & CSPR_BA);
+}
+
+static void fsl_ifc_ctrl_init(void)
+{
+	struct fsl_ifc_ctrl *ctrl;
+
+	ifc_ctrl = kzalloc(sizeof(*ifc_ctrl), GFP_KERNEL);
+	if (!ifc_ctrl)
+		return;
+
+	ctrl = ifc_ctrl;
+	ctrl->read_bytes = 0;
+	ctrl->index = 0;
+	ctrl->addr = NULL;
+
+	ctrl->gregs = IOMEM(IFC_ADDR);
+
+	ctrl->version = ifc_in32(ctrl->gregs + FSL_IFC_REV);
+	if (ctrl->version >= FSL_IFC_V2_0_0)
+		ctrl->rregs = IOMEM(IFC_ADDR + 0x10000);
+	else
+		ctrl->rregs = IOMEM(IFC_ADDR + 0x1000);
+
+	/* clear event registers */
+	ifc_out32(ctrl->rregs + FSL_IFC_NAND_EVTER_STAT, ~0U);
+	ifc_out32(ctrl->rregs + FSL_IFC_PGRDCMPL_EVT_STAT, ~0U);
+
+	/* Enable error and event for any detected errors */
+	ifc_out32(ctrl->rregs + FSL_IFC_EVTER_EN,
+		  IFC_NAND_EVTER_EN_OPC_EN |
+		  IFC_NAND_EVTER_EN_PGRDCMPL_EN |
+		  IFC_NAND_EVTER_EN_FTOER_EN |
+		  IFC_NAND_EVTER_EN_WPER_EN);
+
+	ifc_out32(ctrl->rregs + FSL_IFC_NCFGR, 0x0);
+}
+
+static void fsl_ifc_select_chip(struct nand_chip *chip, int cs)
+{
+}
+
+static int fsl_ifc_sram_init(struct fsl_ifc_mtd *priv, uint32_t ver)
+{
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	uint32_t cs = 0, csor = 0, csor_8k = 0, csor_ext = 0;
+	uint32_t ncfgr = 0;
+	uint32_t time_start;
+
+	if (ctrl->version > FSL_IFC_V1_1_0) {
+		ncfgr = ifc_in32(ctrl->rregs + FSL_IFC_NCFGR);
+		ifc_out32(ctrl->rregs + FSL_IFC_NCFGR,
+				ncfgr | IFC_NAND_SRAM_INIT_EN);
+
+		/* wait for  SRAM_INIT bit to be clear or timeout */
+		time_start = get_time_ns();
+		while (!is_timeout(time_start, IFC_TIMEOUT_MS * MSECOND)) {
+			ifc_ctrl->nand_stat =
+				ifc_in32(ctrl->rregs + FSL_IFC_NAND_EVTER_STAT);
+
+			if (!(ifc_ctrl->nand_stat & IFC_NAND_SRAM_INIT_EN))
+				return 0;
+		}
+		pr_err("fsl-ifc: Failed to Initialise SRAM\n");
+		return 1;
+	}
+
+	cs = priv->cs;
+	/* Save CSOR and CSOR_ext */
+	csor = get_ifc_csor(cs);
+	csor_ext = get_ifc_csor_ext(cs);
+
+	/* change PageSize 8K and SpareSize 1K*/
+	csor_8k = (csor & ~(CSOR_NAND_PGS_MASK)) | 0x0018C000;
+	set_ifc_csor(cs, csor_8k);
+	set_ifc_csor_ext(cs, 0x0000400);
+
+	/* READID */
+	ifc_out32(ctrl->rregs + FSL_IFC_FIR0,
+		  (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+		  (IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
+		  (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT));
+	ifc_out32(ctrl->rregs + FSL_IFC_FCR0,
+		  NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT);
+	ifc_out32(ctrl->rregs + FSL_IFC_ROW3, 0x0);
+
+	ifc_out32(ctrl->rregs + FSL_IFC_NAND_BC, 0x0);
+
+	/* Program ROW0/COL0 */
+	ifc_out32(ctrl->rregs + FSL_IFC_ROW0, 0x0);
+	ifc_out32(ctrl->rregs + FSL_IFC_COL0, 0x0);
+
+	/* set the chip select for NAND Transaction */
+	ifc_out32(ctrl->rregs + FSL_IFC_NAND_CSEL,
+			priv->cs << IFC_NAND_CSEL_SHIFT);
+
+	/* start read seq */
+	ifc_out32(ctrl->rregs + FSL_IFC_NANDSEQ_STRT,
+			IFC_NAND_SEQ_STRT_FIR_STRT);
+
+	time_start = get_time_ns();
+	while (!is_timeout(time_start, IFC_TIMEOUT_MS * MSECOND)) {
+		ifc_ctrl->nand_stat =
+			ifc_in32(ctrl->rregs + FSL_IFC_NAND_EVTER_STAT);
+
+		if (ifc_ctrl->nand_stat & IFC_NAND_EVTER_STAT_OPC)
+			break;
+	}
+
+	if (ifc_ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC) {
+		pr_err("fsl-ifc: Failed to Initialise SRAM\n");
+		return 1;
+	}
+
+	ifc_out32(ctrl->rregs + FSL_IFC_NAND_EVTER_STAT, ifc_ctrl->nand_stat);
+
+	/* Restore CSOR and CSOR_ext */
+	set_ifc_csor(priv->cs, csor);
+	set_ifc_csor_ext(priv->cs, csor_ext);
+
+	return 0;
+}
+
+static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
+{
+	struct fsl_ifc_ctrl *ctrl;
+	struct nand_chip *nand = &priv->chip;
+	struct mtd_info *mtd = nand_to_mtd(&priv->chip);
+	uint32_t cspr = 0, csor = 0;
+	int ret = 0;
+
+	if (!ifc_ctrl) {
+		fsl_ifc_ctrl_init();
+		if (!ifc_ctrl)
+			return -ENOMEM;
+	}
+	ctrl = priv->ctrl = ifc_ctrl;
+
+	if (priv->dev->device_node) {
+		int bank, banks;
+
+		 /* find which chip select it is connected to */
+		banks = (ctrl->version == FSL_IFC_V1_1_0) ? 4 : 8;
+		for (bank = 0; bank < banks; bank++) {
+			if (match_bank(bank, priv->pbase))
+				break;
+		}
+		priv->cs = bank;
+		if (bank >= banks) {
+			pr_err("%s: address did not match any chip selects\n",
+				__func__);
+			return -ENODEV;
+		}
+	}
+
+	/*mtd->priv = nand; */
+	mtd->dev.parent = priv->dev;
+
+	/*
+	 * Fill in nand_chip structure
+	 * set up function call table
+	 */
+	nand->legacy.write_buf = fsl_ifc_write_buf;
+	nand->legacy.read_buf = fsl_ifc_read_buf;
+	nand->legacy.select_chip = fsl_ifc_select_chip;
+	nand->legacy.cmdfunc = fsl_ifc_cmdfunc;
+	nand->legacy.waitfunc = fsl_ifc_wait;
+
+	/* set up nand options */
+	nand->bbt_td = &bbt_main_descr;
+	nand->bbt_md = &bbt_mirror_descr;
+
+	/* set up nand options */
+	nand->options = NAND_NO_SUBPAGE_WRITE;
+	nand->bbt_options = NAND_BBT_USE_FLASH;
+
+	cspr = get_ifc_cspr(priv->cs);
+	csor = get_ifc_csor(priv->cs);
+
+	if (cspr & CSPR_PORT_SIZE_16) {
+		nand->legacy.read_byte = fsl_ifc_read_byte16;
+		nand->options |= NAND_BUSWIDTH_16;
+	} else {
+		nand->legacy.read_byte = fsl_ifc_read_byte;
+	}
+
+	nand->controller = &ifc_ctrl->controller;
+	nand->priv = priv;
+
+	nand->ecc.read_page = fsl_ifc_read_page;
+	nand->ecc.write_page = fsl_ifc_write_page;
+
+	/* Hardware generates ECC per 512 Bytes */
+	nand->ecc.size = 512;
+	nand->ecc.bytes = 8;
+
+	nand->legacy.chip_delay = 30;
+
+	switch (csor & CSOR_NAND_PGS_MASK) {
+	case CSOR_NAND_PGS_512:
+		if (!(nand->options & NAND_BUSWIDTH_16)) {
+			/* Avoid conflict with bad block marker */
+			bbt_main_descr.offs = 0;
+			bbt_mirror_descr.offs = 0;
+		}
+
+		nand->ecc.strength = 4;
+		priv->bufnum_mask = 15;
+		break;
+
+	case CSOR_NAND_PGS_2K:
+		nand->ecc.strength = 4;
+		priv->bufnum_mask = 3;
+		break;
+
+	case CSOR_NAND_PGS_4K:
+		if ((csor & CSOR_NAND_ECC_MODE_MASK) ==
+		    CSOR_NAND_ECC_MODE_4) {
+			nand->ecc.strength = 4;
+		} else {
+			nand->ecc.strength = 8;
+			nand->ecc.bytes = 16;
+		}
+
+		priv->bufnum_mask = 1;
+		break;
+
+	case CSOR_NAND_PGS_8K:
+		if ((csor & CSOR_NAND_ECC_MODE_MASK) ==
+		    CSOR_NAND_ECC_MODE_4) {
+			nand->ecc.strength = 4;
+		} else {
+			nand->ecc.strength = 8;
+			nand->ecc.bytes = 16;
+		}
+
+		priv->bufnum_mask = 0;
+		break;
+
+
+	default:
+		pr_err("ifc nand: bad csor %#x: bad page size\n", csor);
+		return -ENODEV;
+	}
+
+	/* Must also set CSOR_NAND_ECC_ENC_EN if DEC_EN set */
+	if (csor & CSOR_NAND_ECC_DEC_EN) {
+		nand->ecc.mode = NAND_ECC_HW;
+		mtd_set_ooblayout(mtd, &fsl_ifc_ooblayout_ops);
+	} else {
+		nand->ecc.mode = NAND_ECC_SOFT;
+		nand->ecc.algo = NAND_ECC_HAMMING;
+	}
+
+	if (ctrl->version >= FSL_IFC_V1_1_0) {
+		ret = fsl_ifc_sram_init(priv, ctrl->version);
+		if (ret)
+			return ret;
+	}
+
+	if (ctrl->version >= FSL_IFC_V2_0_0)
+		priv->bufnum_mask = (priv->bufnum_mask * 2) + 1;
+
+	return 0;
+}
+
+static int fsl_ifc_nand_probe(struct device_d *dev)
+{
+	struct device_node *np = dev->device_node;
+	struct fsl_ifc_data *pdata = dev->platform_data;
+	struct fsl_ifc_mtd *priv;
+	struct resource *iores;
+	struct mtd_info *mtd;
+	int ret = 0;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = dev;
+	if (!np) {
+		priv->vbase = dev_request_mem_region(dev, 0);
+		priv->cs = pdata->cs;
+	} else {
+		iores = dev_request_mem_resource(dev, 0);
+		if (IS_ERR(iores)) {
+			ret = -ENOMEM;
+			goto bailout;
+		}
+		priv->pbase = iores->start;
+		priv->vbase = IOMEM(iores->start);
+	}
+
+	if (fsl_ifc_chip_init(priv)) {
+		ret = -ENOMEM;
+		goto bailout;
+	}
+
+	ret = nand_scan_ident(&priv->chip, 1, NULL);
+	if (ret)
+		goto bailout;
+
+	ret = nand_scan_tail(&priv->chip);
+	if (ret)
+		goto bailout;
+
+	mtd = nand_to_mtd(&priv->chip);
+	return add_mtd_nand_device(mtd, "nand");
+bailout:
+	kfree(priv);
+	return ret;
+}
+
+static __maybe_unused struct of_device_id fsl_nand_compatible[] = {
+	{
+		.compatible = "fsl,ifc-nand",
+	}, {
+	}
+};
+
+static struct driver_d fsl_ifc_driver = {
+	.name = "fsl_nand",
+	.probe = fsl_ifc_nand_probe,
+	.of_compatible = DRV_OF_COMPAT(fsl_nand_compatible),
+};
+device_platform_driver(fsl_ifc_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("FSL IFC NAND driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/fsl_ifc.h b/include/linux/fsl_ifc.h
new file mode 100644
index 0000000000..9881055671
--- /dev/null
+++ b/include/linux/fsl_ifc.h
@@ -0,0 +1,306 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later  */
+/*
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ * Author: Dipen Dudhat <dipen.dudhat@freescale.com>
+ *
+ */
+
+#ifndef __FSL_IFC_H
+#define __FSL_IFC_H
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <linux/log2.h>
+
+/* Big-Endian */
+#define ifc_in32(a)			ioread32be(a)
+#define ifc_out32(a, v)			iowrite32be(v, a)
+#define ifc_in16(a)			ioread16be(a)
+#define ifc_out16(a, v)			iowrite16be(v, a)
+
+/*
+ * CSPR - Chip Select Property Register
+ */
+#define CSPR_BA				0xFFFF0000
+#define CSPR_BA_SHIFT			16
+#define CSPR_PORT_SIZE			0x00000180
+#define CSPR_PORT_SIZE_SHIFT		7
+#define CSPR_PORT_SIZE_8		0x00000080
+#define CSPR_PORT_SIZE_16		0x00000100
+#define CSPR_PORT_SIZE_32		0x00000180
+/* Write Protect */
+#define CSPR_WP				0x00000040
+#define CSPR_WP_SHIFT			6
+#define CSPR_MSEL			0x00000006
+#define CSPR_MSEL_SHIFT			1
+#define CSPR_MSEL_NOR			0x00000000
+#define CSPR_MSEL_NAND			0x00000002
+#define CSPR_MSEL_GPCM			0x00000004
+#define CSPR_V				0x00000001
+#define CSPR_V_SHIFT			0
+
+/* Convert an address into the right format for the CSPR Registers */
+#define CSPR_PHYS_ADDR(x)		(((uint64_t)x) & 0xffff0000)
+
+/*
+ * Address Mask Register
+ */
+#define IFC_AMASK_MASK			0xFFFF0000
+#define IFC_AMASK_SHIFT			16
+#define IFC_AMASK(n)			(IFC_AMASK_MASK << \
+					(ilog2(n) - IFC_AMASK_SHIFT))
+
+/*
+ * Chip Select Option Register IFC_NAND Machine
+ */
+#define CSOR_NAND_ECC_ENC_EN		0x80000000
+#define CSOR_NAND_ECC_MODE_MASK		0x30000000
+/* 4 bit correction per 520 Byte sector */
+#define CSOR_NAND_ECC_MODE_4		0x00000000
+/* 8 bit correction per 528 Byte sector */
+#define CSOR_NAND_ECC_MODE_8		0x10000000
+#define CSOR_NAND_ECC_DEC_EN		0x04000000
+/* Row Address Length */
+#define CSOR_NAND_RAL_MASK		0x01800000
+#define CSOR_NAND_RAL_SHIFT		20
+#define CSOR_NAND_RAL_1			0x00000000
+#define CSOR_NAND_RAL_2			0x00800000
+#define CSOR_NAND_RAL_3			0x01000000
+#define CSOR_NAND_RAL_4			0x01800000
+/* Page Size 512b, 2k, 4k */
+#define CSOR_NAND_PGS_MASK		0x00180000
+#define CSOR_NAND_PGS_SHIFT		16
+#define CSOR_NAND_PGS_512		0x00000000
+#define CSOR_NAND_PGS_2K		0x00080000
+#define CSOR_NAND_PGS_4K		0x00100000
+#define CSOR_NAND_PGS_8K		0x00180000
+/* Spare region Size */
+#define CSOR_NAND_SPRZ_MASK		0x0000E000
+#define CSOR_NAND_SPRZ_SHIFT		13
+#define CSOR_NAND_SPRZ_16		0x00000000
+#define CSOR_NAND_SPRZ_64		0x00002000
+#define CSOR_NAND_SPRZ_128		0x00004000
+#define CSOR_NAND_SPRZ_210		0x00006000
+#define CSOR_NAND_SPRZ_218		0x00008000
+#define CSOR_NAND_SPRZ_224		0x0000A000
+#define CSOR_NAND_SPRZ_CSOR_EXT	0x0000C000
+/* Pages Per Block */
+#define CSOR_NAND_PB_MASK		0x00000700
+#define CSOR_NAND_PB_SHIFT		8
+#define CSOR_NAND_PB(n)			((ilog2(n) - 5) << CSOR_NAND_PB_SHIFT)
+/* Time for Read Enable High to Output High Impedance */
+#define CSOR_NAND_TRHZ_MASK		0x0000001C
+#define CSOR_NAND_TRHZ_SHIFT		2
+#define CSOR_NAND_TRHZ_20		0x00000000
+#define CSOR_NAND_TRHZ_40		0x00000004
+#define CSOR_NAND_TRHZ_60		0x00000008
+#define CSOR_NAND_TRHZ_80		0x0000000C
+#define CSOR_NAND_TRHZ_100		0x00000010
+/* Buffer control disable */
+#define CSOR_NAND_BCTLD			0x00000001
+
+/*
+ * Chip Select Option Register - NOR Flash Mode
+ */
+/* Enable Address shift Mode */
+#define CSOR_NOR_ADM_SHFT_MODE_EN	0x80000000
+/* Page Read Enable from NOR device */
+#define CSOR_NOR_PGRD_EN		0x10000000
+/* AVD Toggle Enable during Burst Program */
+#define CSOR_NOR_AVD_TGL_PGM_EN		0x01000000
+/* Address Data Multiplexing Shift */
+#define CSOR_NOR_ADM_MASK		0x0003E000
+#define CSOR_NOR_ADM_SHIFT_SHIFT	13
+#define CSOR_NOR_ADM_SHIFT(n)	((n) << CSOR_NOR_ADM_SHIFT_SHIFT)
+/* Type of the NOR device hooked */
+#define CSOR_NOR_NOR_MODE_ASYNC_NOR	0x00000000
+#define CSOR_NOR_NOR_MODE_AVD_NOR	0x00000020
+/* Time for Read Enable High to Output High Impedance */
+#define CSOR_NOR_TRHZ_MASK		0x0000001C
+#define CSOR_NOR_TRHZ_SHIFT		2
+#define CSOR_NOR_TRHZ_20		0x00000000
+#define CSOR_NOR_TRHZ_40		0x00000004
+#define CSOR_NOR_TRHZ_60		0x00000008
+#define CSOR_NOR_TRHZ_80		0x0000000C
+#define CSOR_NOR_TRHZ_100		0x00000010
+/* Buffer control disable */
+#define CSOR_NOR_BCTLD			0x00000001
+
+/*
+ * Flash Timing Registers (FTIM0 - FTIM2_CSn)
+ */
+/*
+ * FTIM0 - NAND Flash Mode
+ */
+#define FTIM0_NAND			0x7EFF3F3F
+#define FTIM0_NAND_TCCST_SHIFT		25
+#define FTIM0_NAND_TCCST(n)		((n) << FTIM0_NAND_TCCST_SHIFT)
+#define FTIM0_NAND_TWP_SHIFT	16
+#define FTIM0_NAND_TWP(n)	((n) << FTIM0_NAND_TWP_SHIFT)
+#define FTIM0_NAND_TWCHT_SHIFT	8
+#define FTIM0_NAND_TWCHT(n)	((n) << FTIM0_NAND_TWCHT_SHIFT)
+#define FTIM0_NAND_TWH_SHIFT	0
+#define FTIM0_NAND_TWH(n)	((n) << FTIM0_NAND_TWH_SHIFT)
+/*
+ * FTIM1 - NAND Flash Mode
+ */
+#define FTIM1_NAND			0xFFFF3FFF
+#define FTIM1_NAND_TADLE_SHIFT	24
+#define FTIM1_NAND_TADLE(n)	((n) << FTIM1_NAND_TADLE_SHIFT)
+#define FTIM1_NAND_TWBE_SHIFT	16
+#define FTIM1_NAND_TWBE(n)	((n) << FTIM1_NAND_TWBE_SHIFT)
+#define FTIM1_NAND_TRR_SHIFT	8
+#define FTIM1_NAND_TRR(n)	((n) << FTIM1_NAND_TRR_SHIFT)
+#define FTIM1_NAND_TRP_SHIFT	0
+#define FTIM1_NAND_TRP(n)	((n) << FTIM1_NAND_TRP_SHIFT)
+/*
+ * FTIM2 - NAND Flash Mode
+ */
+#define FTIM2_NAND			0x1FE1F8FF
+#define FTIM2_NAND_TRAD_SHIFT	21
+#define FTIM2_NAND_TRAD(n)	((n) << FTIM2_NAND_TRAD_SHIFT)
+#define FTIM2_NAND_TREH_SHIFT	11
+#define FTIM2_NAND_TREH(n)	((n) << FTIM2_NAND_TREH_SHIFT)
+#define FTIM2_NAND_TWHRE_SHIFT	0
+#define FTIM2_NAND_TWHRE(n)	((n) << FTIM2_NAND_TWHRE_SHIFT)
+/*
+ * FTIM0 - NOR Flash Mode
+ */
+#define FTIM0_NOR			0xF03F3F3F
+#define FTIM0_NOR_TACSE_SHIFT		28
+#define FTIM0_NOR_TACSE(n)		((n) << FTIM0_NOR_TACSE_SHIFT)
+#define FTIM0_NOR_TEADC_SHIFT		16
+#define FTIM0_NOR_TEADC(n)		((n) << FTIM0_NOR_TEADC_SHIFT)
+#define FTIM0_NOR_TAVDS_SHIFT		8
+#define FTIM0_NOR_TAVDS(n)		((n) << FTIM0_NOR_TAVDS_SHIFT)
+#define FTIM0_NOR_TEAHC_SHIFT		0
+#define FTIM0_NOR_TEAHC(n)		((n) << FTIM0_NOR_TEAHC_SHIFT)
+/*
+ * FTIM1 - NOR Flash Mode
+ */
+#define FTIM1_NOR			0xFF003F3F
+#define FTIM1_NOR_TACO_SHIFT		24
+#define FTIM1_NOR_TACO(n)		((n) << FTIM1_NOR_TACO_SHIFT)
+#define FTIM1_NOR_TRAD_NOR_SHIFT	8
+#define FTIM1_NOR_TRAD_NOR(n)		((n) << FTIM1_NOR_TRAD_NOR_SHIFT)
+#define FTIM1_NOR_TSEQRAD_NOR_SHIFT	0
+#define FTIM1_NOR_TSEQRAD_NOR(n)	((n) << FTIM1_NOR_TSEQRAD_NOR_SHIFT)
+/*
+ * FTIM2 - NOR Flash Mode
+ */
+#define FTIM2_NOR			0x0F3CFCFF
+#define FTIM2_NOR_TCS_SHIFT		24
+#define FTIM2_NOR_TCS(n)		((n) << FTIM2_NOR_TCS_SHIFT)
+#define FTIM2_NOR_TCH_SHIFT		18
+#define FTIM2_NOR_TCH(n)		((n) << FTIM2_NOR_TCH_SHIFT)
+#define FTIM2_NOR_TWPH_SHIFT		10
+#define FTIM2_NOR_TWPH(n)		((n) << FTIM2_NOR_TWPH_SHIFT)
+#define FTIM2_NOR_TWP_SHIFT		0
+#define FTIM2_NOR_TWP(n)		((n) << FTIM2_NOR_TWP_SHIFT)
+
+/*
+ * FTIM0 - Normal GPCM Mode
+ */
+#define FTIM0_GPCM			0xF03F3F3F
+#define FTIM0_GPCM_TACSE_SHIFT		28
+#define FTIM0_GPCM_TACSE(n)		((n) << FTIM0_GPCM_TACSE_SHIFT)
+#define FTIM0_GPCM_TEADC_SHIFT		16
+#define FTIM0_GPCM_TEADC(n)		((n) << FTIM0_GPCM_TEADC_SHIFT)
+#define FTIM0_GPCM_TAVDS_SHIFT		8
+#define FTIM0_GPCM_TAVDS(n)		((n) << FTIM0_GPCM_TAVDS_SHIFT)
+#define FTIM0_GPCM_TEAHC_SHIFT		0
+#define FTIM0_GPCM_TEAHC(n)		((n) << FTIM0_GPCM_TEAHC_SHIFT)
+/*
+ * FTIM1 - Normal GPCM Mode
+ */
+#define FTIM1_GPCM			0xFF003F00
+#define FTIM1_GPCM_TACO_SHIFT		24
+#define FTIM1_GPCM_TACO(n)		((n) << FTIM1_GPCM_TACO_SHIFT)
+#define FTIM1_GPCM_TRAD_SHIFT		8
+#define FTIM1_GPCM_TRAD(n)		((n) << FTIM1_GPCM_TRAD_SHIFT)
+/*
+ * FTIM2 - Normal GPCM Mode
+ */
+#define FTIM2_GPCM			0x0F3C00FF
+#define FTIM2_GPCM_TCS_SHIFT		24
+#define FTIM2_GPCM_TCS(n)		((n) << FTIM2_GPCM_TCS_SHIFT)
+#define FTIM2_GPCM_TCH_SHIFT		18
+#define FTIM2_GPCM_TCH(n)		((n) << FTIM2_GPCM_TCH_SHIFT)
+#define FTIM2_GPCM_TWP_SHIFT		0
+#define FTIM2_GPCM_TWP(n)		((n) << FTIM2_GPCM_TWP_SHIFT)
+
+/*
+ * General Control Register (GCR)
+ */
+#define IFC_GCR_MASK			0x8000F800
+/* reset all IFC hardware */
+#define IFC_GCR_SOFT_RST_ALL		0x80000000
+/* Turnaroud Time of external buffer */
+#define IFC_GCR_TBCTL_TRN_TIME		0x0000F800
+#define IFC_GCR_TBCTL_TRN_TIME_SHIFT	11
+
+/*
+ * Clock Control Register (CCR)
+ */
+#define IFC_CCR_MASK			0x0F0F8800
+/* Clock division ratio */
+#define IFC_CCR_CLK_DIV_MASK		0x0F000000
+#define IFC_CCR_CLK_DIV_SHIFT		24
+#define IFC_CCR_CLK_DIV(n)		((n-1) << IFC_CCR_CLK_DIV_SHIFT)
+/* IFC Clock Delay */
+#define IFC_CCR_CLK_DLY_MASK		0x000F0000
+#define IFC_CCR_CLK_DLY_SHIFT		16
+#define IFC_CCR_CLK_DLY(n)		((n) << IFC_CCR_CLK_DLY_SHIFT)
+
+#ifndef __ASSEMBLY__
+#include <asm/io.h>
+
+#define IFC_BASE_ADDR		((void __iomem *)IFC_ADDR)
+#define FSL_IFC_CSPRX(i)	(0x10 + ((i) * 0xc))
+#define FSL_IFC_CSORX(i)	(0x130 + ((i) * 0xc))
+#define FSL_IFC_CSORX_EXT(i)	(0x134 + ((i) * 0xc))
+#define FSL_IFC_AMASKX(i)	(0xa0 + ((i) * 0xc))
+#define FSL_IFC_CSX_FTIMY(i, j)	((0x1c0 + ((i) * 0x30)) + ((j) * 4))
+
+#define get_ifc_cspr(i) (ifc_in32(IFC_BASE_ADDR + FSL_IFC_CSPRX(i)))
+#define get_ifc_csor(i) (ifc_in32(IFC_BASE_ADDR + FSL_IFC_CSORX(i)))
+#define get_ifc_csor_ext(i) (ifc_in32(IFC_BASE_ADDR + FSL_IFC_CSORX_EXT(i)))
+#define get_ifc_amask(i) (ifc_in32(IFC_BASE_ADDR + FSL_IFC_AMASKX(i)))
+#define get_ifc_ftim(i, j) (ifc_in32(IFC_BASE_ADDR + FSL_IFC_CSX_FTIMY(i, j)))
+
+#define set_ifc_cspr(i, v) (ifc_out32(IFC_BASE_ADDR + FSL_IFC_CSPRX(i), v))
+#define set_ifc_csor(i, v) (ifc_out32(IFC_BASE_ADDR + FSL_IFC_CSORX(i), v))
+#define set_ifc_csor_ext(i, v) (ifc_out32(IFC_BASE_ADDR + FSL_IFC_CSORX_EXT(i),\
+				v))
+#define set_ifc_amask(i, v) (ifc_out32(IFC_BASE_ADDR + FSL_IFC_AMASKX(i), v))
+#define set_ifc_ftim(i, j, v) \
+			(ifc_out32(IFC_BASE_ADDR + FSL_IFC_CSX_FTIMY(i, j), v))
+
+#define FSL_IFC_GCR_OFFSET	0x40c
+#define FSL_IFC_CCR_OFFSET	0x44c
+
+enum ifc_chip_sel {
+	IFC_CS0,
+	IFC_CS1,
+	IFC_CS2,
+	IFC_CS3,
+	IFC_CS4,
+	IFC_CS5,
+	IFC_CS6,
+	IFC_CS7,
+};
+
+enum ifc_ftims {
+	IFC_FTIM0,
+	IFC_FTIM1,
+	IFC_FTIM2,
+	IFC_FTIM3,
+};
+
+#ifdef CONFIG_FSL_ERRATUM_IFC_A002769
+#undef CSPR_MSEL_NOR
+#define CSPR_MSEL_NOR	CSPR_MSEL_GPCM
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __FSL_IFC_H */
-- 
2.27.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 4/4] ls1046ardb: enable IFC NAND.
  2021-07-28 12:47 [PATCH 0/4] NXP IFC nand driver Renaud Barbier
                   ` (2 preceding siblings ...)
  2021-07-28 12:47 ` [PATCH 3/4] nand: add NXP IFC nand driver Renaud Barbier
@ 2021-07-28 12:47 ` Renaud Barbier
  2021-07-29 10:13   ` Ahmad Fatoum
  3 siblings, 1 reply; 10+ messages in thread
From: Renaud Barbier @ 2021-07-28 12:47 UTC (permalink / raw)
  To: barebox; +Cc: Renaud Barbier

Set the NAND timings and enable the IFC NAND driver.

Signed-off-by: Renaud Barbier <renaud.barbier@abaco.com>
---
 arch/arm/boards/ls1046ardb/board.c    | 26 ++++++++++++++++++++++++++
 arch/arm/configs/layerscape_defconfig | 12 ++++++++++++
 2 files changed, 38 insertions(+)

diff --git a/arch/arm/boards/ls1046ardb/board.c b/arch/arm/boards/ls1046ardb/board.c
index ef68e9c7f9..5573d5b486 100644
--- a/arch/arm/boards/ls1046ardb/board.c
+++ b/arch/arm/boards/ls1046ardb/board.c
@@ -12,6 +12,7 @@
 #include <linux/sizes.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
+#include <linux/fsl_ifc.h>
 #include <asm/system.h>
 #include <mach/layerscape.h>
 #include <mach/bbu.h>
@@ -147,6 +148,31 @@ static int rdb_mem_init(void)
 }
 mem_initcall(rdb_mem_init);
 
+static int rdb_nand_init(void)
+{
+	/* NAND mapping and timings. Only for Linux use. */
+	set_ifc_cspr(IFC_CS0, CSPR_PHYS_ADDR(0x7e800000) | CSPR_PORT_SIZE_8 |
+				CSPR_MSEL_NAND | CSPR_V);
+	set_ifc_csor(IFC_CS0, CSOR_NAND_ECC_ENC_EN | CSOR_NAND_ECC_DEC_EN |
+			CSOR_NAND_ECC_MODE_8 |
+			CSOR_NAND_RAL_3 | CSOR_NAND_PGS_4K |
+			CSOR_NAND_SPRZ_224 |  CSOR_NAND_PB(64) |
+			CSOR_NAND_TRHZ_20);
+	set_ifc_amask(IFC_CS0, IFC_AMASK(64*1024));
+	set_ifc_ftim(IFC_CS0, IFC_FTIM0, FTIM0_NAND_TCCST(0x07) |
+			FTIM0_NAND_TWP(0x18) | FTIM0_NAND_TWCHT(0x07) |
+			FTIM0_NAND_TWH(0x0a));
+	set_ifc_ftim(IFC_CS0, IFC_FTIM1, FTIM1_NAND_TADLE(0x32) |
+			FTIM1_NAND_TWBE(0x39) | FTIM1_NAND_TRR(0x0e)|
+			FTIM1_NAND_TRP(0x18));
+	set_ifc_ftim(IFC_CS0, IFC_FTIM2, FTIM2_NAND_TRAD(0xf) |
+			FTIM2_NAND_TREH(0xa) | FTIM2_NAND_TWHRE(0x1e));
+	set_ifc_ftim(IFC_CS0, IFC_FTIM3, 0);
+
+	return 0;
+}
+core_initcall(rdb_nand_init);
+
 static int rdb_postcore_init(void)
 {
 	if (!of_machine_is_compatible("fsl,ls1046a-rdb"))
diff --git a/arch/arm/configs/layerscape_defconfig b/arch/arm/configs/layerscape_defconfig
index 394cd95c98..5c31c9319d 100644
--- a/arch/arm/configs/layerscape_defconfig
+++ b/arch/arm/configs/layerscape_defconfig
@@ -34,6 +34,10 @@ CONFIG_CMD_GO=y
 CONFIG_CMD_RESET=y
 CONFIG_CMD_UIMAGE=y
 CONFIG_CMD_PARTITION=y
+CONFIG_CMD_MOUNT=y
+CONFIG_CMD_UBI=y
+CONFIG_CMD_UBIFORMAT=y
+CONFIG_CMD_UMOUNT=y
 CONFIG_CMD_EXPORT=y
 CONFIG_CMD_LOADENV=y
 CONFIG_CMD_PRINTENV=y
@@ -69,6 +73,7 @@ CONFIG_CMD_GPIO=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_LED=y
 CONFIG_CMD_SPI=y
+CONFIG_CMD_NAND=y
 CONFIG_CMD_LED_TRIGGER=y
 CONFIG_CMD_WD=y
 CONFIG_CMD_BAREBOX_UPDATE=y
@@ -85,6 +90,11 @@ CONFIG_DP83867_PHY=y
 CONFIG_REALTEK_PHY=y
 CONFIG_NET_DSA_MV88E6XXX=y
 CONFIG_DRIVER_SPI_FSL_QUADSPI=y
+CONFIG_NAND=y
+CONFIG_NAND_FSL_IFC=y
+CONFIG_MTD_NAND_ECC_SOFT=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_BEB_LIMIT=20
 CONFIG_I2C=y
 CONFIG_I2C_IMX=y
 CONFIG_I2C_MUX=y
@@ -112,5 +122,7 @@ CONFIG_FS_NFS=y
 CONFIG_FS_FAT=y
 CONFIG_FS_FAT_WRITE=y
 CONFIG_FS_FAT_LFN=y
+CONFIG_FS_UBIFS=y
+CONFIG_FS_UBIFS_COMPRESSION_LZO=y
 CONFIG_ZLIB=y
 CONFIG_LZO_DECOMPRESS=y
-- 
2.27.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/4] ARM: atomic.h: add 64-bit counter support
  2021-07-28 12:47 ` [PATCH 1/4] ARM: atomic.h: add 64-bit counter support Renaud Barbier
@ 2021-07-29  9:58   ` Ahmad Fatoum
  0 siblings, 0 replies; 10+ messages in thread
From: Ahmad Fatoum @ 2021-07-29  9:58 UTC (permalink / raw)
  To: Renaud Barbier, barebox

On 28.07.21 14:47, Renaud Barbier wrote:
> In preparation for the introduction of the FSL IFC nand driver
> for the layerscape CPU, add 64-bit counter support.
> 
> Signed-off-by: Renaud Barbier <renaud.barbier@abaco.com>
> ---
>  include/asm-generic/atomic-long.h |  3 +-
>  include/asm-generic/atomic.h      | 49 +++++++++++++++++++++++++++++++
>  2 files changed, 51 insertions(+), 1 deletion(-)
> 
> diff --git a/include/asm-generic/atomic-long.h b/include/asm-generic/atomic-long.h
> index 322d510f38..dbb503e758 100644
> --- a/include/asm-generic/atomic-long.h
> +++ b/include/asm-generic/atomic-long.h
> @@ -65,7 +65,7 @@ static inline void atomic_long_sub(long i, atomic_long_t *l)
>  
>  	atomic64_sub(i, v);
>  }
> -
> +#if 0
>  static inline int atomic_long_sub_and_test(long i, atomic_long_t *l)
>  {
>  	atomic64_t *v = (atomic64_t *)l;
> @@ -128,6 +128,7 @@ static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u)
>  
>  	return (long)atomic64_add_unless(v, a, u);
>  }
> +#endif

Why comment these out?

>  
>  #define atomic_long_inc_not_zero(l) atomic64_inc_not_zero((atomic64_t *)(l))
>  
> diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h
> index 449cecaabc..6e63b8e8e7 100644
> --- a/include/asm-generic/atomic.h
> +++ b/include/asm-generic/atomic.h
> @@ -11,7 +11,55 @@
>  #ifdef CONFIG_SMP
>  #error SMP not supported
>  #endif
> +#define ATOMIC_INIT(i)	{ (i) }
> +
> +#ifdef CONFIG_64BIT
> +typedef struct { s64 counter; } atomic64_t;
> +
> +#define atomic64_read(v)	((v)->counter)
> +#define atomic64_set(v, i)	(((v)->counter) = (i))
> +
> +static inline void atomic64_add(s64 i, volatile atomic64_t *v)
> +{
> +	v->counter += i;
> +}
> +
> +static inline void atomic64_sub(s64 i, volatile atomic64_t *v)
> +{
> +	v->counter -= i;
> +}
> +
> +static inline void atomic64_inc(volatile atomic64_t *v)
> +{
> +	v->counter += 1;
> +}
> +
> +static inline void atomic64_dec(volatile atomic64_t *v)
> +{
> +	v->counter -= 1;
> +}
> +
> +static inline int atomic64_dec_and_test(volatile atomic64_t *v)
> +{
> +	s64 val;
> +
> +	val = v->counter;
> +	v->counter = val -= 1;
> +
> +	return val == 0;
> +}
>  
> +static inline int atomic64_add_negative(s64 i, volatile atomic64_t *v)
> +{
> +	s64 val;
> +
> +	val = v->counter;
> +	v->counter = val += i;
> +
> +	return val < 0;
> +}
> +
> +#else
>  typedef struct { volatile int counter; } atomic_t;
>  
>  #define ATOMIC_INIT(i)	{ (i) }
> @@ -63,6 +111,7 @@ static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
>  {
>  	*addr &= ~mask;
>  }
> +#endif
>  
>  /* Atomic operations are already serializing on ARM */
>  #define smp_mb__before_atomic_dec()	barrier()
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/4] arm: 64-bit device specific operation
  2021-07-28 12:47 ` [PATCH 2/4] arm: 64-bit device specific operation Renaud Barbier
@ 2021-07-29 10:00   ` Ahmad Fatoum
  0 siblings, 0 replies; 10+ messages in thread
From: Ahmad Fatoum @ 2021-07-29 10:00 UTC (permalink / raw)
  To: Renaud Barbier, barebox

On 28.07.21 14:47, Renaud Barbier wrote:
> In preparation for the introduction of the NXP FSL IFC
> nand driver, add memcpy_ directional I/O operation.
> 
> Code based on NXP Linux support:
> git://source.codeaurora.org/external/qoriq/qoriq-components/linux

barebox next branch already contains cbd23110fca5 ("ARM64: Implement mem*_*io()"),
so I think you can drop this patch here.

> 
> Signed-off-by: Renaud Barbier <renaud.barbier@abaco.com>
> ---
>  arch/arm/lib64/Makefile |  2 +-
>  arch/arm/lib64/io.c     | 98 +++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 99 insertions(+), 1 deletion(-)
>  create mode 100644 arch/arm/lib64/io.c
> 
> diff --git a/arch/arm/lib64/Makefile b/arch/arm/lib64/Makefile
> index 69cb3d8ea1..591727c160 100644
> --- a/arch/arm/lib64/Makefile
> +++ b/arch/arm/lib64/Makefile
> @@ -1,4 +1,4 @@
> -obj-y += stacktrace.o
> +obj-y += stacktrace.o io.o
>  obj-$(CONFIG_ARM_LINUX)	+= armlinux.o
>  obj-y	+= div0.o
>  obj-$(CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS)	+= memcpy.o
> diff --git a/arch/arm/lib64/io.c b/arch/arm/lib64/io.c
> new file mode 100644
> index 0000000000..693cda42b0
> --- /dev/null
> +++ b/arch/arm/lib64/io.c
> @@ -0,0 +1,98 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Based on arch/arm/kernel/io.c
> + *
> + * Copyright (C) 2012 ARM Ltd.
> + */
> +
> +#include <module.h>
> +#include <linux/kernel.h>
> +#include <linux/types.h>
> +#include <io.h>
> +
> +/*
> + * Copy data from IO memory space to "real" memory space.
> + */
> +void memcpy_fromio(void *to, const volatile void __iomem *from, size_t count)
> +{
> +	while (count && !IS_ALIGNED((unsigned long)from, 8)) {
> +		*(u8 *)to = __raw_readb(from);
> +		from++;
> +		to++;
> +		count--;
> +	}
> +
> +	while (count >= 8) {
> +		*(u64 *)to = __raw_readq(from);
> +		from += 8;
> +		to += 8;
> +		count -= 8;
> +	}
> +
> +	while (count) {
> +		*(u8 *)to = __raw_readb(from);
> +		from++;
> +		to++;
> +		count--;
> +	}
> +}
> +EXPORT_SYMBOL(memcpy_fromio);
> +
> +/*
> + * Copy data from "real" memory space to IO memory space.
> + */
> +void memcpy_toio(volatile void __iomem *to, const void *from, size_t count)
> +{
> +	while (count && !IS_ALIGNED((unsigned long)to, 8)) {
> +		__raw_writeb(*(u8 *)from, to);
> +		from++;
> +		to++;
> +		count--;
> +	}
> +
> +	while (count >= 8) {
> +		__raw_writeq(*(u64 *)from, to);
> +		from += 8;
> +		to += 8;
> +		count -= 8;
> +	}
> +
> +	while (count) {
> +		__raw_writeb(*(u8 *)from, to);
> +		from++;
> +		to++;
> +		count--;
> +	}
> +}
> +EXPORT_SYMBOL(memcpy_toio);
> +
> +/*
> + * "memset" on IO memory space.
> + */
> +void memset_io(volatile void __iomem *dst, int c, size_t count)
> +{
> +	u64 qc = (u8)c;
> +
> +	qc |= qc << 8;
> +	qc |= qc << 16;
> +	qc |= qc << 32;
> +
> +	while (count && !IS_ALIGNED((unsigned long)dst, 8)) {
> +		__raw_writeb(c, dst);
> +		dst++;
> +		count--;
> +	}
> +
> +	while (count >= 8) {
> +		__raw_writeq(qc, dst);
> +		dst += 8;
> +		count -= 8;
> +	}
> +
> +	while (count) {
> +		__raw_writeb(c, dst);
> +		dst++;
> +		count--;
> +	}
> +}
> +EXPORT_SYMBOL(memset_io);
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 3/4] nand: add NXP IFC nand driver
  2021-07-28 12:47 ` [PATCH 3/4] nand: add NXP IFC nand driver Renaud Barbier
@ 2021-07-29 10:11   ` Ahmad Fatoum
  0 siblings, 0 replies; 10+ messages in thread
From: Ahmad Fatoum @ 2021-07-29 10:11 UTC (permalink / raw)
  To: Renaud Barbier, barebox

On 28.07.21 14:47, Renaud Barbier wrote:
> Add the NXP IFC nand driver support. This driver
> can be used with the NXP QorIQ cores.
> 
> Signed-off-by: Renaud Barbier <renaud.barbier@abaco.com>
> ---
>  .../mach-layerscape/include/mach/fsl_ifc.h    |   16 +
>  .../mach-layerscape/include/mach/layerscape.h |    3 +
>  drivers/mtd/nand/Kconfig                      |    6 +
>  drivers/mtd/nand/Makefile                     |    1 +
>  drivers/mtd/nand/fsl_ifc.h                    |  116 ++
>  drivers/mtd/nand/nand_fsl_ifc.c               | 1037 +++++++++++++++++
>  include/linux/fsl_ifc.h                       |  306 +++++
>  7 files changed, 1485 insertions(+)
>  create mode 100644 arch/arm/mach-layerscape/include/mach/fsl_ifc.h
>  create mode 100644 drivers/mtd/nand/fsl_ifc.h
>  create mode 100644 drivers/mtd/nand/nand_fsl_ifc.c
>  create mode 100644 include/linux/fsl_ifc.h
> 
> diff --git a/arch/arm/mach-layerscape/include/mach/fsl_ifc.h b/arch/arm/mach-layerscape/include/mach/fsl_ifc.h
> new file mode 100644
> index 0000000000..385d07cb1f
> --- /dev/null
> +++ b/arch/arm/mach-layerscape/include/mach/fsl_ifc.h
> @@ -0,0 +1,16 @@
> +/* SPDX-License-Identifier:     GPL-2.0+ */
> +/*
> + * Copyright 2021 Abaco Systems, Inc
> + */
> +
> +#ifndef __MACH_MTD_FSL_IFC
> +#define __MACH_MTD_FSL_IFC
> +
> +#include <mach/layerscape.h>
> +#include <linux/fsl_ifc.h>
> +
> +
> +struct fsl_ifc_data {
> +	uint32_t cs;
> +};
> +#endif

Header can be dropped as the Layerscape support is DT-only.

> diff --git a/arch/arm/mach-layerscape/include/mach/layerscape.h b/arch/arm/mach-layerscape/include/mach/layerscape.h
> index 1f1da0f66e..cb7bbc56b0 100644
> --- a/arch/arm/mach-layerscape/include/mach/layerscape.h
> +++ b/arch/arm/mach-layerscape/include/mach/layerscape.h
> @@ -3,6 +3,9 @@
>  
>  #define LS1046A_DDR_SDRAM_BASE	0x80000000
>  #define LS1046A_DDR_FREQ	2100000000
> +#define LS10146A_IFC_ADDR	0x01530000
> +
> +#define IFC_ADDR	LS10146A_IFC_ADDR

That's a too generic macro name. You should retrieve the base address
from device tree in the driver. Otherwise, if a new Layerscape SoC
is added, you won't be able to have a multi-image barebox build
that supports both.


> +static int fsl_ifc_nand_probe(struct device_d *dev)
> +{
> +	struct device_node *np = dev->device_node;
> +	struct fsl_ifc_data *pdata = dev->platform_data;
> +	struct fsl_ifc_mtd *priv;
> +	struct resource *iores;
> +	struct mtd_info *mtd;
> +	int ret = 0;
> +
> +	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->dev = dev;
> +	if (!np) {

I'd remove the PPC non-DT support. It doesn't compile now anyway.

Cheers,
Ahmad


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 4/4] ls1046ardb: enable IFC NAND.
  2021-07-28 12:47 ` [PATCH 4/4] ls1046ardb: enable IFC NAND Renaud Barbier
@ 2021-07-29 10:13   ` Ahmad Fatoum
  2021-07-29 18:19     ` Barbier, Renaud
  0 siblings, 1 reply; 10+ messages in thread
From: Ahmad Fatoum @ 2021-07-29 10:13 UTC (permalink / raw)
  To: Renaud Barbier, barebox

Hi,

On 28.07.21 14:47, Renaud Barbier wrote:
> Set the NAND timings and enable the IFC NAND driver.
> 
> Signed-off-by: Renaud Barbier <renaud.barbier@abaco.com>
> ---
>  arch/arm/boards/ls1046ardb/board.c    | 26 ++++++++++++++++++++++++++
>  arch/arm/configs/layerscape_defconfig | 12 ++++++++++++
>  2 files changed, 38 insertions(+)
> 
> diff --git a/arch/arm/boards/ls1046ardb/board.c b/arch/arm/boards/ls1046ardb/board.c
> index ef68e9c7f9..5573d5b486 100644
> --- a/arch/arm/boards/ls1046ardb/board.c
> +++ b/arch/arm/boards/ls1046ardb/board.c
> @@ -12,6 +12,7 @@
>  #include <linux/sizes.h>
>  #include <linux/clk.h>
>  #include <linux/clkdev.h>
> +#include <linux/fsl_ifc.h>
>  #include <asm/system.h>
>  #include <mach/layerscape.h>
>  #include <mach/bbu.h>
> @@ -147,6 +148,31 @@ static int rdb_mem_init(void)
>  }
>  mem_initcall(rdb_mem_init);
>  
> +static int rdb_nand_init(void)
> +{

You should check against board compatible here.

> +	/* NAND mapping and timings. Only for Linux use. */

Why is this only for Linux use? You use the driver in barebox, don't you?

> +	set_ifc_cspr(IFC_CS0, CSPR_PHYS_ADDR(0x7e800000) | CSPR_PORT_SIZE_8 |
> +				CSPR_MSEL_NAND | CSPR_V);
> +	set_ifc_csor(IFC_CS0, CSOR_NAND_ECC_ENC_EN | CSOR_NAND_ECC_DEC_EN |
> +			CSOR_NAND_ECC_MODE_8 |
> +			CSOR_NAND_RAL_3 | CSOR_NAND_PGS_4K |
> +			CSOR_NAND_SPRZ_224 |  CSOR_NAND_PB(64) |
> +			CSOR_NAND_TRHZ_20);
> +	set_ifc_amask(IFC_CS0, IFC_AMASK(64*1024));
> +	set_ifc_ftim(IFC_CS0, IFC_FTIM0, FTIM0_NAND_TCCST(0x07) |
> +			FTIM0_NAND_TWP(0x18) | FTIM0_NAND_TWCHT(0x07) |
> +			FTIM0_NAND_TWH(0x0a));
> +	set_ifc_ftim(IFC_CS0, IFC_FTIM1, FTIM1_NAND_TADLE(0x32) |
> +			FTIM1_NAND_TWBE(0x39) | FTIM1_NAND_TRR(0x0e)|
> +			FTIM1_NAND_TRP(0x18));
> +	set_ifc_ftim(IFC_CS0, IFC_FTIM2, FTIM2_NAND_TRAD(0xf) |
> +			FTIM2_NAND_TREH(0xa) | FTIM2_NAND_TWHRE(0x1e));
> +	set_ifc_ftim(IFC_CS0, IFC_FTIM3, 0);

I assume there are no DT bindings describing these parameters for the
IFC driver to consume?

> +
> +	return 0;
> +}
> +core_initcall(rdb_nand_init);

Cheers,
Ahmad


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 10+ messages in thread

* RE: [PATCH 4/4] ls1046ardb: enable IFC NAND.
  2021-07-29 10:13   ` Ahmad Fatoum
@ 2021-07-29 18:19     ` Barbier, Renaud
  0 siblings, 0 replies; 10+ messages in thread
From: Barbier, Renaud @ 2021-07-29 18:19 UTC (permalink / raw)
  To: Ahmad Fatoum, barebox


>>
>> +static int rdb_nand_init(void)
>> +{

> You should check against board compatible here.

Yes. Found a way to do it from other board support.

Cheers,
Renaud

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2021-07-29 18:21 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-28 12:47 [PATCH 0/4] NXP IFC nand driver Renaud Barbier
2021-07-28 12:47 ` [PATCH 1/4] ARM: atomic.h: add 64-bit counter support Renaud Barbier
2021-07-29  9:58   ` Ahmad Fatoum
2021-07-28 12:47 ` [PATCH 2/4] arm: 64-bit device specific operation Renaud Barbier
2021-07-29 10:00   ` Ahmad Fatoum
2021-07-28 12:47 ` [PATCH 3/4] nand: add NXP IFC nand driver Renaud Barbier
2021-07-29 10:11   ` Ahmad Fatoum
2021-07-28 12:47 ` [PATCH 4/4] ls1046ardb: enable IFC NAND Renaud Barbier
2021-07-29 10:13   ` Ahmad Fatoum
2021-07-29 18:19     ` Barbier, Renaud

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox