All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver
@ 2017-11-21 17:38 Masahiro Yamada
  2017-11-21 17:38 ` [U-Boot] [PATCH 01/22] bitops: collect BIT macros to include/linux/bitops.h Masahiro Yamada
                   ` (22 more replies)
  0 siblings, 23 replies; 29+ messages in thread
From: Masahiro Yamada @ 2017-11-21 17:38 UTC (permalink / raw)
  To: u-boot


My motivation is to complete syncing the Denali driver with Linux.

However, the last sync of NAND core was Linux 4.6
so a lots of parts are missing in U-Boot.

I imported the following:

 - NAND_ECC_MAXIMIZE flag
 - nand_data_interface
 - sync nand_timings
 - NAND_ECC_CUSTOM_PAGE_ACCESS
 - mtd_ooblayout_xxx()
 - chip->buf_align
 - helpers to match ECC requirement
 - NAND_ROW_ADDR_3

The blind syncing often broke drivers.

Forcible syncing often broke drivers in the past.
This time, I imported necessary commits one by one.
I put the corresponding commit ID in Linux.
And, it should be easy to review that the existing drivers
are not affected.

Lastly, I updated the Denali driver.
I tested it on my boards and worked for me.
It is nicely synced with Linux.



Boris Brezillon (9):
  mtd: nand: Add an option to maximize the ECC strength
  mtd: nand: automate NAND timings selection
  mtd: nand: Fix data interface configuration logic
  mtd: nand: Add a few more timings to nand_sdr_timings
  mtd: add mtd_ooblayout_xxx() helper functions
  mtd: nand: Drop unused cached programming support
  mtd: nand: Drop the ->errstat() hook
  mtd: nand: Wait for PAGEPROG to finish in drivers setting
    NAND_ECC_CUSTOM_PAGE_ACCESS
  mtd: nand: Pass the CS line to ->setup_data_interface()

Marc Gonzalez (1):
  mtd: nand: Support controllers with custom page

Masahiro Yamada (7):
  bitops: collect BIT macros to include/linux/bitops.h
  mtd: nand: add onfi_* stubs in case ONFI_DETECTION is disabled
  mtd: nand: allow drivers to request minimum alignment for passed
    buffer
  mtd: nand: add generic helpers to check, match, maximize ECC settings
  mtd: nand: add a shorthand to generate nand_ecc_caps structure
  mtd: nand: introduce NAND_ROW_ADDR_3 flag
  mtd: nand: denali: sync with Linux 4.15-rc1

Sascha Hauer (5):
  mtd: nand: remove unnecessary 'extern' from function declarations
  mtd: nand: Create a NAND reset function
  mtd: nand: Introduce nand_data_interface
  mtd: nand: convert ONFI mode into data interface
  mtd: nand: Expose data interface for ONFI mode 0

 arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h |    3 +-
 arch/arm/mach-kirkwood/include/mach/gpio.h      |    4 -
 drivers/gpio/kw_gpio.c                          |    2 +-
 drivers/mtd/mtdcore.c                           |  360 ++++
 drivers/mtd/nand/Kconfig                        |   11 -
 drivers/mtd/nand/davinci_nand.c                 |   10 +-
 drivers/mtd/nand/denali.c                       | 2028 ++++++++++++-----------
 drivers/mtd/nand/denali.h                       |  473 ++----
 drivers/mtd/nand/denali_dt.c                    |   17 +-
 drivers/mtd/nand/denali_spl.c                   |   14 +-
 drivers/mtd/nand/nand_base.c                    |  530 +++++-
 drivers/mtd/nand/nand_timings.c                 |  494 +++---
 include/linux/bitops.h                          |    7 +
 include/linux/mtd/mtd.h                         |   57 +
 include/linux/mtd/nand.h                        |  314 +++-
 include/usb/lin_gadget_compat.h                 |    4 +-
 16 files changed, 2685 insertions(+), 1643 deletions(-)

-- 
2.7.4

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

