Skip to contentSkip to conversation

arm: iproc: add NAND driver

PATCH New Steve Rae 2 participants 2 messages Aug 9, 2015 – Aug 12, 2015

Subsystems (4)
lore
Share & tools
lore

Steve Rae

author
#0 lore raw

PATCH 1/1 arm: iproc: add NAND driver

From: Jiandong Zheng <[email protected]>

Add support for the iproc NAND, and enable on Cygnus and NSP boards.

---

 arch/arm/include/asm/arch-bcmcygnus/configs.h |   11 +
 arch/arm/include/asm/arch-bcmnsp/configs.h    |   11 +
 drivers/mtd/nand/Makefile                     |    1 +
 drivers/mtd/nand/iproc_nand.c                 | 1732 +++++++++++++++++++++++++
 drivers/mtd/nand/iproc_nand_cygnus.h          |  111 ++
 drivers/mtd/nand/iproc_nand_ns_plus.h         |  113 ++
 6 files changed, 1979 insertions(+)
 create mode 100644 drivers/mtd/nand/iproc_nand.c
 create mode 100644 drivers/mtd/nand/iproc_nand_cygnus.h
 create mode 100644 drivers/mtd/nand/iproc_nand_ns_plus.h
arch/arm/include/asm/arch-bcmcygnus/configs.h +11 -0
index 5354637..5338598 100644
@@ -10,6 +10,7 @@
 #include <asm/iproc-common/configs.h>
 
 /* uArchitecture specifics */
+#define CONFIG_CYGNUS
 
 /* Serial Info */
 /* Post pad 3 bytes after each reg addr */
@@ -22,4 +23,14 @@
 #define CONFIG_CONS_INDEX		3
 #define CONFIG_SYS_NS16550_COM3		0x18023000
 
+/* NAND configuration */
+#define CONFIG_CMD_NAND
+#define CONFIG_NAND_IPROC
+#define CONFIG_IPROC_NAND_TIMING_MODE	5
+#define CONFIG_SYS_NAND_BASE		0
+#define CONFIG_SYS_MAX_NAND_DEVICE	1
+#define CONFIG_SYS_MAX_NAND_CHIPS	1
+#define CONFIG_SYS_NAND_SELF_INIT
+#define CONFIG_SYS_NAND_ONFI_DETECTION
+
 #endif /* __ARCH_CONFIGS_H */
arch/arm/include/asm/arch-bcmnsp/configs.h +11 -0
index 786deae..66f2266 100644
@@ -10,6 +10,7 @@
 #include <asm/iproc-common/configs.h>
 
 /* uArchitecture specifics */
+#define CONFIG_NS_PLUS
 
 /* Serial Info */
 /* no padding */
@@ -19,4 +20,14 @@
 #define CONFIG_CONS_INDEX		1
 #define CONFIG_SYS_NS16550_COM1		0x18000300
 
+/* NAND configuration */
+#define CONFIG_CMD_NAND
+#define CONFIG_NAND_IPROC
+#define CONFIG_IPROC_NAND_TIMING_MODE	5
+#define CONFIG_SYS_NAND_BASE		0
+#define CONFIG_SYS_MAX_NAND_DEVICE	1
+#define CONFIG_SYS_MAX_NAND_CHIPS	1
+#define CONFIG_SYS_NAND_SELF_INIT
+#define CONFIG_SYS_NAND_ONFI_DETECTION
+
 #endif /* __ARCH_CONFIGS_H */
drivers/mtd/nand/Makefile +1 -0
index 347ea62..e111b1a 100644
@@ -48,6 +48,7 @@ obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o
 obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o
 obj-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o
 obj-$(CONFIG_NAND_FSMC) += fsmc_nand.o
+obj-$(CONFIG_NAND_IPROC) += iproc_nand.o
 obj-$(CONFIG_NAND_JZ4740) += jz4740_nand.o
 obj-$(CONFIG_NAND_KB9202) += kb9202_nand.o
 obj-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o
drivers/mtd/nand/iproc_nand.c new file +1732 -0

1,732 lines not on this page · raw message

drivers/mtd/nand/iproc_nand_cygnus.h new file +111 -0

111 lines not on this page · raw message

drivers/mtd/nand/iproc_nand_ns_plus.h new file +113 -0

113 lines not on this page · raw message

Signature · 1 line
1.8.5
#1 lore raw

PATCH 1/1 arm: iproc: add NAND driver

Quoted 24 lines · Steve Rae

From: Jiandong Zheng <[email protected]>

Add support for the iproc NAND, and enable on Cygnus and NSP boards.

---

 arch/arm/include/asm/arch-bcmcygnus/configs.h |   11 +
 arch/arm/include/asm/arch-bcmnsp/configs.h    |   11 +
 drivers/mtd/nand/Makefile                     |    1 +
 drivers/mtd/nand/iproc_nand.c                 | 1732 +++++++++++++++++++++++++
 drivers/mtd/nand/iproc_nand_cygnus.h          |  111 ++
 drivers/mtd/nand/iproc_nand_ns_plus.h         |  113 ++
 6 files changed, 1979 insertions(+)
 create mode 100644 drivers/mtd/nand/iproc_nand.c
 create mode 100644 drivers/mtd/nand/iproc_nand_cygnus.h
 create mode 100644 drivers/mtd/nand/iproc_nand_ns_plus.h
arch/arm/include/asm/arch-bcmcygnus/configs.h +0 -0
index 5354637..5338598 100644

arch/arm/include/asm/arch-bcmcygnus/configs.h line 13

Quoted 4 lines
arch/arm/include/asm/arch-bcmcygnus/configs.h +1 -0
@@ -10,6 +10,7 @@
 #include <asm/iproc-common/configs.h>
 
 /* uArchitecture specifics */
+#define CONFIG_CYGNUS

Undocumented, should be in kconfig, and the name is too vague.

Quoted 5 lines
arch/arm/include/asm/arch-bcmcygnus/configs.h +0 -0
 /* Serial Info */
 /* Post pad 3 bytes after each reg addr */
@@ -22,4 +23,14 @@
 #define CONFIG_CONS_INDEX		3
 #define CONFIG_SYS_NS16550_COM3		0x18023000

arch/arm/include/asm/arch-bcmcygnus/configs.h line 34

Quoted 10 lines
arch/arm/include/asm/arch-bcmcygnus/configs.h +9 -0
 
+/* NAND configuration */
+#define CONFIG_CMD_NAND
+#define CONFIG_NAND_IPROC
+#define CONFIG_IPROC_NAND_TIMING_MODE	5
+#define CONFIG_SYS_NAND_BASE		0
+#define CONFIG_SYS_MAX_NAND_DEVICE	1
+#define CONFIG_SYS_MAX_NAND_CHIPS	1
+#define CONFIG_SYS_NAND_SELF_INIT
+#define CONFIG_SYS_NAND_ONFI_DETECTION

CONFIG_IPROC_NAND_TIMING_MODE and CONFIG_NAND_IPROC are undocumented, and new symbols should be done in kconfig.

Please be consistent about CONFIG_NAND_IPROC* versus CONFIG_IPROC_NAND* (I prefer the former).

If this timing mode is describing hardware, rather than user config, it should be CONFIG_SYS_NAND_IPROC_TIMING_MODE.

arch/arm/include/asm/arch-bcmnsp/configs.h line 13

Quoted 10 lines
arch/arm/include/asm/arch-bcmcygnus/configs.h +0 -0
 #endif /* __ARCH_CONFIGS_H */
arch/arm/include/asm/arch-bcmnsp/configs.h +1 -0
index 786deae..66f2266 100644
@@ -10,6 +10,7 @@
 #include <asm/iproc-common/configs.h>
 
 /* uArchitecture specifics */
+#define CONFIG_NS_PLUS

Undocumented, should be in kconfig, and the name is too vague.

arch/arm/include/asm/arch-bcmnsp/configs.h

Quoted 4 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +4 -0
+/*
+ * Definitions
+ */
+#define DRV_NAME			"iproc_nand"

I suggest using __func__ instead.

arch/arm/include/asm/arch-bcmnsp/configs.h