* [U-Boot] [PATCH 01/22] bitops: collect BIT macros to include/linux/bitops.h
  2017-11-21 17:38 [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
@ 2017-11-21 17:38 ` Masahiro Yamada
  2017-11-21 17:38 ` [U-Boot] [PATCH 02/22] mtd: nand: add onfi_* stubs in case ONFI_DETECTION is disabled Masahiro Yamada
                   ` (21 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Masahiro Yamada @ 2017-11-21 17:38 UTC (permalink / raw)
  To: u-boot

Same macros are defined in various places.  Collect them into
include/linux/bitops.h like Linux.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---

 arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h | 3 ++-
 arch/arm/mach-kirkwood/include/mach/gpio.h      | 4 ----
 drivers/gpio/kw_gpio.c                          | 2 +-
 drivers/mtd/nand/nand_base.c                    | 2 --
 include/linux/bitops.h                          | 7 +++++++
 include/usb/lin_gadget_compat.h                 | 4 +---
 6 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h b/arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h
index 03fd46b..66e206d 100644
--- a/arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h
+++ b/arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h
@@ -13,6 +13,8 @@
 #ifndef _SUNXI_DRAM_SUN8I_H3_H
 #define _SUNXI_DRAM_SUN8I_H3_H
 
+#include <linux/bitops.h>
+
 struct sunxi_mctl_com_reg {
 	u32 cr;			/* 0x00 control register */
 	u32 cr_r1;		/* 0x04 rank 1 control register (R40 only) */
@@ -211,7 +213,6 @@ struct sunxi_mctl_ctl_reg {
  * the 32-bit wide access consists of. Also three control signals can be
  * adjusted individually.
  */
-#define BITS_PER_BYTE		8
 #define NR_OF_BYTE_LANES	(32 / BITS_PER_BYTE)
 /* The eight data lines (DQn) plus DM, DQS and DQSN */
 #define LINES_PER_BYTE_LANE	(BITS_PER_BYTE + 3)
diff --git a/arch/arm/mach-kirkwood/include/mach/gpio.h b/arch/arm/mach-kirkwood/include/mach/gpio.h
index aa8c5da..ac2397d 100644
--- a/arch/arm/mach-kirkwood/include/mach/gpio.h
+++ b/arch/arm/mach-kirkwood/include/mach/gpio.h
@@ -15,10 +15,6 @@
 #ifndef __KIRKWOOD_GPIO_H
 #define __KIRKWOOD_GPIO_H
 
-/* got from kernel include/linux/bitops.h */
-#define BITS_PER_BYTE 8
-#define BITS_TO_LONGS(nr)	DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
-
 #define GPIO_MAX		50
 #define GPIO_OFF(pin)		(((pin) >> 5) ? 0x0040 : 0x0000)
 #define GPIO_OUT(pin)		(MVEBU_GPIO0_BASE + GPIO_OFF(pin) + 0x00)
diff --git a/drivers/gpio/kw_gpio.c b/drivers/gpio/kw_gpio.c
index 43b27e3..cc26cc1 100644
--- a/drivers/gpio/kw_gpio.c
+++ b/drivers/gpio/kw_gpio.c
@@ -14,7 +14,7 @@
  */
 
 #include <common.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <asm/io.h>
 #include <asm/arch/soc.h>
 #include <asm/arch/gpio.h>
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 5bb4ea8..efe3e4f 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -901,8 +901,6 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
 	return status;
 }
 
-#define BITS_PER_BYTE 8
-
 /**
  * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data
  * @buf: buffer to test
diff --git a/include/linux/bitops.h b/include/linux/bitops.h
index 576b15d..a47f6d1 100644
--- a/include/linux/bitops.h
+++ b/include/linux/bitops.h
@@ -5,9 +5,16 @@
 #include <asm-generic/bitsperlong.h>
 #include <linux/compiler.h>
 
+#ifdef	__KERNEL__
 #define BIT(nr)			(1UL << (nr))
+#define BIT_ULL(nr)		(1ULL << (nr))
 #define BIT_MASK(nr)		(1UL << ((nr) % BITS_PER_LONG))
 #define BIT_WORD(nr)		((nr) / BITS_PER_LONG)
+#define BIT_ULL_MASK(nr)	(1ULL << ((nr) % BITS_PER_LONG_LONG))
+#define BIT_ULL_WORD(nr)	((nr) / BITS_PER_LONG_LONG)
+#define BITS_PER_BYTE		8
+#define BITS_TO_LONGS(nr)	DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
+#endif
 
 /*
  * Create a contiguous bitmask starting@bit position @l and ending at
diff --git a/include/usb/lin_gadget_compat.h b/include/usb/lin_gadget_compat.h
index 4a01585..d0d71f7 100644
--- a/include/usb/lin_gadget_compat.h
+++ b/include/usb/lin_gadget_compat.h
@@ -10,12 +10,10 @@
 #ifndef __LIN_COMPAT_H__
 #define __LIN_COMPAT_H__
 
+#include <linux/bitops.h>
 #include <linux/compat.h>
 
 /* common */
-#define BITS_PER_BYTE				8
-#define BITS_TO_LONGS(nr) \
-	DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
 #define DECLARE_BITMAP(name, bits) \
 	unsigned long name[BITS_TO_LONGS(bits)]
 
-- 
2.7.4

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

* [U-Boot] [PATCH 02/22] mtd: nand: add onfi_* stubs in case ONFI_DETECTION is disabled
  2017-11-21 17:38 [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
  2017-11-21 17:38 ` [U-Boot] [PATCH 01/22] bitops: collect BIT macros to include/linux/bitops.h Masahiro Yamada
@ 2017-11-21 17:38 ` Masahiro Yamada
  2017-11-21 17:38 ` [U-Boot] [PATCH 03/22] mtd: nand: Add an option to maximize the ECC strength Masahiro Yamada
                   ` (20 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Masahiro Yamada @ 2017-11-21 17:38 UTC (permalink / raw)
  To: u-boot

Add stubs to the header in case CONFIG_SYS_NAND_ONFI_DETECTION is
disabled.  This is much easier than adding around #ifdef to the
caller side.

Also, I removed the #ifdef around onfi_params.  In Linux, onfi_params
and jedec_params are unified as union.  It will be the right thing
to do.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---

 include/linux/mtd/nand.h | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index d55807b..cba6563 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -741,9 +741,7 @@ struct nand_chip {
 
 	int onfi_version;
 	int jedec_version;
-#ifdef CONFIG_SYS_NAND_ONFI_DETECTION
 	struct nand_onfi_params	onfi_params;
-#endif
 	struct nand_jedec_params jedec_params;
  
 	int read_retries;
@@ -1001,6 +999,21 @@ static inline int onfi_get_sync_timing_mode(struct nand_chip *chip)
 		return ONFI_TIMING_MODE_UNKNOWN;
 	return le16_to_cpu(chip->onfi_params.src_sync_timing_mode);
 }
+#else
+static inline int onfi_feature(struct nand_chip *chip)
+{
+	return 0;
+}
+
+static inline int onfi_get_async_timing_mode(struct nand_chip *chip)
+{
+	return ONFI_TIMING_MODE_UNKNOWN;
+}
+
+static inline int onfi_get_sync_timing_mode(struct nand_chip *chip)
+{
+	return ONFI_TIMING_MODE_UNKNOWN;
+}
 #endif
 
 /*
-- 
2.7.4

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

* [U-Boot] [PATCH 03/22] mtd: nand: Add an option to maximize the ECC strength
  2017-11-21 17:38 [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
  2017-11-21 17:38 ` [U-Boot] [PATCH 01/22] bitops: collect BIT macros to include/linux/bitops.h Masahiro Yamada
  2017-11-21 17:38 ` [U-Boot] [PATCH 02/22] mtd: nand: add onfi_* stubs in case ONFI_DETECTION is disabled Masahiro Yamada
@ 2017-11-21 17:38 ` Masahiro Yamada
  2017-11-21 17:38 ` [U-Boot] [PATCH 04/22] mtd: nand: remove unnecessary 'extern' from function declarations Masahiro Yamada
                   ` (19 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Masahiro Yamada @ 2017-11-21 17:38 UTC (permalink / raw)
  To: u-boot

From: Boris Brezillon <boris.brezillon@free-electrons.com>

The generic NAND DT bindings allows one to tweak the ECC strength and
step size to their need. It can be used to lower the ECC strength to
match a bootloader/firmware config, but might also be used to get a better
reliability.

In the latter case, the user might want to use the maximum ECC strength
without having to explicitly calculate the exact value (this value not
only depends on the OOB size, but also on the NAND controller, and can
be tricky to extract).

Add a generic 'nand-ecc-maximize' DT property and the associated
NAND_ECC_MAXIMIZE flag, to let ECC controller drivers select the best
ECC strength and step-size on their own.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Acked-by: Rob Herring <robh@kernel.org>
[Linux commit: ba78ee00e1ff84de9b3ad33edbd3ec599099ee82]
[masahiro: of_property_read_bool -> fdt_getprop for U-Boot]
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>

---

 drivers/mtd/nand/nand_base.c | 3 +++
 include/linux/mtd/nand.h     | 1 +
 2 files changed, 4 insertions(+)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index efe3e4f..18f4169 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -3817,6 +3817,9 @@ static int nand_dt_init(struct mtd_info *mtd, struct nand_chip *chip, int node)
 	if (ecc_step > 0)
 		chip->ecc.size = ecc_step;
 
+	if (fdt_getprop(blob, node, "nand-ecc-maximize", NULL))
+		chip->ecc.options |= NAND_ECC_MAXIMIZE;
+
 	return 0;
 }
 #else
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index cba6563..eebfb13 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -153,6 +153,7 @@ typedef enum {
  * pages and you want to rely on the default implementation.
  */
 #define NAND_ECC_GENERIC_ERASED_CHECK	BIT(0)
+#define NAND_ECC_MAXIMIZE		BIT(1)
 
 /* Bit mask for flags passed to do_nand_read_ecc */
 #define NAND_GET_DEVICE		0x80
-- 
2.7.4

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

* [U-Boot] [PATCH 04/22] mtd: nand: remove unnecessary 'extern' from function declarations
  2017-11-21 17:38 [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
                   ` (2 preceding siblings ...)
  2017-11-21 17:38 ` [U-Boot] [PATCH 03/22] mtd: nand: Add an option to maximize the ECC strength Masahiro Yamada
@ 2017-11-21 17:38 ` Masahiro Yamada
  2017-11-21 17:38 ` [U-Boot] [PATCH 05/22] mtd: nand: Create a NAND reset function Masahiro Yamada
                   ` (18 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Masahiro Yamada @ 2017-11-21 17:38 UTC (permalink / raw)
  To: u-boot

From: Sascha Hauer <s.hauer@pengutronix.de>

'extern' is not necessary for function declarations. To prevent
people from adding the keyword to new declarations remove the
existing ones.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
[Linux commit: 79022591839f110f465cac0223e117b91d47d5db]
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>

---

 include/linux/mtd/nand.h | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index eebfb13..3facbbd 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -28,20 +28,20 @@ struct nand_flash_dev;
 struct device_node;
 
 /* Scan and identify a NAND device */
-extern int nand_scan(struct mtd_info *mtd, int max_chips);
+int nand_scan(struct mtd_info *mtd, int max_chips);
 /*
  * Separate phases of nand_scan(), allowing board driver to intervene
  * and override command or ECC setup according to flash type.
  */
-extern int nand_scan_ident(struct mtd_info *mtd, int max_chips,
+int nand_scan_ident(struct mtd_info *mtd, int max_chips,
 			   struct nand_flash_dev *table);
-extern int nand_scan_tail(struct mtd_info *mtd);
+int nand_scan_tail(struct mtd_info *mtd);
 
 /* Free resources held by the NAND device */
-extern void nand_release(struct mtd_info *mtd);
+void nand_release(struct mtd_info *mtd);
 
 /* Internal helper for board drivers which need to override command function */
-extern void nand_wait_ready(struct mtd_info *mtd);
+void nand_wait_ready(struct mtd_info *mtd);
 
 /*
  * This constant declares the max. oobsize / page, which
@@ -899,13 +899,13 @@ struct nand_manufacturers {
 extern struct nand_flash_dev nand_flash_ids[];
 extern struct nand_manufacturers nand_manuf_ids[];
 
-extern int nand_default_bbt(struct mtd_info *mtd);
-extern int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);
-extern int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs);
-extern int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt);
-extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
+int nand_default_bbt(struct mtd_info *mtd);
+int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);
+int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs);
+int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt);
+int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
 			   int allowbbt);
-extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
+int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
 			size_t *retlen, uint8_t *buf);
 
 /*
-- 
2.7.4

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

* [U-Boot] [PATCH 05/22] mtd: nand: Create a NAND reset function
  2017-11-21 17:38 [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
                   ` (3 preceding siblings ...)
  2017-11-21 17:38 ` [U-Boot] [PATCH 04/22] mtd: nand: remove unnecessary 'extern' from function declarations Masahiro Yamada
@ 2017-11-21 17:38 ` Masahiro Yamada
  2017-11-21 17:38 ` [U-Boot] [PATCH 06/22] mtd: nand: Introduce nand_data_interface Masahiro Yamada
                   ` (17 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Masahiro Yamada @ 2017-11-21 17:38 UTC (permalink / raw)
  To: u-boot

From: Sascha Hauer <s.hauer@pengutronix.de>

When NAND devices are resetted some initialization may have to be done,
like for example they have to be configured for the timing mode that
shall be used. To get a common place where this initialization can be
implemented create a nand_reset() function. This currently only issues
a NAND_CMD_RESET to the NAND device. The places issuing this command
manually are replaced with a call to nand_reset().

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
[Linux commit: 2f94abfe35b210e7711af9202a3dcfc9e779219a]
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>

---

 drivers/mtd/nand/nand_base.c | 21 ++++++++++++++++++---
 include/linux/mtd/nand.h     |  4 ++++
 2 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 18f4169..77da6fa 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -902,6 +902,21 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
 }
 
 /**
+ * nand_reset - Reset and initialize a NAND device
+ * @chip: The NAND chip
+ *
+ * Returns 0 for success or negative error code otherwise
+ */
+int nand_reset(struct nand_chip *chip)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+
+	return 0;
+}
+
+/**
  * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data
  * @buf: buffer to test
  * @len: buffer length
@@ -2591,7 +2606,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
 	 * if we don't do this. I have no clue why, but I seem to have 'fixed'
 	 * it in the doc2000 driver in August 1999.  dwmw2.
 	 */
-	chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+	nand_reset(chip);
 
 	/* Check, if it is write protected */
 	if (nand_check_wp(mtd)) {
@@ -3612,7 +3627,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
 	 * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
 	 * after power-up.
 	 */
-	chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+	nand_reset(chip);
 
 	/* Send the command for reading device ID */
 	chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
@@ -3873,7 +3888,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
 	for (i = 1; i < maxchips; i++) {
 		chip->select_chip(mtd, i);
 		/* See comment in nand_get_flash_type for reset */
-		chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+		nand_reset(chip);
 		/* Send the command for reading device ID */
 		chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
 		/* Read manufacturer and device IDs */
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 3facbbd..df00fd1 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -1115,4 +1115,8 @@ int nand_check_erased_ecc_chunk(void *data, int datalen,
 				void *ecc, int ecclen,
 				void *extraoob, int extraooblen,
 				int threshold);
+
+/* Reset and initialize a NAND device */
+int nand_reset(struct nand_chip *chip);
+
 #endif /* __LINUX_MTD_NAND_H */
-- 
2.7.4

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

* [U-Boot] [PATCH 06/22] mtd: nand: Introduce nand_data_interface
  2017-11-21 17:38 [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
                   ` (4 preceding siblings ...)
  2017-11-21 17:38 ` [U-Boot] [PATCH 05/22] mtd: nand: Create a NAND reset function Masahiro Yamada
@ 2017-11-21 17:38 ` Masahiro Yamada
  2017-11-21 17:38 ` [U-Boot] [PATCH 07/22] mtd: nand: convert ONFI mode into data interface Masahiro Yamada
                   ` (16 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Masahiro Yamada @ 2017-11-21 17:38 UTC (permalink / raw)
  To: u-boot

From: Sascha Hauer <s.hauer@pengutronix.de>

Currently we have no data structure to fully describe a NAND timing.
We only have struct nand_sdr_timings for NAND timings in SDR mode,
but nothing for DDR mode and also no container to store both types
of timing.
This patch adds struct nand_data_interface which stores the timing
type and a union of different timings. This can be used to pass to
drivers in order to configure the timing.
Add kerneldoc for struct nand_sdr_timings while touching it anyway.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
[Linux commit: eee64b700e26b9bcc6fce024681c31f5e12271fc]
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>

---

 include/linux/mtd/nand.h | 166 +++++++++++++++++++++++++++++++++--------------
 1 file changed, 117 insertions(+), 49 deletions(-)

diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index df00fd1..e321e3e 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -585,6 +585,123 @@ struct nand_buffers {
 };
 
 /**
+ * struct nand_sdr_timings - SDR NAND chip timings
+ *
+ * This struct defines the timing requirements of a SDR NAND chip.
+ * These information can be found in every NAND datasheets and the timings
+ * meaning are described in the ONFI specifications:
+ * www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf (chapter 4.15 Timing
+ * Parameters)
+ *
+ * All these timings are expressed in picoseconds.
+ *
+ * @tALH_min: ALE hold time
+ * @tADL_min: ALE to data loading time
+ * @tALS_min: ALE setup time
+ * @tAR_min: ALE to RE# delay
+ * @tCEA_max: CE# access time
+ * @tCEH_min: CE# high hold time
+ * @tCH_min:  CE# hold time
+ * @tCHZ_max: CE# high to output hi-Z
+ * @tCLH_min: CLE hold time
+ * @tCLR_min: CLE to RE# delay
+ * @tCLS_min: CLE setup time
+ * @tCOH_min: CE# high to output hold
+ * @tCS_min: CE# setup time
+ * @tDH_min: Data hold time
+ * @tDS_min: Data setup time
+ * @tFEAT_max: Busy time for Set Features and Get Features
+ * @tIR_min: Output hi-Z to RE# low
+ * @tITC_max: Interface and Timing Mode Change time
+ * @tRC_min: RE# cycle time
+ * @tREA_max: RE# access time
+ * @tREH_min: RE# high hold time
+ * @tRHOH_min: RE# high to output hold
+ * @tRHW_min: RE# high to WE# low
+ * @tRHZ_max: RE# high to output hi-Z
+ * @tRLOH_min: RE# low to output hold
+ * @tRP_min: RE# pulse width
+ * @tRR_min: Ready to RE# low (data only)
+ * @tRST_max: Device reset time, measured from the falling edge of R/B# to the
+ *	      rising edge of R/B#.
+ * @tWB_max: WE# high to SR[6] low
+ * @tWC_min: WE# cycle time
+ * @tWH_min: WE# high hold time
+ * @tWHR_min: WE# high to RE# low
+ * @tWP_min: WE# pulse width
+ * @tWW_min: WP# transition to WE# low
+ */
+struct nand_sdr_timings {
+	u32 tALH_min;
+	u32 tADL_min;
+	u32 tALS_min;
+	u32 tAR_min;
+	u32 tCEA_max;
+	u32 tCEH_min;
+	u32 tCH_min;
+	u32 tCHZ_max;
+	u32 tCLH_min;
+	u32 tCLR_min;
+	u32 tCLS_min;
+	u32 tCOH_min;
+	u32 tCS_min;
+	u32 tDH_min;
+	u32 tDS_min;
+	u32 tFEAT_max;
+	u32 tIR_min;
+	u32 tITC_max;
+	u32 tRC_min;
+	u32 tREA_max;
+	u32 tREH_min;
+	u32 tRHOH_min;
+	u32 tRHW_min;
+	u32 tRHZ_max;
+	u32 tRLOH_min;
+	u32 tRP_min;
+	u32 tRR_min;
+	u64 tRST_max;
+	u32 tWB_max;
+	u32 tWC_min;
+	u32 tWH_min;
+	u32 tWHR_min;
+	u32 tWP_min;
+	u32 tWW_min;
+};
+
+/**
+ * enum nand_data_interface_type - NAND interface timing type
+ * @NAND_SDR_IFACE:	Single Data Rate interface
+ */
+enum nand_data_interface_type {
+	NAND_SDR_IFACE,
+};
+
+/**
+ * struct nand_data_interface - NAND interface timing
+ * @type:	type of the timing
+ * @timings:	The timing, type according to @type
+ */
+struct nand_data_interface {
+	enum nand_data_interface_type type;
+	union {
+		struct nand_sdr_timings sdr;
+	} timings;
+};
+
+/**
+ * nand_get_sdr_timings - get SDR timing from data interface
+ * @conf:	The data interface
+ */
+static inline const struct nand_sdr_timings *
+nand_get_sdr_timings(const struct nand_data_interface *conf)
+{
+	if (conf->type != NAND_SDR_IFACE)
+		return ERR_PTR(-EINVAL);
+
+	return &conf->timings.sdr;
+}
+
+/**
  * struct nand_chip - NAND Private Flash Chip Data
  * @mtd:		MTD device registered to the MTD framework
  * @IO_ADDR_R:		[BOARDSPECIFIC] address to read the 8 I/O lines of the
@@ -1059,55 +1176,6 @@ void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len);
 void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len);
 uint8_t nand_read_byte(struct mtd_info *mtd);
 
-/*
- * struct nand_sdr_timings - SDR NAND chip timings
- *
- * This struct defines the timing requirements of a SDR NAND chip.
- * These informations can be found in every NAND datasheets and the timings
- * meaning are described in the ONFI specifications:
- * www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf (chapter 4.15 Timing
- * Parameters)
- *
- * All these timings are expressed in picoseconds.
- */
-
-struct nand_sdr_timings {
-	u32 tALH_min;
-	u32 tADL_min;
-	u32 tALS_min;
-	u32 tAR_min;
-	u32 tCEA_max;
-	u32 tCEH_min;
-	u32 tCH_min;
-	u32 tCHZ_max;
-	u32 tCLH_min;
-	u32 tCLR_min;
-	u32 tCLS_min;
-	u32 tCOH_min;
-	u32 tCS_min;
-	u32 tDH_min;
-	u32 tDS_min;
-	u32 tFEAT_max;
-	u32 tIR_min;
-	u32 tITC_max;
-	u32 tRC_min;
-	u32 tREA_max;
-	u32 tREH_min;
-	u32 tRHOH_min;
-	u32 tRHW_min;
-	u32 tRHZ_max;
-	u32 tRLOH_min;
-	u32 tRP_min;
-	u32 tRR_min;
-	u64 tRST_max;
-	u32 tWB_max;
-	u32 tWC_min;
-	u32 tWH_min;
-	u32 tWHR_min;
-	u32 tWP_min;
-	u32 tWW_min;
-};
-
 /* get timing characteristics from ONFI timing mode. */
 const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode);
 
-- 
2.7.4

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

* [U-Boot] [PATCH 07/22] mtd: nand: convert ONFI mode into data interface
  2017-11-21 17:38 [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
                   ` (5 preceding siblings ...)
  2017-11-21 17:38 ` [U-Boot] [PATCH 06/22] mtd: nand: Introduce nand_data_interface Masahiro Yamada
@ 2017-11-21 17:38 ` Masahiro Yamada
  2017-11-21 17:38 ` [U-Boot] [PATCH 08/22] mtd: nand: Expose data interface for ONFI mode 0 Masahiro Yamada
                   ` (15 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Masahiro Yamada @ 2017-11-21 17:38 UTC (permalink / raw)
  To: u-boot

From: Sascha Hauer <s.hauer@pengutronix.de>

struct nand_data_interface is the designated type to pass to
the NAND drivers to configure the timing. To simplify further
patches convert the onfi_sdr_timings array from type struct
nand_sdr_timings nand_data_interface.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
[Linux commit: b1dd3ca203fccd111926c3f6ac59bf903ec62b05]
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>

---

 drivers/mtd/nand/nand_timings.c | 459 ++++++++++++++++++++++------------------
 include/linux/mtd/nand.h        |   5 +
 2 files changed, 258 insertions(+), 206 deletions(-)

diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c
index 53dcbd3..b055d27 100644
--- a/drivers/mtd/nand/nand_timings.c
+++ b/drivers/mtd/nand/nand_timings.c
@@ -12,228 +12,246 @@
 #include <linux/kernel.h>
 #include <linux/mtd/nand.h>
 
-static const struct nand_sdr_timings onfi_sdr_timings[] = {
+static const struct nand_data_interface onfi_sdr_timings[] = {
 	/* Mode 0 */
 	{
-		.tADL_min = 200000,
-		.tALH_min = 20000,
-		.tALS_min = 50000,
-		.tAR_min = 25000,
-		.tCEA_max = 100000,
-		.tCEH_min = 20000,
-		.tCH_min = 20000,
-		.tCHZ_max = 100000,
-		.tCLH_min = 20000,
-		.tCLR_min = 20000,
-		.tCLS_min = 50000,
-		.tCOH_min = 0,
-		.tCS_min = 70000,
-		.tDH_min = 20000,
-		.tDS_min = 40000,
-		.tFEAT_max = 1000000,
-		.tIR_min = 10000,
-		.tITC_max = 1000000,
-		.tRC_min = 100000,
-		.tREA_max = 40000,
-		.tREH_min = 30000,
-		.tRHOH_min = 0,
-		.tRHW_min = 200000,
-		.tRHZ_max = 200000,
-		.tRLOH_min = 0,
-		.tRP_min = 50000,
-		.tRST_max = 250000000000ULL,
-		.tWB_max = 200000,
-		.tRR_min = 40000,
-		.tWC_min = 100000,
-		.tWH_min = 30000,
-		.tWHR_min = 120000,
-		.tWP_min = 50000,
-		.tWW_min = 100000,
+		.type = NAND_SDR_IFACE,
+		.timings.sdr = {
+			.tADL_min = 400000,
+			.tALH_min = 20000,
+			.tALS_min = 50000,
+			.tAR_min = 25000,
+			.tCEA_max = 100000,
+			.tCEH_min = 20000,
+			.tCH_min = 20000,
+			.tCHZ_max = 100000,
+			.tCLH_min = 20000,
+			.tCLR_min = 20000,
+			.tCLS_min = 50000,
+			.tCOH_min = 0,
+			.tCS_min = 70000,
+			.tDH_min = 20000,
+			.tDS_min = 40000,
+			.tFEAT_max = 1000000,
+			.tIR_min = 10000,
+			.tITC_max = 1000000,
+			.tRC_min = 100000,
+			.tREA_max = 40000,
+			.tREH_min = 30000,
+			.tRHOH_min = 0,
+			.tRHW_min = 200000,
+			.tRHZ_max = 200000,
+			.tRLOH_min = 0,
+			.tRP_min = 50000,
+			.tRR_min = 40000,
+			.tRST_max = 250000000000ULL,
+			.tWB_max = 200000,
+			.tWC_min = 100000,
+			.tWH_min = 30000,
+			.tWHR_min = 120000,
+			.tWP_min = 50000,
+			.tWW_min = 100000,
+		},
 	},
 	/* Mode 1 */
 	{
-		.tADL_min = 100000,
-		.tALH_min = 10000,
-		.tALS_min = 25000,
-		.tAR_min = 10000,
-		.tCEA_max = 45000,
-		.tCEH_min = 20000,
-		.tCH_min = 10000,
-		.tCHZ_max = 50000,
-		.tCLH_min = 10000,
-		.tCLR_min = 10000,
-		.tCLS_min = 25000,
-		.tCOH_min = 15000,
-		.tCS_min = 35000,
-		.tDH_min = 10000,
-		.tDS_min = 20000,
-		.tFEAT_max = 1000000,
-		.tIR_min = 0,
-		.tITC_max = 1000000,
-		.tRC_min = 50000,
-		.tREA_max = 30000,
-		.tREH_min = 15000,
-		.tRHOH_min = 15000,
-		.tRHW_min = 100000,
-		.tRHZ_max = 100000,
-		.tRLOH_min = 0,
-		.tRP_min = 25000,
-		.tRR_min = 20000,
-		.tRST_max = 500000000,
-		.tWB_max = 100000,
-		.tWC_min = 45000,
-		.tWH_min = 15000,
-		.tWHR_min = 80000,
-		.tWP_min = 25000,
-		.tWW_min = 100000,
+		.type = NAND_SDR_IFACE,
+		.timings.sdr = {
+			.tADL_min = 400000,
+			.tALH_min = 10000,
+			.tALS_min = 25000,
+			.tAR_min = 10000,
+			.tCEA_max = 45000,
+			.tCEH_min = 20000,
+			.tCH_min = 10000,
+			.tCHZ_max = 50000,
+			.tCLH_min = 10000,
+			.tCLR_min = 10000,
+			.tCLS_min = 25000,
+			.tCOH_min = 15000,
+			.tCS_min = 35000,
+			.tDH_min = 10000,
+			.tDS_min = 20000,
+			.tFEAT_max = 1000000,
+			.tIR_min = 0,
+			.tITC_max = 1000000,
+			.tRC_min = 50000,
+			.tREA_max = 30000,
+			.tREH_min = 15000,
+			.tRHOH_min = 15000,
+			.tRHW_min = 100000,
+			.tRHZ_max = 100000,
+			.tRLOH_min = 0,
+			.tRP_min = 25000,
+			.tRR_min = 20000,
+			.tRST_max = 500000000,
+			.tWB_max = 100000,
+			.tWC_min = 45000,
+			.tWH_min = 15000,
+			.tWHR_min = 80000,
+			.tWP_min = 25000,
+			.tWW_min = 100000,
+		},
 	},
 	/* Mode 2 */
 	{
-		.tADL_min = 100000,
-		.tALH_min = 10000,
-		.tALS_min = 15000,
-		.tAR_min = 10000,
-		.tCEA_max = 30000,
-		.tCEH_min = 20000,
-		.tCH_min = 10000,
-		.tCHZ_max = 50000,
-		.tCLH_min = 10000,
-		.tCLR_min = 10000,
-		.tCLS_min = 15000,
-		.tCOH_min = 15000,
-		.tCS_min = 25000,
-		.tDH_min = 5000,
-		.tDS_min = 15000,
-		.tFEAT_max = 1000000,
-		.tIR_min = 0,
-		.tITC_max = 1000000,
-		.tRC_min = 35000,
-		.tREA_max = 25000,
-		.tREH_min = 15000,
-		.tRHOH_min = 15000,
-		.tRHW_min = 100000,
-		.tRHZ_max = 100000,
-		.tRLOH_min = 0,
-		.tRR_min = 20000,
-		.tRST_max = 500000000,
-		.tWB_max = 100000,
-		.tRP_min = 17000,
-		.tWC_min = 35000,
-		.tWH_min = 15000,
-		.tWHR_min = 80000,
-		.tWP_min = 17000,
-		.tWW_min = 100000,
+		.type = NAND_SDR_IFACE,
+		.timings.sdr = {
+			.tADL_min = 400000,
+			.tALH_min = 10000,
+			.tALS_min = 15000,
+			.tAR_min = 10000,
+			.tCEA_max = 30000,
+			.tCEH_min = 20000,
+			.tCH_min = 10000,
+			.tCHZ_max = 50000,
+			.tCLH_min = 10000,
+			.tCLR_min = 10000,
+			.tCLS_min = 15000,
+			.tCOH_min = 15000,
+			.tCS_min = 25000,
+			.tDH_min = 5000,
+			.tDS_min = 15000,
+			.tFEAT_max = 1000000,
+			.tIR_min = 0,
+			.tITC_max = 1000000,
+			.tRC_min = 35000,
+			.tREA_max = 25000,
+			.tREH_min = 15000,
+			.tRHOH_min = 15000,
+			.tRHW_min = 100000,
+			.tRHZ_max = 100000,
+			.tRLOH_min = 0,
+			.tRR_min = 20000,
+			.tRST_max = 500000000,
+			.tWB_max = 100000,
+			.tRP_min = 17000,
+			.tWC_min = 35000,
+			.tWH_min = 15000,
+			.tWHR_min = 80000,
+			.tWP_min = 17000,
+			.tWW_min = 100000,
+		},
 	},
 	/* Mode 3 */
 	{
-		.tADL_min = 100000,
-		.tALH_min = 5000,
-		.tALS_min = 10000,
-		.tAR_min = 10000,
-		.tCEA_max = 25000,
-		.tCEH_min = 20000,
-		.tCH_min = 5000,
-		.tCHZ_max = 50000,
-		.tCLH_min = 5000,
-		.tCLR_min = 10000,
-		.tCLS_min = 10000,
-		.tCOH_min = 15000,
-		.tCS_min = 25000,
-		.tDH_min = 5000,
-		.tDS_min = 10000,
-		.tFEAT_max = 1000000,
-		.tIR_min = 0,
-		.tITC_max = 1000000,
-		.tRC_min = 30000,
-		.tREA_max = 20000,
-		.tREH_min = 10000,
-		.tRHOH_min = 15000,
-		.tRHW_min = 100000,
-		.tRHZ_max = 100000,
-		.tRLOH_min = 0,
-		.tRP_min = 15000,
-		.tRR_min = 20000,
-		.tRST_max = 500000000,
-		.tWB_max = 100000,
-		.tWC_min = 30000,
-		.tWH_min = 10000,
-		.tWHR_min = 80000,
-		.tWP_min = 15000,
-		.tWW_min = 100000,
+		.type = NAND_SDR_IFACE,
+		.timings.sdr = {
+			.tADL_min = 400000,
+			.tALH_min = 5000,
+			.tALS_min = 10000,
+			.tAR_min = 10000,
+			.tCEA_max = 25000,
+			.tCEH_min = 20000,
+			.tCH_min = 5000,
+			.tCHZ_max = 50000,
+			.tCLH_min = 5000,
+			.tCLR_min = 10000,
+			.tCLS_min = 10000,
+			.tCOH_min = 15000,
+			.tCS_min = 25000,
+			.tDH_min = 5000,
+			.tDS_min = 10000,
+			.tFEAT_max = 1000000,
+			.tIR_min = 0,
+			.tITC_max = 1000000,
+			.tRC_min = 30000,
+			.tREA_max = 20000,
+			.tREH_min = 10000,
+			.tRHOH_min = 15000,
+			.tRHW_min = 100000,
+			.tRHZ_max = 100000,
+			.tRLOH_min = 0,
+			.tRP_min = 15000,
+			.tRR_min = 20000,
+			.tRST_max = 500000000,
+			.tWB_max = 100000,
+			.tWC_min = 30000,
+			.tWH_min = 10000,
+			.tWHR_min = 80000,
+			.tWP_min = 15000,
+			.tWW_min = 100000,
+		},
 	},
 	/* Mode 4 */
 	{
-		.tADL_min = 70000,
-		.tALH_min = 5000,
-		.tALS_min = 10000,
-		.tAR_min = 10000,
-		.tCEA_max = 25000,
-		.tCEH_min = 20000,
-		.tCH_min = 5000,
-		.tCHZ_max = 30000,
-		.tCLH_min = 5000,
-		.tCLR_min = 10000,
-		.tCLS_min = 10000,
-		.tCOH_min = 15000,
-		.tCS_min = 20000,
-		.tDH_min = 5000,
-		.tDS_min = 10000,
-		.tFEAT_max = 1000000,
-		.tIR_min = 0,
-		.tITC_max = 1000000,
-		.tRC_min = 25000,
-		.tREA_max = 20000,
-		.tREH_min = 10000,
-		.tRHOH_min = 15000,
-		.tRHW_min = 100000,
-		.tRHZ_max = 100000,
-		.tRLOH_min = 5000,
-		.tRP_min = 12000,
-		.tRR_min = 20000,
-		.tRST_max = 500000000,
-		.tWB_max = 100000,
-		.tWC_min = 25000,
-		.tWH_min = 10000,
-		.tWHR_min = 80000,
-		.tWP_min = 12000,
-		.tWW_min = 100000,
+		.type = NAND_SDR_IFACE,
+		.timings.sdr = {
+			.tADL_min = 400000,
+			.tALH_min = 5000,
+			.tALS_min = 10000,
+			.tAR_min = 10000,
+			.tCEA_max = 25000,
+			.tCEH_min = 20000,
+			.tCH_min = 5000,
+			.tCHZ_max = 30000,
+			.tCLH_min = 5000,
+			.tCLR_min = 10000,
+			.tCLS_min = 10000,
+			.tCOH_min = 15000,
+			.tCS_min = 20000,
+			.tDH_min = 5000,
+			.tDS_min = 10000,
+			.tFEAT_max = 1000000,
+			.tIR_min = 0,
+			.tITC_max = 1000000,
+			.tRC_min = 25000,
+			.tREA_max = 20000,
+			.tREH_min = 10000,
+			.tRHOH_min = 15000,
+			.tRHW_min = 100000,
+			.tRHZ_max = 100000,
+			.tRLOH_min = 5000,
+			.tRP_min = 12000,
+			.tRR_min = 20000,
+			.tRST_max = 500000000,
+			.tWB_max = 100000,
+			.tWC_min = 25000,
+			.tWH_min = 10000,
+			.tWHR_min = 80000,
+			.tWP_min = 12000,
+			.tWW_min = 100000,
+		},
 	},
 	/* Mode 5 */
 	{
-		.tADL_min = 70000,
-		.tALH_min = 5000,
-		.tALS_min = 10000,
-		.tAR_min = 10000,
-		.tCEA_max = 25000,
-		.tCEH_min = 20000,
-		.tCH_min = 5000,
-		.tCHZ_max = 30000,
-		.tCLH_min = 5000,
-		.tCLR_min = 10000,
-		.tCLS_min = 10000,
-		.tCOH_min = 15000,
-		.tCS_min = 15000,
-		.tDH_min = 5000,
-		.tDS_min = 7000,
-		.tFEAT_max = 1000000,
-		.tIR_min = 0,
-		.tITC_max = 1000000,
-		.tRC_min = 20000,
-		.tREA_max = 16000,
-		.tREH_min = 7000,
-		.tRHOH_min = 15000,
-		.tRHW_min = 100000,
-		.tRHZ_max = 100000,
-		.tRLOH_min = 5000,
-		.tRP_min = 10000,
-		.tRR_min = 20000,
-		.tRST_max = 500000000,
-		.tWB_max = 100000,
-		.tWC_min = 20000,
-		.tWH_min = 7000,
-		.tWHR_min = 80000,
-		.tWP_min = 10000,
-		.tWW_min = 100000,
+		.type = NAND_SDR_IFACE,
+		.timings.sdr = {
+			.tADL_min = 400000,
+			.tALH_min = 5000,
+			.tALS_min = 10000,
+			.tAR_min = 10000,
+			.tCEA_max = 25000,
+			.tCEH_min = 20000,
+			.tCH_min = 5000,
+			.tCHZ_max = 30000,
+			.tCLH_min = 5000,
+			.tCLR_min = 10000,
+			.tCLS_min = 10000,
+			.tCOH_min = 15000,
+			.tCS_min = 15000,
+			.tDH_min = 5000,
+			.tDS_min = 7000,
+			.tFEAT_max = 1000000,
+			.tIR_min = 0,
+			.tITC_max = 1000000,
+			.tRC_min = 20000,
+			.tREA_max = 16000,
+			.tREH_min = 7000,
+			.tRHOH_min = 15000,
+			.tRHW_min = 100000,
+			.tRHZ_max = 100000,
+			.tRLOH_min = 5000,
+			.tRP_min = 10000,
+			.tRR_min = 20000,
+			.tRST_max = 500000000,
+			.tWB_max = 100000,
+			.tWC_min = 20000,
+			.tWH_min = 7000,
+			.tWHR_min = 80000,
+			.tWP_min = 10000,
+			.tWW_min = 100000,
+		},
 	},
 };
 
@@ -247,6 +265,35 @@ const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode)
 	if (mode < 0 || mode >= ARRAY_SIZE(onfi_sdr_timings))
 		return ERR_PTR(-EINVAL);
 
-	return &onfi_sdr_timings[mode];
+	return &onfi_sdr_timings[mode].timings.sdr;
 }
 EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings);
+
+/**
+ * onfi_init_data_interface - [NAND Interface] Initialize a data interface from
+ * given ONFI mode
+ * @iface: The data interface to be initialized
+ * @mode: The ONFI timing mode
+ */
+int onfi_init_data_interface(struct nand_chip *chip,
+			     struct nand_data_interface *iface,
+			     enum nand_data_interface_type type,
+			     int timing_mode)
+{
+	if (type != NAND_SDR_IFACE)
+		return -EINVAL;
+
+	if (timing_mode < 0 || timing_mode >= ARRAY_SIZE(onfi_sdr_timings))
+		return -EINVAL;
+
+	*iface = onfi_sdr_timings[timing_mode];
+
+	/*
+	 * TODO: initialize timings that cannot be deduced from timing mode:
+	 * tR, tPROG, tCCS, ...
+	 * These information are part of the ONFI parameter page.
+	 */
+
+	return 0;
+}
+EXPORT_SYMBOL(onfi_init_data_interface);
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index e321e3e..a633fd0 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -1134,6 +1134,11 @@ static inline int onfi_get_sync_timing_mode(struct nand_chip *chip)
 }
 #endif
 
+int onfi_init_data_interface(struct nand_chip *chip,
+			     struct nand_data_interface *iface,
+			     enum nand_data_interface_type type,
+			     int timing_mode);
+
 /*
  * Check if it is a SLC nand.
  * The !nand_is_slc() can be used to check the MLC/TLC nand chips.
-- 
2.7.4

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

* [U-Boot] [PATCH 08/22] mtd: nand: Expose data interface for ONFI mode 0
  2017-11-21 17:38 [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
                   ` (6 preceding siblings ...)
  2017-11-21 17:38 ` [U-Boot] [PATCH 07/22] mtd: nand: convert ONFI mode into data interface Masahiro Yamada
@ 2017-11-21 17:38 ` Masahiro Yamada
  2017-11-21 17:38 ` [U-Boot] [PATCH 09/22] mtd: nand: automate NAND timings selection Masahiro Yamada
                   ` (14 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Masahiro Yamada @ 2017-11-21 17:38 UTC (permalink / raw)
  To: u-boot

From: Sascha Hauer <s.hauer@pengutronix.de>

The nand layer will need ONFI mode 0 to use it as timing mode
before and right after reset.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
[Linux commit: 6e1f9708dbf3c50a8da93c1952a01a7a2acb5e66]
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>

---

 drivers/mtd/nand/nand_timings.c | 11 +++++++++++
 include/linux/mtd/nand.h        |  2 ++
 2 files changed, 13 insertions(+)

diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c
index b055d27..ba4f22f 100644
--- a/drivers/mtd/nand/nand_timings.c
+++ b/drivers/mtd/nand/nand_timings.c
@@ -297,3 +297,14 @@ int onfi_init_data_interface(struct nand_chip *chip,
 	return 0;
 }
 EXPORT_SYMBOL(onfi_init_data_interface);
+
+/**
+ * nand_get_default_data_interface - [NAND Interface] Retrieve NAND
+ * data interface for mode 0. This is used as default timing after
+ * reset.
+ */
+const struct nand_data_interface *nand_get_default_data_interface(void)
+{
+	return &onfi_sdr_timings[0];
+}
+EXPORT_SYMBOL(nand_get_default_data_interface);
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index a633fd0..0b9fe3f 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -1183,6 +1183,8 @@ uint8_t nand_read_byte(struct mtd_info *mtd);
 
 /* get timing characteristics from ONFI timing mode. */
 const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode);
+/* get data interface from ONFI timing mode 0, used after reset. */
+const struct nand_data_interface *nand_get_default_data_interface(void);
 
 int nand_check_erased_ecc_chunk(void *data, int datalen,
 				void *ecc, int ecclen,
-- 
2.7.4

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

* [U-Boot] [PATCH 09/22] mtd: nand: automate NAND timings selection
  2017-11-21 17:38 [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
                   ` (7 preceding siblings ...)
  2017-11-21 17:38 ` [U-Boot] [PATCH 08/22] mtd: nand: Expose data interface for ONFI mode 0 Masahiro Yamada
@ 2017-11-21 17:38 ` Masahiro Yamada
  2017-12-04 22:37   ` York Sun
  2017-11-21 17:38 ` [U-Boot] [PATCH 10/22] mtd: nand: Fix data interface configuration logic Masahiro Yamada
                   ` (13 subsequent siblings)
  22 siblings, 1 reply; 29+ messages in thread
From: Masahiro Yamada @ 2017-11-21 17:38 UTC (permalink / raw)
  To: u-boot

From: Boris Brezillon <boris.brezillon@free-electrons.com>

The NAND framework provides several helpers to query timing modes supported
by a NAND chip, but this implies that all NAND controller drivers have
to implement the same timings selection dance. Also currently NAND
devices can be resetted at arbitrary places which also resets the timing
for ONFI chips to timing mode 0.

Provide a common logic to select the best timings based on ONFI or
->onfi_timing_mode_default information. Hook this into nand_reset()
to make sure the new timing is applied each time during a reset.

NAND controller willing to support timings adjustment should just
implement the ->setup_data_interface() method.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
[Linux commit: d8e725dd831186a3595036b2b1df9f68cbc6efa3]
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>

---

 drivers/mtd/nand/nand_base.c | 155 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/nand.h     |  14 ++--
 2 files changed, 165 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 77da6fa..f452f59 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -902,6 +902,148 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
 }
 
 /**
+ * nand_reset_data_interface - Reset data interface and timings
+ * @chip: The NAND chip
+ *
+ * Reset the Data interface and timings to ONFI mode 0.
+ *
+ * Returns 0 for success or negative error code otherwise.
+ */
+static int nand_reset_data_interface(struct nand_chip *chip)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	const struct nand_data_interface *conf;
+	int ret;
+
+	if (!chip->setup_data_interface)
+		return 0;
+
+	/*
+	 * The ONFI specification says:
+	 * "
+	 * To transition from NV-DDR or NV-DDR2 to the SDR data
+	 * interface, the host shall use the Reset (FFh) command
+	 * using SDR timing mode 0. A device in any timing mode is
+	 * required to recognize Reset (FFh) command issued in SDR
+	 * timing mode 0.
+	 * "
+	 *
+	 * Configure the data interface in SDR mode and set the
+	 * timings to timing mode 0.
+	 */
+
+	conf = nand_get_default_data_interface();
+	ret = chip->setup_data_interface(mtd, conf, false);
+	if (ret)
+		pr_err("Failed to configure data interface to SDR timing mode 0\n");
+
+	return ret;
+}
+
+/**
+ * nand_setup_data_interface - Setup the best data interface and timings
+ * @chip: The NAND chip
+ *
+ * Find and configure the best data interface and NAND timings supported by
+ * the chip and the driver.
+ * First tries to retrieve supported timing modes from ONFI information,
+ * and if the NAND chip does not support ONFI, relies on the
+ * ->onfi_timing_mode_default specified in the nand_ids table.
+ *
+ * Returns 0 for success or negative error code otherwise.
+ */
+static int nand_setup_data_interface(struct nand_chip *chip)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int ret;
+
+	if (!chip->setup_data_interface || !chip->data_interface)
+		return 0;
+
+	/*
+	 * Ensure the timing mode has been changed on the chip side
+	 * before changing timings on the controller side.
+	 */
+	if (chip->onfi_version) {
+		u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = {
+			chip->onfi_timing_mode_default,
+		};
+
+		ret = chip->onfi_set_features(mtd, chip,
+				ONFI_FEATURE_ADDR_TIMING_MODE,
+				tmode_param);
+		if (ret)
+			goto err;
+	}
+
+	ret = chip->setup_data_interface(mtd, chip->data_interface, false);
+err:
+	return ret;
+}
+
+/**
+ * nand_init_data_interface - find the best data interface and timings
+ * @chip: The NAND chip
+ *
+ * Find the best data interface and NAND timings supported by the chip
+ * and the driver.
+ * First tries to retrieve supported timing modes from ONFI information,
+ * and if the NAND chip does not support ONFI, relies on the
+ * ->onfi_timing_mode_default specified in the nand_ids table. After this
+ * function nand_chip->data_interface is initialized with the best timing mode
+ * available.
+ *
+ * Returns 0 for success or negative error code otherwise.
+ */
+static int nand_init_data_interface(struct nand_chip *chip)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	int modes, mode, ret;
+
+	if (!chip->setup_data_interface)
+		return 0;
+
+	/*
+	 * First try to identify the best timings from ONFI parameters and
+	 * if the NAND does not support ONFI, fallback to the default ONFI
+	 * timing mode.
+	 */
+	modes = onfi_get_async_timing_mode(chip);
+	if (modes == ONFI_TIMING_MODE_UNKNOWN) {
+		if (!chip->onfi_timing_mode_default)
+			return 0;
+
+		modes = GENMASK(chip->onfi_timing_mode_default, 0);
+	}
+
+	chip->data_interface = kzalloc(sizeof(*chip->data_interface),
+				       GFP_KERNEL);
+	if (!chip->data_interface)
+		return -ENOMEM;
+
+	for (mode = fls(modes) - 1; mode >= 0; mode--) {
+		ret = onfi_init_data_interface(chip, chip->data_interface,
+					       NAND_SDR_IFACE, mode);
+		if (ret)
+			continue;
+
+		ret = chip->setup_data_interface(mtd, chip->data_interface,
+						 true);
+		if (!ret) {
+			chip->onfi_timing_mode_default = mode;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static void __maybe_unused nand_release_data_interface(struct nand_chip *chip)
+{
+	kfree(chip->data_interface);
+}
+
+/**
  * nand_reset - Reset and initialize a NAND device
  * @chip: The NAND chip
  *
@@ -910,9 +1052,18 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
 int nand_reset(struct nand_chip *chip)
 {
 	struct mtd_info *mtd = nand_to_mtd(chip);
+	int ret;
+
+	ret = nand_reset_data_interface(chip);
+	if (ret)
+		return ret;
 
 	chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
 
+	ret = nand_setup_data_interface(chip);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
@@ -3882,6 +4033,10 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
 		return PTR_ERR(type);
 	}
 
+	ret = nand_init_data_interface(chip);
+	if (ret)
+		return ret;
+
 	chip->select_chip(mtd, -1);
 
 	/* Check for a chip array */
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 0b9fe3f..274bd8d 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -764,10 +764,9 @@ nand_get_sdr_timings(const struct nand_data_interface *conf)
  *                      also from the datasheet. It is the recommended ECC step
  *			size, if known; if unknown, set to zero.
  * @onfi_timing_mode_default: [INTERN] default ONFI timing mode. This field is
- *			      either deduced from the datasheet if the NAND
- *			      chip is not ONFI compliant or set to 0 if it is
- *			      (an ONFI chip is always configured in mode 0
- *			      after a NAND reset)
+ *			      set to the actually used ONFI mode if the chip is
+ *			      ONFI compliant or deduced from the datasheet if
+ *			      the NAND chip is not ONFI compliant.
  * @numchips:		[INTERN] number of physical chips
  * @chipsize:		[INTERN] the size of one chip for multichip arrays
  * @pagemask:		[INTERN] page number mask = number of (pages / chip) - 1
@@ -787,6 +786,7 @@ nand_get_sdr_timings(const struct nand_data_interface *conf)
  * @read_retries:	[INTERN] the number of read retry modes supported
  * @onfi_set_features:	[REPLACEABLE] set the features for ONFI nand
  * @onfi_get_features:	[REPLACEABLE] get the features for ONFI nand
+ * @setup_data_interface: [OPTIONAL] setup the data interface and timing
  * @bbt:		[INTERN] bad block table pointer
  * @bbt_td:		[REPLACEABLE] bad block table descriptor for flash
  *			lookup.
@@ -835,6 +835,10 @@ struct nand_chip {
 	int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip,
 			int feature_addr, uint8_t *subfeature_para);
 	int (*setup_read_retry)(struct mtd_info *mtd, int retry_mode);
+	int (*setup_data_interface)(struct mtd_info *mtd,
+				    const struct nand_data_interface *conf,
+				    bool check_only);
+
 
 	int chip_delay;
 	unsigned int options;
@@ -862,6 +866,8 @@ struct nand_chip {
 	struct nand_onfi_params	onfi_params;
 	struct nand_jedec_params jedec_params;
  
+	struct nand_data_interface *data_interface;
+
 	int read_retries;
 
 	flstate_t state;
-- 
2.7.4

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

* [U-Boot] [PATCH 10/22] mtd: nand: Fix data interface configuration logic
  2017-11-21 17:38 [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
                   ` (8 preceding siblings ...)
  2017-11-21 17:38 ` [U-Boot] [PATCH 09/22] mtd: nand: automate NAND timings selection Masahiro Yamada
@ 2017-11-21 17:38 ` Masahiro Yamada
  2017-11-21 17:38 ` [U-Boot] [PATCH 11/22] mtd: nand: Add a few more timings to nand_sdr_timings Masahiro Yamada
                   ` (12 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Masahiro Yamada @ 2017-11-21 17:38 UTC (permalink / raw)
  To: u-boot

From: Boris Brezillon <boris.brezillon@free-electrons.com>

When changing from one data interface setting to another, one has to
ensure a specific sequence which is described in the ONFI spec.

One of these constraints is that the CE line has go high after a reset
before a command can be sent with the new data interface setting, which
is not guaranteed by the current implementation.

Rework the nand_reset() function and all the call sites to make sure the
CE line is asserted and released when required.

Also make sure to actually apply the new data interface setting on the
first die.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Fixes: d8e725dd8311 ("mtd: nand: automate NAND timings selection")
Reviewed-by: Sascha Hauer <s.hauer@pengutronix.de>
Tested-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
[Linux commit: 73f907fd5fa56b0066d199bdd7126bbd04f6cd7b]
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>

---

 drivers/mtd/nand/nand_base.c | 48 +++++++++++++++++++++++++++++++++-----------
 include/linux/mtd/nand.h     |  2 +-
 2 files changed, 37 insertions(+), 13 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index f452f59..5054c0e 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1046,10 +1046,11 @@ static void __maybe_unused nand_release_data_interface(struct nand_chip *chip)
 /**
  * nand_reset - Reset and initialize a NAND device
  * @chip: The NAND chip
+ * @chipnr: Internal die id
  *
  * Returns 0 for success or negative error code otherwise
  */
-int nand_reset(struct nand_chip *chip)
+int nand_reset(struct nand_chip *chip, int chipnr)
 {
 	struct mtd_info *mtd = nand_to_mtd(chip);
 	int ret;
@@ -1058,9 +1059,17 @@ int nand_reset(struct nand_chip *chip)
 	if (ret)
 		return ret;
 
+	/*
+	 * The CS line has to be released before we can apply the new NAND
+	 * interface settings, hence this weird ->select_chip() dance.
+	 */
+	chip->select_chip(mtd, chipnr);
 	chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+	chip->select_chip(mtd, -1);
 
+	chip->select_chip(mtd, chipnr);
 	ret = nand_setup_data_interface(chip);
+	chip->select_chip(mtd, -1);
 	if (ret)
 		return ret;
 
@@ -2746,10 +2755,6 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
 	}
 
 	chipnr = (int)(to >> chip->chip_shift);
-	chip->select_chip(mtd, chipnr);
-
-	/* Shift to get page */
-	page = (int)(to >> chip->page_shift);
 
 	/*
 	 * Reset the chip. Some chips (like the Toshiba TC5832DC found in one
@@ -2757,7 +2762,12 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
 	 * if we don't do this. I have no clue why, but I seem to have 'fixed'
 	 * it in the doc2000 driver in August 1999.  dwmw2.
 	 */
-	nand_reset(chip);
+	nand_reset(chip, chipnr);
+
+	chip->select_chip(mtd, chipnr);
+
+	/* Shift to get page */
+	page = (int)(to >> chip->page_shift);
 
 	/* Check, if it is write protected */
 	if (nand_check_wp(mtd)) {
@@ -3771,14 +3781,14 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
 	int i, maf_idx;
 	u8 id_data[8];
 
-	/* Select the device */
-	chip->select_chip(mtd, 0);
-
 	/*
 	 * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
 	 * after power-up.
 	 */
-	nand_reset(chip);
+	nand_reset(chip, 0);
+
+	/* Select the device */
+	chip->select_chip(mtd, 0);
 
 	/* Send the command for reading device ID */
 	chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
@@ -4033,17 +4043,31 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
 		return PTR_ERR(type);
 	}
 
+	/* Initialize the ->data_interface field. */
 	ret = nand_init_data_interface(chip);
 	if (ret)
 		return ret;
 
+	/*
+	 * Setup the data interface correctly on the chip and controller side.
+	 * This explicit call to nand_setup_data_interface() is only required
+	 * for the first die, because nand_reset() has been called before
+	 * ->data_interface and ->default_onfi_timing_mode were set.
+	 * For the other dies, nand_reset() will automatically switch to the
+	 * best mode for us.
+	 */
+	ret = nand_setup_data_interface(chip);
+	if (ret)
+		return ret;
+
 	chip->select_chip(mtd, -1);
 
 	/* Check for a chip array */
 	for (i = 1; i < maxchips; i++) {
-		chip->select_chip(mtd, i);
 		/* See comment in nand_get_flash_type for reset */
-		nand_reset(chip);
+		nand_reset(chip, i);
+
+		chip->select_chip(mtd, i);
 		/* Send the command for reading device ID */
 		chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
 		/* Read manufacturer and device IDs */
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 274bd8d..8cff83b 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -1198,6 +1198,6 @@ int nand_check_erased_ecc_chunk(void *data, int datalen,
 				int threshold);
 
 /* Reset and initialize a NAND device */
-int nand_reset(struct nand_chip *chip);
+int nand_reset(struct nand_chip *chip, int chipnr);
 
 #endif /* __LINUX_MTD_NAND_H */
-- 
2.7.4

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

* [U-Boot] [PATCH 11/22] mtd: nand: Add a few more timings to nand_sdr_timings
  2017-11-21 17:38 [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
                   ` (9 preceding siblings ...)
  2017-11-21 17:38 ` [U-Boot] [PATCH 10/22] mtd: nand: Fix data interface configuration logic Masahiro Yamada
@ 2017-11-21 17:38 ` Masahiro Yamada
  2017-11-21 17:38 ` [U-Boot] [PATCH 12/22] mtd: nand: Support controllers with custom page Masahiro Yamada
                   ` (11 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Masahiro Yamada @ 2017-11-21 17:38 UTC (permalink / raw)
  To: u-boot

From: Boris Brezillon <boris.brezillon@free-electrons.com>

Add the tR_max, tBERS_max, tPROG_max and tCCS_min timings to the
nand_sdr_timings struct.
Assign default/safe values for the statically defined timings, and
extract them from the ONFI parameter table if the NAND is ONFI
compliant.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Tested-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
[Linux commit: 204e7ecd47e26cc12d9e8e8a7e7a2eeb9573f0ba
 Fixup commit: 6d29231000bbe0fb9e4893a9c68151ffdd3b5469]
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>

---

 drivers/mtd/nand/nand_timings.c | 26 +++++++++++++++++++++++++-
 include/linux/mtd/nand.h        |  8 ++++++++
 2 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c
index ba4f22f..9935557 100644
--- a/drivers/mtd/nand/nand_timings.c
+++ b/drivers/mtd/nand/nand_timings.c
@@ -17,6 +17,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
 	{
 		.type = NAND_SDR_IFACE,
 		.timings.sdr = {
+			.tCCS_min = 500000,
+			.tR_max = 200000000,
 			.tADL_min = 400000,
 			.tALH_min = 20000,
 			.tALS_min = 50000,
@@ -57,6 +59,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
 	{
 		.type = NAND_SDR_IFACE,
 		.timings.sdr = {
+			.tCCS_min = 500000,
+			.tR_max = 200000000,
 			.tADL_min = 400000,
 			.tALH_min = 10000,
 			.tALS_min = 25000,
@@ -97,6 +101,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
 	{
 		.type = NAND_SDR_IFACE,
 		.timings.sdr = {
+			.tCCS_min = 500000,
+			.tR_max = 200000000,
 			.tADL_min = 400000,
 			.tALH_min = 10000,
 			.tALS_min = 15000,
@@ -137,6 +143,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
 	{
 		.type = NAND_SDR_IFACE,
 		.timings.sdr = {
+			.tCCS_min = 500000,
+			.tR_max = 200000000,
 			.tADL_min = 400000,
 			.tALH_min = 5000,
 			.tALS_min = 10000,
@@ -177,6 +185,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
 	{
 		.type = NAND_SDR_IFACE,
 		.timings.sdr = {
+			.tCCS_min = 500000,
+			.tR_max = 200000000,
 			.tADL_min = 400000,
 			.tALH_min = 5000,
 			.tALS_min = 10000,
@@ -217,6 +227,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
 	{
 		.type = NAND_SDR_IFACE,
 		.timings.sdr = {
+			.tCCS_min = 500000,
+			.tR_max = 200000000,
 			.tADL_min = 400000,
 			.tALH_min = 5000,
 			.tALS_min = 10000,
@@ -289,10 +301,22 @@ int onfi_init_data_interface(struct nand_chip *chip,
 	*iface = onfi_sdr_timings[timing_mode];
 
 	/*
-	 * TODO: initialize timings that cannot be deduced from timing mode:
+	 * Initialize timings that cannot be deduced from timing mode:
 	 * tR, tPROG, tCCS, ...
 	 * These information are part of the ONFI parameter page.
 	 */
+	if (chip->onfi_version) {
+		struct nand_onfi_params *params = &chip->onfi_params;
+		struct nand_sdr_timings *timings = &iface->timings.sdr;
+
+		/* microseconds -> picoseconds */
+		timings->tPROG_max = 1000000ULL * le16_to_cpu(params->t_prog);
+		timings->tBERS_max = 1000000ULL * le16_to_cpu(params->t_bers);
+		timings->tR_max = 1000000ULL * le16_to_cpu(params->t_r);
+
+		/* nanoseconds -> picoseconds */
+		timings->tCCS_min = 1000UL * le16_to_cpu(params->t_ccs);
+	}
 
 	return 0;
 }
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 8cff83b..8b76275 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -595,6 +595,10 @@ struct nand_buffers {
  *
  * All these timings are expressed in picoseconds.
  *
+ * @tBERS_max: Block erase time
+ * @tCCS_min: Change column setup time
+ * @tPROG_max: Page program time
+ * @tR_max: Page read time
  * @tALH_min: ALE hold time
  * @tADL_min: ALE to data loading time
  * @tALS_min: ALE setup time
@@ -632,6 +636,10 @@ struct nand_buffers {
  * @tWW_min: WP# transition to WE# low
  */
 struct nand_sdr_timings {
+	u64 tBERS_max;
+	u32 tCCS_min;
+	u64 tPROG_max;
+	u64 tR_max;
 	u32 tALH_min;
 	u32 tADL_min;
 	u32 tALS_min;
-- 
2.7.4

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

* [U-Boot] [PATCH 12/22] mtd: nand: Support controllers with custom page
  2017-11-21 17:38 [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
                   ` (10 preceding siblings ...)
  2017-11-21 17:38 ` [U-Boot] [PATCH 11/22] mtd: nand: Add a few more timings to nand_sdr_timings Masahiro Yamada
@ 2017-11-21 17:38 ` Masahiro Yamada
  2017-11-21 17:38 ` [U-Boot] [PATCH 13/22] mtd: add mtd_ooblayout_xxx() helper functions Masahiro Yamada
                   ` (10 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Masahiro Yamada @ 2017-11-21 17:38 UTC (permalink / raw)
  To: u-boot

From: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>

If your controller already sends the required NAND commands when
reading or writing a page, then the framework is not supposed to
send READ0 and SEQIN/PAGEPROG respectively.

Signed-off-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
[Linux commit: 3371d663bb4579f1b2003a92162edd6d90edd089]
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>

---

 drivers/mtd/nand/nand_base.c | 34 +++++++++++++++++++++++++++++++---
 include/linux/mtd/nand.h     | 12 ++++++++++++
 2 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 5054c0e..d9f0a75 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1732,7 +1732,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 						 __func__, buf);
 
 read_retry:
-			chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
+			if (nand_standard_page_accessors(&chip->ecc))
+				chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
 
 			/*
 			 * Now read the page into the buffer.  Absent an error,
@@ -2423,7 +2424,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 	else
 		subpage = 0;
 
-	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+	if (nand_standard_page_accessors(&chip->ecc))
+		chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
 
 	if (unlikely(raw))
 		status = chip->ecc.write_page_raw(mtd, chip, buf,
@@ -2446,7 +2448,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 
 	if (!cached || !NAND_HAS_CACHEPROG(chip)) {
 
-		chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+		if (nand_standard_page_accessors(&chip->ecc))
+			chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
 		status = chip->waitfunc(mtd, chip);
 		/*
 		 * See if operation failed and additional status checks are
@@ -4126,6 +4129,26 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd)
 	return corr >= ds_corr && ecc->strength >= chip->ecc_strength_ds;
 }
 
+static bool invalid_ecc_page_accessors(struct nand_chip *chip)
+{
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+	if (nand_standard_page_accessors(ecc))
+		return false;
+
+	/*
+	 * NAND_ECC_CUSTOM_PAGE_ACCESS flag is set, make sure the NAND
+	 * controller driver implements all the page accessors because
+	 * default helpers are not suitable when the core does not
+	 * send the READ0/PAGEPROG commands.
+	 */
+	return (!ecc->read_page || !ecc->write_page ||
+		!ecc->read_page_raw || !ecc->write_page_raw ||
+		(NAND_HAS_SUBPAGE_READ(chip) && !ecc->read_subpage) ||
+		(NAND_HAS_SUBPAGE_WRITE(chip) && !ecc->write_subpage &&
+		 ecc->hwctl && ecc->calculate));
+}
+
 /**
  * nand_scan_tail - [NAND Interface] Scan for the NAND device
  * @mtd: MTD device structure
@@ -4145,6 +4168,11 @@ int nand_scan_tail(struct mtd_info *mtd)
 	BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
 			!(chip->bbt_options & NAND_BBT_USE_FLASH));
 
+	if (invalid_ecc_page_accessors(chip)) {
+		pr_err("Invalid ECC page accessors setup\n");
+		return -EINVAL;
+	}
+
 	if (!(chip->options & NAND_OWN_BUFFERS)) {
 		nbuf = kzalloc(sizeof(struct nand_buffers), GFP_KERNEL);
 		chip->buffers = nbuf;
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 8b76275..72b2328 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -154,6 +154,12 @@ typedef enum {
  */
 #define NAND_ECC_GENERIC_ERASED_CHECK	BIT(0)
 #define NAND_ECC_MAXIMIZE		BIT(1)
+/*
+ * If your controller already sends the required NAND commands when
+ * reading or writing a page, then the framework is not supposed to
+ * send READ0 and SEQIN/PAGEPROG respectively.
+ */
+#define NAND_ECC_CUSTOM_PAGE_ACCESS	BIT(2)
 
 /* Bit mask for flags passed to do_nand_read_ecc */
 #define NAND_GET_DEVICE		0x80
@@ -202,6 +208,7 @@ typedef enum {
 /* Macros to identify the above */
 #define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG))
 #define NAND_HAS_SUBPAGE_READ(chip) ((chip->options & NAND_SUBPAGE_READ))
+#define NAND_HAS_SUBPAGE_WRITE(chip) !((chip)->options & NAND_NO_SUBPAGE_WRITE)
 
 /* Non chip related options */
 /* This option skips the bbt scan during initialization. */
@@ -568,6 +575,11 @@ struct nand_ecc_ctrl {
 			int page);
 };
 
+static inline int nand_standard_page_accessors(struct nand_ecc_ctrl *ecc)
+{
+	return !(ecc->options & NAND_ECC_CUSTOM_PAGE_ACCESS);
+}
+
 /**
  * struct nand_buffers - buffer structure for read/write
  * @ecccalc:	buffer pointer for calculated ECC, size is oobsize.
-- 
2.7.4

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

* [U-Boot] [PATCH 13/22] mtd: add mtd_ooblayout_xxx() helper functions
  2017-11-21 17:38 [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
                   ` (11 preceding siblings ...)
  2017-11-21 17:38 ` [U-Boot] [PATCH 12/22] mtd: nand: Support controllers with custom page Masahiro Yamada
@ 2017-11-21 17:38 ` Masahiro Yamada
  2017-11-21 17:38 ` [U-Boot] [PATCH 14/22] mtd: nand: Drop unused cached programming support Masahiro Yamada
                   ` (9 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Masahiro Yamada @ 2017-11-21 17:38 UTC (permalink / raw)
  To: u-boot

From: Boris Brezillon <boris.brezillon@free-electrons.com>

In order to make the ecclayout definition completely dynamic we need to
rework the way the OOB layout are defined and iterated.

Create a few mtd_ooblayout_xxx() helpers to ease OOB bytes manipulation
and hide ecclayout internals to their users.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
[Linux commit: 75eb2cec251fda33c9bb716ecc372819abb9278a]
[masahiro:
 cherry-pick more code from adbbc3bc827eb1f43a932d783f09ba55c8ec8379]
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>

---

 drivers/mtd/mtdcore.c   | 360 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/mtd.h |  57 ++++++++
 2 files changed, 417 insertions(+)

diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index e3f56e5..2cda051 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -1005,6 +1005,366 @@ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
 }
 EXPORT_SYMBOL_GPL(mtd_read_oob);
 
+/**
+ * mtd_ooblayout_ecc - Get the OOB region definition of a specific ECC section
+ * @mtd: MTD device structure
+ * @section: ECC section. Depending on the layout you may have all the ECC
+ *	     bytes stored in a single contiguous section, or one section
+ *	     per ECC chunk (and sometime several sections for a single ECC
+ *	     ECC chunk)
+ * @oobecc: OOB region struct filled with the appropriate ECC position
+ *	    information
+ *
+ * This function returns ECC section information in the OOB area. If you want
+ * to get all the ECC bytes information, then you should call
+ * mtd_ooblayout_ecc(mtd, section++, oobecc) until it returns -ERANGE.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
+		      struct mtd_oob_region *oobecc)
+{
+	memset(oobecc, 0, sizeof(*oobecc));
+
+	if (!mtd || section < 0)
+		return -EINVAL;
+
+	if (!mtd->ooblayout || !mtd->ooblayout->ecc)
+		return -ENOTSUPP;
+
+	return mtd->ooblayout->ecc(mtd, section, oobecc);
+}
+EXPORT_SYMBOL_GPL(mtd_ooblayout_ecc);
+
+/**
+ * mtd_ooblayout_free - Get the OOB region definition of a specific free
+ *			section
+ * @mtd: MTD device structure
+ * @section: Free section you are interested in. Depending on the layout
+ *	     you may have all the free bytes stored in a single contiguous
+ *	     section, or one section per ECC chunk plus an extra section
+ *	     for the remaining bytes (or other funky layout).
+ * @oobfree: OOB region struct filled with the appropriate free position
+ *	     information
+ *
+ * This function returns free bytes position in the OOB area. If you want
+ * to get all the free bytes information, then you should call
+ * mtd_ooblayout_free(mtd, section++, oobfree) until it returns -ERANGE.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+int mtd_ooblayout_free(struct mtd_info *mtd, int section,
+		       struct mtd_oob_region *oobfree)
+{
+	memset(oobfree, 0, sizeof(*oobfree));
+
+	if (!mtd || section < 0)
+		return -EINVAL;
+
+	if (!mtd->ooblayout || !mtd->ooblayout->free)
+		return -ENOTSUPP;
+
+	return mtd->ooblayout->free(mtd, section, oobfree);
+}
+EXPORT_SYMBOL_GPL(mtd_ooblayout_free);
+
+/**
+ * mtd_ooblayout_find_region - Find the region attached to a specific byte
+ * @mtd: mtd info structure
+ * @byte: the byte we are searching for
+ * @sectionp: pointer where the section id will be stored
+ * @oobregion: used to retrieve the ECC position
+ * @iter: iterator function. Should be either mtd_ooblayout_free or
+ *	  mtd_ooblayout_ecc depending on the region type you're searching for
+ *
+ * This function returns the section id and oobregion information of a
+ * specific byte. For example, say you want to know where the 4th ECC byte is
+ * stored, you'll use:
+ *
+ * mtd_ooblayout_find_region(mtd, 3, &section, &oobregion, mtd_ooblayout_ecc);
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+static int mtd_ooblayout_find_region(struct mtd_info *mtd, int byte,
+				int *sectionp, struct mtd_oob_region *oobregion,
+				int (*iter)(struct mtd_info *,
+					    int section,
+					    struct mtd_oob_region *oobregion))
+{
+	int pos = 0, ret, section = 0;
+
+	memset(oobregion, 0, sizeof(*oobregion));
+
+	while (1) {
+		ret = iter(mtd, section, oobregion);
+		if (ret)
+			return ret;
+
+		if (pos + oobregion->length > byte)
+			break;
+
+		pos += oobregion->length;
+		section++;
+	}
+
+	/*
+	 * Adjust region info to make it start at the beginning at the
+	 * 'start' ECC byte.
+	 */
+	oobregion->offset += byte - pos;
+	oobregion->length -= byte - pos;
+	*sectionp = section;
+
+	return 0;
+}
+
+/**
+ * mtd_ooblayout_find_eccregion - Find the ECC region attached to a specific
+ *				  ECC byte
+ * @mtd: mtd info structure
+ * @eccbyte: the byte we are searching for
+ * @sectionp: pointer where the section id will be stored
+ * @oobregion: OOB region information
+ *
+ * Works like mtd_ooblayout_find_region() except it searches for a specific ECC
+ * byte.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+int mtd_ooblayout_find_eccregion(struct mtd_info *mtd, int eccbyte,
+				 int *section,
+				 struct mtd_oob_region *oobregion)
+{
+	return mtd_ooblayout_find_region(mtd, eccbyte, section, oobregion,
+					 mtd_ooblayout_ecc);
+}
+EXPORT_SYMBOL_GPL(mtd_ooblayout_find_eccregion);
+
+/**
+ * mtd_ooblayout_get_bytes - Extract OOB bytes from the oob buffer
+ * @mtd: mtd info structure
+ * @buf: destination buffer to store OOB bytes
+ * @oobbuf: OOB buffer
+ * @start: first byte to retrieve
+ * @nbytes: number of bytes to retrieve
+ * @iter: section iterator
+ *
+ * Extract bytes attached to a specific category (ECC or free)
+ * from the OOB buffer and copy them into buf.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+static int mtd_ooblayout_get_bytes(struct mtd_info *mtd, u8 *buf,
+				const u8 *oobbuf, int start, int nbytes,
+				int (*iter)(struct mtd_info *,
+					    int section,
+					    struct mtd_oob_region *oobregion))
+{
+	struct mtd_oob_region oobregion;
+	int section, ret;
+
+	ret = mtd_ooblayout_find_region(mtd, start, &section,
+					&oobregion, iter);
+
+	while (!ret) {
+		int cnt;
+
+		cnt = min_t(int, nbytes, oobregion.length);
+		memcpy(buf, oobbuf + oobregion.offset, cnt);
+		buf += cnt;
+		nbytes -= cnt;
+
+		if (!nbytes)
+			break;
+
+		ret = iter(mtd, ++section, &oobregion);
+	}
+
+	return ret;
+}
+
+/**
+ * mtd_ooblayout_set_bytes - put OOB bytes into the oob buffer
+ * @mtd: mtd info structure
+ * @buf: source buffer to get OOB bytes from
+ * @oobbuf: OOB buffer
+ * @start: first OOB byte to set
+ * @nbytes: number of OOB bytes to set
+ * @iter: section iterator
+ *
+ * Fill the OOB buffer with data provided in buf. The category (ECC or free)
+ * is selected by passing the appropriate iterator.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+static int mtd_ooblayout_set_bytes(struct mtd_info *mtd, const u8 *buf,
+				u8 *oobbuf, int start, int nbytes,
+				int (*iter)(struct mtd_info *,
+					    int section,
+					    struct mtd_oob_region *oobregion))
+{
+	struct mtd_oob_region oobregion;
+	int section, ret;
+
+	ret = mtd_ooblayout_find_region(mtd, start, &section,
+					&oobregion, iter);
+
+	while (!ret) {
+		int cnt;
+
+		cnt = min_t(int, nbytes, oobregion.length);
+		memcpy(oobbuf + oobregion.offset, buf, cnt);
+		buf += cnt;
+		nbytes -= cnt;
+
+		if (!nbytes)
+			break;
+
+		ret = iter(mtd, ++section, &oobregion);
+	}
+
+	return ret;
+}
+
+/**
+ * mtd_ooblayout_count_bytes - count the number of bytes in a OOB category
+ * @mtd: mtd info structure
+ * @iter: category iterator
+ *
+ * Count the number of bytes in a given category.
+ *
+ * Returns a positive value on success, a negative error code otherwise.
+ */
+static int mtd_ooblayout_count_bytes(struct mtd_info *mtd,
+				int (*iter)(struct mtd_info *,
+					    int section,
+					    struct mtd_oob_region *oobregion))
+{
+	struct mtd_oob_region oobregion;
+	int section = 0, ret, nbytes = 0;
+
+	while (1) {
+		ret = iter(mtd, section++, &oobregion);
+		if (ret) {
+			if (ret == -ERANGE)
+				ret = nbytes;
+			break;
+		}
+
+		nbytes += oobregion.length;
+	}
+
+	return ret;
+}
+
+/**
+ * mtd_ooblayout_get_eccbytes - extract ECC bytes from the oob buffer
+ * @mtd: mtd info structure
+ * @eccbuf: destination buffer to store ECC bytes
+ * @oobbuf: OOB buffer
+ * @start: first ECC byte to retrieve
+ * @nbytes: number of ECC bytes to retrieve
+ *
+ * Works like mtd_ooblayout_get_bytes(), except it acts on ECC bytes.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+int mtd_ooblayout_get_eccbytes(struct mtd_info *mtd, u8 *eccbuf,
+			       const u8 *oobbuf, int start, int nbytes)
+{
+	return mtd_ooblayout_get_bytes(mtd, eccbuf, oobbuf, start, nbytes,
+				       mtd_ooblayout_ecc);
+}
+EXPORT_SYMBOL_GPL(mtd_ooblayout_get_eccbytes);
+
+/**
+ * mtd_ooblayout_set_eccbytes - set ECC bytes into the oob buffer
+ * @mtd: mtd info structure
+ * @eccbuf: source buffer to get ECC bytes from
+ * @oobbuf: OOB buffer
+ * @start: first ECC byte to set
+ * @nbytes: number of ECC bytes to set
+ *
+ * Works like mtd_ooblayout_set_bytes(), except it acts on ECC bytes.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+int mtd_ooblayout_set_eccbytes(struct mtd_info *mtd, const u8 *eccbuf,
+			       u8 *oobbuf, int start, int nbytes)
+{
+	return mtd_ooblayout_set_bytes(mtd, eccbuf, oobbuf, start, nbytes,
+				       mtd_ooblayout_ecc);
+}
+EXPORT_SYMBOL_GPL(mtd_ooblayout_set_eccbytes);
+
+/**
+ * mtd_ooblayout_get_databytes - extract data bytes from the oob buffer
+ * @mtd: mtd info structure
+ * @databuf: destination buffer to store ECC bytes
+ * @oobbuf: OOB buffer
+ * @start: first ECC byte to retrieve
+ * @nbytes: number of ECC bytes to retrieve
+ *
+ * Works like mtd_ooblayout_get_bytes(), except it acts on free bytes.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+int mtd_ooblayout_get_databytes(struct mtd_info *mtd, u8 *databuf,
+				const u8 *oobbuf, int start, int nbytes)
+{
+	return mtd_ooblayout_get_bytes(mtd, databuf, oobbuf, start, nbytes,
+				       mtd_ooblayout_free);
+}
+EXPORT_SYMBOL_GPL(mtd_ooblayout_get_databytes);
+
+/**
+ * mtd_ooblayout_get_eccbytes - set data bytes into the oob buffer
+ * @mtd: mtd info structure
+ * @eccbuf: source buffer to get data bytes from
+ * @oobbuf: OOB buffer
+ * @start: first ECC byte to set
+ * @nbytes: number of ECC bytes to set
+ *
+ * Works like mtd_ooblayout_get_bytes(), except it acts on free bytes.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+int mtd_ooblayout_set_databytes(struct mtd_info *mtd, const u8 *databuf,
+				u8 *oobbuf, int start, int nbytes)
+{
+	return mtd_ooblayout_set_bytes(mtd, databuf, oobbuf, start, nbytes,
+				       mtd_ooblayout_free);
+}
+EXPORT_SYMBOL_GPL(mtd_ooblayout_set_databytes);
+
+/**
+ * mtd_ooblayout_count_freebytes - count the number of free bytes in OOB
+ * @mtd: mtd info structure
+ *
+ * Works like mtd_ooblayout_count_bytes(), except it count free bytes.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+int mtd_ooblayout_count_freebytes(struct mtd_info *mtd)
+{
+	return mtd_ooblayout_count_bytes(mtd, mtd_ooblayout_free);
+}
+EXPORT_SYMBOL_GPL(mtd_ooblayout_count_freebytes);
+
+/**
+ * mtd_ooblayout_count_freebytes - count the number of ECC bytes in OOB
+ * @mtd: mtd info structure
+ *
+ * Works like mtd_ooblayout_count_bytes(), except it count ECC bytes.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd)
+{
+	return mtd_ooblayout_count_bytes(mtd, mtd_ooblayout_ecc);
+}
+EXPORT_SYMBOL_GPL(mtd_ooblayout_count_eccbytes);
+
 /*
  * Method to access the protection register area, present in some flash
  * devices. The user data is one time programmable but the factory data is read
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 4bde251..ba4cbba 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -103,6 +103,36 @@ struct mtd_oob_ops {
 #else
 #define MTD_MAX_ECCPOS_ENTRIES_LARGE	680
 #endif
+/**
+ * struct mtd_oob_region - oob region definition
+ * @offset: region offset
+ * @length: region length
+ *
+ * This structure describes a region of the OOB area, and is used
+ * to retrieve ECC or free bytes sections.
+ * Each section is defined by an offset within the OOB area and a
+ * length.
+ */
+struct mtd_oob_region {
+	u32 offset;
+	u32 length;
+};
+
+/*
+ * struct mtd_ooblayout_ops - NAND OOB layout operations
+ * @ecc: function returning an ECC region in the OOB area.
+ *	 Should return -ERANGE if %section exceeds the total number of
+ *	 ECC sections.
+ * @free: function returning a free region in the OOB area.
+ *	  Should return -ERANGE if %section exceeds the total number of
+ *	  free sections.
+ */
+struct mtd_ooblayout_ops {
+	int (*ecc)(struct mtd_info *mtd, int section,
+		   struct mtd_oob_region *oobecc);
+	int (*free)(struct mtd_info *mtd, int section,
+		    struct mtd_oob_region *oobfree);
+};
 
 /*
  * Internal ECC layout control structure. For historical reasons, there is a
@@ -179,6 +209,9 @@ struct mtd_info {
 #endif
 	int index;
 
+	/* OOB layout description */
+	const struct mtd_ooblayout_ops *ooblayout;
+
 	/* ECC layout structure pointer - read only! */
 	struct nand_ecclayout *ecclayout;
 
@@ -278,6 +311,30 @@ struct mtd_info {
 	int usecount;
 };
 
+int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
+		      struct mtd_oob_region *oobecc);
+int mtd_ooblayout_find_eccregion(struct mtd_info *mtd, int eccbyte,
+				 int *section,
+				 struct mtd_oob_region *oobregion);
+int mtd_ooblayout_get_eccbytes(struct mtd_info *mtd, u8 *eccbuf,
+			       const u8 *oobbuf, int start, int nbytes);
+int mtd_ooblayout_set_eccbytes(struct mtd_info *mtd, const u8 *eccbuf,
+			       u8 *oobbuf, int start, int nbytes);
+int mtd_ooblayout_free(struct mtd_info *mtd, int section,
+		       struct mtd_oob_region *oobfree);
+int mtd_ooblayout_get_databytes(struct mtd_info *mtd, u8 *databuf,
+				const u8 *oobbuf, int start, int nbytes);
+int mtd_ooblayout_set_databytes(struct mtd_info *mtd, const u8 *databuf,
+				u8 *oobbuf, int start, int nbytes);
+int mtd_ooblayout_count_freebytes(struct mtd_info *mtd);
+int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd);
+
+static inline void mtd_set_ooblayout(struct mtd_info *mtd,
+				     const struct mtd_ooblayout_ops *ooblayout)
+{
+	mtd->ooblayout = ooblayout;
+}
+
 static inline int mtd_oobavail(struct mtd_info *mtd, struct mtd_oob_ops *ops)
 {
 	return ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize;
-- 
2.7.4

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

* [U-Boot] [PATCH 14/22] mtd: nand: Drop unused cached programming support
  2017-11-21 17:38 [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
                   ` (12 preceding siblings ...)
  2017-11-21 17:38 ` [U-Boot] [PATCH 13/22] mtd: add mtd_ooblayout_xxx() helper functions Masahiro Yamada
@ 2017-11-21 17:38 ` Masahiro Yamada
  2017-11-21 17:38 ` [U-Boot] [PATCH 15/22] mtd: nand: Drop the ->errstat() hook Masahiro Yamada
                   ` (8 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Masahiro Yamada @ 2017-11-21 17:38 UTC (permalink / raw)
  To: u-boot

From: Boris Brezillon <boris.brezillon@free-electrons.com>

Cached programming is always skipped, so drop the associated code until
we decide to really support it.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
[Linux commit: 0b4773fd1649e0d418275557723a7ef54f769dc9]
[masahiro: modify davinci_nand.c for U-Boot]
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>

---

 drivers/mtd/nand/davinci_nand.c |  3 +--
 drivers/mtd/nand/nand_base.c    | 42 +++++++++++++----------------------------
 include/linux/mtd/nand.h        |  2 +-
 3 files changed, 15 insertions(+), 32 deletions(-)

diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
index 2a01fd3..1e1f4b5 100644
--- a/drivers/mtd/nand/davinci_nand.c
+++ b/drivers/mtd/nand/davinci_nand.c
@@ -358,13 +358,12 @@ static struct nand_ecclayout nand_keystone_rbl_4bit_layout_oobfirst = {
  * @buf: the data to write
  * @oob_required: must write chip->oob_poi to OOB
  * @page: page number to write
- * @cached: cached programming
  * @raw: use _raw version of write_page
  */
 static int nand_davinci_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 				   uint32_t offset, int data_len,
 				   const uint8_t *buf, int oob_required,
-				   int page, int cached, int raw)
+				   int page, int raw)
 {
 	int status;
 	int ret = 0;
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index d9f0a75..0be427f 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2409,12 +2409,11 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
  * @buf: the data to write
  * @oob_required: must write chip->oob_poi to OOB
  * @page: page number to write
- * @cached: cached programming
  * @raw: use _raw version of write_page
  */
 static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 		uint32_t offset, int data_len, const uint8_t *buf,
-		int oob_required, int page, int cached, int raw)
+		int oob_required, int page, int raw)
 {
 	int status, subpage;
 
@@ -2440,31 +2439,19 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 	if (status < 0)
 		return status;
 
+	if (nand_standard_page_accessors(&chip->ecc))
+		chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+	status = chip->waitfunc(mtd, chip);
 	/*
-	 * Cached progamming disabled for now. Not sure if it's worth the
-	 * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s).
+	 * See if operation failed and additional status checks are
+	 * available.
 	 */
-	cached = 0;
-
-	if (!cached || !NAND_HAS_CACHEPROG(chip)) {
-
-		if (nand_standard_page_accessors(&chip->ecc))
-			chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-		status = chip->waitfunc(mtd, chip);
-		/*
-		 * See if operation failed and additional status checks are
-		 * available.
-		 */
-		if ((status & NAND_STATUS_FAIL) && (chip->errstat))
-			status = chip->errstat(mtd, chip, FL_WRITING, status,
-					       page);
+	if ((status & NAND_STATUS_FAIL) && (chip->errstat))
+		status = chip->errstat(mtd, chip, FL_WRITING, status,
+				       page);
 
-		if (status & NAND_STATUS_FAIL)
-			return -EIO;
-	} else {
-		chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);
-		status = chip->waitfunc(mtd, chip);
-	}
+	if (status & NAND_STATUS_FAIL)
+		return -EIO;
 
 	return 0;
 }
@@ -2538,7 +2525,7 @@ static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len,
 static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
 			     struct mtd_oob_ops *ops)
 {
-	int chipnr, realpage, page, blockmask, column;
+	int chipnr, realpage, page, column;
 	struct nand_chip *chip = mtd_to_nand(mtd);
 	uint32_t writelen = ops->len;
 
@@ -2574,7 +2561,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
 
 	realpage = (int)(to >> chip->page_shift);
 	page = realpage & chip->pagemask;
-	blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
 
 	/* Invalidate the page cache, when we write to the cached page */
 	if (to <= ((loff_t)chip->pagebuf << chip->page_shift) &&
@@ -2589,7 +2575,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
 
 	while (1) {
 		int bytes = mtd->writesize;
-		int cached = writelen > bytes && page != blockmask;
 		uint8_t *wbuf = buf;
 		int use_bufpoi;
 		int part_pagewr = (column || writelen < mtd->writesize);
@@ -2604,7 +2589,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
 		if (use_bufpoi) {
 			pr_debug("%s: using write bounce buffer for buf@%p\n",
 					 __func__, buf);
-			cached = 0;
 			if (part_pagewr)
 				bytes = min_t(int, bytes - column, writelen);
 			chip->pagebuf = -1;
@@ -2622,7 +2606,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
 			memset(chip->oob_poi, 0xff, mtd->oobsize);
 		}
 		ret = chip->write_page(mtd, chip, column, bytes, wbuf,
-					oob_required, page, cached,
+					oob_required, page,
 					(ops->mode == MTD_OPS_RAW));
 		if (ret)
 			break;
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 72b2328..c4363cc 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -849,7 +849,7 @@ struct nand_chip {
 			int status, int page);
 	int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
 			uint32_t offset, int data_len, const uint8_t *buf,
-			int oob_required, int page, int cached, int raw);
+			int oob_required, int page, int raw);
 	int (*onfi_set_features)(struct mtd_info *mtd, struct nand_chip *chip,
 			int feature_addr, uint8_t *subfeature_para);
 	int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip,
-- 
2.7.4

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

* [U-Boot] [PATCH 15/22] mtd: nand: Drop the ->errstat() hook
  2017-11-21 17:38 [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
                   ` (13 preceding siblings ...)
  2017-11-21 17:38 ` [U-Boot] [PATCH 14/22] mtd: nand: Drop unused cached programming support Masahiro Yamada
@ 2017-11-21 17:38 ` Masahiro Yamada
  2017-11-21 17:38 ` [U-Boot] [PATCH 16/22] mtd: nand: Wait for PAGEPROG to finish in drivers setting NAND_ECC_CUSTOM_PAGE_ACCESS Masahiro Yamada
                   ` (7 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Masahiro Yamada @ 2017-11-21 17:38 UTC (permalink / raw)
  To: u-boot

From: Boris Brezillon <boris.brezillon@free-electrons.com>

The ->errstat() hook is no longer implemented NAND controller drivers.
Get rid of it before someone starts abusing it.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
[Linux commit: 7d135bcced20be2b50128432c5426a7278ec4f6d]
[masahiro: modify davinci_nand.c for U-Boot]
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>

---

 drivers/mtd/nand/davinci_nand.c |  7 -------
 drivers/mtd/nand/nand_base.c    | 15 ---------------
 include/linux/mtd/nand.h        |  5 -----
 3 files changed, 27 deletions(-)

diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
index 1e1f4b5..65104c6 100644
--- a/drivers/mtd/nand/davinci_nand.c
+++ b/drivers/mtd/nand/davinci_nand.c
@@ -394,13 +394,6 @@ static int nand_davinci_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
 	status = chip->waitfunc(mtd, chip);
 
-	/*
-	 * See if operation failed and additional status checks are
-	 * available.
-	 */
-	if ((status & NAND_STATUS_FAIL) && (chip->errstat))
-		status = chip->errstat(mtd, chip, FL_WRITING, status, page);
-
 	if (status & NAND_STATUS_FAIL) {
 		ret = -EIO;
 		goto err;
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 0be427f..91afa47 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2442,13 +2442,6 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 	if (nand_standard_page_accessors(&chip->ecc))
 		chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
 	status = chip->waitfunc(mtd, chip);
-	/*
-	 * See if operation failed and additional status checks are
-	 * available.
-	 */
-	if ((status & NAND_STATUS_FAIL) && (chip->errstat))
-		status = chip->errstat(mtd, chip, FL_WRITING, status,
-				       page);
 
 	if (status & NAND_STATUS_FAIL)
 		return -EIO;
@@ -2924,14 +2917,6 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
 
 		status = chip->erase(mtd, page & chip->pagemask);
 
-		/*
-		 * See if operation failed and additional status checks are
-		 * available
-		 */
-		if ((status & NAND_STATUS_FAIL) && (chip->errstat))
-			status = chip->errstat(mtd, chip, FL_ERASING,
-					       status, page);
-
 		/* See if block erase succeeded */
 		if (status & NAND_STATUS_FAIL) {
 			pr_debug("%s: failed erase, page 0x%08x\n",
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index c4363cc..be30059 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -817,9 +817,6 @@ nand_get_sdr_timings(const struct nand_data_interface *conf)
  *			structure which is shared among multiple independent
  *			devices.
  * @priv:		[OPTIONAL] pointer to private chip data
- * @errstat:		[OPTIONAL] hardware specific function to perform
- *			additional error status checks (determine if errors are
- *			correctable).
  * @write_page:		[REPLACEABLE] High-level page write function
  */
 
@@ -845,8 +842,6 @@ struct nand_chip {
 	int(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);
 	int (*erase)(struct mtd_info *mtd, int page);
 	int (*scan_bbt)(struct mtd_info *mtd);
-	int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state,
-			int status, int page);
 	int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
 			uint32_t offset, int data_len, const uint8_t *buf,
 			int oob_required, int page, int raw);
-- 
2.7.4

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

* [U-Boot] [PATCH 16/22] mtd: nand: Wait for PAGEPROG to finish in drivers setting NAND_ECC_CUSTOM_PAGE_ACCESS
  2017-11-21 17:38 [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
                   ` (14 preceding siblings ...)
  2017-11-21 17:38 ` [U-Boot] [PATCH 15/22] mtd: nand: Drop the ->errstat() hook Masahiro Yamada
@ 2017-11-21 17:38 ` Masahiro Yamada
  2017-11-21 17:38 ` [U-Boot] [PATCH 17/22] mtd: nand: allow drivers to request minimum alignment for passed buffer Masahiro Yamada
                   ` (6 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Masahiro Yamada @ 2017-11-21 17:38 UTC (permalink / raw)
  To: u-boot

From: Boris Brezillon <boris.brezillon@free-electrons.com>

Drivers setting NAND_ECC_CUSTOM_PAGE_ACCESS are supposed to handle the
full read/write page sequence, and waiting for a page to actually be
programmed is part of this write-page sequence.
This is also what is done in ->write_oob_xxx() hooks, so let's do that in
->write_page_xxx() as well to make it consistent.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
[Linux commit: 41145649f4acb30249b636b945053db50c9331c5]
[masahiro:
 There is no driver setting NAND_ECC_CUSTOM_PAGE_ACCESS in U-Boot.
 No driver is affected by this change.]
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>

---

 drivers/mtd/nand/nand_base.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 91afa47..16d4554 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2439,12 +2439,13 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 	if (status < 0)
 		return status;
 
-	if (nand_standard_page_accessors(&chip->ecc))
+	if (nand_standard_page_accessors(&chip->ecc)) {
 		chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-	status = chip->waitfunc(mtd, chip);
 
-	if (status & NAND_STATUS_FAIL)
-		return -EIO;
+		status = chip->waitfunc(mtd, chip);
+		if (status & NAND_STATUS_FAIL)
+			return -EIO;
+	}
 
 	return 0;
 }
-- 
2.7.4

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

* [U-Boot] [PATCH 17/22] mtd: nand: allow drivers to request minimum alignment for passed buffer
  2017-11-21 17:38 [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
                   ` (15 preceding siblings ...)
  2017-11-21 17:38 ` [U-Boot] [PATCH 16/22] mtd: nand: Wait for PAGEPROG to finish in drivers setting NAND_ECC_CUSTOM_PAGE_ACCESS Masahiro Yamada
@ 2017-11-21 17:38 ` Masahiro Yamada
  2017-11-21 17:38 ` [U-Boot] [PATCH 18/22] mtd: nand: Pass the CS line to ->setup_data_interface() Masahiro Yamada
                   ` (5 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Masahiro Yamada @ 2017-11-21 17:38 UTC (permalink / raw)
  To: u-boot

In some cases, nand_do_{read,write}_ops is passed with unaligned
ops->datbuf.  Drivers using DMA will be unhappy about unaligned
buffer.

The new struct member, buf_align, represents the minimum alignment
the driver require for the buffer.  If the buffer passed from the
upper MTD layer does not have enough alignment, nand_do_*_ops will
use bufpoi.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>

[Linux commit: 477544c62a84d3bacd9f90ba75ffc16c04d78071]

---

 drivers/mtd/nand/nand_base.c | 8 ++++++++
 include/linux/mtd/nand.h     | 2 ++
 2 files changed, 10 insertions(+)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 16d4554..f3c515b 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1720,6 +1720,9 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 
 		if (!aligned)
 			use_bufpoi = 1;
+		else if (chip->options & NAND_USE_BOUNCE_BUFFER)
+			use_bufpoi = !IS_ALIGNED((unsigned long)buf,
+						 chip->buf_align);
 		else
 			use_bufpoi = 0;
 
@@ -2575,6 +2578,9 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
 
 		if (part_pagewr)
 			use_bufpoi = 1;
+		else if (chip->options & NAND_USE_BOUNCE_BUFFER)
+			use_bufpoi = !IS_ALIGNED((unsigned long)buf,
+						 chip->buf_align);
 		else
 			use_bufpoi = 0;
 
@@ -3119,6 +3125,8 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
 		init_waitqueue_head(&chip->controller->wq);
 	}
 
+	if (!chip->buf_align)
+		chip->buf_align = 1;
 }
 
 /* Sanitize ONFI strings so we can safely print them */
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index be30059..90c6010 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -752,6 +752,7 @@ nand_get_sdr_timings(const struct nand_data_interface *conf)
  *			setting the read-retry mode. Mostly needed for MLC NAND.
  * @ecc:		[BOARDSPECIFIC] ECC control structure
  * @buffers:		buffer structure for read/write
+ * @buf_align:		minimum buffer alignment required by a platform
  * @hwcontrol:		platform-specific hardware control structure
  * @erase:		[REPLACEABLE] erase function
  * @scan_bbt:		[REPLACEABLE] function to scan bad block table
@@ -893,6 +894,7 @@ struct nand_chip {
 
 	struct nand_ecc_ctrl ecc;
 	struct nand_buffers *buffers;
+	unsigned long buf_align;
 	struct nand_hw_control hwcontrol;
 
 	uint8_t *bbt;
-- 
2.7.4

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

* [U-Boot] [PATCH 18/22] mtd: nand: Pass the CS line to ->setup_data_interface()
  2017-11-21 17:38 [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
                   ` (16 preceding siblings ...)
  2017-11-21 17:38 ` [U-Boot] [PATCH 17/22] mtd: nand: allow drivers to request minimum alignment for passed buffer Masahiro Yamada
@ 2017-11-21 17:38 ` Masahiro Yamada
  2017-11-21 17:38 ` [U-Boot] [PATCH 19/22] mtd: nand: add generic helpers to check, match, maximize ECC settings Masahiro Yamada
                   ` (4 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Masahiro Yamada @ 2017-11-21 17:38 UTC (permalink / raw)
  To: u-boot

From: Boris Brezillon <boris.brezillon@free-electrons.com>

Some NAND controllers can assign different NAND timings to different
CS lines. Pass the CS line information to ->setup_data_interface() so
that the NAND controller driver knows which CS line is concerned by
the setup_data_interface() request.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
[Linux commit: 104e442a67cfba4d0cc982384761befb917fb6a1]
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>

---

 drivers/mtd/nand/nand_base.c | 22 +++++++++++++---------
 include/linux/mtd/nand.h     | 12 ++++++++----
 2 files changed, 21 insertions(+), 13 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index f3c515b..e490c84 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -904,12 +904,13 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
 /**
  * nand_reset_data_interface - Reset data interface and timings
  * @chip: The NAND chip
+ * @chipnr: Internal die id
  *
  * Reset the Data interface and timings to ONFI mode 0.
  *
  * Returns 0 for success or negative error code otherwise.
  */
-static int nand_reset_data_interface(struct nand_chip *chip)
+static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
 {
 	struct mtd_info *mtd = nand_to_mtd(chip);
 	const struct nand_data_interface *conf;
@@ -933,7 +934,7 @@ static int nand_reset_data_interface(struct nand_chip *chip)
 	 */
 
 	conf = nand_get_default_data_interface();
-	ret = chip->setup_data_interface(mtd, conf, false);
+	ret = chip->setup_data_interface(mtd, chipnr, conf);
 	if (ret)
 		pr_err("Failed to configure data interface to SDR timing mode 0\n");
 
@@ -943,6 +944,7 @@ static int nand_reset_data_interface(struct nand_chip *chip)
 /**
  * nand_setup_data_interface - Setup the best data interface and timings
  * @chip: The NAND chip
+ * @chipnr: Internal die id
  *
  * Find and configure the best data interface and NAND timings supported by
  * the chip and the driver.
@@ -952,7 +954,7 @@ static int nand_reset_data_interface(struct nand_chip *chip)
  *
  * Returns 0 for success or negative error code otherwise.
  */
-static int nand_setup_data_interface(struct nand_chip *chip)
+static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
 {
 	struct mtd_info *mtd = nand_to_mtd(chip);
 	int ret;
@@ -976,7 +978,7 @@ static int nand_setup_data_interface(struct nand_chip *chip)
 			goto err;
 	}
 
-	ret = chip->setup_data_interface(mtd, chip->data_interface, false);
+	ret = chip->setup_data_interface(mtd, chipnr, chip->data_interface);
 err:
 	return ret;
 }
@@ -1027,8 +1029,10 @@ static int nand_init_data_interface(struct nand_chip *chip)
 		if (ret)
 			continue;
 
-		ret = chip->setup_data_interface(mtd, chip->data_interface,
-						 true);
+		/* Pass -1 to only */
+		ret = chip->setup_data_interface(mtd,
+						 NAND_DATA_IFACE_CHECK_ONLY,
+						 chip->data_interface);
 		if (!ret) {
 			chip->onfi_timing_mode_default = mode;
 			break;
@@ -1055,7 +1059,7 @@ int nand_reset(struct nand_chip *chip, int chipnr)
 	struct mtd_info *mtd = nand_to_mtd(chip);
 	int ret;
 
-	ret = nand_reset_data_interface(chip);
+	ret = nand_reset_data_interface(chip, chipnr);
 	if (ret)
 		return ret;
 
@@ -1068,7 +1072,7 @@ int nand_reset(struct nand_chip *chip, int chipnr)
 	chip->select_chip(mtd, -1);
 
 	chip->select_chip(mtd, chipnr);
-	ret = nand_setup_data_interface(chip);
+	ret = nand_setup_data_interface(chip, chipnr);
 	chip->select_chip(mtd, -1);
 	if (ret)
 		return ret;
@@ -4037,7 +4041,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
 	 * For the other dies, nand_reset() will automatically switch to the
 	 * best mode for us.
 	 */
-	ret = nand_setup_data_interface(chip);
+	ret = nand_setup_data_interface(chip, 0);
 	if (ret)
 		return ret;
 
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 90c6010..b1a6648 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -124,6 +124,8 @@ void nand_wait_ready(struct mtd_info *mtd);
 #define NAND_STATUS_READY	0x40
 #define NAND_STATUS_WP		0x80
 
+#define NAND_DATA_IFACE_CHECK_ONLY	-1
+
 /*
  * Constants for ECC_MODES
  */
@@ -807,7 +809,10 @@ nand_get_sdr_timings(const struct nand_data_interface *conf)
  * @read_retries:	[INTERN] the number of read retry modes supported
  * @onfi_set_features:	[REPLACEABLE] set the features for ONFI nand
  * @onfi_get_features:	[REPLACEABLE] get the features for ONFI nand
- * @setup_data_interface: [OPTIONAL] setup the data interface and timing
+ * @setup_data_interface: [OPTIONAL] setup the data interface and timing. If
+ *			  chipnr is set to %NAND_DATA_IFACE_CHECK_ONLY this
+ *			  means the configuration should not be applied but
+ *			  only checked.
  * @bbt:		[INTERN] bad block table pointer
  * @bbt_td:		[REPLACEABLE] bad block table descriptor for flash
  *			lookup.
@@ -851,9 +856,8 @@ struct nand_chip {
 	int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip,
 			int feature_addr, uint8_t *subfeature_para);
 	int (*setup_read_retry)(struct mtd_info *mtd, int retry_mode);
-	int (*setup_data_interface)(struct mtd_info *mtd,
-				    const struct nand_data_interface *conf,
-				    bool check_only);
+	int (*setup_data_interface)(struct mtd_info *mtd, int chipnr,
+				    const struct nand_data_interface *conf);
 
 
 	int chip_delay;
-- 
2.7.4

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

* [U-Boot] [PATCH 19/22] mtd: nand: add generic helpers to check, match, maximize ECC settings
  2017-11-21 17:38 [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
                   ` (17 preceding siblings ...)
  2017-11-21 17:38 ` [U-Boot] [PATCH 18/22] mtd: nand: Pass the CS line to ->setup_data_interface() Masahiro Yamada
@ 2017-11-21 17:38 ` Masahiro Yamada
  2017-11-21 17:38 ` [U-Boot] [PATCH 20/22] mtd: nand: add a shorthand to generate nand_ecc_caps structure Masahiro Yamada
                   ` (3 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Masahiro Yamada @ 2017-11-21 17:38 UTC (permalink / raw)
  To: u-boot

Driver are responsible for setting up ECC parameters correctly.
Those include:
  - Check if ECC parameters specified (usually by DT) are valid
  - Meet the chip's ECC requirement
  - Maximize ECC strength if NAND_ECC_MAXIMIZE flag is set

The logic can be generalized by factoring out common code.

This commit adds 3 helpers to the NAND framework:
nand_check_ecc_caps - Check if preset step_size and strength are valid
nand_match_ecc_req - Match the chip's requirement
nand_maximize_ecc - Maximize the ECC strength

To use the helpers above, a driver needs to provide:
  - Data array of supported ECC step size and strength
  - A hook that calculates ECC bytes from the combination of
    step_size and strength.

By using those helpers, code duplication among drivers will be
reduced.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>

[Linux commit: 2c8f8afa7f92acb07641bf95b940d384ed1d0294]

---

 drivers/mtd/nand/nand_base.c | 220 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/nand.h     |  33 +++++++
 2 files changed, 253 insertions(+)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index e490c84..77a3f16 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -4077,6 +4077,226 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
 }
 EXPORT_SYMBOL(nand_scan_ident);
 
+/**
+ * nand_check_ecc_caps - check the sanity of preset ECC settings
+ * @chip: nand chip info structure
+ * @caps: ECC caps info structure
+ * @oobavail: OOB size that the ECC engine can use
+ *
+ * When ECC step size and strength are already set, check if they are supported
+ * by the controller and the calculated ECC bytes fit within the chip's OOB.
+ * On success, the calculated ECC bytes is set.
+ */
+int nand_check_ecc_caps(struct nand_chip *chip,
+			const struct nand_ecc_caps *caps, int oobavail)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	const struct nand_ecc_step_info *stepinfo;
+	int preset_step = chip->ecc.size;
+	int preset_strength = chip->ecc.strength;
+	int nsteps, ecc_bytes;
+	int i, j;
+
+	if (WARN_ON(oobavail < 0))
+		return -EINVAL;
+
+	if (!preset_step || !preset_strength)
+		return -ENODATA;
+
+	nsteps = mtd->writesize / preset_step;
+
+	for (i = 0; i < caps->nstepinfos; i++) {
+		stepinfo = &caps->stepinfos[i];
+
+		if (stepinfo->stepsize != preset_step)
+			continue;
+
+		for (j = 0; j < stepinfo->nstrengths; j++) {
+			if (stepinfo->strengths[j] != preset_strength)
+				continue;
+
+			ecc_bytes = caps->calc_ecc_bytes(preset_step,
+							 preset_strength);
+			if (WARN_ON_ONCE(ecc_bytes < 0))
+				return ecc_bytes;
+
+			if (ecc_bytes * nsteps > oobavail) {
+				pr_err("ECC (step, strength) = (%d, %d) does not fit in OOB",
+				       preset_step, preset_strength);
+				return -ENOSPC;
+			}
+
+			chip->ecc.bytes = ecc_bytes;
+
+			return 0;
+		}
+	}
+
+	pr_err("ECC (step, strength) = (%d, %d) not supported on this controller",
+	       preset_step, preset_strength);
+
+	return -ENOTSUPP;
+}
+EXPORT_SYMBOL_GPL(nand_check_ecc_caps);
+
+/**
+ * nand_match_ecc_req - meet the chip's requirement with least ECC bytes
+ * @chip: nand chip info structure
+ * @caps: ECC engine caps info structure
+ * @oobavail: OOB size that the ECC engine can use
+ *
+ * If a chip's ECC requirement is provided, try to meet it with the least
+ * number of ECC bytes (i.e. with the largest number of OOB-free bytes).
+ * On success, the chosen ECC settings are set.
+ */
+int nand_match_ecc_req(struct nand_chip *chip,
+		       const struct nand_ecc_caps *caps, int oobavail)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	const struct nand_ecc_step_info *stepinfo;
+	int req_step = chip->ecc_step_ds;
+	int req_strength = chip->ecc_strength_ds;
+	int req_corr, step_size, strength, nsteps, ecc_bytes, ecc_bytes_total;
+	int best_step, best_strength, best_ecc_bytes;
+	int best_ecc_bytes_total = INT_MAX;
+	int i, j;
+
+	if (WARN_ON(oobavail < 0))
+		return -EINVAL;
+
+	/* No information provided by the NAND chip */
+	if (!req_step || !req_strength)
+		return -ENOTSUPP;
+
+	/* number of correctable bits the chip requires in a page */
+	req_corr = mtd->writesize / req_step * req_strength;
+
+	for (i = 0; i < caps->nstepinfos; i++) {
+		stepinfo = &caps->stepinfos[i];
+		step_size = stepinfo->stepsize;
+
+		for (j = 0; j < stepinfo->nstrengths; j++) {
+			strength = stepinfo->strengths[j];
+
+			/*
+			 * If both step size and strength are smaller than the
+			 * chip's requirement, it is not easy to compare the
+			 * resulted reliability.
+			 */
+			if (step_size < req_step && strength < req_strength)
+				continue;
+
+			if (mtd->writesize % step_size)
+				continue;
+
+			nsteps = mtd->writesize / step_size;
+
+			ecc_bytes = caps->calc_ecc_bytes(step_size, strength);
+			if (WARN_ON_ONCE(ecc_bytes < 0))
+				continue;
+			ecc_bytes_total = ecc_bytes * nsteps;
+
+			if (ecc_bytes_total > oobavail ||
+			    strength * nsteps < req_corr)
+				continue;
+
+			/*
+			 * We assume the best is to meet the chip's requrement
+			 * with the least number of ECC bytes.
+			 */
+			if (ecc_bytes_total < best_ecc_bytes_total) {
+				best_ecc_bytes_total = ecc_bytes_total;
+				best_step = step_size;
+				best_strength = strength;
+				best_ecc_bytes = ecc_bytes;
+			}
+		}
+	}
+
+	if (best_ecc_bytes_total == INT_MAX)
+		return -ENOTSUPP;
+
+	chip->ecc.size = best_step;
+	chip->ecc.strength = best_strength;
+	chip->ecc.bytes = best_ecc_bytes;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nand_match_ecc_req);
+
+/**
+ * nand_maximize_ecc - choose the max ECC strength available
+ * @chip: nand chip info structure
+ * @caps: ECC engine caps info structure
+ * @oobavail: OOB size that the ECC engine can use
+ *
+ * Choose the max ECC strength that is supported on the controller, and can fit
+ * within the chip's OOB.  On success, the chosen ECC settings are set.
+ */
+int nand_maximize_ecc(struct nand_chip *chip,
+		      const struct nand_ecc_caps *caps, int oobavail)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	const struct nand_ecc_step_info *stepinfo;
+	int step_size, strength, nsteps, ecc_bytes, corr;
+	int best_corr = 0;
+	int best_step = 0;
+	int best_strength, best_ecc_bytes;
+	int i, j;
+
+	if (WARN_ON(oobavail < 0))
+		return -EINVAL;
+
+	for (i = 0; i < caps->nstepinfos; i++) {
+		stepinfo = &caps->stepinfos[i];
+		step_size = stepinfo->stepsize;
+
+		/* If chip->ecc.size is already set, respect it */
+		if (chip->ecc.size && step_size != chip->ecc.size)
+			continue;
+
+		for (j = 0; j < stepinfo->nstrengths; j++) {
+			strength = stepinfo->strengths[j];
+
+			if (mtd->writesize % step_size)
+				continue;
+
+			nsteps = mtd->writesize / step_size;
+
+			ecc_bytes = caps->calc_ecc_bytes(step_size, strength);
+			if (WARN_ON_ONCE(ecc_bytes < 0))
+				continue;
+
+			if (ecc_bytes * nsteps > oobavail)
+				continue;
+
+			corr = strength * nsteps;
+
+			/*
+			 * If the number of correctable bits is the same,
+			 * bigger step_size has more reliability.
+			 */
+			if (corr > best_corr ||
+			    (corr == best_corr && step_size > best_step)) {
+				best_corr = corr;
+				best_step = step_size;
+				best_strength = strength;
+				best_ecc_bytes = ecc_bytes;
+			}
+		}
+	}
+
+	if (!best_corr)
+		return -ENOTSUPP;
+
+	chip->ecc.size = best_step;
+	chip->ecc.strength = best_strength;
+	chip->ecc.bytes = best_ecc_bytes;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nand_maximize_ecc);
+
 /*
  * Check if the chip configuration meet the datasheet requirements.
 
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index b1a6648..2d5f9a4 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -488,6 +488,30 @@ struct nand_hw_control {
 };
 
 /**
+ * struct nand_ecc_step_info - ECC step information of ECC engine
+ * @stepsize: data bytes per ECC step
+ * @strengths: array of supported strengths
+ * @nstrengths: number of supported strengths
+ */
+struct nand_ecc_step_info {
+	int stepsize;
+	const int *strengths;
+	int nstrengths;
+};
+
+/**
+ * struct nand_ecc_caps - capability of ECC engine
+ * @stepinfos: array of ECC step information
+ * @nstepinfos: number of ECC step information
+ * @calc_ecc_bytes: driver's hook to calculate ECC bytes per step
+ */
+struct nand_ecc_caps {
+	const struct nand_ecc_step_info *stepinfos;
+	int nstepinfos;
+	int (*calc_ecc_bytes)(int step_size, int strength);
+};
+
+/**
  * struct nand_ecc_ctrl - Control structure for ECC
  * @mode:	ECC mode
  * @steps:	number of ECC steps per page
@@ -1218,6 +1242,15 @@ int nand_check_erased_ecc_chunk(void *data, int datalen,
 				void *extraoob, int extraooblen,
 				int threshold);
 
+int nand_check_ecc_caps(struct nand_chip *chip,
+			const struct nand_ecc_caps *caps, int oobavail);
+
+int nand_match_ecc_req(struct nand_chip *chip,
+		       const struct nand_ecc_caps *caps,  int oobavail);
+
+int nand_maximize_ecc(struct nand_chip *chip,
+		      const struct nand_ecc_caps *caps, int oobavail);
+
 /* Reset and initialize a NAND device */
 int nand_reset(struct nand_chip *chip, int chipnr);
 
-- 
2.7.4

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

* [U-Boot] [PATCH 20/22] mtd: nand: add a shorthand to generate nand_ecc_caps structure
  2017-11-21 17:38 [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
                   ` (18 preceding siblings ...)
  2017-11-21 17:38 ` [U-Boot] [PATCH 19/22] mtd: nand: add generic helpers to check, match, maximize ECC settings Masahiro Yamada
@ 2017-11-21 17:38 ` Masahiro Yamada
  2017-11-21 17:38 ` [U-Boot] [PATCH 21/22] mtd: nand: introduce NAND_ROW_ADDR_3 flag Masahiro Yamada
                   ` (2 subsequent siblings)
  22 siblings, 0 replies; 29+ messages in thread
From: Masahiro Yamada @ 2017-11-21 17:38 UTC (permalink / raw)
  To: u-boot

struct nand_ecc_caps was designed as flexible as possible to support
multiple stepsizes (like sunxi_nand.c).

So, we need to write multiple arrays even for the simplest case.
I guess many controllers support a single stepsize, so here is a
shorthand macro for the case.

It allows to describe like ...

NAND_ECC_CAPS_SINGLE(denali_pci_ecc_caps, denali_calc_ecc_bytes, 512, 8, 15);

... instead of

static const int denali_pci_ecc_strengths[] = {8, 15};
static const struct nand_ecc_step_info denali_pci_ecc_stepinfo = {
        .stepsize = 512,
        .strengths = denali_pci_ecc_strengths,
        .nstrengths = ARRAY_SIZE(denali_pci_ecc_strengths),
};
static const struct nand_ecc_caps denali_pci_ecc_caps = {
        .stepinfos = &denali_pci_ecc_stepinfo,
        .nstepinfos = 1,
        .calc_ecc_bytes = denali_calc_ecc_bytes,
};

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>

[Linux commit: a03c60178c181767ecfb26fb311a88742d228118]

---

 include/linux/mtd/nand.h | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 2d5f9a4..150e3b8 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -511,6 +511,20 @@ struct nand_ecc_caps {
 	int (*calc_ecc_bytes)(int step_size, int strength);
 };
 
+/* a shorthand to generate struct nand_ecc_caps with only one ECC stepsize */
+#define NAND_ECC_CAPS_SINGLE(__name, __calc, __step, ...)	\
+static const int __name##_strengths[] = { __VA_ARGS__ };	\
+static const struct nand_ecc_step_info __name##_stepinfo = {	\
+	.stepsize = __step,					\
+	.strengths = __name##_strengths,			\
+	.nstrengths = ARRAY_SIZE(__name##_strengths),		\
+};								\
+static const struct nand_ecc_caps __name = {			\
+	.stepinfos = &__name##_stepinfo,			\
+	.nstepinfos = 1,					\
+	.calc_ecc_bytes = __calc,				\
+}
+
 /**
  * struct nand_ecc_ctrl - Control structure for ECC
  * @mode:	ECC mode
-- 
2.7.4

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

* [U-Boot] [PATCH 21/22] mtd: nand: introduce NAND_ROW_ADDR_3 flag
  2017-11-21 17:38 [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
                   ` (19 preceding siblings ...)
  2017-11-21 17:38 ` [U-Boot] [PATCH 20/22] mtd: nand: add a shorthand to generate nand_ecc_caps structure Masahiro Yamada
@ 2017-11-21 17:38 ` Masahiro Yamada
  2017-11-21 17:38 ` [U-Boot] [PATCH 22/22] mtd: nand: denali: sync with Linux 4.15-rc1 Masahiro Yamada
  2017-11-28  0:35 ` [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
  22 siblings, 0 replies; 29+ messages in thread
From: Masahiro Yamada @ 2017-11-21 17:38 UTC (permalink / raw)
  To: u-boot

Several drivers check ->chipsize to see if the third row address cycle
is needed.  Instead of embedding magic sizes such as 32MB, 128MB in
drivers, introduce a new flag NAND_ROW_ADDR_3 for clean-up.  Since
nand_scan_ident() knows well about the device, it can handle this
properly.  The flag is set if the row address bit width is greater
than 16.

Delete comments such as "One more address cycle for ..." because
intention is now clear enough from the code.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Acked-by: Wenyou Yang <wenyou.yang@microchip.com>
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>

[Linux commit: 14157f861437ebe2d624b0a845b91bbdf8ca9a2d]

---

 drivers/mtd/nand/nand_base.c | 9 +++++----
 include/linux/mtd/nand.h     | 3 +++
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 77a3f16..aca3231 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -634,8 +634,7 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
 		chip->cmd_ctrl(mtd, page_addr, ctrl);
 		ctrl &= ~NAND_CTRL_CHANGE;
 		chip->cmd_ctrl(mtd, page_addr >> 8, ctrl);
-		/* One more address cycle for devices > 32MiB */
-		if (chip->chipsize > (32 << 20))
+		if (chip->options & NAND_ROW_ADDR_3)
 			chip->cmd_ctrl(mtd, page_addr >> 16, ctrl);
 	}
 	chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
@@ -729,8 +728,7 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
 			chip->cmd_ctrl(mtd, page_addr, ctrl);
 			chip->cmd_ctrl(mtd, page_addr >> 8,
 				       NAND_NCE | NAND_ALE);
-			/* One more address cycle for devices > 128MiB */
-			if (chip->chipsize > (128 << 20))
+			if (chip->options & NAND_ROW_ADDR_3)
 				chip->cmd_ctrl(mtd, page_addr >> 16,
 					       NAND_NCE | NAND_ALE);
 		}
@@ -3889,6 +3887,9 @@ ident_done:
 		chip->chip_shift += 32 - 1;
 	}
 
+	if (chip->chip_shift - chip->page_shift > 16)
+		chip->options |= NAND_ROW_ADDR_3;
+
 	chip->badblockbits = 8;
 	chip->erase = single_erase;
 
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 150e3b8..d1db34c 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -204,6 +204,9 @@ typedef enum {
  */
 #define NAND_NEED_SCRAMBLING	0x00002000
 
+/* Device needs 3rd row address cycle */
+#define NAND_ROW_ADDR_3		0x00004000
+
 /* Options valid for Samsung large page devices */
 #define NAND_SAMSUNG_LP_OPTIONS NAND_CACHEPRG
 
-- 
2.7.4

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

* [U-Boot] [PATCH 22/22] mtd: nand: denali: sync with Linux 4.15-rc1
  2017-11-21 17:38 [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
                   ` (20 preceding siblings ...)
  2017-11-21 17:38 ` [U-Boot] [PATCH 21/22] mtd: nand: introduce NAND_ROW_ADDR_3 flag Masahiro Yamada
@ 2017-11-21 17:38 ` Masahiro Yamada
  2017-11-28  0:35 ` [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
  22 siblings, 0 replies; 29+ messages in thread
From: Masahiro Yamada @ 2017-11-21 17:38 UTC (permalink / raw)
  To: u-boot

I largely reworked the Denali NAND controller driver in Linux.
This commit imports the improvements from Linux.  The code is
almost synced with Linux 4.15-rc1.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---

 drivers/mtd/nand/Kconfig      |   11 -
 drivers/mtd/nand/denali.c     | 2028 +++++++++++++++++++++--------------------
 drivers/mtd/nand/denali.h     |  473 ++++------
 drivers/mtd/nand/denali_dt.c  |   17 +-
 drivers/mtd/nand/denali_spl.c |   14 +-
 5 files changed, 1248 insertions(+), 1295 deletions(-)

diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index ca98193..cbdbd2f 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -23,17 +23,6 @@ config NAND_DENALI_DT
 	  Enable the driver for NAND flash on platforms using a Denali NAND
 	  controller as a DT device.
 
-config SYS_NAND_DENALI_64BIT
-	bool "Use 64-bit variant of Denali NAND controller"
-	depends on NAND_DENALI
-	help
-	  The Denali NAND controller IP has some variations in terms of
-	  the bus interface.  The DMA setup sequence is completely differenct
-	  between 32bit / 64bit AXI bus variants.
-
-	  If your Denali NAND controller is the 64-bit variant, say Y.
-	  Otherwise (32 bit), say N.
-
 config NAND_DENALI_SPARE_AREA_SKIP_BYTES
 	int "Number of bytes skipped in OOB area"
 	depends on NAND_DENALI
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index 54718f4..e61cafc 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -9,1144 +9,1076 @@
 #include <common.h>
 #include <malloc.h>
 #include <nand.h>
+#include <dm.h>
+#include <linux/bitfield.h>
+#include <linux/dma-direction.h>
 #include <linux/errno.h>
 #include <linux/io.h>
 
 #include "denali.h"
 
-#define NAND_DEFAULT_TIMINGS	-1
-
-static int onfi_timing_mode = NAND_DEFAULT_TIMINGS;
-
-/*
- * We define a macro here that combines all interrupts this driver uses into
- * a single constant value, for convenience.
- */
-#define DENALI_IRQ_ALL	(INTR_STATUS__DMA_CMD_COMP | \
-			INTR_STATUS__ECC_TRANSACTION_DONE | \
-			INTR_STATUS__ECC_ERR | \
-			INTR_STATUS__PROGRAM_FAIL | \
-			INTR_STATUS__LOAD_COMP | \
-			INTR_STATUS__PROGRAM_COMP | \
-			INTR_STATUS__TIME_OUT | \
-			INTR_STATUS__ERASE_FAIL | \
-			INTR_STATUS__RST_COMP | \
-			INTR_STATUS__ERASE_COMP | \
-			INTR_STATUS__ECC_UNCOR_ERR | \
-			INTR_STATUS__INT_ACT | \
-			INTR_STATUS__LOCKED_BLK)
+static dma_addr_t dma_map_single(void *dev, void *ptr, size_t size,
+				 enum dma_data_direction dir)
+{
+	unsigned long addr = (unsigned long)ptr;
 
-/*
- * indicates whether or not the internal value for the flash bank is
- * valid or not
- */
-#define CHIP_SELECT_INVALID	-1
+	if (dir == DMA_FROM_DEVICE)
+		invalidate_dcache_range(addr, addr + size);
+	else
+		flush_dcache_range(addr, addr + size);
 
-#define SUPPORT_8BITECC		1
+	return addr;
+}
 
-/*
- * this macro allows us to convert from an MTD structure to our own
- * device context (denali) structure.
- */
-static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd)
+static void dma_unmap_single(void *dev, dma_addr_t addr, size_t size,
+			     enum dma_data_direction dir)
 {
-	return container_of(mtd_to_nand(mtd), struct denali_nand_info, nand);
+	if (dir != DMA_TO_DEVICE)
+		invalidate_dcache_range(addr, addr + size);
 }
 
-/*
- * These constants are defined by the driver to enable common driver
- * configuration options.
- */
-#define SPARE_ACCESS		0x41
-#define MAIN_ACCESS		0x42
-#define MAIN_SPARE_ACCESS	0x43
-#define PIPELINE_ACCESS		0x2000
-
-#define DENALI_UNLOCK_START	0x10
-#define DENALI_UNLOCK_END	0x11
-#define DENALI_LOCK		0x21
-#define DENALI_LOCK_TIGHT	0x31
-#define DENALI_BUFFER_LOAD	0x60
-#define DENALI_BUFFER_WRITE	0x62
-
-#define DENALI_READ	0
-#define DENALI_WRITE	0x100
-
-/* types of device accesses. We can issue commands and get status */
-#define COMMAND_CYCLE	0
-#define ADDR_CYCLE	1
-#define STATUS_CYCLE	2
-
-/*
- * this is a helper macro that allows us to
- * format the bank into the proper bits for the controller
- */
-#define BANK(x) ((x) << 24)
-
-/* Interrupts are cleared by writing a 1 to the appropriate status bit */
-static inline void clear_interrupt(struct denali_nand_info *denali,
-							uint32_t irq_mask)
+static int dma_mapping_error(void *dev, dma_addr_t addr)
 {
-	uint32_t intr_status_reg;
-
-	intr_status_reg = INTR_STATUS(denali->flash_bank);
-
-	writel(irq_mask, denali->flash_reg + intr_status_reg);
+	return 0;
 }
 
-static uint32_t read_interrupt_status(struct denali_nand_info *denali)
-{
-	uint32_t intr_status_reg;
+#define DENALI_NAND_NAME    "denali-nand"
 
-	intr_status_reg = INTR_STATUS(denali->flash_bank);
+/* for Indexed Addressing */
+#define DENALI_INDEXED_CTRL	0x00
+#define DENALI_INDEXED_DATA	0x10
 
-	return readl(denali->flash_reg + intr_status_reg);
-}
+#define DENALI_MAP00		(0 << 26)	/* direct access to buffer */
+#define DENALI_MAP01		(1 << 26)	/* read/write pages in PIO */
+#define DENALI_MAP10		(2 << 26)	/* high-level control plane */
+#define DENALI_MAP11		(3 << 26)	/* direct controller access */
 
-static void clear_interrupts(struct denali_nand_info *denali)
-{
-	uint32_t status;
+/* MAP11 access cycle type */
+#define DENALI_MAP11_CMD	((DENALI_MAP11) | 0)	/* command cycle */
+#define DENALI_MAP11_ADDR	((DENALI_MAP11) | 1)	/* address cycle */
+#define DENALI_MAP11_DATA	((DENALI_MAP11) | 2)	/* data cycle */
 
-	status = read_interrupt_status(denali);
-	clear_interrupt(denali, status);
+/* MAP10 commands */
+#define DENALI_ERASE		0x01
 
-	denali->irq_status = 0;
-}
+#define DENALI_BANK(denali)	((denali)->active_bank << 24)
 
-static void denali_irq_enable(struct denali_nand_info *denali,
-							uint32_t int_mask)
-{
-	int i;
+#define DENALI_INVALID_BANK	-1
+#define DENALI_NR_BANKS		4
 
-	for (i = 0; i < denali->max_banks; ++i)
-		writel(int_mask, denali->flash_reg + INTR_EN(i));
-}
+/*
+ * The bus interface clock, clk_x, is phase aligned with the core clock.  The
+ * clk_x is an integral multiple N of the core clk.  The value N is configured
+ * at IP delivery time, and its available value is 4, 5, or 6.  We need to align
+ * to the largest value to make it work with any possible configuration.
+ */
+#define DENALI_CLK_X_MULT	6
 
-static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask)
+static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd)
 {
-	unsigned long timeout = 1000000;
-	uint32_t intr_status;
-
-	do {
-		intr_status = read_interrupt_status(denali) & DENALI_IRQ_ALL;
-		if (intr_status & irq_mask) {
-			denali->irq_status &= ~irq_mask;
-			/* our interrupt was detected */
-			break;
-		}
-		udelay(1);
-		timeout--;
-	} while (timeout != 0);
-
-	if (timeout == 0) {
-		/* timeout */
-		printf("Denali timeout with interrupt status %08x\n",
-		       read_interrupt_status(denali));
-		intr_status = 0;
-	}
-	return intr_status;
+	return container_of(mtd_to_nand(mtd), struct denali_nand_info, nand);
 }
 
 /*
- * Certain operations for the denali NAND controller use an indexed mode to
- * read/write data. The operation is performed by writing the address value
- * of the command to the device memory followed by the data. This function
- * abstracts this common operation.
+ * Direct Addressing - the slave address forms the control information (command
+ * type, bank, block, and page address).  The slave data is the actual data to
+ * be transferred.  This mode requires 28 bits of address region allocated.
  */
-static void index_addr(struct denali_nand_info *denali,
-				uint32_t address, uint32_t data)
+static u32 denali_direct_read(struct denali_nand_info *denali, u32 addr)
 {
-	writel(address, denali->flash_mem + INDEX_CTRL_REG);
-	writel(data, denali->flash_mem + INDEX_DATA_REG);
+	return ioread32(denali->host + addr);
 }
 
-/* Perform an indexed read of the device */
-static void index_addr_read_data(struct denali_nand_info *denali,
-				 uint32_t address, uint32_t *pdata)
+static void denali_direct_write(struct denali_nand_info *denali, u32 addr,
+				u32 data)
 {
-	writel(address, denali->flash_mem + INDEX_CTRL_REG);
-	*pdata = readl(denali->flash_mem + INDEX_DATA_REG);
+	iowrite32(data, denali->host + addr);
 }
 
 /*
- * We need to buffer some data for some of the NAND core routines.
- * The operations manage buffering that data.
+ * Indexed Addressing - address translation module intervenes in passing the
+ * control information.  This mode reduces the required address range.  The
+ * control information and transferred data are latched by the registers in
+ * the translation module.
  */
-static void reset_buf(struct denali_nand_info *denali)
+static u32 denali_indexed_read(struct denali_nand_info *denali, u32 addr)
 {
-	denali->buf.head = 0;
-	denali->buf.tail = 0;
+	iowrite32(addr, denali->host + DENALI_INDEXED_CTRL);
+	return ioread32(denali->host + DENALI_INDEXED_DATA);
 }
 
-static void write_byte_to_buf(struct denali_nand_info *denali, uint8_t byte)
+static void denali_indexed_write(struct denali_nand_info *denali, u32 addr,
+				 u32 data)
 {
-	denali->buf.buf[denali->buf.tail++] = byte;
+	iowrite32(addr, denali->host + DENALI_INDEXED_CTRL);
+	iowrite32(data, denali->host + DENALI_INDEXED_DATA);
 }
 
-/* resets a specific device connected to the core */
-static void reset_bank(struct denali_nand_info *denali)
+/*
+ * Use the configuration feature register to determine the maximum number of
+ * banks that the hardware supports.
+ */
+static void denali_detect_max_banks(struct denali_nand_info *denali)
 {
-	uint32_t irq_status;
-	uint32_t irq_mask = INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT;
-
-	clear_interrupts(denali);
+	uint32_t features = ioread32(denali->reg + FEATURES);
 
-	writel(1 << denali->flash_bank, denali->flash_reg + DEVICE_RESET);
+	denali->max_banks = 1 << FIELD_GET(FEATURES__N_BANKS, features);
 
-	irq_status = wait_for_irq(denali, irq_mask);
-	if (irq_status & INTR_STATUS__TIME_OUT)
-		debug("reset bank failed.\n");
+	/* the encoding changed from rev 5.0 to 5.1 */
+	if (denali->revision < 0x0501)
+		denali->max_banks <<= 1;
 }
 
-/* Reset the flash controller */
-static uint32_t denali_nand_reset(struct denali_nand_info *denali)
+static void __maybe_unused denali_enable_irq(struct denali_nand_info *denali)
 {
 	int i;
 
-	for (i = 0; i < denali->max_banks; i++)
-		writel(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT,
-		       denali->flash_reg + INTR_STATUS(i));
+	for (i = 0; i < DENALI_NR_BANKS; i++)
+		iowrite32(U32_MAX, denali->reg + INTR_EN(i));
+	iowrite32(GLOBAL_INT_EN_FLAG, denali->reg + GLOBAL_INT_ENABLE);
+}
 
-	for (i = 0; i < denali->max_banks; i++) {
-		writel(1 << i, denali->flash_reg + DEVICE_RESET);
-		while (!(readl(denali->flash_reg + INTR_STATUS(i)) &
-			(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT)))
-			if (readl(denali->flash_reg + INTR_STATUS(i)) &
-				INTR_STATUS__TIME_OUT)
-				debug("NAND Reset operation timed out on bank"
-				      " %d\n", i);
-	}
+static void __maybe_unused denali_disable_irq(struct denali_nand_info *denali)
+{
+	int i;
 
-	for (i = 0; i < denali->max_banks; i++)
-		writel(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT,
-		       denali->flash_reg + INTR_STATUS(i));
+	for (i = 0; i < DENALI_NR_BANKS; i++)
+		iowrite32(0, denali->reg + INTR_EN(i));
+	iowrite32(0, denali->reg + GLOBAL_INT_ENABLE);
+}
 
-	return 0;
+static void denali_clear_irq(struct denali_nand_info *denali,
+			     int bank, uint32_t irq_status)
+{
+	/* write one to clear bits */
+	iowrite32(irq_status, denali->reg + INTR_STATUS(bank));
 }
 
-/*
- * this routine calculates the ONFI timing values for a given mode and
- * programs the clocking register accordingly. The mode is determined by
- * the get_onfi_nand_para routine.
- */
-static void nand_onfi_timing_set(struct denali_nand_info *denali,
-								uint16_t mode)
+static void denali_clear_irq_all(struct denali_nand_info *denali)
 {
-	uint32_t trea[6] = {40, 30, 25, 20, 20, 16};
-	uint32_t trp[6] = {50, 25, 17, 15, 12, 10};
-	uint32_t treh[6] = {30, 15, 15, 10, 10, 7};
-	uint32_t trc[6] = {100, 50, 35, 30, 25, 20};
-	uint32_t trhoh[6] = {0, 15, 15, 15, 15, 15};
-	uint32_t trloh[6] = {0, 0, 0, 0, 5, 5};
-	uint32_t tcea[6] = {100, 45, 30, 25, 25, 25};
-	uint32_t tadl[6] = {200, 100, 100, 100, 70, 70};
-	uint32_t trhw[6] = {200, 100, 100, 100, 100, 100};
-	uint32_t trhz[6] = {200, 100, 100, 100, 100, 100};
-	uint32_t twhr[6] = {120, 80, 80, 60, 60, 60};
-	uint32_t tcs[6] = {70, 35, 25, 25, 20, 15};
-
-	uint32_t data_invalid_rhoh, data_invalid_rloh, data_invalid;
-	uint32_t dv_window = 0;
-	uint32_t en_lo, en_hi;
-	uint32_t acc_clks;
-	uint32_t addr_2_data, re_2_we, re_2_re, we_2_re, cs_cnt;
-
-	en_lo = DIV_ROUND_UP(trp[mode], CLK_X);
-	en_hi = DIV_ROUND_UP(treh[mode], CLK_X);
-	if ((en_hi * CLK_X) < (treh[mode] + 2))
-		en_hi++;
-
-	if ((en_lo + en_hi) * CLK_X < trc[mode])
-		en_lo += DIV_ROUND_UP((trc[mode] - (en_lo + en_hi) * CLK_X),
-				      CLK_X);
-
-	if ((en_lo + en_hi) < CLK_MULTI)
-		en_lo += CLK_MULTI - en_lo - en_hi;
-
-	while (dv_window < 8) {
-		data_invalid_rhoh = en_lo * CLK_X + trhoh[mode];
-
-		data_invalid_rloh = (en_lo + en_hi) * CLK_X + trloh[mode];
-
-		data_invalid = data_invalid_rhoh < data_invalid_rloh ?
-					data_invalid_rhoh : data_invalid_rloh;
-
-		dv_window = data_invalid - trea[mode];
-
-		if (dv_window < 8)
-			en_lo++;
-	}
+	int i;
 
-	acc_clks = DIV_ROUND_UP(trea[mode], CLK_X);
+	for (i = 0; i < DENALI_NR_BANKS; i++)
+		denali_clear_irq(denali, i, U32_MAX);
+}
 
-	while (acc_clks * CLK_X - trea[mode] < 3)
-		acc_clks++;
+static void __denali_check_irq(struct denali_nand_info *denali)
+{
+	uint32_t irq_status;
+	int i;
 
-	if (data_invalid - acc_clks * CLK_X < 2)
-		debug("%s, Line %d: Warning!\n", __FILE__, __LINE__);
+	for (i = 0; i < DENALI_NR_BANKS; i++) {
+		irq_status = ioread32(denali->reg + INTR_STATUS(i));
+		denali_clear_irq(denali, i, irq_status);
 
-	addr_2_data = DIV_ROUND_UP(tadl[mode], CLK_X);
-	re_2_we = DIV_ROUND_UP(trhw[mode], CLK_X);
-	re_2_re = DIV_ROUND_UP(trhz[mode], CLK_X);
-	we_2_re = DIV_ROUND_UP(twhr[mode], CLK_X);
-	cs_cnt = DIV_ROUND_UP((tcs[mode] - trp[mode]), CLK_X);
-	if (cs_cnt == 0)
-		cs_cnt = 1;
+		if (i != denali->active_bank)
+			continue;
 
-	if (tcea[mode]) {
-		while (cs_cnt * CLK_X + trea[mode] < tcea[mode])
-			cs_cnt++;
+		denali->irq_status |= irq_status;
 	}
+}
 
-	/* Sighting 3462430: Temporary hack for MT29F128G08CJABAWP:B */
-	if (readl(denali->flash_reg + MANUFACTURER_ID) == 0 &&
-	    readl(denali->flash_reg + DEVICE_ID) == 0x88)
-		acc_clks = 6;
-
-	writel(acc_clks, denali->flash_reg + ACC_CLKS);
-	writel(re_2_we, denali->flash_reg + RE_2_WE);
-	writel(re_2_re, denali->flash_reg + RE_2_RE);
-	writel(we_2_re, denali->flash_reg + WE_2_RE);
-	writel(addr_2_data, denali->flash_reg + ADDR_2_DATA);
-	writel(en_lo, denali->flash_reg + RDWR_EN_LO_CNT);
-	writel(en_hi, denali->flash_reg + RDWR_EN_HI_CNT);
-	writel(cs_cnt, denali->flash_reg + CS_SETUP_CNT);
+static void denali_reset_irq(struct denali_nand_info *denali)
+{
+	denali->irq_status = 0;
+	denali->irq_mask = 0;
 }
 
-/* queries the NAND device to see what ONFI modes it supports. */
-static uint32_t get_onfi_nand_para(struct denali_nand_info *denali)
+static uint32_t denali_wait_for_irq(struct denali_nand_info *denali,
+				    uint32_t irq_mask)
 {
-	int i;
+	unsigned long time_left = 1000000;
 
-	/*
-	 * we needn't to do a reset here because driver has already
-	 * reset all the banks before
-	 */
-	if (!(readl(denali->flash_reg + ONFI_TIMING_MODE) &
-	    ONFI_TIMING_MODE__VALUE))
-		return -EIO;
+	while (time_left) {
+		__denali_check_irq(denali);
 
-	for (i = 5; i > 0; i--) {
-		if (readl(denali->flash_reg + ONFI_TIMING_MODE) &
-			(0x01 << i))
-			break;
+		if (irq_mask & denali->irq_status)
+			return denali->irq_status;
+		udelay(1);
+		time_left--;
 	}
 
-	nand_onfi_timing_set(denali, i);
-
-	/*
-	 * By now, all the ONFI devices we know support the page cache
-	 * rw feature. So here we enable the pipeline_rw_ahead feature
-	 */
+	if (!time_left) {
+		dev_err(denali->dev, "timeout while waiting for irq 0x%x\n",
+			irq_mask);
+		return 0;
+	}
 
-	return 0;
+	return denali->irq_status;
 }
 
-static void get_samsung_nand_para(struct denali_nand_info *denali,
-							uint8_t device_id)
+static uint32_t denali_check_irq(struct denali_nand_info *denali)
 {
-	if (device_id == 0xd3) { /* Samsung K9WAG08U1A */
-		/* Set timing register values according to datasheet */
-		writel(5, denali->flash_reg + ACC_CLKS);
-		writel(20, denali->flash_reg + RE_2_WE);
-		writel(12, denali->flash_reg + WE_2_RE);
-		writel(14, denali->flash_reg + ADDR_2_DATA);
-		writel(3, denali->flash_reg + RDWR_EN_LO_CNT);
-		writel(2, denali->flash_reg + RDWR_EN_HI_CNT);
-		writel(2, denali->flash_reg + CS_SETUP_CNT);
-	}
+	__denali_check_irq(denali);
+
+	return denali->irq_status;
 }
 
-static void get_toshiba_nand_para(struct denali_nand_info *denali)
+static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
-	uint32_t tmp;
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
+	int i;
 
-	/*
-	 * Workaround to fix a controller bug which reports a wrong
-	 * spare area size for some kind of Toshiba NAND device
-	 */
-	if ((readl(denali->flash_reg + DEVICE_MAIN_AREA_SIZE) == 4096) &&
-	    (readl(denali->flash_reg + DEVICE_SPARE_AREA_SIZE) == 64)) {
-		writel(216, denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
-		tmp = readl(denali->flash_reg + DEVICES_CONNECTED) *
-			readl(denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
-		writel(tmp, denali->flash_reg + LOGICAL_PAGE_SPARE_SIZE);
-	}
+	for (i = 0; i < len; i++)
+		buf[i] = denali->host_read(denali, addr);
 }
 
-static void get_hynix_nand_para(struct denali_nand_info *denali,
-							uint8_t device_id)
+static void denali_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
-	uint32_t main_size, spare_size;
-
-	switch (device_id) {
-	case 0xD5: /* Hynix H27UAG8T2A, H27UBG8U5A or H27UCG8VFA */
-	case 0xD7: /* Hynix H27UDG8VEM, H27UCG8UDM or H27UCG8V5A */
-		writel(128, denali->flash_reg + PAGES_PER_BLOCK);
-		writel(4096, denali->flash_reg + DEVICE_MAIN_AREA_SIZE);
-		writel(224, denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
-		main_size = 4096 *
-			readl(denali->flash_reg + DEVICES_CONNECTED);
-		spare_size = 224 *
-			readl(denali->flash_reg + DEVICES_CONNECTED);
-		writel(main_size, denali->flash_reg + LOGICAL_PAGE_DATA_SIZE);
-		writel(spare_size, denali->flash_reg + LOGICAL_PAGE_SPARE_SIZE);
-		writel(0, denali->flash_reg + DEVICE_WIDTH);
-		break;
-	default:
-		debug("Spectra: Unknown Hynix NAND (Device ID: 0x%x).\n"
-		      "Will use default parameter values instead.\n",
-		      device_id);
-	}
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
+	int i;
+
+	for (i = 0; i < len; i++)
+		denali->host_write(denali, addr, buf[i]);
 }
 
-/*
- * determines how many NAND chips are connected to the controller. Note for
- * Intel CE4100 devices we don't support more than one device.
- */
-static void find_valid_banks(struct denali_nand_info *denali)
+static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
 {
-	uint32_t id[denali->max_banks];
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
+	uint16_t *buf16 = (uint16_t *)buf;
 	int i;
 
-	denali->total_used_banks = 1;
-	for (i = 0; i < denali->max_banks; i++) {
-		index_addr(denali, MODE_11 | (i << 24) | 0, 0x90);
-		index_addr(denali, MODE_11 | (i << 24) | 1, 0);
-		index_addr_read_data(denali, MODE_11 | (i << 24) | 2, &id[i]);
+	for (i = 0; i < len / 2; i++)
+		buf16[i] = denali->host_read(denali, addr);
+}
 
-		if (i == 0) {
-			if (!(id[i] & 0x0ff))
-				break;
-		} else {
-			if ((id[i] & 0x0ff) == (id[0] & 0x0ff))
-				denali->total_used_banks++;
-			else
-				break;
-		}
-	}
+static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf,
+			       int len)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali);
+	const uint16_t *buf16 = (const uint16_t *)buf;
+	int i;
+
+	for (i = 0; i < len / 2; i++)
+		denali->host_write(denali, addr, buf16[i]);
 }
 
-/*
- * Use the configuration feature register to determine the maximum number of
- * banks that the hardware supports.
- */
-static void detect_max_banks(struct denali_nand_info *denali)
+static uint8_t denali_read_byte(struct mtd_info *mtd)
 {
-	uint32_t features = ioread32(denali->flash_reg + FEATURES);
+	uint8_t byte;
 
-	denali->max_banks = 1 << (features & FEATURES__N_BANKS);
+	denali_read_buf(mtd, &byte, 1);
 
-	/* the encoding changed from rev 5.0 to 5.1 */
-	if (denali->revision < 0x0501)
-		denali->max_banks <<= 1;
+	return byte;
 }
 
-static void detect_partition_feature(struct denali_nand_info *denali)
+static void denali_write_byte(struct mtd_info *mtd, uint8_t byte)
 {
-	/*
-	 * For MRST platform, denali->fwblks represent the
-	 * number of blocks firmware is taken,
-	 * FW is in protect partition and MTD driver has no
-	 * permission to access it. So let driver know how many
-	 * blocks it can't touch.
-	 */
-	if (readl(denali->flash_reg + FEATURES) & FEATURES__PARTITION) {
-		if ((readl(denali->flash_reg + PERM_SRC_ID(1)) &
-			PERM_SRC_ID__SRCID) == SPECTRA_PARTITION_ID) {
-			denali->fwblks =
-			    ((readl(denali->flash_reg + MIN_MAX_BANK(1)) &
-			      MIN_MAX_BANK__MIN_VALUE) *
-			     denali->blksperchip)
-			    +
-			    (readl(denali->flash_reg + MIN_BLK_ADDR(1)) &
-			    MIN_BLK_ADDR__VALUE);
-		} else {
-			denali->fwblks = SPECTRA_START_BLOCK;
-		}
-	} else {
-		denali->fwblks = SPECTRA_START_BLOCK;
-	}
+	denali_write_buf(mtd, &byte, 1);
 }
 
-static uint32_t denali_nand_timing_set(struct denali_nand_info *denali)
+static uint16_t denali_read_word(struct mtd_info *mtd)
 {
-	uint32_t id_bytes[8], addr;
-	uint8_t maf_id, device_id;
-	int i;
+	uint16_t word;
 
-	/*
-	 * Use read id method to get device ID and other params.
-	 * For some NAND chips, controller can't report the correct
-	 * device ID by reading from DEVICE_ID register
-	 */
-	addr = MODE_11 | BANK(denali->flash_bank);
-	index_addr(denali, addr | 0, 0x90);
-	index_addr(denali, addr | 1, 0);
-	for (i = 0; i < 8; i++)
-		index_addr_read_data(denali, addr | 2, &id_bytes[i]);
-	maf_id = id_bytes[0];
-	device_id = id_bytes[1];
-
-	if (readl(denali->flash_reg + ONFI_DEVICE_NO_OF_LUNS) &
-		ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE) { /* ONFI 1.0 NAND */
-		if (get_onfi_nand_para(denali))
-			return -EIO;
-	} else if (maf_id == 0xEC) { /* Samsung NAND */
-		get_samsung_nand_para(denali, device_id);
-	} else if (maf_id == 0x98) { /* Toshiba NAND */
-		get_toshiba_nand_para(denali);
-	} else if (maf_id == 0xAD) { /* Hynix NAND */
-		get_hynix_nand_para(denali, device_id);
-	}
+	denali_read_buf16(mtd, (uint8_t *)&word, 2);
 
-	find_valid_banks(denali);
+	return word;
+}
 
-	detect_partition_feature(denali);
+static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	uint32_t type;
+
+	if (ctrl & NAND_CLE)
+		type = DENALI_MAP11_CMD;
+	else if (ctrl & NAND_ALE)
+		type = DENALI_MAP11_ADDR;
+	else
+		return;
 
 	/*
-	 * If the user specified to override the default timings
-	 * with a specific ONFI mode, we apply those changes here.
+	 * Some commands are followed by chip->dev_ready or chip->waitfunc.
+	 * irq_status must be cleared here to catch the R/B# interrupt later.
 	 */
-	if (onfi_timing_mode != NAND_DEFAULT_TIMINGS)
-		nand_onfi_timing_set(denali, onfi_timing_mode);
+	if (ctrl & NAND_CTRL_CHANGE)
+		denali_reset_irq(denali);
 
-	return 0;
+	denali->host_write(denali, DENALI_BANK(denali) | type, dat);
 }
 
-/*
- * validation function to verify that the controlling software is making
- * a valid request
- */
-static inline bool is_flash_bank_valid(int flash_bank)
-{
-	return flash_bank >= 0 && flash_bank < 4;
-}
-
-static void denali_irq_init(struct denali_nand_info *denali)
+static int denali_dev_ready(struct mtd_info *mtd)
 {
-	uint32_t int_mask;
-	int i;
-
-	/* Disable global interrupts */
-	writel(0, denali->flash_reg + GLOBAL_INT_ENABLE);
-
-	int_mask = DENALI_IRQ_ALL;
-
-	/* Clear all status bits */
-	for (i = 0; i < denali->max_banks; ++i)
-		writel(0xFFFF, denali->flash_reg + INTR_STATUS(i));
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
 
-	denali_irq_enable(denali, int_mask);
+	return !!(denali_check_irq(denali) & INTR__INT_ACT);
 }
 
-/*
- * This helper function setups the registers for ECC and whether or not
- * the spare area will be transferred.
- */
-static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en,
-				bool transfer_spare)
+static int denali_check_erased_page(struct mtd_info *mtd,
+				    struct nand_chip *chip, uint8_t *buf,
+				    unsigned long uncor_ecc_flags,
+				    unsigned int max_bitflips)
 {
-	int ecc_en_flag, transfer_spare_flag;
+	uint8_t *ecc_code = chip->buffers->ecccode;
+	int ecc_steps = chip->ecc.steps;
+	int ecc_size = chip->ecc.size;
+	int ecc_bytes = chip->ecc.bytes;
+	int i, ret, stat;
+
+	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
+					 chip->ecc.total);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < ecc_steps; i++) {
+		if (!(uncor_ecc_flags & BIT(i)))
+			continue;
+
+		stat = nand_check_erased_ecc_chunk(buf, ecc_size,
+						  ecc_code, ecc_bytes,
+						  NULL, 0,
+						  chip->ecc.strength);
+		if (stat < 0) {
+			mtd->ecc_stats.failed++;
+		} else {
+			mtd->ecc_stats.corrected += stat;
+			max_bitflips = max_t(unsigned int, max_bitflips, stat);
+		}
 
-	/* set ECC, transfer spare bits if needed */
-	ecc_en_flag = ecc_en ? ECC_ENABLE__FLAG : 0;
-	transfer_spare_flag = transfer_spare ? TRANSFER_SPARE_REG__FLAG : 0;
+		buf += ecc_size;
+		ecc_code += ecc_bytes;
+	}
 
-	/* Enable spare area/ECC per user's request. */
-	writel(ecc_en_flag, denali->flash_reg + ECC_ENABLE);
-	/* applicable for MAP01 only */
-	writel(transfer_spare_flag, denali->flash_reg + TRANSFER_SPARE_REG);
+	return max_bitflips;
 }
 
-/*
- * sends a pipeline command operation to the controller. See the Denali NAND
- * controller's user guide for more information (section 4.2.3.6).
- */
-static int denali_send_pipeline_cmd(struct denali_nand_info *denali,
-				    bool ecc_en, bool transfer_spare,
-				    int access_type, int op)
+static int denali_hw_ecc_fixup(struct mtd_info *mtd,
+			       struct denali_nand_info *denali,
+			       unsigned long *uncor_ecc_flags)
 {
-	uint32_t addr, cmd, irq_status;
-	static uint32_t page_count = 1;
-
-	setup_ecc_for_xfer(denali, ecc_en, transfer_spare);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	int bank = denali->active_bank;
+	uint32_t ecc_cor;
+	unsigned int max_bitflips;
 
-	clear_interrupts(denali);
+	ecc_cor = ioread32(denali->reg + ECC_COR_INFO(bank));
+	ecc_cor >>= ECC_COR_INFO__SHIFT(bank);
 
-	addr = BANK(denali->flash_bank) | denali->page;
+	if (ecc_cor & ECC_COR_INFO__UNCOR_ERR) {
+		/*
+		 * This flag is set when uncorrectable error occurs at least in
+		 * one ECC sector.  We can not know "how many sectors", or
+		 * "which sector(s)".  We need erase-page check for all sectors.
+		 */
+		*uncor_ecc_flags = GENMASK(chip->ecc.steps - 1, 0);
+		return 0;
+	}
 
-	/* setup the acccess type */
-	cmd = MODE_10 | addr;
-	index_addr(denali, cmd, access_type);
+	max_bitflips = FIELD_GET(ECC_COR_INFO__MAX_ERRORS, ecc_cor);
 
-	/* setup the pipeline command */
-	index_addr(denali, cmd, 0x2000 | op | page_count);
+	/*
+	 * The register holds the maximum of per-sector corrected bitflips.
+	 * This is suitable for the return value of the ->read_page() callback.
+	 * Unfortunately, we can not know the total number of corrected bits in
+	 * the page.  Increase the stats by max_bitflips. (compromised solution)
+	 */
+	mtd->ecc_stats.corrected += max_bitflips;
 
-	cmd = MODE_01 | addr;
-	writel(cmd, denali->flash_mem + INDEX_CTRL_REG);
+	return max_bitflips;
+}
 
-	if (op == DENALI_READ) {
-		/* wait for command to be accepted */
-		irq_status = wait_for_irq(denali, INTR_STATUS__LOAD_COMP);
+static int denali_sw_ecc_fixup(struct mtd_info *mtd,
+			       struct denali_nand_info *denali,
+			       unsigned long *uncor_ecc_flags, uint8_t *buf)
+{
+	unsigned int ecc_size = denali->nand.ecc.size;
+	unsigned int bitflips = 0;
+	unsigned int max_bitflips = 0;
+	uint32_t err_addr, err_cor_info;
+	unsigned int err_byte, err_sector, err_device;
+	uint8_t err_cor_value;
+	unsigned int prev_sector = 0;
+	uint32_t irq_status;
 
-		if (irq_status == 0)
-			return -EIO;
-	}
+	denali_reset_irq(denali);
 
-	return 0;
-}
+	do {
+		err_addr = ioread32(denali->reg + ECC_ERROR_ADDRESS);
+		err_sector = FIELD_GET(ECC_ERROR_ADDRESS__SECTOR, err_addr);
+		err_byte = FIELD_GET(ECC_ERROR_ADDRESS__OFFSET, err_addr);
+
+		err_cor_info = ioread32(denali->reg + ERR_CORRECTION_INFO);
+		err_cor_value = FIELD_GET(ERR_CORRECTION_INFO__BYTE,
+					  err_cor_info);
+		err_device = FIELD_GET(ERR_CORRECTION_INFO__DEVICE,
+				       err_cor_info);
+
+		/* reset the bitflip counter when crossing ECC sector */
+		if (err_sector != prev_sector)
+			bitflips = 0;
+
+		if (err_cor_info & ERR_CORRECTION_INFO__UNCOR) {
+			/*
+			 * Check later if this is a real ECC error, or
+			 * an erased sector.
+			 */
+			*uncor_ecc_flags |= BIT(err_sector);
+		} else if (err_byte < ecc_size) {
+			/*
+			 * If err_byte is larger than ecc_size, means error
+			 * happened in OOB, so we ignore it. It's no need for
+			 * us to correct it err_device is represented the NAND
+			 * error bits are happened in if there are more than
+			 * one NAND connected.
+			 */
+			int offset;
+			unsigned int flips_in_byte;
+
+			offset = (err_sector * ecc_size + err_byte) *
+					denali->devs_per_cs + err_device;
+
+			/* correct the ECC error */
+			flips_in_byte = hweight8(buf[offset] ^ err_cor_value);
+			buf[offset] ^= err_cor_value;
+			mtd->ecc_stats.corrected += flips_in_byte;
+			bitflips += flips_in_byte;
+
+			max_bitflips = max(max_bitflips, bitflips);
+		}
 
-/* helper function that simply writes a buffer to the flash */
-static int write_data_to_flash_mem(struct denali_nand_info *denali,
-				   const uint8_t *buf, int len)
-{
-	uint32_t *buf32;
-	int i;
+		prev_sector = err_sector;
+	} while (!(err_cor_info & ERR_CORRECTION_INFO__LAST_ERR));
 
 	/*
-	 * verify that the len is a multiple of 4.
-	 * see comment in read_data_from_flash_mem()
+	 * Once handle all ECC errors, controller will trigger an
+	 * ECC_TRANSACTION_DONE interrupt.
 	 */
-	BUG_ON((len % 4) != 0);
+	irq_status = denali_wait_for_irq(denali, INTR__ECC_TRANSACTION_DONE);
+	if (!(irq_status & INTR__ECC_TRANSACTION_DONE))
+		return -EIO;
 
-	/* write the data to the flash memory */
-	buf32 = (uint32_t *)buf;
-	for (i = 0; i < len / 4; i++)
-		writel(*buf32++, denali->flash_mem + INDEX_DATA_REG);
-	return i * 4; /* intent is to return the number of bytes read */
+	return max_bitflips;
 }
 
-/* helper function that simply reads a buffer from the flash */
-static int read_data_from_flash_mem(struct denali_nand_info *denali,
-				    uint8_t *buf, int len)
+static void denali_setup_dma64(struct denali_nand_info *denali,
+			       dma_addr_t dma_addr, int page, int write)
 {
-	uint32_t *buf32;
-	int i;
+	uint32_t mode;
+	const int page_count = 1;
 
-	/*
-	 * we assume that len will be a multiple of 4, if not it would be nice
-	 * to know about it ASAP rather than have random failures...
-	 * This assumption is based on the fact that this function is designed
-	 * to be used to read flash pages, which are typically multiples of 4.
-	 */
-	BUG_ON((len % 4) != 0);
+	mode = DENALI_MAP10 | DENALI_BANK(denali) | page;
 
-	/* transfer the data from the flash */
-	buf32 = (uint32_t *)buf;
-	for (i = 0; i < len / 4; i++)
-		*buf32++ = readl(denali->flash_mem + INDEX_DATA_REG);
+	/* DMA is a three step process */
 
-	return i * 4; /* intent is to return the number of bytes read */
-}
+	/*
+	 * 1. setup transfer type, interrupt when complete,
+	 *    burst len = 64 bytes, the number of pages
+	 */
+	denali->host_write(denali, mode,
+			   0x01002000 | (64 << 16) | (write << 8) | page_count);
 
-static void denali_mode_main_access(struct denali_nand_info *denali)
-{
-	uint32_t addr, cmd;
+	/* 2. set memory low address */
+	denali->host_write(denali, mode, lower_32_bits(dma_addr));
 
-	addr = BANK(denali->flash_bank) | denali->page;
-	cmd = MODE_10 | addr;
-	index_addr(denali, cmd, MAIN_ACCESS);
+	/* 3. set memory high address */
+	denali->host_write(denali, mode, upper_32_bits(dma_addr));
 }
 
-static void denali_mode_main_spare_access(struct denali_nand_info *denali)
+static void denali_setup_dma32(struct denali_nand_info *denali,
+			       dma_addr_t dma_addr, int page, int write)
 {
-	uint32_t addr, cmd;
+	uint32_t mode;
+	const int page_count = 1;
 
-	addr = BANK(denali->flash_bank) | denali->page;
-	cmd = MODE_10 | addr;
-	index_addr(denali, cmd, MAIN_SPARE_ACCESS);
-}
+	mode = DENALI_MAP10 | DENALI_BANK(denali);
 
-/* writes OOB data to the device */
-static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
-{
-	struct denali_nand_info *denali = mtd_to_denali(mtd);
-	uint32_t irq_status;
-	uint32_t irq_mask = INTR_STATUS__PROGRAM_COMP |
-						INTR_STATUS__PROGRAM_FAIL;
-	int status = 0;
+	/* DMA is a four step process */
 
-	denali->page = page;
+	/* 1. setup transfer type and # of pages */
+	denali->host_write(denali, mode | page,
+			   0x2000 | (write << 8) | page_count);
 
-	if (denali_send_pipeline_cmd(denali, false, true, SPARE_ACCESS,
-				     DENALI_WRITE) == 0) {
-		write_data_to_flash_mem(denali, buf, mtd->oobsize);
+	/* 2. set memory high address bits 23:8 */
+	denali->host_write(denali, mode | ((dma_addr >> 16) << 8), 0x2200);
 
-		/* wait for operation to complete */
-		irq_status = wait_for_irq(denali, irq_mask);
+	/* 3. set memory low address bits 23:8 */
+	denali->host_write(denali, mode | ((dma_addr & 0xffff) << 8), 0x2300);
 
-		if (irq_status == 0) {
-			dev_err(denali->dev, "OOB write failed\n");
-			status = -EIO;
-		}
-	} else {
-		printf("unable to send pipeline command\n");
-		status = -EIO;
-	}
-	return status;
+	/* 4. interrupt when complete, burst len = 64 bytes */
+	denali->host_write(denali, mode | 0x14000, 0x2400);
 }
 
-/* reads OOB data from the device */
-static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
+static int denali_pio_read(struct denali_nand_info *denali, void *buf,
+			   size_t size, int page, int raw)
 {
-	struct denali_nand_info *denali = mtd_to_denali(mtd);
-	uint32_t irq_mask = INTR_STATUS__LOAD_COMP;
-	uint32_t irq_status, addr, cmd;
+	u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page;
+	uint32_t *buf32 = (uint32_t *)buf;
+	uint32_t irq_status, ecc_err_mask;
+	int i;
 
-	denali->page = page;
+	if (denali->caps & DENALI_CAP_HW_ECC_FIXUP)
+		ecc_err_mask = INTR__ECC_UNCOR_ERR;
+	else
+		ecc_err_mask = INTR__ECC_ERR;
 
-	if (denali_send_pipeline_cmd(denali, false, true, SPARE_ACCESS,
-				     DENALI_READ) == 0) {
-		read_data_from_flash_mem(denali, buf, mtd->oobsize);
+	denali_reset_irq(denali);
 
-		/*
-		 * wait for command to be accepted
-		 * can always use status0 bit as the
-		 * mask is identical for each bank.
-		 */
-		irq_status = wait_for_irq(denali, irq_mask);
+	for (i = 0; i < size / 4; i++)
+		*buf32++ = denali->host_read(denali, addr);
 
-		if (irq_status == 0)
-			printf("page on OOB timeout %d\n", denali->page);
+	irq_status = denali_wait_for_irq(denali, INTR__PAGE_XFER_INC);
+	if (!(irq_status & INTR__PAGE_XFER_INC))
+		return -EIO;
 
-		/*
-		 * We set the device back to MAIN_ACCESS here as I observed
-		 * instability with the controller if you do a block erase
-		 * and the last transaction was a SPARE_ACCESS. Block erase
-		 * is reliable (according to the MTD test infrastructure)
-		 * if you are in MAIN_ACCESS.
-		 */
-		addr = BANK(denali->flash_bank) | denali->page;
-		cmd = MODE_10 | addr;
-		index_addr(denali, cmd, MAIN_ACCESS);
-	}
+	if (irq_status & INTR__ERASED_PAGE)
+		memset(buf, 0xff, size);
+
+	return irq_status & ecc_err_mask ? -EBADMSG : 0;
 }
 
-/*
- * this function examines buffers to see if they contain data that
- * indicate that the buffer is part of an erased region of flash.
- */
-static bool is_erased(uint8_t *buf, int len)
+static int denali_pio_write(struct denali_nand_info *denali,
+			    const void *buf, size_t size, int page, int raw)
 {
+	u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page;
+	const uint32_t *buf32 = (uint32_t *)buf;
+	uint32_t irq_status;
 	int i;
 
-	for (i = 0; i < len; i++)
-		if (buf[i] != 0xFF)
-			return false;
-	return true;
+	denali_reset_irq(denali);
+
+	for (i = 0; i < size / 4; i++)
+		denali->host_write(denali, addr, *buf32++);
+
+	irq_status = denali_wait_for_irq(denali,
+				INTR__PROGRAM_COMP | INTR__PROGRAM_FAIL);
+	if (!(irq_status & INTR__PROGRAM_COMP))
+		return -EIO;
+
+	return 0;
 }
 
-/* programs the controller to either enable/disable DMA transfers */
-static void denali_enable_dma(struct denali_nand_info *denali, bool en)
+static int denali_pio_xfer(struct denali_nand_info *denali, void *buf,
+			   size_t size, int page, int raw, int write)
 {
-	writel(en ? DMA_ENABLE__FLAG : 0, denali->flash_reg + DMA_ENABLE);
-	readl(denali->flash_reg + DMA_ENABLE);
+	if (write)
+		return denali_pio_write(denali, buf, size, page, raw);
+	else
+		return denali_pio_read(denali, buf, size, page, raw);
 }
 
-/* setups the HW to perform the data DMA */
-static void denali_setup_dma(struct denali_nand_info *denali, int op)
+static int denali_dma_xfer(struct denali_nand_info *denali, void *buf,
+			   size_t size, int page, int raw, int write)
 {
-	uint32_t mode;
-	const int page_count = 1;
-	uint64_t addr = (unsigned long)denali->buf.dma_buf;
-
-	flush_dcache_range(addr, addr + sizeof(denali->buf.dma_buf));
-
-/* For Denali controller that is 64 bit bus IP core */
-#ifdef CONFIG_SYS_NAND_DENALI_64BIT
-	mode = MODE_10 | BANK(denali->flash_bank) | denali->page;
-
-	/* DMA is a three step process */
+	dma_addr_t dma_addr;
+	uint32_t irq_mask, irq_status, ecc_err_mask;
+	enum dma_data_direction dir = write ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+	int ret = 0;
+
+	dma_addr = dma_map_single(denali->dev, buf, size, dir);
+	if (dma_mapping_error(denali->dev, dma_addr)) {
+		dev_dbg(denali->dev, "Failed to DMA-map buffer. Trying PIO.\n");
+		return denali_pio_xfer(denali, buf, size, page, raw, write);
+	}
 
-	/* 1. setup transfer type, interrupt when complete,
-	      burst len = 64 bytes, the number of pages */
-	index_addr(denali, mode, 0x01002000 | (64 << 16) | op | page_count);
+	if (write) {
+		/*
+		 * INTR__PROGRAM_COMP is never asserted for the DMA transfer.
+		 * We can use INTR__DMA_CMD_COMP instead.  This flag is asserted
+		 * when the page program is completed.
+		 */
+		irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL;
+		ecc_err_mask = 0;
+	} else if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) {
+		irq_mask = INTR__DMA_CMD_COMP;
+		ecc_err_mask = INTR__ECC_UNCOR_ERR;
+	} else {
+		irq_mask = INTR__DMA_CMD_COMP;
+		ecc_err_mask = INTR__ECC_ERR;
+	}
 
-	/* 2. set memory low address bits 31:0 */
-	index_addr(denali, mode, addr);
+	iowrite32(DMA_ENABLE__FLAG, denali->reg + DMA_ENABLE);
 
-	/* 3. set memory high address bits 64:32 */
-	index_addr(denali, mode, addr >> 32);
-#else
-	mode = MODE_10 | BANK(denali->flash_bank);
+	denali_reset_irq(denali);
+	denali->setup_dma(denali, dma_addr, page, write);
 
-	/* DMA is a four step process */
+	irq_status = denali_wait_for_irq(denali, irq_mask);
+	if (!(irq_status & INTR__DMA_CMD_COMP))
+		ret = -EIO;
+	else if (irq_status & ecc_err_mask)
+		ret = -EBADMSG;
 
-	/* 1. setup transfer type and # of pages */
-	index_addr(denali, mode | denali->page, 0x2000 | op | page_count);
+	iowrite32(0, denali->reg + DMA_ENABLE);
 
-	/* 2. set memory high address bits 23:8 */
-	index_addr(denali, mode | (((addr >> 16) & 0xffff) << 8), 0x2200);
+	dma_unmap_single(denali->dev, dma_addr, size, dir);
 
-	/* 3. set memory low address bits 23:8 */
-	index_addr(denali, mode | ((addr & 0xffff) << 8), 0x2300);
+	if (irq_status & INTR__ERASED_PAGE)
+		memset(buf, 0xff, size);
 
-	/* 4. interrupt when complete, burst len = 64 bytes */
-	index_addr(denali, mode | 0x14000, 0x2400);
-#endif
+	return ret;
 }
 
-/* Common DMA function */
-static uint32_t denali_dma_configuration(struct denali_nand_info *denali,
-					 uint32_t ops, bool raw_xfer,
-					 uint32_t irq_mask, int oob_required)
+static int denali_data_xfer(struct denali_nand_info *denali, void *buf,
+			    size_t size, int page, int raw, int write)
 {
-	uint32_t irq_status = 0;
-	/* setup_ecc_for_xfer(bool ecc_en, bool transfer_spare) */
-	setup_ecc_for_xfer(denali, !raw_xfer, oob_required);
-
-	/* clear any previous interrupt flags */
-	clear_interrupts(denali);
-
-	/* enable the DMA */
-	denali_enable_dma(denali, true);
-
-	/* setup the DMA */
-	denali_setup_dma(denali, ops);
-
-	/* wait for operation to complete */
-	irq_status = wait_for_irq(denali, irq_mask);
+	iowrite32(raw ? 0 : ECC_ENABLE__FLAG, denali->reg + ECC_ENABLE);
+	iowrite32(raw ? TRANSFER_SPARE_REG__FLAG : 0,
+		  denali->reg + TRANSFER_SPARE_REG);
 
-	/* if ECC fault happen, seems we need delay before turning off DMA.
-	 * If not, the controller will go into non responsive condition */
-	if (irq_status & INTR_STATUS__ECC_UNCOR_ERR)
-		udelay(100);
-
-	/* disable the DMA */
-	denali_enable_dma(denali, false);
-
-	return irq_status;
+	if (denali->dma_avail)
+		return denali_dma_xfer(denali, buf, size, page, raw, write);
+	else
+		return denali_pio_xfer(denali, buf, size, page, raw, write);
 }
 
-static int write_page(struct mtd_info *mtd, struct nand_chip *chip,
-			const uint8_t *buf, bool raw_xfer, int oob_required)
+static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip,
+			    int page, int write)
 {
 	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	unsigned int start_cmd = write ? NAND_CMD_SEQIN : NAND_CMD_READ0;
+	unsigned int rnd_cmd = write ? NAND_CMD_RNDIN : NAND_CMD_RNDOUT;
+	int writesize = mtd->writesize;
+	int oobsize = mtd->oobsize;
+	uint8_t *bufpoi = chip->oob_poi;
+	int ecc_steps = chip->ecc.steps;
+	int ecc_size = chip->ecc.size;
+	int ecc_bytes = chip->ecc.bytes;
+	int oob_skip = denali->oob_skip_bytes;
+	size_t size = writesize + oobsize;
+	int i, pos, len;
+
+	/* BBM at the beginning of the OOB area */
+	chip->cmdfunc(mtd, start_cmd, writesize, page);
+	if (write)
+		chip->write_buf(mtd, bufpoi, oob_skip);
+	else
+		chip->read_buf(mtd, bufpoi, oob_skip);
+	bufpoi += oob_skip;
+
+	/* OOB ECC */
+	for (i = 0; i < ecc_steps; i++) {
+		pos = ecc_size + i * (ecc_size + ecc_bytes);
+		len = ecc_bytes;
+
+		if (pos >= writesize)
+			pos += oob_skip;
+		else if (pos + len > writesize)
+			len = writesize - pos;
+
+		chip->cmdfunc(mtd, rnd_cmd, pos, -1);
+		if (write)
+			chip->write_buf(mtd, bufpoi, len);
+		else
+			chip->read_buf(mtd, bufpoi, len);
+		bufpoi += len;
+		if (len < ecc_bytes) {
+			len = ecc_bytes - len;
+			chip->cmdfunc(mtd, rnd_cmd, writesize + oob_skip, -1);
+			if (write)
+				chip->write_buf(mtd, bufpoi, len);
+			else
+				chip->read_buf(mtd, bufpoi, len);
+			bufpoi += len;
+		}
+	}
 
-	uint32_t irq_status = 0;
-	uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP;
-
-	denali->status = 0;
-
-	/* copy buffer into DMA buffer */
-	memcpy(denali->buf.dma_buf, buf, mtd->writesize);
+	/* OOB free */
+	len = oobsize - (bufpoi - chip->oob_poi);
+	chip->cmdfunc(mtd, rnd_cmd, size - len, -1);
+	if (write)
+		chip->write_buf(mtd, bufpoi, len);
+	else
+		chip->read_buf(mtd, bufpoi, len);
+}
 
-	/* need extra memcpy for raw transfer */
-	if (raw_xfer)
-		memcpy(denali->buf.dma_buf + mtd->writesize,
-		       chip->oob_poi, mtd->oobsize);
+static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+				uint8_t *buf, int oob_required, int page)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	int writesize = mtd->writesize;
+	int oobsize = mtd->oobsize;
+	int ecc_steps = chip->ecc.steps;
+	int ecc_size = chip->ecc.size;
+	int ecc_bytes = chip->ecc.bytes;
+	void *tmp_buf = denali->buf;
+	int oob_skip = denali->oob_skip_bytes;
+	size_t size = writesize + oobsize;
+	int ret, i, pos, len;
+
+	ret = denali_data_xfer(denali, tmp_buf, size, page, 1, 0);
+	if (ret)
+		return ret;
+
+	/* Arrange the buffer for syndrome payload/ecc layout */
+	if (buf) {
+		for (i = 0; i < ecc_steps; i++) {
+			pos = i * (ecc_size + ecc_bytes);
+			len = ecc_size;
+
+			if (pos >= writesize)
+				pos += oob_skip;
+			else if (pos + len > writesize)
+				len = writesize - pos;
+
+			memcpy(buf, tmp_buf + pos, len);
+			buf += len;
+			if (len < ecc_size) {
+				len = ecc_size - len;
+				memcpy(buf, tmp_buf + writesize + oob_skip,
+				       len);
+				buf += len;
+			}
+		}
+	}
 
-	/* setting up DMA */
-	irq_status = denali_dma_configuration(denali, DENALI_WRITE, raw_xfer,
-					      irq_mask, oob_required);
+	if (oob_required) {
+		uint8_t *oob = chip->oob_poi;
+
+		/* BBM at the beginning of the OOB area */
+		memcpy(oob, tmp_buf + writesize, oob_skip);
+		oob += oob_skip;
+
+		/* OOB ECC */
+		for (i = 0; i < ecc_steps; i++) {
+			pos = ecc_size + i * (ecc_size + ecc_bytes);
+			len = ecc_bytes;
+
+			if (pos >= writesize)
+				pos += oob_skip;
+			else if (pos + len > writesize)
+				len = writesize - pos;
+
+			memcpy(oob, tmp_buf + pos, len);
+			oob += len;
+			if (len < ecc_bytes) {
+				len = ecc_bytes - len;
+				memcpy(oob, tmp_buf + writesize + oob_skip,
+				       len);
+				oob += len;
+			}
+		}
 
-	/* if timeout happen, error out */
-	if (!(irq_status & INTR_STATUS__DMA_CMD_COMP)) {
-		debug("DMA timeout for denali write_page\n");
-		denali->status = NAND_STATUS_FAIL;
-		return -EIO;
+		/* OOB free */
+		len = oobsize - (oob - chip->oob_poi);
+		memcpy(oob, tmp_buf + size - len, len);
 	}
 
-	if (irq_status & INTR_STATUS__LOCKED_BLK) {
-		debug("Failed as write to locked block\n");
-		denali->status = NAND_STATUS_FAIL;
-		return -EIO;
-	}
 	return 0;
 }
 
-/* NAND core entry points */
-
-/*
- * this is the callback that the NAND core calls to write a page. Since
- * writing a page with ECC or without is similar, all the work is done
- * by write_page above.
- */
-static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-				const uint8_t *buf, int oob_required, int page)
+static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+			   int page)
 {
-	struct denali_nand_info *denali = mtd_to_denali(mtd);
-
-	/*
-	 * for regular page writes, we let HW handle all the ECC
-	 * data written to the device.
-	 */
-	if (oob_required)
-		/* switch to main + spare access */
-		denali_mode_main_spare_access(denali);
-	else
-		/* switch to main access only */
-		denali_mode_main_access(denali);
+	denali_oob_xfer(mtd, chip, page, 0);
 
-	return write_page(mtd, chip, buf, false, oob_required);
+	return 0;
 }
 
-/*
- * This is the callback that the NAND core calls to write a page without ECC.
- * raw access is similar to ECC page writes, so all the work is done in the
- * write_page() function above.
- */
-static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-				 const uint8_t *buf, int oob_required,
-				 int page)
+static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+			    int page)
 {
 	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	int status;
 
-	/*
-	 * for raw page writes, we want to disable ECC and simply write
-	 * whatever data is in the buffer.
-	 */
+	denali_reset_irq(denali);
 
-	if (oob_required)
-		/* switch to main + spare access */
-		denali_mode_main_spare_access(denali);
-	else
-		/* switch to main access only */
-		denali_mode_main_access(denali);
+	denali_oob_xfer(mtd, chip, page, 1);
 
-	return write_page(mtd, chip, buf, true, oob_required);
-}
+	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+	status = chip->waitfunc(mtd, chip);
 
-static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
-				int page)
-{
-	return write_oob_data(mtd, chip->oob_poi, page);
+	return status & NAND_STATUS_FAIL ? -EIO : 0;
 }
 
-/* raw include ECC value and all the spare area */
-static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-				uint8_t *buf, int oob_required, int page)
+static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+			    uint8_t *buf, int oob_required, int page)
 {
 	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	unsigned long uncor_ecc_flags = 0;
+	int stat = 0;
+	int ret;
 
-	uint32_t irq_status, irq_mask = INTR_STATUS__DMA_CMD_COMP;
+	ret = denali_data_xfer(denali, buf, mtd->writesize, page, 0, 0);
+	if (ret && ret != -EBADMSG)
+		return ret;
 
-	if (denali->page != page) {
-		debug("Missing NAND_CMD_READ0 command\n");
-		return -EIO;
-	}
+	if (denali->caps & DENALI_CAP_HW_ECC_FIXUP)
+		stat = denali_hw_ecc_fixup(mtd, denali, &uncor_ecc_flags);
+	else if (ret == -EBADMSG)
+		stat = denali_sw_ecc_fixup(mtd, denali, &uncor_ecc_flags, buf);
 
-	if (oob_required)
-		/* switch to main + spare access */
-		denali_mode_main_spare_access(denali);
-	else
-		/* switch to main access only */
-		denali_mode_main_access(denali);
+	if (stat < 0)
+		return stat;
 
-	/* setting up the DMA where ecc_enable is false */
-	irq_status = denali_dma_configuration(denali, DENALI_READ, true,
-					      irq_mask, oob_required);
+	if (uncor_ecc_flags) {
+		ret = denali_read_oob(mtd, chip, page);
+		if (ret)
+			return ret;
 
-	/* if timeout happen, error out */
-	if (!(irq_status & INTR_STATUS__DMA_CMD_COMP)) {
-		debug("DMA timeout for denali_read_page_raw\n");
-		return -EIO;
+		stat = denali_check_erased_page(mtd, chip, buf,
+						uncor_ecc_flags, stat);
 	}
 
-	/* splitting the content to destination buffer holder */
-	memcpy(chip->oob_poi, (denali->buf.dma_buf + mtd->writesize),
-	       mtd->oobsize);
-	memcpy(buf, denali->buf.dma_buf, mtd->writesize);
-
-	return 0;
+	return stat;
 }
 
-static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-				uint8_t *buf, int oob_required, int page)
+static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+				 const uint8_t *buf, int oob_required, int page)
 {
 	struct denali_nand_info *denali = mtd_to_denali(mtd);
-	uint32_t irq_status, irq_mask =	INTR_STATUS__DMA_CMD_COMP;
+	int writesize = mtd->writesize;
+	int oobsize = mtd->oobsize;
+	int ecc_steps = chip->ecc.steps;
+	int ecc_size = chip->ecc.size;
+	int ecc_bytes = chip->ecc.bytes;
+	void *tmp_buf = denali->buf;
+	int oob_skip = denali->oob_skip_bytes;
+	size_t size = writesize + oobsize;
+	int i, pos, len;
 
-	if (denali->page != page) {
-		debug("Missing NAND_CMD_READ0 command\n");
-		return -EIO;
+	/*
+	 * Fill the buffer with 0xff first except the full page transfer.
+	 * This simplifies the logic.
+	 */
+	if (!buf || !oob_required)
+		memset(tmp_buf, 0xff, size);
+
+	/* Arrange the buffer for syndrome payload/ecc layout */
+	if (buf) {
+		for (i = 0; i < ecc_steps; i++) {
+			pos = i * (ecc_size + ecc_bytes);
+			len = ecc_size;
+
+			if (pos >= writesize)
+				pos += oob_skip;
+			else if (pos + len > writesize)
+				len = writesize - pos;
+
+			memcpy(tmp_buf + pos, buf, len);
+			buf += len;
+			if (len < ecc_size) {
+				len = ecc_size - len;
+				memcpy(tmp_buf + writesize + oob_skip, buf,
+				       len);
+				buf += len;
+			}
+		}
 	}
 
-	if (oob_required)
-		/* switch to main + spare access */
-		denali_mode_main_spare_access(denali);
-	else
-		/* switch to main access only */
-		denali_mode_main_access(denali);
-
-	/* setting up the DMA where ecc_enable is true */
-	irq_status = denali_dma_configuration(denali, DENALI_READ, false,
-					      irq_mask, oob_required);
-
-	memcpy(buf, denali->buf.dma_buf, mtd->writesize);
-
-	/* check whether any ECC error */
-	if (irq_status & INTR_STATUS__ECC_UNCOR_ERR) {
-		/* is the ECC cause by erase page, check using read_page_raw */
-		debug("  Uncorrected ECC detected\n");
-		denali_read_page_raw(mtd, chip, buf, oob_required,
-				     denali->page);
-
-		if (is_erased(buf, mtd->writesize) == true &&
-		    is_erased(chip->oob_poi, mtd->oobsize) == true) {
-			debug("  ECC error cause by erased block\n");
-			/* false alarm, return the 0xFF */
-		} else {
-			return -EBADMSG;
+	if (oob_required) {
+		const uint8_t *oob = chip->oob_poi;
+
+		/* BBM at the beginning of the OOB area */
+		memcpy(tmp_buf + writesize, oob, oob_skip);
+		oob += oob_skip;
+
+		/* OOB ECC */
+		for (i = 0; i < ecc_steps; i++) {
+			pos = ecc_size + i * (ecc_size + ecc_bytes);
+			len = ecc_bytes;
+
+			if (pos >= writesize)
+				pos += oob_skip;
+			else if (pos + len > writesize)
+				len = writesize - pos;
+
+			memcpy(tmp_buf + pos, oob, len);
+			oob += len;
+			if (len < ecc_bytes) {
+				len = ecc_bytes - len;
+				memcpy(tmp_buf + writesize + oob_skip, oob,
+				       len);
+				oob += len;
+			}
 		}
+
+		/* OOB free */
+		len = oobsize - (oob - chip->oob_poi);
+		memcpy(tmp_buf + size - len, oob, len);
 	}
-	memcpy(buf, denali->buf.dma_buf, mtd->writesize);
-	return 0;
+
+	return denali_data_xfer(denali, tmp_buf, size, page, 1, 1);
 }
 
-static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-				int page)
+static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+			     const uint8_t *buf, int oob_required, int page)
 {
-	read_oob_data(mtd, chip->oob_poi, page);
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
 
-	return 0;
+	return denali_data_xfer(denali, (void *)buf, mtd->writesize,
+				page, 0, 1);
 }
 
-static uint8_t denali_read_byte(struct mtd_info *mtd)
+static void denali_select_chip(struct mtd_info *mtd, int chip)
 {
 	struct denali_nand_info *denali = mtd_to_denali(mtd);
-	uint32_t addr, result;
 
-	addr = (uint32_t)MODE_11 | BANK(denali->flash_bank);
-	index_addr_read_data(denali, addr | 2, &result);
-	return (uint8_t)result & 0xFF;
+	denali->active_bank = chip;
 }
 
-static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
 {
 	struct denali_nand_info *denali = mtd_to_denali(mtd);
-	uint32_t i, addr, result;
-
-	/* delay for tR (data transfer from Flash array to data register) */
-	udelay(25);
+	uint32_t irq_status;
 
-	/* ensure device completed else additional delay and polling */
-	wait_for_irq(denali, INTR_STATUS__INT_ACT);
+	/* R/B# pin transitioned from low to high? */
+	irq_status = denali_wait_for_irq(denali, INTR__INT_ACT);
 
-	addr = (uint32_t)MODE_11 | BANK(denali->flash_bank);
-	for (i = 0; i < len; i++) {
-		index_addr_read_data(denali, (uint32_t)addr | 2, &result);
-		write_byte_to_buf(denali, result);
-	}
-	memcpy(buf, denali->buf.buf, len);
+	return irq_status & INTR__INT_ACT ? 0 : NAND_STATUS_FAIL;
 }
 
-static void denali_select_chip(struct mtd_info *mtd, int chip)
+static int denali_erase(struct mtd_info *mtd, int page)
 {
 	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	uint32_t irq_status;
 
-	denali->flash_bank = chip;
-}
+	denali_reset_irq(denali);
 
-static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
-{
-	struct denali_nand_info *denali = mtd_to_denali(mtd);
-	int status = denali->status;
+	denali->host_write(denali, DENALI_MAP10 | DENALI_BANK(denali) | page,
+			   DENALI_ERASE);
 
-	denali->status = 0;
+	/* wait for erase to complete or failure to occur */
+	irq_status = denali_wait_for_irq(denali,
+					 INTR__ERASE_COMP | INTR__ERASE_FAIL);
 
-	return status;
+	return irq_status & INTR__ERASE_COMP ? 0 : NAND_STATUS_FAIL;
 }
 
-static int denali_erase(struct mtd_info *mtd, int page)
+static int __maybe_unused denali_setup_data_interface(struct mtd_info *mtd, int chipnr,
+				       const struct nand_data_interface *conf)
 {
 	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	const struct nand_sdr_timings *timings;
+	unsigned long t_clk;
+	int acc_clks, re_2_we, re_2_re, we_2_re, addr_2_data;
+	int rdwr_en_lo, rdwr_en_hi, rdwr_en_lo_hi, cs_setup;
+	int addr_2_data_mask;
+	uint32_t tmp;
 
-	uint32_t cmd, irq_status;
+	timings = nand_get_sdr_timings(conf);
+	if (IS_ERR(timings))
+		return PTR_ERR(timings);
 
-	clear_interrupts(denali);
+	/* clk_x period in picoseconds */
+	t_clk = DIV_ROUND_DOWN_ULL(1000000000000ULL, denali->clk_x_rate);
+	if (!t_clk)
+		return -EINVAL;
 
-	/* setup page read request for access type */
-	cmd = MODE_10 | BANK(denali->flash_bank) | page;
-	index_addr(denali, cmd, 0x1);
+	if (chipnr == NAND_DATA_IFACE_CHECK_ONLY)
+		return 0;
 
-	/* wait for erase to complete or failure to occur */
-	irq_status = wait_for_irq(denali, INTR_STATUS__ERASE_COMP |
-					INTR_STATUS__ERASE_FAIL);
+	/* tREA -> ACC_CLKS */
+	acc_clks = DIV_ROUND_UP(timings->tREA_max, t_clk);
+	acc_clks = min_t(int, acc_clks, ACC_CLKS__VALUE);
+
+	tmp = ioread32(denali->reg + ACC_CLKS);
+	tmp &= ~ACC_CLKS__VALUE;
+	tmp |= FIELD_PREP(ACC_CLKS__VALUE, acc_clks);
+	iowrite32(tmp, denali->reg + ACC_CLKS);
+
+	/* tRWH -> RE_2_WE */
+	re_2_we = DIV_ROUND_UP(timings->tRHW_min, t_clk);
+	re_2_we = min_t(int, re_2_we, RE_2_WE__VALUE);
+
+	tmp = ioread32(denali->reg + RE_2_WE);
+	tmp &= ~RE_2_WE__VALUE;
+	tmp |= FIELD_PREP(RE_2_WE__VALUE, re_2_we);
+	iowrite32(tmp, denali->reg + RE_2_WE);
+
+	/* tRHZ -> RE_2_RE */
+	re_2_re = DIV_ROUND_UP(timings->tRHZ_max, t_clk);
+	re_2_re = min_t(int, re_2_re, RE_2_RE__VALUE);
+
+	tmp = ioread32(denali->reg + RE_2_RE);
+	tmp &= ~RE_2_RE__VALUE;
+	tmp |= FIELD_PREP(RE_2_RE__VALUE, re_2_re);
+	iowrite32(tmp, denali->reg + RE_2_RE);
+
+	/*
+	 * tCCS, tWHR -> WE_2_RE
+	 *
+	 * With WE_2_RE properly set, the Denali controller automatically takes
+	 * care of the delay; the driver need not set NAND_WAIT_TCCS.
+	 */
+	we_2_re = DIV_ROUND_UP(max(timings->tCCS_min, timings->tWHR_min),
+			       t_clk);
+	we_2_re = min_t(int, we_2_re, TWHR2_AND_WE_2_RE__WE_2_RE);
+
+	tmp = ioread32(denali->reg + TWHR2_AND_WE_2_RE);
+	tmp &= ~TWHR2_AND_WE_2_RE__WE_2_RE;
+	tmp |= FIELD_PREP(TWHR2_AND_WE_2_RE__WE_2_RE, we_2_re);
+	iowrite32(tmp, denali->reg + TWHR2_AND_WE_2_RE);
+
+	/* tADL -> ADDR_2_DATA */
 
-	if (irq_status & INTR_STATUS__ERASE_FAIL ||
-	    irq_status & INTR_STATUS__LOCKED_BLK)
-		return NAND_STATUS_FAIL;
+	/* for older versions, ADDR_2_DATA is only 6 bit wide */
+	addr_2_data_mask = TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA;
+	if (denali->revision < 0x0501)
+		addr_2_data_mask >>= 1;
+
+	addr_2_data = DIV_ROUND_UP(timings->tADL_min, t_clk);
+	addr_2_data = min_t(int, addr_2_data, addr_2_data_mask);
+
+	tmp = ioread32(denali->reg + TCWAW_AND_ADDR_2_DATA);
+	tmp &= ~TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA;
+	tmp |= FIELD_PREP(TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA, addr_2_data);
+	iowrite32(tmp, denali->reg + TCWAW_AND_ADDR_2_DATA);
+
+	/* tREH, tWH -> RDWR_EN_HI_CNT */
+	rdwr_en_hi = DIV_ROUND_UP(max(timings->tREH_min, timings->tWH_min),
+				  t_clk);
+	rdwr_en_hi = min_t(int, rdwr_en_hi, RDWR_EN_HI_CNT__VALUE);
+
+	tmp = ioread32(denali->reg + RDWR_EN_HI_CNT);
+	tmp &= ~RDWR_EN_HI_CNT__VALUE;
+	tmp |= FIELD_PREP(RDWR_EN_HI_CNT__VALUE, rdwr_en_hi);
+	iowrite32(tmp, denali->reg + RDWR_EN_HI_CNT);
+
+	/* tRP, tWP -> RDWR_EN_LO_CNT */
+	rdwr_en_lo = DIV_ROUND_UP(max(timings->tRP_min, timings->tWP_min),
+				  t_clk);
+	rdwr_en_lo_hi = DIV_ROUND_UP(max(timings->tRC_min, timings->tWC_min),
+				     t_clk);
+	rdwr_en_lo_hi = max(rdwr_en_lo_hi, DENALI_CLK_X_MULT);
+	rdwr_en_lo = max(rdwr_en_lo, rdwr_en_lo_hi - rdwr_en_hi);
+	rdwr_en_lo = min_t(int, rdwr_en_lo, RDWR_EN_LO_CNT__VALUE);
+
+	tmp = ioread32(denali->reg + RDWR_EN_LO_CNT);
+	tmp &= ~RDWR_EN_LO_CNT__VALUE;
+	tmp |= FIELD_PREP(RDWR_EN_LO_CNT__VALUE, rdwr_en_lo);
+	iowrite32(tmp, denali->reg + RDWR_EN_LO_CNT);
+
+	/* tCS, tCEA -> CS_SETUP_CNT */
+	cs_setup = max3((int)DIV_ROUND_UP(timings->tCS_min, t_clk) - rdwr_en_lo,
+			(int)DIV_ROUND_UP(timings->tCEA_max, t_clk) - acc_clks,
+			0);
+	cs_setup = min_t(int, cs_setup, CS_SETUP_CNT__VALUE);
+
+	tmp = ioread32(denali->reg + CS_SETUP_CNT);
+	tmp &= ~CS_SETUP_CNT__VALUE;
+	tmp |= FIELD_PREP(CS_SETUP_CNT__VALUE, cs_setup);
+	iowrite32(tmp, denali->reg + CS_SETUP_CNT);
 
 	return 0;
 }
 
-static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col,
-			   int page)
+static void denali_reset_banks(struct denali_nand_info *denali)
 {
-	struct denali_nand_info *denali = mtd_to_denali(mtd);
-	uint32_t addr;
-
-	switch (cmd) {
-	case NAND_CMD_PAGEPROG:
-		break;
-	case NAND_CMD_STATUS:
-		addr = MODE_11 | BANK(denali->flash_bank);
-		index_addr(denali, addr | 0, cmd);
-		break;
-	case NAND_CMD_READID:
-	case NAND_CMD_PARAM:
-		reset_buf(denali);
-		/*
-		 * sometimes ManufactureId read from register is not right
-		 * e.g. some of Micron MT29F32G08QAA MLC NAND chips
-		 * So here we send READID cmd to NAND insteand
-		 */
-		addr = MODE_11 | BANK(denali->flash_bank);
-		index_addr(denali, addr | 0, cmd);
-		index_addr(denali, addr | 1, col & 0xFF);
-		if (cmd == NAND_CMD_PARAM)
-			udelay(50);
-		break;
-	case NAND_CMD_RNDOUT:
-		addr = MODE_11 | BANK(denali->flash_bank);
-		index_addr(denali, addr | 0, cmd);
-		index_addr(denali, addr | 1, col & 0xFF);
-		index_addr(denali, addr | 1, col >> 8);
-		index_addr(denali, addr | 0, NAND_CMD_RNDOUTSTART);
-		break;
-	case NAND_CMD_READ0:
-	case NAND_CMD_SEQIN:
-		denali->page = page;
-		break;
-	case NAND_CMD_RESET:
-		reset_bank(denali);
-		break;
-	case NAND_CMD_READOOB:
-		/* TODO: Read OOB data */
-		break;
-	case NAND_CMD_ERASE1:
-		/*
-		 * supporting block erase only, not multiblock erase as
-		 * it will cross plane and software need complex calculation
-		 * to identify the block count for the cross plane
-		 */
-		denali_erase(mtd, page);
-		break;
-	case NAND_CMD_ERASE2:
-		/* nothing to do here as it was done during NAND_CMD_ERASE1 */
-		break;
-	case NAND_CMD_UNLOCK1:
-		addr = MODE_10 | BANK(denali->flash_bank) | page;
-		index_addr(denali, addr | 0, DENALI_UNLOCK_START);
-		break;
-	case NAND_CMD_UNLOCK2:
-		addr = MODE_10 | BANK(denali->flash_bank) | page;
-		index_addr(denali, addr | 0, DENALI_UNLOCK_END);
-		break;
-	case NAND_CMD_LOCK:
-		addr = MODE_10 | BANK(denali->flash_bank);
-		index_addr(denali, addr | 0, DENALI_LOCK);
-		break;
-	default:
-		printf(": unsupported command received 0x%x\n", cmd);
-		break;
+	u32 irq_status;
+	int i;
+
+	for (i = 0; i < denali->max_banks; i++) {
+		denali->active_bank = i;
+
+		denali_reset_irq(denali);
+
+		iowrite32(DEVICE_RESET__BANK(i),
+			  denali->reg + DEVICE_RESET);
+
+		irq_status = denali_wait_for_irq(denali,
+			INTR__RST_COMP | INTR__INT_ACT | INTR__TIME_OUT);
+		if (!(irq_status & INTR__INT_ACT))
+			break;
 	}
+
+	dev_dbg(denali->dev, "%d chips connected\n", i);
+	denali->max_banks = i;
 }
-/* end NAND core entry points */
 
-/* Initialization code to bring the device up to a known good state */
 static void denali_hw_init(struct denali_nand_info *denali)
 {
 	/*
@@ -1154,125 +1086,285 @@ static void denali_hw_init(struct denali_nand_info *denali)
 	 * override it.
 	 */
 	if (!denali->revision)
-		denali->revision = swab16(ioread32(denali->flash_reg + REVISION));
+		denali->revision = swab16(ioread32(denali->reg + REVISION));
 
 	/*
 	 * tell driver how many bit controller will skip before writing
 	 * ECC code in OOB. This is normally used for bad block marker
 	 */
-	writel(CONFIG_NAND_DENALI_SPARE_AREA_SKIP_BYTES,
-	       denali->flash_reg + SPARE_AREA_SKIP_BYTES);
-	detect_max_banks(denali);
-	denali_nand_reset(denali);
-	writel(0x0F, denali->flash_reg + RB_PIN_ENABLED);
-	writel(CHIP_EN_DONT_CARE__FLAG,
-	       denali->flash_reg + CHIP_ENABLE_DONT_CARE);
-	writel(0xffff, denali->flash_reg + SPARE_AREA_MARKER);
-
-	/* Should set value for these registers when init */
-	writel(0, denali->flash_reg + TWO_ROW_ADDR_CYCLES);
-	writel(1, denali->flash_reg + ECC_ENABLE);
-	denali_nand_timing_set(denali);
-	denali_irq_init(denali);
+	denali->oob_skip_bytes = CONFIG_NAND_DENALI_SPARE_AREA_SKIP_BYTES;
+	iowrite32(denali->oob_skip_bytes, denali->reg + SPARE_AREA_SKIP_BYTES);
+	denali_detect_max_banks(denali);
+	iowrite32(0x0F, denali->reg + RB_PIN_ENABLED);
+	iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->reg + CHIP_ENABLE_DONT_CARE);
+
+	iowrite32(0xffff, denali->reg + SPARE_AREA_MARKER);
 }
 
-static struct nand_ecclayout nand_oob;
+int denali_calc_ecc_bytes(int step_size, int strength)
+{
+	/* BCH code.  Denali requires ecc.bytes to be multiple of 2 */
+	return DIV_ROUND_UP(strength * fls(step_size * 8), 16) * 2;
+}
+EXPORT_SYMBOL(denali_calc_ecc_bytes);
 
-int denali_init(struct denali_nand_info *denali)
+static int denali_ecc_setup(struct mtd_info *mtd, struct nand_chip *chip,
+			    struct denali_nand_info *denali)
 {
-	struct mtd_info *mtd = nand_to_mtd(&denali->nand);
+	int oobavail = mtd->oobsize - denali->oob_skip_bytes;
 	int ret;
 
-	denali_hw_init(denali);
+	/*
+	 * If .size and .strength are already set (usually by DT),
+	 * check if they are supported by this controller.
+	 */
+	if (chip->ecc.size && chip->ecc.strength)
+		return nand_check_ecc_caps(chip, denali->ecc_caps, oobavail);
+
+	/*
+	 * We want .size and .strength closest to the chip's requirement
+	 * unless NAND_ECC_MAXIMIZE is requested.
+	 */
+	if (!(chip->ecc.options & NAND_ECC_MAXIMIZE)) {
+		ret = nand_match_ecc_req(chip, denali->ecc_caps, oobavail);
+		if (!ret)
+			return 0;
+	}
+
+	/* Max ECC strength is the last thing we can do */
+	return nand_maximize_ecc(chip, denali->ecc_caps, oobavail);
+}
+
+static struct nand_ecclayout nand_oob;
+
+static int denali_ooblayout_ecc(struct mtd_info *mtd, int section,
+				struct mtd_oob_region *oobregion)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = denali->oob_skip_bytes;
+	oobregion->length = chip->ecc.total;
+
+	return 0;
+}
 
-	mtd->name = "denali-nand";
-	mtd->owner = THIS_MODULE;
+static int denali_ooblayout_free(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *oobregion)
+{
+	struct denali_nand_info *denali = mtd_to_denali(mtd);
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	if (section)
+		return -ERANGE;
+
+	oobregion->offset = chip->ecc.total + denali->oob_skip_bytes;
+	oobregion->length = mtd->oobsize - oobregion->offset;
+
+	return 0;
+}
 
-	/* register the driver with the NAND core subsystem */
-	denali->nand.select_chip = denali_select_chip;
-	denali->nand.cmdfunc = denali_cmdfunc;
-	denali->nand.read_byte = denali_read_byte;
-	denali->nand.read_buf = denali_read_buf;
-	denali->nand.waitfunc = denali_waitfunc;
+static const struct mtd_ooblayout_ops denali_ooblayout_ops = {
+	.ecc = denali_ooblayout_ecc,
+	.free = denali_ooblayout_free,
+};
+
+static int denali_multidev_fixup(struct denali_nand_info *denali)
+{
+	struct nand_chip *chip = &denali->nand;
+	struct mtd_info *mtd = nand_to_mtd(chip);
 
 	/*
-	 * scan for NAND devices attached to the controller
-	 * this is the first stage in a two step process to register
-	 * with the nand subsystem
+	 * Support for multi device:
+	 * When the IP configuration is x16 capable and two x8 chips are
+	 * connected in parallel, DEVICES_CONNECTED should be set to 2.
+	 * In this case, the core framework knows nothing about this fact,
+	 * so we should tell it the _logical_ pagesize and anything necessary.
 	 */
-	if (nand_scan_ident(mtd, denali->max_banks, NULL)) {
-		ret = -ENXIO;
-		goto fail;
-	}
+	denali->devs_per_cs = ioread32(denali->reg + DEVICES_CONNECTED);
 
-#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT
-	/* check whether flash got BBT table (located at end of flash). As we
-	 * use NAND_BBT_NO_OOB, the BBT page will start with
-	 * bbt_pattern. We will have mirror pattern too */
-	denali->nand.bbt_options |= NAND_BBT_USE_FLASH;
 	/*
-	 * We are using main + spare with ECC support. As BBT need ECC support,
-	 * we need to ensure BBT code don't write to OOB for the BBT pattern.
-	 * All BBT info will be stored into data area with ECC support.
+	 * On some SoCs, DEVICES_CONNECTED is not auto-detected.
+	 * For those, DEVICES_CONNECTED is left to 0.  Set 1 if it is the case.
 	 */
-	denali->nand.bbt_options |= NAND_BBT_NO_OOB;
-#endif
+	if (denali->devs_per_cs == 0) {
+		denali->devs_per_cs = 1;
+		iowrite32(1, denali->reg + DEVICES_CONNECTED);
+	}
+
+	if (denali->devs_per_cs == 1)
+		return 0;
+
+	if (denali->devs_per_cs != 2) {
+		dev_err(denali->dev, "unsupported number of devices %d\n",
+			denali->devs_per_cs);
+		return -EINVAL;
+	}
+
+	/* 2 chips in parallel */
+	mtd->size <<= 1;
+	mtd->erasesize <<= 1;
+	mtd->writesize <<= 1;
+	mtd->oobsize <<= 1;
+	chip->chipsize <<= 1;
+	chip->page_shift += 1;
+	chip->phys_erase_shift += 1;
+	chip->bbt_erase_shift += 1;
+	chip->chip_shift += 1;
+	chip->pagemask <<= 1;
+	chip->ecc.size <<= 1;
+	chip->ecc.bytes <<= 1;
+	chip->ecc.strength <<= 1;
+	denali->oob_skip_bytes <<= 1;
+
+	return 0;
+}
+
+int denali_init(struct denali_nand_info *denali)
+{
+	struct nand_chip *chip = &denali->nand;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	u32 features = ioread32(denali->reg + FEATURES);
+	int ret;
+
+	mtd->dev->parent = denali->dev;
+	denali_hw_init(denali);
+
+	denali_clear_irq_all(denali);
 
-	denali->nand.ecc.mode = NAND_ECC_HW;
-	denali->nand.ecc.size = CONFIG_NAND_DENALI_ECC_SIZE;
+	denali_reset_banks(denali);
+
+	denali->active_bank = DENALI_INVALID_BANK;
+
+	chip->flash_node = dev_of_offset(denali->dev);
+	/* Fallback to the default name if DT did not give "label" property */
+	if (!mtd->name)
+		mtd->name = "denali-nand";
+
+	chip->select_chip = denali_select_chip;
+	chip->read_byte = denali_read_byte;
+	chip->write_byte = denali_write_byte;
+	chip->read_word = denali_read_word;
+	chip->cmd_ctrl = denali_cmd_ctrl;
+	chip->dev_ready = denali_dev_ready;
+	chip->waitfunc = denali_waitfunc;
+
+	if (features & FEATURES__INDEX_ADDR) {
+		denali->host_read = denali_indexed_read;
+		denali->host_write = denali_indexed_write;
+	} else {
+		denali->host_read = denali_direct_read;
+		denali->host_write = denali_direct_write;
+	}
+
+	/* clk rate info is needed for setup_data_interface */
+	if (denali->clk_x_rate)
+		chip->setup_data_interface = denali_setup_data_interface;
+
+	ret = nand_scan_ident(mtd, denali->max_banks, NULL);
+	if (ret)
+		return ret;
+
+	if (ioread32(denali->reg + FEATURES) & FEATURES__DMA)
+		denali->dma_avail = 1;
+
+	if (denali->dma_avail) {
+		chip->buf_align = 16;
+		if (denali->caps & DENALI_CAP_DMA_64BIT)
+			denali->setup_dma = denali_setup_dma64;
+		else
+			denali->setup_dma = denali_setup_dma32;
+	} else {
+		chip->buf_align = 4;
+	}
+
+	chip->options |= NAND_USE_BOUNCE_BUFFER;
+	chip->bbt_options |= NAND_BBT_USE_FLASH;
+	chip->bbt_options |= NAND_BBT_NO_OOB;
+	denali->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
 
 	/* no subpage writes on denali */
-	denali->nand.options |= NAND_NO_SUBPAGE_WRITE;
+	chip->options |= NAND_NO_SUBPAGE_WRITE;
 
-	/*
-	 * Tell driver the ecc strength. This register may be already set
-	 * correctly. So we read this value out.
-	 */
-	denali->nand.ecc.strength = readl(denali->flash_reg + ECC_CORRECTION);
-	switch (denali->nand.ecc.size) {
-	case 512:
-		denali->nand.ecc.bytes =
-			(denali->nand.ecc.strength * 13 + 15) / 16 * 2;
-		break;
-	case 1024:
-		denali->nand.ecc.bytes =
-			(denali->nand.ecc.strength * 14 + 15) / 16 * 2;
-		break;
-	default:
-		pr_err("Unsupported ECC size\n");
-		ret = -EINVAL;
-		goto fail;
+	ret = denali_ecc_setup(mtd, chip, denali);
+	if (ret) {
+		dev_err(denali->dev, "Failed to setup ECC settings.\n");
+		return ret;
 	}
+
+	dev_dbg(denali->dev,
+		"chosen ECC settings: step=%d, strength=%d, bytes=%d\n",
+		chip->ecc.size, chip->ecc.strength, chip->ecc.bytes);
+
+	iowrite32(FIELD_PREP(ECC_CORRECTION__ERASE_THRESHOLD, 1) |
+		  FIELD_PREP(ECC_CORRECTION__VALUE, chip->ecc.strength),
+		  denali->reg + ECC_CORRECTION);
+	iowrite32(mtd->erasesize / mtd->writesize,
+		  denali->reg + PAGES_PER_BLOCK);
+	iowrite32(chip->options & NAND_BUSWIDTH_16 ? 1 : 0,
+		  denali->reg + DEVICE_WIDTH);
+	iowrite32(chip->options & NAND_ROW_ADDR_3 ? 0 : TWO_ROW_ADDR_CYCLES__FLAG,
+		  denali->reg + TWO_ROW_ADDR_CYCLES);
+	iowrite32(mtd->writesize, denali->reg + DEVICE_MAIN_AREA_SIZE);
+	iowrite32(mtd->oobsize, denali->reg + DEVICE_SPARE_AREA_SIZE);
+
+	iowrite32(chip->ecc.size, denali->reg + CFG_DATA_BLOCK_SIZE);
+	iowrite32(chip->ecc.size, denali->reg + CFG_LAST_DATA_BLOCK_SIZE);
+	/* chip->ecc.steps is set by nand_scan_tail(); not available here */
+	iowrite32(mtd->writesize / chip->ecc.size,
+		  denali->reg + CFG_NUM_DATA_BLOCKS);
+
+	mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
+
 	nand_oob.eccbytes = denali->nand.ecc.bytes;
 	denali->nand.ecc.layout = &nand_oob;
 
-	writel(mtd->erasesize / mtd->writesize,
-	       denali->flash_reg + PAGES_PER_BLOCK);
-	writel(denali->nand.options & NAND_BUSWIDTH_16 ? 1 : 0,
-	       denali->flash_reg + DEVICE_WIDTH);
-	writel(mtd->writesize,
-	       denali->flash_reg + DEVICE_MAIN_AREA_SIZE);
-	writel(mtd->oobsize,
-	       denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
-	if (readl(denali->flash_reg + DEVICES_CONNECTED) == 0)
-		writel(1, denali->flash_reg + DEVICES_CONNECTED);
-
-	/* override the default operations */
-	denali->nand.ecc.read_page = denali_read_page;
-	denali->nand.ecc.read_page_raw = denali_read_page_raw;
-	denali->nand.ecc.write_page = denali_write_page;
-	denali->nand.ecc.write_page_raw = denali_write_page_raw;
-	denali->nand.ecc.read_oob = denali_read_oob;
-	denali->nand.ecc.write_oob = denali_write_oob;
-
-	if (nand_scan_tail(mtd)) {
-		ret = -ENXIO;
-		goto fail;
+	if (chip->options & NAND_BUSWIDTH_16) {
+		chip->read_buf = denali_read_buf16;
+		chip->write_buf = denali_write_buf16;
+	} else {
+		chip->read_buf = denali_read_buf;
+		chip->write_buf = denali_write_buf;
 	}
+	chip->ecc.options |= NAND_ECC_CUSTOM_PAGE_ACCESS;
+	chip->ecc.read_page = denali_read_page;
+	chip->ecc.read_page_raw = denali_read_page_raw;
+	chip->ecc.write_page = denali_write_page;
+	chip->ecc.write_page_raw = denali_write_page_raw;
+	chip->ecc.read_oob = denali_read_oob;
+	chip->ecc.write_oob = denali_write_oob;
+	chip->erase = denali_erase;
+
+	ret = denali_multidev_fixup(denali);
+	if (ret)
+		return ret;
+
+	/*
+	 * This buffer is DMA-mapped by denali_{read,write}_page_raw.  Do not
+	 * use devm_kmalloc() because the memory allocated by devm_ does not
+	 * guarantee DMA-safe alignment.
+	 */
+	denali->buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
+	if (!denali->buf)
+		return -ENOMEM;
+
+	ret = nand_scan_tail(mtd);
+	if (ret)
+		goto free_buf;
 
 	ret = nand_register(0, mtd);
+	if (ret) {
+		dev_err(denali->dev, "Failed to register MTD: %d\n", ret);
+		goto free_buf;
+	}
+	return 0;
+
+free_buf:
+	kfree(denali->buf);
 
-fail:
 	return ret;
 }
 
@@ -1289,8 +1381,8 @@ static int __board_nand_init(void)
 	 * In the future, these base addresses should be taken from
 	 * Device Tree or platform data.
 	 */
-	denali->flash_reg = (void  __iomem *)CONFIG_SYS_NAND_REGS_BASE;
-	denali->flash_mem = (void  __iomem *)CONFIG_SYS_NAND_DATA_BASE;
+	denali->reg = (void  __iomem *)CONFIG_SYS_NAND_REGS_BASE;
+	denali->host = (void  __iomem *)CONFIG_SYS_NAND_DATA_BASE;
 
 	return denali_init(denali);
 }
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
index f796f0d..04b4ae2 100644
--- a/drivers/mtd/nand/denali.h
+++ b/drivers/mtd/nand/denali.h
@@ -8,466 +8,319 @@
 #ifndef __DENALI_H__
 #define __DENALI_H__
 
+#include <linux/bitops.h>
 #include <linux/mtd/nand.h>
+#include <linux/types.h>
 
 #define DEVICE_RESET				0x0
-#define     DEVICE_RESET__BANK0				0x0001
-#define     DEVICE_RESET__BANK1				0x0002
-#define     DEVICE_RESET__BANK2				0x0004
-#define     DEVICE_RESET__BANK3				0x0008
+#define     DEVICE_RESET__BANK(bank)			BIT(bank)
 
 #define TRANSFER_SPARE_REG			0x10
-#define     TRANSFER_SPARE_REG__FLAG			0x0001
+#define     TRANSFER_SPARE_REG__FLAG			BIT(0)
 
 #define LOAD_WAIT_CNT				0x20
-#define     LOAD_WAIT_CNT__VALUE			0xffff
+#define     LOAD_WAIT_CNT__VALUE			GENMASK(15, 0)
 
 #define PROGRAM_WAIT_CNT			0x30
-#define     PROGRAM_WAIT_CNT__VALUE			0xffff
+#define     PROGRAM_WAIT_CNT__VALUE			GENMASK(15, 0)
 
 #define ERASE_WAIT_CNT				0x40
-#define     ERASE_WAIT_CNT__VALUE			0xffff
+#define     ERASE_WAIT_CNT__VALUE			GENMASK(15, 0)
 
 #define INT_MON_CYCCNT				0x50
-#define     INT_MON_CYCCNT__VALUE			0xffff
+#define     INT_MON_CYCCNT__VALUE			GENMASK(15, 0)
 
 #define RB_PIN_ENABLED				0x60
-#define     RB_PIN_ENABLED__BANK0			0x0001
-#define     RB_PIN_ENABLED__BANK1			0x0002
-#define     RB_PIN_ENABLED__BANK2			0x0004
-#define     RB_PIN_ENABLED__BANK3			0x0008
+#define     RB_PIN_ENABLED__BANK(bank)			BIT(bank)
 
 #define MULTIPLANE_OPERATION			0x70
-#define     MULTIPLANE_OPERATION__FLAG			0x0001
+#define     MULTIPLANE_OPERATION__FLAG			BIT(0)
 
 #define MULTIPLANE_READ_ENABLE			0x80
-#define     MULTIPLANE_READ_ENABLE__FLAG		0x0001
+#define     MULTIPLANE_READ_ENABLE__FLAG		BIT(0)
 
 #define COPYBACK_DISABLE			0x90
-#define     COPYBACK_DISABLE__FLAG			0x0001
+#define     COPYBACK_DISABLE__FLAG			BIT(0)
 
 #define CACHE_WRITE_ENABLE			0xa0
-#define     CACHE_WRITE_ENABLE__FLAG			0x0001
+#define     CACHE_WRITE_ENABLE__FLAG			BIT(0)
 
 #define CACHE_READ_ENABLE			0xb0
-#define     CACHE_READ_ENABLE__FLAG			0x0001
+#define     CACHE_READ_ENABLE__FLAG			BIT(0)
 
 #define PREFETCH_MODE				0xc0
-#define     PREFETCH_MODE__PREFETCH_EN			0x0001
-#define     PREFETCH_MODE__PREFETCH_BURST_LENGTH	0xfff0
+#define     PREFETCH_MODE__PREFETCH_EN			BIT(0)
+#define     PREFETCH_MODE__PREFETCH_BURST_LENGTH	GENMASK(15, 4)
 
 #define CHIP_ENABLE_DONT_CARE			0xd0
-#define     CHIP_EN_DONT_CARE__FLAG			0x01
+#define     CHIP_EN_DONT_CARE__FLAG			BIT(0)
 
 #define ECC_ENABLE				0xe0
-#define     ECC_ENABLE__FLAG				0x0001
+#define     ECC_ENABLE__FLAG				BIT(0)
 
 #define GLOBAL_INT_ENABLE			0xf0
-#define     GLOBAL_INT_EN_FLAG				0x01
+#define     GLOBAL_INT_EN_FLAG				BIT(0)
 
-#define WE_2_RE					0x100
-#define     WE_2_RE__VALUE				0x003f
+#define TWHR2_AND_WE_2_RE			0x100
+#define     TWHR2_AND_WE_2_RE__WE_2_RE			GENMASK(5, 0)
+#define     TWHR2_AND_WE_2_RE__TWHR2			GENMASK(13, 8)
 
-#define ADDR_2_DATA				0x110
-#define     ADDR_2_DATA__VALUE				0x003f
+#define TCWAW_AND_ADDR_2_DATA			0x110
+/* The width of ADDR_2_DATA is 6 bit for old IP, 7 bit for new IP */
+#define     TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA		GENMASK(6, 0)
+#define     TCWAW_AND_ADDR_2_DATA__TCWAW		GENMASK(13, 8)
 
 #define RE_2_WE					0x120
-#define     RE_2_WE__VALUE				0x003f
+#define     RE_2_WE__VALUE				GENMASK(5, 0)
 
 #define ACC_CLKS				0x130
-#define     ACC_CLKS__VALUE				0x000f
+#define     ACC_CLKS__VALUE				GENMASK(3, 0)
 
 #define NUMBER_OF_PLANES			0x140
-#define     NUMBER_OF_PLANES__VALUE			0x0007
+#define     NUMBER_OF_PLANES__VALUE			GENMASK(2, 0)
 
 #define PAGES_PER_BLOCK				0x150
-#define     PAGES_PER_BLOCK__VALUE			0xffff
+#define     PAGES_PER_BLOCK__VALUE			GENMASK(15, 0)
 
 #define DEVICE_WIDTH				0x160
-#define     DEVICE_WIDTH__VALUE				0x0003
+#define     DEVICE_WIDTH__VALUE				GENMASK(1, 0)
 
 #define DEVICE_MAIN_AREA_SIZE			0x170
-#define     DEVICE_MAIN_AREA_SIZE__VALUE		0xffff
+#define     DEVICE_MAIN_AREA_SIZE__VALUE		GENMASK(15, 0)
 
 #define DEVICE_SPARE_AREA_SIZE			0x180
-#define     DEVICE_SPARE_AREA_SIZE__VALUE		0xffff
+#define     DEVICE_SPARE_AREA_SIZE__VALUE		GENMASK(15, 0)
 
 #define TWO_ROW_ADDR_CYCLES			0x190
-#define     TWO_ROW_ADDR_CYCLES__FLAG			0x0001
+#define     TWO_ROW_ADDR_CYCLES__FLAG			BIT(0)
 
 #define MULTIPLANE_ADDR_RESTRICT		0x1a0
-#define     MULTIPLANE_ADDR_RESTRICT__FLAG		0x0001
+#define     MULTIPLANE_ADDR_RESTRICT__FLAG		BIT(0)
 
 #define ECC_CORRECTION				0x1b0
-#define     ECC_CORRECTION__VALUE			0x001f
+#define     ECC_CORRECTION__VALUE			GENMASK(4, 0)
+#define     ECC_CORRECTION__ERASE_THRESHOLD		GENMASK(31, 16)
 
 #define READ_MODE				0x1c0
-#define     READ_MODE__VALUE				0x000f
+#define     READ_MODE__VALUE				GENMASK(3, 0)
 
 #define WRITE_MODE				0x1d0
-#define     WRITE_MODE__VALUE				0x000f
+#define     WRITE_MODE__VALUE				GENMASK(3, 0)
 
 #define COPYBACK_MODE				0x1e0
-#define     COPYBACK_MODE__VALUE			0x000f
+#define     COPYBACK_MODE__VALUE			GENMASK(3, 0)
 
 #define RDWR_EN_LO_CNT				0x1f0
-#define     RDWR_EN_LO_CNT__VALUE			0x001f
+#define     RDWR_EN_LO_CNT__VALUE			GENMASK(4, 0)
 
 #define RDWR_EN_HI_CNT				0x200
-#define     RDWR_EN_HI_CNT__VALUE			0x001f
+#define     RDWR_EN_HI_CNT__VALUE			GENMASK(4, 0)
 
 #define MAX_RD_DELAY				0x210
-#define     MAX_RD_DELAY__VALUE				0x000f
+#define     MAX_RD_DELAY__VALUE				GENMASK(3, 0)
 
 #define CS_SETUP_CNT				0x220
-#define     CS_SETUP_CNT__VALUE				0x001f
+#define     CS_SETUP_CNT__VALUE				GENMASK(4, 0)
+#define     CS_SETUP_CNT__TWB				GENMASK(17, 12)
 
 #define SPARE_AREA_SKIP_BYTES			0x230
-#define     SPARE_AREA_SKIP_BYTES__VALUE		0x003f
+#define     SPARE_AREA_SKIP_BYTES__VALUE		GENMASK(5, 0)
 
 #define SPARE_AREA_MARKER			0x240
-#define     SPARE_AREA_MARKER__VALUE			0xffff
+#define     SPARE_AREA_MARKER__VALUE			GENMASK(15, 0)
 
 #define DEVICES_CONNECTED			0x250
-#define     DEVICES_CONNECTED__VALUE			0x0007
+#define     DEVICES_CONNECTED__VALUE			GENMASK(2, 0)
 
 #define DIE_MASK				0x260
-#define     DIE_MASK__VALUE				0x00ff
+#define     DIE_MASK__VALUE				GENMASK(7, 0)
 
 #define FIRST_BLOCK_OF_NEXT_PLANE		0x270
-#define     FIRST_BLOCK_OF_NEXT_PLANE__VALUE		0xffff
+#define     FIRST_BLOCK_OF_NEXT_PLANE__VALUE		GENMASK(15, 0)
 
 #define WRITE_PROTECT				0x280
-#define     WRITE_PROTECT__FLAG				0x0001
+#define     WRITE_PROTECT__FLAG				BIT(0)
 
 #define RE_2_RE					0x290
-#define     RE_2_RE__VALUE				0x003f
+#define     RE_2_RE__VALUE				GENMASK(5, 0)
 
 #define MANUFACTURER_ID				0x300
-#define     MANUFACTURER_ID__VALUE			0x00ff
+#define     MANUFACTURER_ID__VALUE			GENMASK(7, 0)
 
 #define DEVICE_ID				0x310
-#define     DEVICE_ID__VALUE				0x00ff
+#define     DEVICE_ID__VALUE				GENMASK(7, 0)
 
 #define DEVICE_PARAM_0				0x320
-#define     DEVICE_PARAM_0__VALUE			0x00ff
+#define     DEVICE_PARAM_0__VALUE			GENMASK(7, 0)
 
 #define DEVICE_PARAM_1				0x330
-#define     DEVICE_PARAM_1__VALUE			0x00ff
+#define     DEVICE_PARAM_1__VALUE			GENMASK(7, 0)
 
 #define DEVICE_PARAM_2				0x340
-#define     DEVICE_PARAM_2__VALUE			0x00ff
+#define     DEVICE_PARAM_2__VALUE			GENMASK(7, 0)
 
 #define LOGICAL_PAGE_DATA_SIZE			0x350
-#define     LOGICAL_PAGE_DATA_SIZE__VALUE		0xffff
+#define     LOGICAL_PAGE_DATA_SIZE__VALUE		GENMASK(15, 0)
 
 #define LOGICAL_PAGE_SPARE_SIZE			0x360
-#define     LOGICAL_PAGE_SPARE_SIZE__VALUE		0xffff
+#define     LOGICAL_PAGE_SPARE_SIZE__VALUE		GENMASK(15, 0)
 
 #define REVISION				0x370
-#define     REVISION__VALUE				0xffff
+#define     REVISION__VALUE				GENMASK(15, 0)
 
 #define ONFI_DEVICE_FEATURES			0x380
-#define     ONFI_DEVICE_FEATURES__VALUE			0x003f
+#define     ONFI_DEVICE_FEATURES__VALUE			GENMASK(5, 0)
 
 #define ONFI_OPTIONAL_COMMANDS			0x390
-#define     ONFI_OPTIONAL_COMMANDS__VALUE		0x003f
+#define     ONFI_OPTIONAL_COMMANDS__VALUE		GENMASK(5, 0)
 
 #define ONFI_TIMING_MODE			0x3a0
-#define     ONFI_TIMING_MODE__VALUE			0x003f
+#define     ONFI_TIMING_MODE__VALUE			GENMASK(5, 0)
 
 #define ONFI_PGM_CACHE_TIMING_MODE		0x3b0
-#define     ONFI_PGM_CACHE_TIMING_MODE__VALUE		0x003f
+#define     ONFI_PGM_CACHE_TIMING_MODE__VALUE		GENMASK(5, 0)
 
 #define ONFI_DEVICE_NO_OF_LUNS			0x3c0
-#define     ONFI_DEVICE_NO_OF_LUNS__NO_OF_LUNS		0x00ff
-#define     ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE		0x0100
+#define     ONFI_DEVICE_NO_OF_LUNS__NO_OF_LUNS		GENMASK(7, 0)
+#define     ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE		BIT(8)
 
 #define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L	0x3d0
-#define     ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L__VALUE	0xffff
+#define     ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L__VALUE	GENMASK(15, 0)
 
 #define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U	0x3e0
-#define     ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U__VALUE	0xffff
-
-#define FEATURES					0x3f0
-#define     FEATURES__N_BANKS				0x0003
-#define     FEATURES__ECC_MAX_ERR			0x003c
-#define     FEATURES__DMA				0x0040
-#define     FEATURES__CMD_DMA				0x0080
-#define     FEATURES__PARTITION				0x0100
-#define     FEATURES__XDMA_SIDEBAND			0x0200
-#define     FEATURES__GPREG				0x0400
-#define     FEATURES__INDEX_ADDR			0x0800
+#define     ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U__VALUE	GENMASK(15, 0)
+
+#define FEATURES				0x3f0
+#define     FEATURES__N_BANKS				GENMASK(1, 0)
+#define     FEATURES__ECC_MAX_ERR			GENMASK(5, 2)
+#define     FEATURES__DMA				BIT(6)
+#define     FEATURES__CMD_DMA				BIT(7)
+#define     FEATURES__PARTITION				BIT(8)
+#define     FEATURES__XDMA_SIDEBAND			BIT(9)
+#define     FEATURES__GPREG				BIT(10)
+#define     FEATURES__INDEX_ADDR			BIT(11)
 
 #define TRANSFER_MODE				0x400
-#define     TRANSFER_MODE__VALUE			0x0003
-
-#define INTR_STATUS(__bank)	(0x410 + ((__bank) * 0x50))
-#define INTR_EN(__bank)		(0x420 + ((__bank) * 0x50))
-
-/*
- * Some versions of the IP have the ECC fixup handled in hardware.  In this
- * configuration we only get interrupted when the error is uncorrectable.
- * Unfortunately this bit replaces INTR_STATUS__ECC_TRANSACTION_DONE from the
- * old IP.
- */
-#define     INTR_STATUS__ECC_UNCOR_ERR			0x0001
-#define     INTR_STATUS__ECC_TRANSACTION_DONE		0x0001
-#define     INTR_STATUS__ECC_ERR			0x0002
-#define     INTR_STATUS__DMA_CMD_COMP			0x0004
-#define     INTR_STATUS__TIME_OUT			0x0008
-#define     INTR_STATUS__PROGRAM_FAIL			0x0010
-#define     INTR_STATUS__ERASE_FAIL			0x0020
-#define     INTR_STATUS__LOAD_COMP			0x0040
-#define     INTR_STATUS__PROGRAM_COMP			0x0080
-#define     INTR_STATUS__ERASE_COMP			0x0100
-#define     INTR_STATUS__PIPE_CPYBCK_CMD_COMP		0x0200
-#define     INTR_STATUS__LOCKED_BLK			0x0400
-#define     INTR_STATUS__UNSUP_CMD			0x0800
-#define     INTR_STATUS__INT_ACT			0x1000
-#define     INTR_STATUS__RST_COMP			0x2000
-#define     INTR_STATUS__PIPE_CMD_ERR			0x4000
-#define     INTR_STATUS__PAGE_XFER_INC			0x8000
-
-#define     INTR_EN__ECC_TRANSACTION_DONE		0x0001
-#define     INTR_EN__ECC_ERR				0x0002
-#define     INTR_EN__DMA_CMD_COMP			0x0004
-#define     INTR_EN__TIME_OUT				0x0008
-#define     INTR_EN__PROGRAM_FAIL			0x0010
-#define     INTR_EN__ERASE_FAIL				0x0020
-#define     INTR_EN__LOAD_COMP				0x0040
-#define     INTR_EN__PROGRAM_COMP			0x0080
-#define     INTR_EN__ERASE_COMP				0x0100
-#define     INTR_EN__PIPE_CPYBCK_CMD_COMP		0x0200
-#define     INTR_EN__LOCKED_BLK				0x0400
-#define     INTR_EN__UNSUP_CMD				0x0800
-#define     INTR_EN__INT_ACT				0x1000
-#define     INTR_EN__RST_COMP				0x2000
-#define     INTR_EN__PIPE_CMD_ERR			0x4000
-#define     INTR_EN__PAGE_XFER_INC			0x8000
-
-#define PAGE_CNT(__bank)	(0x430 + ((__bank) * 0x50))
-#define ERR_PAGE_ADDR(__bank)	(0x440 + ((__bank) * 0x50))
-#define ERR_BLOCK_ADDR(__bank)	(0x450 + ((__bank) * 0x50))
-
-#define DATA_INTR				0x550
-#define     DATA_INTR__WRITE_SPACE_AV			0x0001
-#define     DATA_INTR__READ_DATA_AV			0x0002
-
-#define DATA_INTR_EN				0x560
-#define     DATA_INTR_EN__WRITE_SPACE_AV		0x0001
-#define     DATA_INTR_EN__READ_DATA_AV			0x0002
-
-#define GPREG_0					0x570
-#define     GPREG_0__VALUE				0xffff
-
-#define GPREG_1					0x580
-#define     GPREG_1__VALUE				0xffff
-
-#define GPREG_2					0x590
-#define     GPREG_2__VALUE				0xffff
-
-#define GPREG_3					0x5a0
-#define     GPREG_3__VALUE				0xffff
+#define     TRANSFER_MODE__VALUE			GENMASK(1, 0)
+
+#define INTR_STATUS(bank)			(0x410 + (bank) * 0x50)
+#define INTR_EN(bank)				(0x420 + (bank) * 0x50)
+/* bit[1:0] is used differently depending on IP version */
+#define     INTR__ECC_UNCOR_ERR				BIT(0)	/* new IP */
+#define     INTR__ECC_TRANSACTION_DONE			BIT(0)	/* old IP */
+#define     INTR__ECC_ERR				BIT(1)	/* old IP */
+#define     INTR__DMA_CMD_COMP				BIT(2)
+#define     INTR__TIME_OUT				BIT(3)
+#define     INTR__PROGRAM_FAIL				BIT(4)
+#define     INTR__ERASE_FAIL				BIT(5)
+#define     INTR__LOAD_COMP				BIT(6)
+#define     INTR__PROGRAM_COMP				BIT(7)
+#define     INTR__ERASE_COMP				BIT(8)
+#define     INTR__PIPE_CPYBCK_CMD_COMP			BIT(9)
+#define     INTR__LOCKED_BLK				BIT(10)
+#define     INTR__UNSUP_CMD				BIT(11)
+#define     INTR__INT_ACT				BIT(12)
+#define     INTR__RST_COMP				BIT(13)
+#define     INTR__PIPE_CMD_ERR				BIT(14)
+#define     INTR__PAGE_XFER_INC				BIT(15)
+#define     INTR__ERASED_PAGE				BIT(16)
+
+#define PAGE_CNT(bank)				(0x430 + (bank) * 0x50)
+#define ERR_PAGE_ADDR(bank)			(0x440 + (bank) * 0x50)
+#define ERR_BLOCK_ADDR(bank)			(0x450 + (bank) * 0x50)
 
 #define ECC_THRESHOLD				0x600
-#define     ECC_THRESHOLD__VALUE			0x03ff
+#define     ECC_THRESHOLD__VALUE			GENMASK(9, 0)
 
 #define ECC_ERROR_BLOCK_ADDRESS			0x610
-#define     ECC_ERROR_BLOCK_ADDRESS__VALUE		0xffff
+#define     ECC_ERROR_BLOCK_ADDRESS__VALUE		GENMASK(15, 0)
 
 #define ECC_ERROR_PAGE_ADDRESS			0x620
-#define     ECC_ERROR_PAGE_ADDRESS__VALUE		0x0fff
-#define     ECC_ERROR_PAGE_ADDRESS__BANK		0xf000
+#define     ECC_ERROR_PAGE_ADDRESS__VALUE		GENMASK(11, 0)
+#define     ECC_ERROR_PAGE_ADDRESS__BANK		GENMASK(15, 12)
 
 #define ECC_ERROR_ADDRESS			0x630
-#define     ECC_ERROR_ADDRESS__OFFSET			0x0fff
-#define     ECC_ERROR_ADDRESS__SECTOR_NR		0xf000
+#define     ECC_ERROR_ADDRESS__OFFSET			GENMASK(11, 0)
+#define     ECC_ERROR_ADDRESS__SECTOR			GENMASK(15, 12)
 
 #define ERR_CORRECTION_INFO			0x640
-#define     ERR_CORRECTION_INFO__BYTEMASK		0x00ff
-#define     ERR_CORRECTION_INFO__DEVICE_NR		0x0f00
-#define     ERR_CORRECTION_INFO__ERROR_TYPE		0x4000
-#define     ERR_CORRECTION_INFO__LAST_ERR_INFO		0x8000
+#define     ERR_CORRECTION_INFO__BYTE			GENMASK(7, 0)
+#define     ERR_CORRECTION_INFO__DEVICE			GENMASK(11, 8)
+#define     ERR_CORRECTION_INFO__UNCOR			BIT(14)
+#define     ERR_CORRECTION_INFO__LAST_ERR		BIT(15)
+
+#define ECC_COR_INFO(bank)			(0x650 + (bank) / 2 * 0x10)
+#define     ECC_COR_INFO__SHIFT(bank)			((bank) % 2 * 8)
+#define     ECC_COR_INFO__MAX_ERRORS			GENMASK(6, 0)
+#define     ECC_COR_INFO__UNCOR_ERR			BIT(7)
+
+#define CFG_DATA_BLOCK_SIZE			0x6b0
+
+#define CFG_LAST_DATA_BLOCK_SIZE		0x6c0
+
+#define CFG_NUM_DATA_BLOCKS			0x6d0
+
+#define CFG_META_DATA_SIZE			0x6e0
 
 #define DMA_ENABLE				0x700
-#define     DMA_ENABLE__FLAG				0x0001
+#define     DMA_ENABLE__FLAG				BIT(0)
 
 #define IGNORE_ECC_DONE				0x710
-#define     IGNORE_ECC_DONE__FLAG			0x0001
+#define     IGNORE_ECC_DONE__FLAG			BIT(0)
 
 #define DMA_INTR				0x720
-#define     DMA_INTR__TARGET_ERROR			0x0001
-#define     DMA_INTR__DESC_COMP_CHANNEL0		0x0002
-#define     DMA_INTR__DESC_COMP_CHANNEL1		0x0004
-#define     DMA_INTR__DESC_COMP_CHANNEL2		0x0008
-#define     DMA_INTR__DESC_COMP_CHANNEL3		0x0010
-#define     DMA_INTR__MEMCOPY_DESC_COMP		0x0020
-
 #define DMA_INTR_EN				0x730
-#define     DMA_INTR_EN__TARGET_ERROR			0x0001
-#define     DMA_INTR_EN__DESC_COMP_CHANNEL0		0x0002
-#define     DMA_INTR_EN__DESC_COMP_CHANNEL1		0x0004
-#define     DMA_INTR_EN__DESC_COMP_CHANNEL2		0x0008
-#define     DMA_INTR_EN__DESC_COMP_CHANNEL3		0x0010
-#define     DMA_INTR_EN__MEMCOPY_DESC_COMP		0x0020
+#define     DMA_INTR__TARGET_ERROR			BIT(0)
+#define     DMA_INTR__DESC_COMP_CHANNEL0		BIT(1)
+#define     DMA_INTR__DESC_COMP_CHANNEL1		BIT(2)
+#define     DMA_INTR__DESC_COMP_CHANNEL2		BIT(3)
+#define     DMA_INTR__DESC_COMP_CHANNEL3		BIT(4)
+#define     DMA_INTR__MEMCOPY_DESC_COMP			BIT(5)
 
 #define TARGET_ERR_ADDR_LO			0x740
-#define     TARGET_ERR_ADDR_LO__VALUE			0xffff
+#define     TARGET_ERR_ADDR_LO__VALUE			GENMASK(15, 0)
 
 #define TARGET_ERR_ADDR_HI			0x750
-#define     TARGET_ERR_ADDR_HI__VALUE			0xffff
+#define     TARGET_ERR_ADDR_HI__VALUE			GENMASK(15, 0)
 
 #define CHNL_ACTIVE				0x760
-#define     CHNL_ACTIVE__CHANNEL0			0x0001
-#define     CHNL_ACTIVE__CHANNEL1			0x0002
-#define     CHNL_ACTIVE__CHANNEL2			0x0004
-#define     CHNL_ACTIVE__CHANNEL3			0x0008
-
-#define ACTIVE_SRC_ID				0x800
-#define     ACTIVE_SRC_ID__VALUE			0x00ff
-
-#define PTN_INTR					0x810
-#define     PTN_INTR__CONFIG_ERROR			0x0001
-#define     PTN_INTR__ACCESS_ERROR_BANK0		0x0002
-#define     PTN_INTR__ACCESS_ERROR_BANK1		0x0004
-#define     PTN_INTR__ACCESS_ERROR_BANK2		0x0008
-#define     PTN_INTR__ACCESS_ERROR_BANK3		0x0010
-#define     PTN_INTR__REG_ACCESS_ERROR			0x0020
-
-#define PTN_INTR_EN				0x820
-#define     PTN_INTR_EN__CONFIG_ERROR			0x0001
-#define     PTN_INTR_EN__ACCESS_ERROR_BANK0		0x0002
-#define     PTN_INTR_EN__ACCESS_ERROR_BANK1		0x0004
-#define     PTN_INTR_EN__ACCESS_ERROR_BANK2		0x0008
-#define     PTN_INTR_EN__ACCESS_ERROR_BANK3		0x0010
-#define     PTN_INTR_EN__REG_ACCESS_ERROR		0x0020
-
-#define PERM_SRC_ID(__bank)	(0x830 + ((__bank) * 0x40))
-#define     PERM_SRC_ID__SRCID				0x00ff
-#define     PERM_SRC_ID__DIRECT_ACCESS_ACTIVE		0x0800
-#define     PERM_SRC_ID__WRITE_ACTIVE			0x2000
-#define     PERM_SRC_ID__READ_ACTIVE			0x4000
-#define     PERM_SRC_ID__PARTITION_VALID		0x8000
-
-#define MIN_BLK_ADDR(__bank)	(0x840 + ((__bank) * 0x40))
-#define     MIN_BLK_ADDR__VALUE				0xffff
-
-#define MAX_BLK_ADDR(__bank)	(0x850 + ((__bank) * 0x40))
-#define     MAX_BLK_ADDR__VALUE				0xffff
-
-#define MIN_MAX_BANK(__bank)	(0x860 + ((__bank) * 0x40))
-#define     MIN_MAX_BANK__MIN_VALUE			0x0003
-#define     MIN_MAX_BANK__MAX_VALUE			0x000c
-
-/* lld.h */
-#define GOOD_BLOCK 0
-#define DEFECTIVE_BLOCK 1
-#define READ_ERROR 2
-
-#define CLK_X  5
-#define CLK_MULTI 4
-
-/* spectraswconfig.h */
-#define CMD_DMA 0
-
-#define SPECTRA_PARTITION_ID    0
-/**** Block Table and Reserved Block Parameters *****/
-#define SPECTRA_START_BLOCK     3
-#define NUM_FREE_BLOCKS_GATE    30
-
-/* KBV - Updated to LNW scratch register address */
-#define SCRATCH_REG_ADDR    CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR
-#define SCRATCH_REG_SIZE    64
-
-#define GLOB_HWCTL_DEFAULT_BLKS    2048
-
-#define CUSTOM_CONF_PARAMS      0
-
-#define INDEX_CTRL_REG    0x0
-#define INDEX_DATA_REG    0x10
-
-#define MODE_00    0x00000000
-#define MODE_01    0x04000000
-#define MODE_10    0x08000000
-#define MODE_11    0x0C000000
-
-
-#define DATA_TRANSFER_MODE              0
-#define PROTECTION_PER_BLOCK            1
-#define LOAD_WAIT_COUNT                 2
-#define PROGRAM_WAIT_COUNT              3
-#define ERASE_WAIT_COUNT                4
-#define INT_MONITOR_CYCLE_COUNT         5
-#define READ_BUSY_PIN_ENABLED           6
-#define MULTIPLANE_OPERATION_SUPPORT    7
-#define PRE_FETCH_MODE                  8
-#define CE_DONT_CARE_SUPPORT            9
-#define COPYBACK_SUPPORT                10
-#define CACHE_WRITE_SUPPORT             11
-#define CACHE_READ_SUPPORT              12
-#define NUM_PAGES_IN_BLOCK              13
-#define ECC_ENABLE_SELECT               14
-#define WRITE_ENABLE_2_READ_ENABLE      15
-#define ADDRESS_2_DATA                  16
-#define READ_ENABLE_2_WRITE_ENABLE      17
-#define TWO_ROW_ADDRESS_CYCLES          18
-#define MULTIPLANE_ADDRESS_RESTRICT     19
-#define ACC_CLOCKS                      20
-#define READ_WRITE_ENABLE_LOW_COUNT     21
-#define READ_WRITE_ENABLE_HIGH_COUNT    22
-
-#define ECC_SECTOR_SIZE     512
-
-#define DENALI_BUF_SIZE		(NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE)
-
-struct nand_buf {
-	int head;
-	int tail;
-	/* seprating dma_buf as buf can be used for status read purpose */
-	uint8_t dma_buf[DENALI_BUF_SIZE]  __aligned(64);
-	uint8_t buf[DENALI_BUF_SIZE];
-};
+#define     CHNL_ACTIVE__CHANNEL0			BIT(0)
+#define     CHNL_ACTIVE__CHANNEL1			BIT(1)
+#define     CHNL_ACTIVE__CHANNEL2			BIT(2)
+#define     CHNL_ACTIVE__CHANNEL3			BIT(3)
 
-#define INTEL_CE4100	1
-#define INTEL_MRST	2
-#define DT		3
+struct udevice;
 
 struct denali_nand_info {
 	struct nand_chip nand;
 	unsigned long clk_x_rate;	/* bus interface clock rate */
-	int flash_bank; /* currently selected chip */
-	int status;
-	int platform;
-	struct nand_buf buf;
-	struct device *dev;
-	int total_used_banks;
-	uint32_t block;  /* stored for future use */
+	int active_bank;		/* currently selected bank */
+	struct udevice *dev;
 	uint32_t page;
-	void __iomem *flash_reg;  /* Mapped io reg base address */
-	void __iomem *flash_mem;  /* Mapped io reg base address */
-
-	/* elements used by ISR */
-	/*struct completion complete;*/
-
-	uint32_t irq_status;
-	int irq_debug_array[32];
-	int idx;
+	void __iomem *reg;		/* Register Interface */
+	void __iomem *host;		/* Host Data/Command Interface */
+	u32 irq_mask;			/* interrupts we are waiting for */
+	u32 irq_status;			/* interrupts that have happened */
 	int irq;
-
-	uint32_t devnum;	/* represent how many nands connected */
-	uint32_t fwblks; /* represent how many blocks FW used */
-	uint32_t totalblks;
-	uint32_t blksperchip;
-	uint32_t bbtskipbytes;
-	uint32_t max_banks;
-	unsigned int revision;
-	unsigned int caps;
+	void *buf;			/* for syndrome layout conversion */
+	dma_addr_t dma_addr;
+	int dma_avail;			/* can support DMA? */
+	int devs_per_cs;		/* devices connected in parallel */
+	int oob_skip_bytes;		/* number of bytes reserved for BBM */
+	int max_banks;
+	unsigned int revision;		/* IP revision */
+	unsigned int caps;		/* IP capability (or quirk) */
+	const struct nand_ecc_caps *ecc_caps;
+	u32 (*host_read)(struct denali_nand_info *denali, u32 addr);
+	void (*host_write)(struct denali_nand_info *denali, u32 addr, u32 data);
+	void (*setup_dma)(struct denali_nand_info *denali, dma_addr_t dma_addr,
+			  int page, int write);
 };
 
 #define DENALI_CAP_HW_ECC_FIXUP			BIT(0)
 #define DENALI_CAP_DMA_64BIT			BIT(1)
 
+int denali_calc_ecc_bytes(int step_size, int strength);
 int denali_init(struct denali_nand_info *denali);
 
 #endif /* __DENALI_H__ */
diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c
index 805c066..9d6cb09 100644
--- a/drivers/mtd/nand/denali_dt.c
+++ b/drivers/mtd/nand/denali_dt.c
@@ -16,21 +16,31 @@
 struct denali_dt_data {
 	unsigned int revision;
 	unsigned int caps;
+	const struct nand_ecc_caps *ecc_caps;
 };
 
+NAND_ECC_CAPS_SINGLE(denali_socfpga_ecc_caps, denali_calc_ecc_bytes,
+		     512, 8, 15);
 static const struct denali_dt_data denali_socfpga_data = {
 	.caps = DENALI_CAP_HW_ECC_FIXUP,
+	.ecc_caps = &denali_socfpga_ecc_caps,
 };
 
+NAND_ECC_CAPS_SINGLE(denali_uniphier_v5a_ecc_caps, denali_calc_ecc_bytes,
+		     1024, 8, 16, 24);
 static const struct denali_dt_data denali_uniphier_v5a_data = {
 	.caps = DENALI_CAP_HW_ECC_FIXUP |
 		DENALI_CAP_DMA_64BIT,
+	.ecc_caps = &denali_uniphier_v5a_ecc_caps,
 };
 
+NAND_ECC_CAPS_SINGLE(denali_uniphier_v5b_ecc_caps, denali_calc_ecc_bytes,
+		     1024, 8, 16);
 static const struct denali_dt_data denali_uniphier_v5b_data = {
 	.revision = 0x0501,
 	.caps = DENALI_CAP_HW_ECC_FIXUP |
 		DENALI_CAP_DMA_64BIT,
+	.ecc_caps = &denali_uniphier_v5b_ecc_caps,
 };
 
 static const struct udevice_id denali_nand_dt_ids[] = {
@@ -61,19 +71,22 @@ static int denali_dt_probe(struct udevice *dev)
 	if (data) {
 		denali->revision = data->revision;
 		denali->caps = data->caps;
+		denali->ecc_caps = data->ecc_caps;
 	}
 
+	denali->dev = dev;
+
 	ret = dev_read_resource_byname(dev, "denali_reg", &res);
 	if (ret)
 		return ret;
 
-	denali->flash_reg = devm_ioremap(dev, res.start, resource_size(&res));
+	denali->reg = devm_ioremap(dev, res.start, resource_size(&res));
 
 	ret = dev_read_resource_byname(dev, "nand_data", &res);
 	if (ret)
 		return ret;
 
-	denali->flash_mem = devm_ioremap(dev, res.start, resource_size(&res));
+	denali->host = devm_ioremap(dev, res.start, resource_size(&res));
 
 	ret = clk_get_by_index(dev, 0, &clk);
 	if (ret)
diff --git a/drivers/mtd/nand/denali_spl.c b/drivers/mtd/nand/denali_spl.c
index c693032..3cb9849 100644
--- a/drivers/mtd/nand/denali_spl.c
+++ b/drivers/mtd/nand/denali_spl.c
@@ -11,6 +11,12 @@
 #include <linux/mtd/nand.h>
 #include "denali.h"
 
+#define DENALI_MAP01		(1 << 26)	/* read/write pages in PIO */
+#define DENALI_MAP10		(2 << 26)	/* high-level control plane */
+
+#define INDEX_CTRL_REG		0x0
+#define INDEX_DATA_REG		0x10
+
 #define SPARE_ACCESS		0x41
 #define MAIN_ACCESS		0x42
 #define PIPELINE_ACCESS		0x2000
@@ -39,7 +45,7 @@ static int wait_for_irq(uint32_t irq_mask)
 	do {
 		intr_status = readl(denali_flash_reg + INTR_STATUS(flash_bank));
 
-		if (intr_status & INTR_STATUS__ECC_UNCOR_ERR) {
+		if (intr_status & INTR__ECC_UNCOR_ERR) {
 			debug("Uncorrected ECC detected\n");
 			return -EBADMSG;
 		}
@@ -106,16 +112,16 @@ int denali_send_pipeline_cmd(int page, int ecc_en, int access_type)
 	addr = BANK(flash_bank) | page;
 
 	/* setup the acccess type */
-	cmd = MODE_10 | addr;
+	cmd = DENALI_MAP10 | addr;
 	index_addr(cmd, access_type);
 
 	/* setup the pipeline command */
 	index_addr(cmd, PIPELINE_ACCESS | page_count);
 
-	cmd = MODE_01 | addr;
+	cmd = DENALI_MAP01 | addr;
 	writel(cmd, denali_flash_mem + INDEX_CTRL_REG);
 
-	return wait_for_irq(INTR_STATUS__LOAD_COMP);
+	return wait_for_irq(INTR__LOAD_COMP);
 }
 
 static int nand_read_oob(void *buf, int page)
-- 
2.7.4

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

* [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver
  2017-11-21 17:38 [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
                   ` (21 preceding siblings ...)
  2017-11-21 17:38 ` [U-Boot] [PATCH 22/22] mtd: nand: denali: sync with Linux 4.15-rc1 Masahiro Yamada
@ 2017-11-28  0:35 ` Masahiro Yamada
  22 siblings, 0 replies; 29+ messages in thread
From: Masahiro Yamada @ 2017-11-28  0:35 UTC (permalink / raw)
  To: u-boot

2017-11-22 2:38 GMT+09:00 Masahiro Yamada <yamada.masahiro@socionext.com>:
>
> My motivation is to complete syncing the Denali driver with Linux.
>
> However, the last sync of NAND core was Linux 4.6
> so a lots of parts are missing in U-Boot.
>
> I imported the following:
>
>  - NAND_ECC_MAXIMIZE flag
>  - nand_data_interface
>  - sync nand_timings
>  - NAND_ECC_CUSTOM_PAGE_ACCESS
>  - mtd_ooblayout_xxx()
>  - chip->buf_align
>  - helpers to match ECC requirement
>  - NAND_ROW_ADDR_3
>
> The blind syncing often broke drivers.
>
> Forcible syncing often broke drivers in the past.
> This time, I imported necessary commits one by one.
> I put the corresponding commit ID in Linux.
> And, it should be easy to review that the existing drivers
> are not affected.
>
> Lastly, I updated the Denali driver.
> I tested it on my boards and worked for me.
> It is nicely synced with Linux.
>

Applied to u-boot-uniphier.




-- 
Best Regards
Masahiro Yamada

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

* [U-Boot] [PATCH 09/22] mtd: nand: automate NAND timings selection
  2017-11-21 17:38 ` [U-Boot] [PATCH 09/22] mtd: nand: automate NAND timings selection Masahiro Yamada
@ 2017-12-04 22:37   ` York Sun
  2017-12-05  0:30     ` Masahiro Yamada
  0 siblings, 1 reply; 29+ messages in thread
From: York Sun @ 2017-12-04 22:37 UTC (permalink / raw)
  To: u-boot

On 11/21/2017 09:47 AM, Masahiro Yamada wrote:
> From: Boris Brezillon <boris.brezillon@free-electrons.com>
> 
> The NAND framework provides several helpers to query timing modes supported
> by a NAND chip, but this implies that all NAND controller drivers have
> to implement the same timings selection dance. Also currently NAND
> devices can be resetted at arbitrary places which also resets the timing
> for ONFI chips to timing mode 0.
> 
> Provide a common logic to select the best timings based on ONFI or
> ->onfi_timing_mode_default information. Hook this into nand_reset()
> to make sure the new timing is applied each time during a reset.
> 
> NAND controller willing to support timings adjustment should just
> implement the ->setup_data_interface() method.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> [Linux commit: d8e725dd831186a3595036b2b1df9f68cbc6efa3]
> Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
> 
> ---
> 
>  drivers/mtd/nand/nand_base.c | 155 +++++++++++++++++++++++++++++++++++++++++++
>  include/linux/mtd/nand.h     |  14 ++--
>  2 files changed, 165 insertions(+), 4 deletions(-)
> 

I am having a weird problem with this patch. My board is T2080QDS,
powerpc-based. Booting from SD, if the environmental variable sectors
are invalid, the default variables are loaded. U-Boot crashes after
hitting a key to stop the autoboot. However, if the environmental
variables are valid (even with the default values), U-Boot is fine. Git
bisect points to this patch. I don't see a direct connection between
this patch and the failure. Any suggestion?

Please see the log with this commit (27c4792cd23) and one commit before
this (b893e83330662).

York


Log 1, failing case with invalid environment

SD boot...
Initializing....using SPD
WARNING: Calling __hwconfig without a buffer and before environment is ready
WARNING: Calling __hwconfig without a buffer and before environment is ready
WARNING: Calling __hwconfig without a buffer and before environment is ready
WARNING: Calling __hwconfig without a buffer and before environment is ready
6 GiB left unmapped


U-Boot 2017.11-00208-g27c4792 (Dec 04 2017 - 14:18:57 -0800)

CPU0:  T2080E, Version: 1.1, (0x85380011)
Core:  e6500, Version: 2.0, (0x80400120)
Clock Configuration:
       CPU0:1200 MHz, CPU1:1200 MHz, CPU2:1200 MHz, CPU3:1200 MHz,
       CCB:400  MHz,
       DDR:933.333 MHz (1866.667 MT/s data rate) (Asynchronous), IFC:400
 MHz
       FMAN1: 466.667 MHz
       QMAN:  200 MHz
       PME:   400 MHz
L1:    D-cache 32 KiB enabled
       I-cache 32 KiB enabled
Reset Configuration Word (RCW):
       00000000: 0c070012 0e000000 00000000 00000000
       00000010: 66150002 00000000 68104000 c1000000
       00000020: 00000000 00000000 00000000 000307fc
       00000030: 00000000 00000000 00000000 00000004
Board: T2080QDS, Sys ID: 0x28, Board Arch: V1, Board Version: A, boot
from SD/MMC
FPGA: v11 (T1040QDS_2014_0318_1724), build 317 on Tue Mar 18 21:24:26 2014
SERDES Reference Clocks:
SD1_CLK1=156.25MHZ, SD1_CLK2=100.00MHz
SD2_CLK1=100.00MHz, SD2_CLK2=100.00MHz
I2C:   ready
SPI:   ready
DRAM:  Detected UDIMM
6 GiB left unmapped
8 GiB (DDR3, 64-bit, CL=13, ECC on)
Flash: 128 MiB
L2:    2 MiB enabled
Corenet Platform Cache: 512 KiB enabled
Using SERDES1 Protocol: 102 (0x66)
Using SERDES2 Protocol: 21 (0x15)
SRIO1: disabled
SRIO2: disabled
RNG: Instantiation failed with error 2000025b
SEC0: RNG instantiated
NAND:  512 MiB
MMC:   FSL_SDHC: 0
*** Warning - bad CRC, using default environment

EEPROM: NXID v1
PCIe1: Root Complex, x1 gen1, regs @ 0xfe240000
  01:00.0     - 8086:107d - Network controller
PCIe1: Bus 00 - 01
PCIe2: Root Complex, no link, regs @ 0xfe250000
PCIe2: Bus 02 - 02
PCIe3: disabled
PCIe4: Root Complex, no link, regs @ 0xfe270000
PCIe4: Bus 03 - 03
In:    serial
Out:   serial
Err:   serial
Net:
MMC read: dev # 0, block # 2080, count 128 ...
Fman1: Data at 7faf67d0 is not a firmware
e1000#0: Out of Memory!
No ethernet found.
Hit any key to stop autoboot:  0
(York: Hit a key to stop the counting down here)
ERROR : memory not allocated

(Hanging here)


Log 2, passing case with invalid environment

SD boot...
Initializing....using SPD
WARNING: Calling __hwconfig without a buffer and before environment is ready
WARNING: Calling __hwconfig without a buffer and before environment is ready
WARNING: Calling __hwconfig without a buffer and before environment is ready
WARNING: Calling __hwconfig without a buffer and before environment is ready
6 GiB left unmapped


U-Boot 2017.11-00207-gb893e83 (Dec 04 2017 - 14:17:47 -0800)

CPU0:  T2080E, Version: 1.1, (0x85380011)
Core:  e6500, Version: 2.0, (0x80400120)
Clock Configuration:
       CPU0:1200 MHz, CPU1:1200 MHz, CPU2:1200 MHz, CPU3:1200 MHz,
       CCB:400  MHz,
       DDR:933.333 MHz (1866.667 MT/s data rate) (Asynchronous), IFC:400
 MHz
       FMAN1: 466.667 MHz
       QMAN:  200 MHz
       PME:   400 MHz
L1:    D-cache 32 KiB enabled
       I-cache 32 KiB enabled
Reset Configuration Word (RCW):
       00000000: 0c070012 0e000000 00000000 00000000
       00000010: 66150002 00000000 68104000 c1000000
       00000020: 00000000 00000000 00000000 000307fc
       00000030: 00000000 00000000 00000000 00000004
Board: T2080QDS, Sys ID: 0x28, Board Arch: V1, Board Version: A, boot
from SD/MMC
FPGA: v11 (T1040QDS_2014_0318_1724), build 317 on Tue Mar 18 21:24:26 2014
SERDES Reference Clocks:
SD1_CLK1=156.25MHZ, SD1_CLK2=100.00MHz
SD2_CLK1=100.00MHz, SD2_CLK2=100.00MHz
I2C:   ready
SPI:   ready
DRAM:  Detected UDIMM
6 GiB left unmapped
8 GiB (DDR3, 64-bit, CL=13, ECC on)
Flash: 128 MiB
L2:    2 MiB enabled
Corenet Platform Cache: 512 KiB enabled
Using SERDES1 Protocol: 102 (0x66)
Using SERDES2 Protocol: 21 (0x15)
SRIO1: disabled
SRIO2: disabled
RNG: Instantiation failed with error 2000025b
SEC0: RNG instantiated
NAND:  512 MiB
MMC:   FSL_SDHC: 0
*** Warning - bad CRC, using default environment

EEPROM: NXID v1
PCIe1: Root Complex, x1 gen1, regs @ 0xfe240000
  01:00.0     - 8086:107d - Network controller
PCIe1: Bus 00 - 01
PCIe2: Root Complex, no link, regs @ 0xfe250000
PCIe2: Bus 02 - 02
PCIe3: disabled
PCIe4: Root Complex, no link, regs @ 0xfe270000
PCIe4: Bus 03 - 03
In:    serial
Out:   serial
Err:   serial
Net:
MMC read: dev # 0, block # 2080, count 128 ...
Fman1: Data at 7faf67c0 is not a firmware
e1000: 00:15:17:bf:ed:40
       e1000#0
Warning: e1000#0 MAC addresses don't match:
Address in SROM is         00:15:17:bf:ed:40
Address in environment is  00:04:9f:03:0a:24

Hit any key to stop autoboot:  0
(York: hit a key to stop the counting down here)
=>
=>
=> saveenv
Saving Environment to MMC...
Writing to MMC(0)... done


Log 3, with valid environment, the failing case passes.

SD boot...
Initializing....using SPD
6 GiB left unmapped


U-Boot 2017.11-00208-g27c4792 (Dec 04 2017 - 14:33:34 -0800)

CPU0:  T2080E, Version: 1.1, (0x85380011)
Core:  e6500, Version: 2.0, (0x80400120)
Clock Configuration:
       CPU0:1200 MHz, CPU1:1200 MHz, CPU2:1200 MHz, CPU3:1200 MHz,
       CCB:400  MHz,
       DDR:933.333 MHz (1866.667 MT/s data rate) (Asynchronous), IFC:400
 MHz
       FMAN1: 466.667 MHz
       QMAN:  200 MHz
       PME:   400 MHz
L1:    D-cache 32 KiB enabled
       I-cache 32 KiB enabled
Reset Configuration Word (RCW):
       00000000: 0c070012 0e000000 00000000 00000000
       00000010: 66150002 00000000 68104000 c1000000
       00000020: 00000000 00000000 00000000 000307fc
       00000030: 00000000 00000000 00000000 00000004
Board: T2080QDS, Sys ID: 0x28, Board Arch: V1, Board Version: A, boot
from SD/MMC
FPGA: v11 (T1040QDS_2014_0318_1724), build 317 on Tue Mar 18 21:24:26 2014
SERDES Reference Clocks:
SD1_CLK1=156.25MHZ, SD1_CLK2=100.00MHz
SD2_CLK1=100.00MHz, SD2_CLK2=100.00MHz
I2C:   ready
SPI:   ready
DRAM:  Detected UDIMM
6 GiB left unmapped
8 GiB (DDR3, 64-bit, CL=13, ECC on)
       DDR Chip-Select Interleaving Mode: CS0+CS1
Flash: 128 MiB
L2:    2 MiB enabled
Corenet Platform Cache: 512 KiB enabled
Using SERDES1 Protocol: 102 (0x66)
Using SERDES2 Protocol: 21 (0x15)
SRIO1: disabled
SRIO2: disabled
RNG: Instantiation failed with error 2000025b
SEC0: RNG instantiated
NAND:  512 MiB
MMC:   FSL_SDHC: 0
EEPROM: NXID v1
PCIe1: Root Complex, x1 gen1, regs @ 0xfe240000
  01:00.0     - 8086:107d - Network controller
PCIe1: Bus 00 - 01
PCIe2: Root Complex, no link, regs @ 0xfe250000
PCIe2: Bus 02 - 02
PCIe3: disabled
PCIe4: Root Complex, no link, regs @ 0xfe270000
PCIe4: Bus 03 - 03
In:    serial
Out:   serial
Err:   serial
Net:
MMC read: dev # 0, block # 2080, count 128 ...
Fman1: Data at 7faf8f48 is not a firmware
e1000: 00:15:17:bf:ed:40
       e1000#0
Warning: e1000#0 MAC addresses don't match:
Address in SROM is         00:15:17:bf:ed:40
Address in environment is  00:04:9f:03:0a:24

Hit any key to stop autoboot:  0
=>
=>
=>
=>

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

* [U-Boot] [PATCH 09/22] mtd: nand: automate NAND timings selection
  2017-12-04 22:37   ` York Sun
@ 2017-12-05  0:30     ` Masahiro Yamada
  2017-12-05  0:34       ` York Sun
  2017-12-05 16:38       ` York Sun
  0 siblings, 2 replies; 29+ messages in thread
From: Masahiro Yamada @ 2017-12-05  0:30 UTC (permalink / raw)
  To: u-boot

2017-12-05 7:37 GMT+09:00 York Sun <york.sun@nxp.com>:
> On 11/21/2017 09:47 AM, Masahiro Yamada wrote:
>> From: Boris Brezillon <boris.brezillon@free-electrons.com>
>>
>> The NAND framework provides several helpers to query timing modes supported
>> by a NAND chip, but this implies that all NAND controller drivers have
>> to implement the same timings selection dance. Also currently NAND
>> devices can be resetted at arbitrary places which also resets the timing
>> for ONFI chips to timing mode 0.
>>
>> Provide a common logic to select the best timings based on ONFI or
>> ->onfi_timing_mode_default information. Hook this into nand_reset()
>> to make sure the new timing is applied each time during a reset.
>>
>> NAND controller willing to support timings adjustment should just
>> implement the ->setup_data_interface() method.
>>
>> Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
>> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
>> [Linux commit: d8e725dd831186a3595036b2b1df9f68cbc6efa3]
>> Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
>>
>> ---
>>
>>  drivers/mtd/nand/nand_base.c | 155 +++++++++++++++++++++++++++++++++++++++++++
>>  include/linux/mtd/nand.h     |  14 ++--
>>  2 files changed, 165 insertions(+), 4 deletions(-)
>>
>
> I am having a weird problem with this patch. My board is T2080QDS,
> powerpc-based. Booting from SD, if the environmental variable sectors
> are invalid, the default variables are loaded. U-Boot crashes after
> hitting a key to stop the autoboot. However, if the environmental
> variables are valid (even with the default values), U-Boot is fine. Git
> bisect points to this patch. I don't see a direct connection between
> this patch and the failure. Any suggestion?
>
> Please see the log with this commit (27c4792cd23) and one commit before
> this (b893e83330662).
>
> York
>
>
> Log 1, failing case with invalid environment
>
> SD boot...
> Initializing....using SPD
> WARNING: Calling __hwconfig without a buffer and before environment is ready
> WARNING: Calling __hwconfig without a buffer and before environment is ready
> WARNING: Calling __hwconfig without a buffer and before environment is ready
> WARNING: Calling __hwconfig without a buffer and before environment is ready
> 6 GiB left unmapped
>
>
> U-Boot 2017.11-00208-g27c4792 (Dec 04 2017 - 14:18:57 -0800)
>
> CPU0:  T2080E, Version: 1.1, (0x85380011)
> Core:  e6500, Version: 2.0, (0x80400120)
> Clock Configuration:
>        CPU0:1200 MHz, CPU1:1200 MHz, CPU2:1200 MHz, CPU3:1200 MHz,
>        CCB:400  MHz,
>        DDR:933.333 MHz (1866.667 MT/s data rate) (Asynchronous), IFC:400
>  MHz
>        FMAN1: 466.667 MHz
>        QMAN:  200 MHz
>        PME:   400 MHz
> L1:    D-cache 32 KiB enabled
>        I-cache 32 KiB enabled
> Reset Configuration Word (RCW):
>        00000000: 0c070012 0e000000 00000000 00000000
>        00000010: 66150002 00000000 68104000 c1000000
>        00000020: 00000000 00000000 00000000 000307fc
>        00000030: 00000000 00000000 00000000 00000004
> Board: T2080QDS, Sys ID: 0x28, Board Arch: V1, Board Version: A, boot
> from SD/MMC
> FPGA: v11 (T1040QDS_2014_0318_1724), build 317 on Tue Mar 18 21:24:26 2014
> SERDES Reference Clocks:
> SD1_CLK1=156.25MHZ, SD1_CLK2=100.00MHz
> SD2_CLK1=100.00MHz, SD2_CLK2=100.00MHz
> I2C:   ready
> SPI:   ready
> DRAM:  Detected UDIMM
> 6 GiB left unmapped
> 8 GiB (DDR3, 64-bit, CL=13, ECC on)
> Flash: 128 MiB
> L2:    2 MiB enabled
> Corenet Platform Cache: 512 KiB enabled
> Using SERDES1 Protocol: 102 (0x66)
> Using SERDES2 Protocol: 21 (0x15)
> SRIO1: disabled
> SRIO2: disabled
> RNG: Instantiation failed with error 2000025b
> SEC0: RNG instantiated
> NAND:  512 MiB
> MMC:   FSL_SDHC: 0
> *** Warning - bad CRC, using default environment
>
> EEPROM: NXID v1
> PCIe1: Root Complex, x1 gen1, regs @ 0xfe240000
>   01:00.0     - 8086:107d - Network controller
> PCIe1: Bus 00 - 01
> PCIe2: Root Complex, no link, regs @ 0xfe250000
> PCIe2: Bus 02 - 02
> PCIe3: disabled
> PCIe4: Root Complex, no link, regs @ 0xfe270000
> PCIe4: Bus 03 - 03
> In:    serial
> Out:   serial
> Err:   serial
> Net:
> MMC read: dev # 0, block # 2080, count 128 ...
> Fman1: Data at 7faf67d0 is not a firmware
> e1000#0: Out of Memory!


Looks like malloc() failed.


> No ethernet found.
> Hit any key to stop autoboot:  0
> (York: Hit a key to stop the counting down here)
> ERROR : memory not allocated


This error message comes from xmalloc() or xrealloc().



I think your board grew in size by my commit.


Does disabling some features solve your problem?





-- 
Best Regards
Masahiro Yamada

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

* [U-Boot] [PATCH 09/22] mtd: nand: automate NAND timings selection
  2017-12-05  0:30     ` Masahiro Yamada
@ 2017-12-05  0:34       ` York Sun
  2017-12-05 16:38       ` York Sun
  1 sibling, 0 replies; 29+ messages in thread
From: York Sun @ 2017-12-05  0:34 UTC (permalink / raw)
  To: u-boot

On 12/04/2017 04:31 PM, Masahiro Yamada wrote:
> 2017-12-05 7:37 GMT+09:00 York Sun <york.sun@nxp.com>:
>> On 11/21/2017 09:47 AM, Masahiro Yamada wrote:
>>> From: Boris Brezillon <boris.brezillon@free-electrons.com>
>>>
>>> The NAND framework provides several helpers to query timing modes supported
>>> by a NAND chip, but this implies that all NAND controller drivers have
>>> to implement the same timings selection dance. Also currently NAND
>>> devices can be resetted at arbitrary places which also resets the timing
>>> for ONFI chips to timing mode 0.
>>>
>>> Provide a common logic to select the best timings based on ONFI or
>>> ->onfi_timing_mode_default information. Hook this into nand_reset()
>>> to make sure the new timing is applied each time during a reset.
>>>
>>> NAND controller willing to support timings adjustment should just
>>> implement the ->setup_data_interface() method.
>>>
>>> Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
>>> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
>>> [Linux commit: d8e725dd831186a3595036b2b1df9f68cbc6efa3]
>>> Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
>>>
>>> ---
>>>
>>>  drivers/mtd/nand/nand_base.c | 155 +++++++++++++++++++++++++++++++++++++++++++
>>>  include/linux/mtd/nand.h     |  14 ++--
>>>  2 files changed, 165 insertions(+), 4 deletions(-)
>>>
>>
>> I am having a weird problem with this patch. My board is T2080QDS,
>> powerpc-based. Booting from SD, if the environmental variable sectors
>> are invalid, the default variables are loaded. U-Boot crashes after
>> hitting a key to stop the autoboot. However, if the environmental
>> variables are valid (even with the default values), U-Boot is fine. Git
>> bisect points to this patch. I don't see a direct connection between
>> this patch and the failure. Any suggestion?
>>
>> Please see the log with this commit (27c4792cd23) and one commit before
>> this (b893e83330662).
>>
>> York
>>
>>
>> Log 1, failing case with invalid environment
>>
>> SD boot...
>> Initializing....using SPD
>> WARNING: Calling __hwconfig without a buffer and before environment is ready
>> WARNING: Calling __hwconfig without a buffer and before environment is ready
>> WARNING: Calling __hwconfig without a buffer and before environment is ready
>> WARNING: Calling __hwconfig without a buffer and before environment is ready
>> 6 GiB left unmapped
>>
>>
>> U-Boot 2017.11-00208-g27c4792 (Dec 04 2017 - 14:18:57 -0800)
>>
>> CPU0:  T2080E, Version: 1.1, (0x85380011)
>> Core:  e6500, Version: 2.0, (0x80400120)
>> Clock Configuration:
>>        CPU0:1200 MHz, CPU1:1200 MHz, CPU2:1200 MHz, CPU3:1200 MHz,
>>        CCB:400  MHz,
>>        DDR:933.333 MHz (1866.667 MT/s data rate) (Asynchronous), IFC:400
>>  MHz
>>        FMAN1: 466.667 MHz
>>        QMAN:  200 MHz
>>        PME:   400 MHz
>> L1:    D-cache 32 KiB enabled
>>        I-cache 32 KiB enabled
>> Reset Configuration Word (RCW):
>>        00000000: 0c070012 0e000000 00000000 00000000
>>        00000010: 66150002 00000000 68104000 c1000000
>>        00000020: 00000000 00000000 00000000 000307fc
>>        00000030: 00000000 00000000 00000000 00000004
>> Board: T2080QDS, Sys ID: 0x28, Board Arch: V1, Board Version: A, boot
>> from SD/MMC
>> FPGA: v11 (T1040QDS_2014_0318_1724), build 317 on Tue Mar 18 21:24:26 2014
>> SERDES Reference Clocks:
>> SD1_CLK1=156.25MHZ, SD1_CLK2=100.00MHz
>> SD2_CLK1=100.00MHz, SD2_CLK2=100.00MHz
>> I2C:   ready
>> SPI:   ready
>> DRAM:  Detected UDIMM
>> 6 GiB left unmapped
>> 8 GiB (DDR3, 64-bit, CL=13, ECC on)
>> Flash: 128 MiB
>> L2:    2 MiB enabled
>> Corenet Platform Cache: 512 KiB enabled
>> Using SERDES1 Protocol: 102 (0x66)
>> Using SERDES2 Protocol: 21 (0x15)
>> SRIO1: disabled
>> SRIO2: disabled
>> RNG: Instantiation failed with error 2000025b
>> SEC0: RNG instantiated
>> NAND:  512 MiB
>> MMC:   FSL_SDHC: 0
>> *** Warning - bad CRC, using default environment
>>
>> EEPROM: NXID v1
>> PCIe1: Root Complex, x1 gen1, regs @ 0xfe240000
>>   01:00.0     - 8086:107d - Network controller
>> PCIe1: Bus 00 - 01
>> PCIe2: Root Complex, no link, regs @ 0xfe250000
>> PCIe2: Bus 02 - 02
>> PCIe3: disabled
>> PCIe4: Root Complex, no link, regs @ 0xfe270000
>> PCIe4: Bus 03 - 03
>> In:    serial
>> Out:   serial
>> Err:   serial
>> Net:
>> MMC read: dev # 0, block # 2080, count 128 ...
>> Fman1: Data at 7faf67d0 is not a firmware
>> e1000#0: Out of Memory!
> 
> 
> Looks like malloc() failed.
> 
> 
>> No ethernet found.
>> Hit any key to stop autoboot:  0
>> (York: Hit a key to stop the counting down here)
>> ERROR : memory not allocated
> 
> 
> This error message comes from xmalloc() or xrealloc().
> 
> 
> 
> I think your board grew in size by my commit.
> 
> 
> Does disabling some features solve your problem?
> 

Hmm, _this_ patch doesn't add much. I will try again with some features
removed.

York

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

* [U-Boot] [PATCH 09/22] mtd: nand: automate NAND timings selection
  2017-12-05  0:30     ` Masahiro Yamada
  2017-12-05  0:34       ` York Sun
@ 2017-12-05 16:38       ` York Sun
  2017-12-05 19:48         ` York Sun
  1 sibling, 1 reply; 29+ messages in thread
From: York Sun @ 2017-12-05 16:38 UTC (permalink / raw)
  To: u-boot

On 12/04/2017 04:31 PM, Masahiro Yamada wrote:
>> Err:   serial
>> Net:
>> MMC read: dev # 0, block # 2080, count 128 ...
>> Fman1: Data at 7faf67d0 is not a firmware
>> e1000#0: Out of Memory!
> 
> 
> Looks like malloc() failed.
> 
> 
>> No ethernet found.
>> Hit any key to stop autoboot:  0
>> (York: Hit a key to stop the counting down here)
>> ERROR : memory not allocated
> 
> 
> This error message comes from xmalloc() or xrealloc().
> 
> 
> 
> I think your board grew in size by my commit.
> 
> 
> Does disabling some features solve your problem?
> 
I tried to disable USB feature and reduced the image size, but that
didn't fix this issue. I don't believe NAND driver has anything to do
with this issue though. I will keep debugging.

York

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

* [U-Boot] [PATCH 09/22] mtd: nand: automate NAND timings selection
  2017-12-05 16:38       ` York Sun
@ 2017-12-05 19:48         ` York Sun
  0 siblings, 0 replies; 29+ messages in thread
From: York Sun @ 2017-12-05 19:48 UTC (permalink / raw)
  To: u-boot

On 12/05/2017 08:38 AM, York Sun wrote:
> On 12/04/2017 04:31 PM, Masahiro Yamada wrote:
>>> Err:   serial
>>> Net:
>>> MMC read: dev # 0, block # 2080, count 128 ...
>>> Fman1: Data at 7faf67d0 is not a firmware
>>> e1000#0: Out of Memory!
>>
>>
>> Looks like malloc() failed.
>>
>>
>>> No ethernet found.
>>> Hit any key to stop autoboot:  0
>>> (York: Hit a key to stop the counting down here)
>>> ERROR : memory not allocated
>>
>>
>> This error message comes from xmalloc() or xrealloc().
>>
>>
>>
>> I think your board grew in size by my commit.
>>
>>
>> Does disabling some features solve your problem?
>>
> I tried to disable USB feature and reduced the image size, but that
> didn't fix this issue. I don't believe NAND driver has anything to do
> with this issue though. I will keep debugging.
> 

I think I found the root cause. It is dcache related. I am testing on
more platform before sending out a patch.

Sorry for the noise.

York

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

end of thread, other threads:[~2017-12-05 19:48 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-21 17:38 [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada
2017-11-21 17:38 ` [U-Boot] [PATCH 01/22] bitops: collect BIT macros to include/linux/bitops.h Masahiro Yamada
2017-11-21 17:38 ` [U-Boot] [PATCH 02/22] mtd: nand: add onfi_* stubs in case ONFI_DETECTION is disabled Masahiro Yamada
2017-11-21 17:38 ` [U-Boot] [PATCH 03/22] mtd: nand: Add an option to maximize the ECC strength Masahiro Yamada
2017-11-21 17:38 ` [U-Boot] [PATCH 04/22] mtd: nand: remove unnecessary 'extern' from function declarations Masahiro Yamada
2017-11-21 17:38 ` [U-Boot] [PATCH 05/22] mtd: nand: Create a NAND reset function Masahiro Yamada
2017-11-21 17:38 ` [U-Boot] [PATCH 06/22] mtd: nand: Introduce nand_data_interface Masahiro Yamada
2017-11-21 17:38 ` [U-Boot] [PATCH 07/22] mtd: nand: convert ONFI mode into data interface Masahiro Yamada
2017-11-21 17:38 ` [U-Boot] [PATCH 08/22] mtd: nand: Expose data interface for ONFI mode 0 Masahiro Yamada
2017-11-21 17:38 ` [U-Boot] [PATCH 09/22] mtd: nand: automate NAND timings selection Masahiro Yamada
2017-12-04 22:37   ` York Sun
2017-12-05  0:30     ` Masahiro Yamada
2017-12-05  0:34       ` York Sun
2017-12-05 16:38       ` York Sun
2017-12-05 19:48         ` York Sun
2017-11-21 17:38 ` [U-Boot] [PATCH 10/22] mtd: nand: Fix data interface configuration logic Masahiro Yamada
2017-11-21 17:38 ` [U-Boot] [PATCH 11/22] mtd: nand: Add a few more timings to nand_sdr_timings Masahiro Yamada
2017-11-21 17:38 ` [U-Boot] [PATCH 12/22] mtd: nand: Support controllers with custom page Masahiro Yamada
2017-11-21 17:38 ` [U-Boot] [PATCH 13/22] mtd: add mtd_ooblayout_xxx() helper functions Masahiro Yamada
2017-11-21 17:38 ` [U-Boot] [PATCH 14/22] mtd: nand: Drop unused cached programming support Masahiro Yamada
2017-11-21 17:38 ` [U-Boot] [PATCH 15/22] mtd: nand: Drop the ->errstat() hook Masahiro Yamada
2017-11-21 17:38 ` [U-Boot] [PATCH 16/22] mtd: nand: Wait for PAGEPROG to finish in drivers setting NAND_ECC_CUSTOM_PAGE_ACCESS Masahiro Yamada
2017-11-21 17:38 ` [U-Boot] [PATCH 17/22] mtd: nand: allow drivers to request minimum alignment for passed buffer Masahiro Yamada
2017-11-21 17:38 ` [U-Boot] [PATCH 18/22] mtd: nand: Pass the CS line to ->setup_data_interface() Masahiro Yamada
2017-11-21 17:38 ` [U-Boot] [PATCH 19/22] mtd: nand: add generic helpers to check, match, maximize ECC settings Masahiro Yamada
2017-11-21 17:38 ` [U-Boot] [PATCH 20/22] mtd: nand: add a shorthand to generate nand_ecc_caps structure Masahiro Yamada
2017-11-21 17:38 ` [U-Boot] [PATCH 21/22] mtd: nand: introduce NAND_ROW_ADDR_3 flag Masahiro Yamada
2017-11-21 17:38 ` [U-Boot] [PATCH 22/22] mtd: nand: denali: sync with Linux 4.15-rc1 Masahiro Yamada
2017-11-28  0:35 ` [U-Boot] [PATCH 00/22] mtd: nand: imports NAND core updates from Linux 4.15-rc1 and sync Denali driver Masahiro Yamada

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.