Quoted 6 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +6 -0
+/*
+ * IRQ operations
+ */
+#define NAND_ACK_IRQ(bit) writel(1, ((u32 *)ctrl.nand_intr_regs) + (bit))
+
+#define NAND_TEST_IRQ(bit) (readl(((u32 *)ctrl.nand_intr_regs) + (bit)) & 1)

This is the only place you ever use nand_intr_regs, so why not just define it as a u32 pointer? Also, use __iomem.

Quoted 7 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +7 -0
+
+/*
+ * Data access macros for endianness
+ */
+#ifdef __LITTLE_ENDIAN
+#define NAND_BEGIN_DATA_ACCESS()					\
+	writel(readl(ctrl.nand_idm_io_ctrl_direct_reg) |		\

arch/arm/include/asm/arch-bcmnsp/configs.h

Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10 -0
+	       IDMFLD_NAND_IO_CONTROL_DIRECT_APB_LE_MODE,		\
+	       ctrl.nand_idm_io_ctrl_direct_reg)
+#define NAND_END_DATA_ACCESS()						\
+	writel(readl(ctrl.nand_idm_io_ctrl_direct_reg) &		\
+	       ~IDMFLD_NAND_IO_CONTROL_DIRECT_APB_LE_MODE,		\
+	       ctrl.nand_idm_io_ctrl_direct_reg)
+#else				/* !__LITTLE_ENDIAN */
+#define NAND_BEGIN_DATA_ACCESS()
+#define NAND_END_DATA_ACCESS()
+#endif				/* !__LITTLE_ENDIAN */

Huh?

Quoted 41 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +41 -0
+
+/*
+ * Misc NAND controller configuration/status macros
+ */
+#define NC_REG_CONFIG(cs) (NCREG_CONFIG_CS0 + ((cs) << 4))
+
+#define WR_CONFIG(cs, field, val) do {					\
+	u32 reg = NC_REG_CONFIG(cs), contents = NAND_REG_RD(reg);	\
+	contents &= ~(NCFLD_CONFIG_CS0_##field##_MASK);			\
+	contents |= (val) << NCFLD_CONFIG_CS0_##field##_SHIFT;		\
+	NAND_REG_WR(reg, contents);					\
+} while (0)
+
+#define RD_CONFIG(cs, field)						\
+	((NAND_REG_RD(NC_REG_CONFIG(cs)) & NCFLD_CONFIG_CS0_##field##_MASK) \
+	>> NCFLD_CONFIG_CS0_##field##_SHIFT)
+
+#define NC_REG_ACC_CONTROL(cs) (NCREG_ACC_CONTROL_CS0 + ((cs) << 4))
+
+#define WR_ACC_CONTROL(cs, field, val) do {				\
+	u32 reg = NC_REG_ACC_CONTROL(cs), contents = NAND_REG_RD(reg);	\
+	contents &= ~(NCFLD_ACC_CONTROL_CS0_##field##_MASK);		\
+	contents |= (val) << NCFLD_ACC_CONTROL_CS0_##field##_SHIFT;	\
+	NAND_REG_WR(reg, contents);					\
+} while (0)
+
+#define RD_ACC_CONTROL(cs, field)					\
+	((NAND_REG_RD(NC_REG_ACC_CONTROL(cs)) &				\
+	 NCFLD_ACC_CONTROL_CS0_##field##_MASK)				\
+	 >> NCFLD_ACC_CONTROL_CS0_##field##_SHIFT)
+
+#define CORR_ERROR_COUNT (NAND_REG_RD(NCREG_CORR_ERROR_COUNT))
+#define UNCORR_ERROR_COUNT (NAND_REG_RD(NCREG_UNCORR_ERROR_COUNT))
+
+#define WR_CORR_THRESH(cs, val) do {					\
+	u32 contents = NAND_REG_RD(NCREG_CORR_STAT_THRESHOLD);		\
+	u32 shift = NCFLD_CORR_STAT_THRESHOLD_CS1_SHIFT * (cs);		\
+	contents &= ~(NCFLD_CORR_STAT_THRESHOLD_CS0_MASK << shift);	\
+	contents |= ((val) & NCFLD_CORR_STAT_THRESHOLD_CS0_MASK) << shift; \
+	NAND_REG_WR(NCREG_CORR_STAT_THRESHOLD, contents);		\
+} while (0)

arch/arm/include/asm/arch-bcmnsp/configs.h

Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10 -0
+
+#define NC_REG_TIMING1(cs) (NCREG_TIMING_1_CS0 + ((cs) << 4))
+#define NC_REG_TIMING2(cs) (NCREG_TIMING_2_CS0 + ((cs) << 4))
+
+#define NAND_STRAP_TYPE							\
+	((readl(ctrl.nand_strap_regs) & ctrl.data->strap_type_bitfield.mask) \
+	>> ctrl.data->strap_type_bitfield.shift)
+#define NAND_STRAP_PAGE							\
+	((readl(ctrl.nand_strap_regs) & ctrl.data->strap_page_bitfield.mask) \
+	>> ctrl.data->strap_page_bitfield.shift)

Please use functions instead of macros where possible.

Quoted 4 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +4 -0
+
+/*
+ * Internal structures
+ */

arch/arm/include/asm/arch-bcmnsp/configs.h

Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10 -0
+struct nand_strap_type {
+	uint8_t sector_1k;
+	uint8_t ecc_level;
+	uint16_t spare_size;
+};
+
+struct nand_strap_bitfield {
+	uint32_t mask;
+	uint32_t shift;
+};

What does "strap" mean here?

arch/arm/include/asm/arch-bcmnsp/configs.h

Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10 -0
+/*
+ * Internal support functions
+ */
+static inline int fls64(u64 x)
+{
+	u32 h = x >> 32;
+	if (h)
+		return fls(h) + 32;
+	return fls(x);
+}

Put this in a generic header.

arch/arm/include/asm/arch-bcmnsp/configs.h

Quoted 9 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +9 -0
+/*
+ * NAND MTD API: read/program/erase
+ */
+
+static void iproc_nand_cmd_ctrl(struct mtd_info *mtd,
+				int dat, unsigned int ctrl)
+{
+	/* intentionally left blank */
+}

Leave cmd_ctrl NULL instead of making it empty.

Quoted 70 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +70 -0
+static int iproc_nand_read(struct mtd_info *mtd,
+			   struct nand_chip *chip, u64 addr, unsigned int trans,
+			   u32 *buf, u8 *oob)
+{
+	struct iproc_nand_host *host = chip->priv;
+	u64 start_addr = addr;
+	int i;
+	int oob_bytes;
+	unsigned int max_bitflips, bitflips;
+	unsigned int corr_error_count, uncorr_error_count;
+	u32 *sector_buf = buf;
+	u8 *sector_oob = oob;
+
+	debug("%s %llx -> %p (trans %x)\n", __func__,
+	      (unsigned long long)addr, buf, trans);
+
+	BUG_ON(!oob);
+
+	NAND_ACK_IRQ(NCINTR_UNC);
+	NAND_ACK_IRQ(NCINTR_CORR);
+	max_bitflips = 0;
+	corr_error_count = 0;
+	uncorr_error_count = 0;
+
+	NAND_REG_WR(NCREG_CMD_EXT_ADDRESS,
+		    (host->cs << 16) | ((addr >> 32) & 0xffff));
+
+	for (i = 0; i < trans; i++, addr += FC_BYTES) {
+		if (!host->hwcfg.sector_size_1k || ((i & 0x1) == 0)) {
+			sector_buf = buf;
+			sector_oob = oob;
+		}
+
+		NAND_REG_WR(NCREG_CMD_ADDRESS, addr & 0xffffffff);
+
+		if (ctrl.data_cache_invalid) {
+			if ((i == 0) && RD_ACC_CONTROL(host->cs, PAGE_HIT_EN))
+				/*
+				 * temporarily disable the PAGE_HIT to force
+				 * data to be read from NAND
+				 */
+				WR_ACC_CONTROL(host->cs, PAGE_HIT_EN, 0);
+			else
+				ctrl.data_cache_invalid = 0;
+		}
+
+		/* SPARE_AREA_READ does not use ECC, so just use PAGE_READ */
+		iproc_nand_send_cmd(CMD_PAGE_READ);
+		iproc_nand_waitfunc(mtd, chip);
+
+		/* OOB bytes per sector */
+		oob_bytes = (mtd->oobsize / trans) <<
+				host->hwcfg.sector_size_1k;
+		/* OOB bytes per 512B transfer */
+		if (host->hwcfg.sector_size_1k && (i & 0x01))
+			oob_bytes = max(0, oob_bytes -
+					MAX_CONTROLLER_OOB_BYTES);
+		oob_bytes = min(oob_bytes, MAX_CONTROLLER_OOB_BYTES);
+
+		iproc_nand_cache_read(&buf, &oob, oob_bytes);
+
+		if (ctrl.data_cache_invalid) {
+			/* re-enable PAGE_HIT */
+			WR_ACC_CONTROL(host->cs, PAGE_HIT_EN, 1);
+			ctrl.data_cache_invalid = 0;
+		}
+
+		if (buf && (!host->hwcfg.sector_size_1k || (i & 0x1))) {
+			/* check uncorrectable errors */
+			if (NAND_TEST_IRQ(NCINTR_UNC)) {

arch/arm/include/asm/arch-bcmnsp/configs.h

Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10 -0
+				if (erased_sector(mtd,
+						  (u8 *)sector_buf,
+						  sector_oob,
+						  &bitflips)) {
+					corr_error_count += bitflips;
+					if (bitflips > max_bitflips)
+						max_bitflips = bitflips;
+				} else {
+					uncorr_error_count += 1;
+				}

This level of indentation should be a hint that this function needs to be broken up into smaller ones.

Quoted 31 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +31 -0
+				NAND_ACK_IRQ(NCINTR_UNC);
+				ctrl.data_cache_invalid = 1;
+			}
+			/* check correctable errors */
+			if (NAND_TEST_IRQ(NCINTR_CORR)) {
+				bitflips = CORR_ERROR_COUNT;
+				corr_error_count += bitflips;
+				if (bitflips > max_bitflips)
+					max_bitflips = bitflips;
+				NAND_ACK_IRQ(NCINTR_CORR);
+				ctrl.data_cache_invalid = 1;
+			}
+		}
+	}
+	if (uncorr_error_count) {
+		printf(DRV_NAME ": %d uncorrectable errors at 0x%llx\n",
+		       uncorr_error_count, (unsigned long long)start_addr);
+		mtd->ecc_stats.failed += uncorr_error_count;
+		/* NAND layer expects zero on ECC errors */
+		return 0;
+	}
+	if (max_bitflips) {
+		debug("%s: corrected %d bit errors at 0x%llx\n",
+		      __func__, max_bitflips, (unsigned long long)start_addr);
+		mtd->ecc_stats.corrected += corr_error_count;
+		return max_bitflips;
+	}
+
+	return 0;
+}
+

arch/arm/include/asm/arch-bcmnsp/configs.h

Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10 -0
+static int iproc_nand_read_page(struct mtd_info *mtd,
+				struct nand_chip *chip,
+				uint8_t *buf,
+				int oob_required,
+				int page)
+{
+	struct iproc_nand_host *host = chip->priv;
+
+	BUG_ON(!buf);
+

What's with all these !buf checks? Do you think it's more likely that you'll get a NULL buf than any of the other pointers that get passed in?

Quoted 6 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +6 -0
+static int iproc_nand_mark_bad(struct mtd_info *mtd, loff_t ofs)
+{
+	struct nand_chip *chip = mtd->priv;
+	u64 blk_addr = (u64)ofs;
+
+	debug("%s %llx\n", __func__, (unsigned long long)ofs);

arch/arm/include/asm/arch-bcmnsp/configs.h

Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10 -0
+
+	/* get NAND block address */
+	blk_addr &= ~((1 << chip->phys_erase_shift) - 1);
+
+	memset(chip->oob_poi, 0xff, mtd->oobsize);
+	chip->oob_poi[chip->badblockpos] = 0;
+
+	return iproc_nand_write(mtd, chip, blk_addr, NULL,
+				(u8 *)chip->oob_poi);
+}

Why do you need a custom version of this?

Quoted 8 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +8 -0
+
+/*
+ * Per-CS setup (1 NAND device)
+ */
+
+static const unsigned int block_sizes[] = { 8, 16, 128, 256, 512, 1024, 2048 };
+static const unsigned int page_sizes[] = { 512, 2048, 4096, 8192 };
+

arch/arm/include/asm/arch-bcmnsp/configs.h

Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10 -0
+static void iproc_nand_set_cfg(struct iproc_nand_host *host,
+			       struct iproc_nand_cfg *cfg)
+{
+	int i, found;
+
+	for (i = 0, found = 0; i < ARRAY_SIZE(block_sizes); i++)
+		if ((block_sizes[i] << 10) == cfg->block_size) {
+			WR_CONFIG(host->cs, BLOCK_SIZE, i);
+			found = 1;
+		}

U-Boot coding style requires braces around multiline statements.

Quoted 59 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +59 -0
+	debug("%s: mtd configuration\n"
+	      "\tdevice_size 0x%llx\n"
+	      "\tblock_size 0x%x\n"
+	      "\tpage_size 0x%x\n"
+	      "\tdevice_width 0x%x\n"
+	      "\tcol_adr_bytes 0x%x\n"
+	      "\tblk_adr_bytes 0x%x\n"
+	      "\tspare_area_size 0x%x\n"
+	      "\tecc_level 0x%x\n"
+	      "\tsector_size_1k 0x%x\n",
+	      __func__,
+	      new_cfg.device_size,
+	      new_cfg.block_size,
+	      new_cfg.page_size,
+	      new_cfg.device_width,
+	      new_cfg.col_adr_bytes,
+	      new_cfg.blk_adr_bytes,
+	      new_cfg.spare_area_size,
+	      new_cfg.ecc_level,
+	      new_cfg.sector_size_1k);
+
+	/* check settings determined by controller auto-init */
+	if (ctrl.auto_inited) {
+		debug("%s: auto-init configuration\n"
+		      "\tdevice_size 0x%llx\n"
+		      "\tblock_size 0x%x\n"
+		      "\tpage_size 0x%x\n"
+		      "\tdevice_width 0x%x\n"
+		      "\tcol_adr_bytes 0x%x\n"
+		      "\tblk_adr_bytes 0x%x\n"
+		      "\tspare_area_size 0x%x\n"
+		      "\tecc_level 0x%x\n"
+		      "\tsector_size_1k 0x%x\n",
+		      __func__,
+		      orig_cfg.device_size,
+		      orig_cfg.block_size,
+		      orig_cfg.page_size,
+		      orig_cfg.device_width,
+		      orig_cfg.col_adr_bytes,
+		      orig_cfg.blk_adr_bytes,
+		      orig_cfg.spare_area_size,
+		      orig_cfg.ecc_level,
+		      orig_cfg.sector_size_1k);
+		/* check basic device attributes first */
+		if (orig_cfg.device_size != new_cfg.device_size ||
+		    orig_cfg.block_size != new_cfg.block_size ||
+		    orig_cfg.page_size != new_cfg.page_size ||
+		    orig_cfg.device_width != new_cfg.device_width ||
+		    orig_cfg.col_adr_bytes != new_cfg.col_adr_bytes ||
+		    orig_cfg.blk_adr_bytes != new_cfg.blk_adr_bytes ||
+		    orig_cfg.ful_adr_bytes != new_cfg.ful_adr_bytes ||
+		    orig_cfg.ecc_level == 0 ||
+		    ((orig_cfg.ecc_code == ECC_CODE_BCH) &&
+		     (orig_cfg.ecc_level >
+		      iproc_max_bch_ecc_level[orig_cfg.sector_size_1k])) ||
+		    orig_cfg.spare_area_size > new_cfg.spare_area_size ||
+		    ((orig_cfg.ecc_code == ECC_CODE_BCH) &&
+		     (iproc_bch_ecc_bytes[orig_cfg.ecc_level] >
+		      orig_cfg.spare_area_size))) {

arch/arm/include/asm/arch-bcmnsp/configs.h

Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10 -0
+			/* ignore invalid auto-init settings */
+			ctrl.auto_inited = 0;
+			printf(DRV_NAME ": invalid auto-init settings\n");
+
+		} else {
+			/* auto-init has initialized the flash correctly. */
+			new_cfg = orig_cfg;
+			printf(DRV_NAME ": following auto-init settings\n");
+		}
+	}

This is a bit elaborate... what is "auto-init"?

Quoted 5 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +5 -0
+static void iproc_nand_timing_setup(struct iproc_nand_host *host)
+{
+	struct nand_chip *chip = &host->chip;
+	int onfi_tmode; /* bit mask of supported onfi timing modes */
+

arch/arm/include/asm/arch-bcmnsp/configs.h

Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10 -0
+	/*
+	 * ctrl.tmode has the configured tmode upper limit [0-5]
+	 * or is -1 to indicate power-on default timing
+	 */
+	if (ctrl.tmode < 0 || ctrl.tmode >= ONFI_TIMING_MODES)
+		return;
+
+	if (chip->onfi_version) {
+		onfi_tmode = le16_to_cpu(get_unaligned(
+				(u16 *)&chip->onfi_params.async_timing_mode));

Fix onfi_get_async_timing_mode() instead, and have it use get_unaligned_le16().

Quoted 12 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +12 -0
+		if ((onfi_tmode == 0) || (onfi_tmode & ~0x3F)) { 
+			printf(DRV_NAME
+			       ": invalid ONFI timing mode ignored 0x%x\n",
+			       onfi_tmode);
+		} else {
+			/*
+			 * select the maximum supported ONFI timing mode
+			 * that is lower than the configured limit
+			 */
+			while (ctrl.tmode > 0) {
+				if (onfi_tmode & (1 << ctrl.tmode))
+					break;

arch/arm/include/asm/arch-bcmnsp/configs.h

Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10 -0
+				ctrl.tmode--;
+			}
+		}
+	}
+
+	NAND_REG_WR(NC_REG_TIMING1(host->cs),
+		    ctrl.data->onfi_tmode[ctrl.tmode].timing1);
+	NAND_REG_WR(NC_REG_TIMING2(host->cs),
+		    ctrl.data->onfi_tmode[ctrl.tmode].timing2);
+	printf(DRV_NAME ": timing mode %d\n", ctrl.tmode);

This verbosity is not appropriate for normal driver init.

Quoted 20 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +20 -0
+#ifdef CONFIG_SYS_MAX_NAND_CHIPS
+#if (CONFIG_SYS_MAX_NAND_CHIPS > NAND_MAX_CS)
+#error "Invalid CONFIG_SYS_MAX_NAND_CHIPS value"
+#endif
+	ctrl.max_cs = CONFIG_SYS_MAX_NAND_CHIPS;
+#else
+	ctrl.max_cs = 1;
+#endif
+
+	/* write protect configuration */
+#ifdef CONFIG_IPROC_NAND_WP_MODE
+#if ((CONFIG_IPROC_NAND_WP_MODE < 0) || \
+	(CONFIG_IPROC_NAND_WP_MODE > WP_ALWAYS_CLEARED))
+#error "Invalid CONFIG_IPROC_NAND_WP_MODE value"
+#endif
+	ctrl.wp_mode = CONFIG_IPROC_NAND_WP_MODE;
+#else
+	ctrl.wp_mode = WP_SET_BY_DEFAULT;
+#endif
+

arch/arm/include/asm/arch-bcmnsp/configs.h

Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10 -0
+	/* timing mode configuration */
+#ifdef CONFIG_IPROC_NAND_TIMING_MODE
+#if ((CONFIG_IPROC_NAND_TIMING_MODE < 0) || \
+	(CONFIG_IPROC_NAND_TIMING_MODE >= ONFI_TIMING_MODES))
+#error "Invalid CONFIG_IPROC_NAND_TIMING_MODE value"
+#endif
+	ctrl.tmode = CONFIG_IPROC_NAND_TIMING_MODE;
+#else
+	ctrl.tmode = -1; /* use default timing configuration */
+#endif

These would be more readable as:

#ifdef CONFIG_FOO
#define CONFIG_FOO <default_value>
#endif

...

BUILD_BUG_ON(CONFIG_FOO is bad);
ctrl.foo = CONFIG_FOO;

arch/arm/include/asm/arch-bcmnsp/configs.h

Quoted 8 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +8 -0
+	debug("%s: nand_regs %p\n", __func__, ctrl.nand_regs);
+	debug("%s: nand_intr_regs %p\n", __func__, ctrl.nand_intr_regs);
+	debug("%s: nand_idm_regs %p\n", __func__, ctrl.nand_idm_regs);
+	debug("%s: nand_idm_io_ctrl_direct_reg %p\n", __func__,
+	      ctrl.nand_idm_io_ctrl_direct_reg);
+	debug("%s: nand_strap_regs %p\n", __func__, ctrl.nand_strap_regs);
+	debug("%s: max_cs %d\n", __func__, ctrl.max_cs);
+	debug("%s: wp_mode %d\n", __func__, ctrl.wp_mode);

This driver has a lot of debug clutter. Is it really

Quoted 1 line

+#ifdef CONFIG_IPROC_NAND_AUTO_INIT

Undocumented, and should be in kconfig.

Quoted 19 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +19 -0
+int iproc_nand_init(void)
+{
+	struct iproc_nand_host *host;
+	struct mtd_info *mtd;
+	struct nand_chip *chip;
+
+	NAND_REG_WR(NCREG_SEMAPHORE, 0);
+
+	host = &nand_host;
+	memset(host, 0, sizeof(*host));
+
+	host->mtd = &nand_info[0];
+
+	host->cs = 0;
+
+	mtd = host->mtd;
+	chip = &host->chip;
+
+	chip->priv = host;

arch/arm/include/asm/arch-bcmnsp/configs.h

Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10 -0
+	mtd->priv = chip;
+	mtd->name = "iproc_nand";
+	/*
+	 * set mtd bitflip threshold to 1 as the desired threshold will
+	 * be set in the controller register.
+	 */
+	mtd->bitflip_threshold = 1;
+
+	chip->IO_ADDR_R = (void *)0xdeadbeef;
+	chip->IO_ADDR_W = (void *)0xdeadbeef;

Why?

Quoted 22 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +22 -0
+	chip->cmd_ctrl = iproc_nand_cmd_ctrl;
+	chip->cmdfunc = iproc_nand_cmdfunc;
+	chip->waitfunc = iproc_nand_waitfunc;
+	chip->read_byte = iproc_nand_read_byte;
+	chip->read_buf = iproc_nand_read_buf;
+	if (ctrl.max_cs > 1)
+		chip->select_chip = iproc_nand_select_chip;
+
+	chip->block_bad = iproc_nand_block_bad;
+	chip->block_markbad = iproc_nand_mark_bad;
+
+	chip->ecc.mode = NAND_ECC_HW;
+	chip->ecc.layout = &iproc_nand_oob_layout;
+	chip->ecc.read_page = iproc_nand_read_page;
+	chip->ecc.write_page = iproc_nand_write_page;
+	chip->ecc.read_page_raw = iproc_nand_read_page_raw;
+	chip->ecc.write_page_raw = iproc_nand_write_page_raw;
+
+	chip->ecc.write_oob_raw = iproc_nand_write_oob_raw;
+	chip->ecc.read_oob_raw = iproc_nand_read_oob_raw;
+
+	chip->ecc.read_oob = (void *)iproc_nand_read_oob;

arch/arm/include/asm/arch-bcmnsp/configs.h

Quoted 10 lines
arch/arm/include/asm/arch-bcmnsp/configs.h +10 -0
+	chip->ecc.write_oob = iproc_nand_write_oob;
+
+	chip->controller = &ctrl.controller;
+
+	if (nand_scan_ident(mtd, ctrl.max_cs, NULL))
+		return -ENXIO;
+
+	chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_SKIP_BBTSCAN;
+
+	chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;

Why skip the BBT scan?

-Scott