[U-Boot-Users] [PATCH] Update MTD NAND to Linux-2.6.14

Ladislav Michl ladis at linux-mips.org
Thu Nov 3 13:05:23 CET 2005


Generated against testing-NAND branch.

Signed-off-by: Ladislav Michl <ladis at linux-mips.org>

CHANGELOG:
* Update NAND code to be based on what is in Linux-2.6.14
  Patch by Ladislav Michl, 3 Nov 2005

diff -Naurw a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
--- a/include/linux/mtd/nand.h	2005-11-03 12:48:27.000000000 +0100
+++ b/include/linux/mtd/nand.h	2005-11-03 12:49:41.000000000 +0100
@@ -5,7 +5,7 @@
  *                     Steven J. Hill <sjhill at realitydiluted.com>
  *		       Thomas Gleixner <tglx at linutronix.de>
  *
- * $Id: nand.h,v 1.68 2004/11/12 10:40:37 gleixner Exp $
+ * $Id: nand.h,v 1.73 2005/05/31 19:39:17 gleixner Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -48,12 +48,15 @@
  *  02-08-2004 tglx 	added option field to nand structure for chip anomalities
  *  05-25-2004 tglx 	added bad block table support, ST-MICRO manufacturer id
  *			update of nand_chip structure description
+ *  01-17-2005 dmarlin	added extended commands for AG-AND device and added option 
+ * 			for BBT_AUTO_REFRESH.
+ *  01-20-2005 dmarlin	added optional pointer to hardware specific callback for 
+ *			extra error status checks.
  */
 #ifndef __LINUX_MTD_NAND_H
 #define __LINUX_MTD_NAND_H
 
 #include <linux/mtd/compat.h>
-#include <linux/mtd/mtd.h>
 
 struct mtd_info;
 /* Scan and identify a NAND device */
@@ -113,6 +116,25 @@
 #define NAND_CMD_READSTART	0x30
 #define NAND_CMD_CACHEDPROG	0x15
 
+/* Extended commands for AG-AND device */
+/* 
+ * Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but 
+ *       there is no way to distinguish that from NAND_CMD_READ0
+ *       until the remaining sequence of commands has been completed
+ *       so add a high order bit and mask it off in the command.
+ */
+#define NAND_CMD_DEPLETE1	0x100
+#define NAND_CMD_DEPLETE2	0x38
+#define NAND_CMD_STATUS_MULTI	0x71
+#define NAND_CMD_STATUS_ERROR	0x72
+/* multi-bank error status (banks 0-3) */
+#define NAND_CMD_STATUS_ERROR0	0x73
+#define NAND_CMD_STATUS_ERROR1	0x74
+#define NAND_CMD_STATUS_ERROR2	0x75
+#define NAND_CMD_STATUS_ERROR3	0x76
+#define NAND_CMD_STATUS_RESET	0x7f
+#define NAND_CMD_STATUS_CLEAR	0xff
+
 /* Status bits */
 #define NAND_STATUS_FAIL	0x01
 #define NAND_STATUS_FAIL_N1	0x02
@@ -149,6 +171,10 @@
 /* Enable Hardware ECC before syndrom is read back from flash */
 #define NAND_ECC_READSYN	2
 
+/* Bit mask for flags passed to do_nand_read_ecc */
+#define NAND_GET_DEVICE		0x80
+
+
 /* Option constants for bizarre disfunctionality and real
 *  features
 */
@@ -168,6 +194,10 @@
 /* Chip has a array of 4 pages which can be read without
  * additional ready /busy waits */
 #define NAND_4PAGE_ARRAY	0x00000040
+/* Chip requires that BBT is periodically rewritten to prevent
+ * bits from adjacent blocks from 'leaking' in altering data.
+ * This happens with the Renesas AG-AND chips, possibly others.  */
+#define BBT_AUTO_REFRESH	0x00000080
 
 /* Options valid for Samsung large page devices */
 #define NAND_SAMSUNG_LP_OPTIONS \
@@ -190,7 +220,8 @@
  * This can only work if we have the ecc bytes directly behind the
  * data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */
 #define NAND_HWECC_SYNDROME	0x00020000
-
+/* This option skips the bbt scan during initialization. */
+#define NAND_SKIP_BBTSCAN	0x00040000
 
 /* Options set by nand scan */
 /* Nand scan has allocated oob_buf */
@@ -215,15 +246,18 @@
 /* Keep gcc happy */
 struct nand_chip;
 
-#if 0
 /**
  * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independend devices
  * @lock:               protection lock
  * @active:		the mtd device which holds the controller currently
+ * @wq:			wait queue to sleep on if a NAND operation is in progress
+ *                      used instead of the per chip wait queue when a hw controller is available
  */
+#if 0
 struct nand_hw_control {
 	spinlock_t	 lock;
 	struct nand_chip *active;
+	wait_queue_head_t wq;
 };
 #endif
 
@@ -283,6 +317,8 @@
  * @badblock_pattern:	[REPLACEABLE] bad block scan pattern used for initial bad block scan
  * @controller:		[OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices
  * @priv:		[OPTIONAL] pointer to private chip date
+ * @errstat:		[OPTIONAL] hardware specific function to perform additional error status checks 
+ *			(determine if errors are correctable)
  */
 
 struct nand_chip {
@@ -338,8 +374,9 @@
 	struct nand_bbt_descr	*bbt_td;
 	struct nand_bbt_descr	*bbt_md;
 	struct nand_bbt_descr	*badblock_pattern;
-	struct nand_hw_control  *controller;
+/*	struct nand_hw_control  *controller; */
 	void		*priv;
+	int		(*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page);
 };
 
 /*
@@ -351,6 +388,7 @@
 #define NAND_MFR_NATIONAL	0x8f
 #define NAND_MFR_RENESAS	0x07
 #define NAND_MFR_STMICRO	0x20
+#define NAND_MFR_HYNIX          0xad
 
 /**
  * struct nand_flash_dev - NAND Flash Device ID Structure
@@ -461,6 +499,9 @@
 extern int nand_default_bbt (struct mtd_info *mtd);
 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 allowbbt);
+extern int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
+                             size_t * retlen, u_char * buf, u_char * oob_buf,
+                             struct nand_oobinfo *oobsel, int flags);
 
 /*
 * Constants for oob configuration
diff -Naurw drivers/nand/diskonchip.c drivers/nand.orig/diskonchip.c
--- a/drivers/nand/diskonchip.c	2005-11-03 12:42:45.000000000 +0100
+++ b/drivers/nand/diskonchip.c	2005-11-03 10:04:07.000000000 +0100
@@ -16,7 +16,7 @@
  *
  * Interface to generic NAND code for M-Systems DiskOnChip devices
  *
- * $Id: diskonchip.c,v 1.45 2005/01/05 18:05:14 dwmw2 Exp $
+ * $Id: diskonchip.c,v 1.54 2005/04/07 14:22:55 dbrown Exp $
  */
 
 #include <linux/kernel.h>
@@ -35,13 +35,13 @@
 #include <linux/mtd/inftl.h>
 
 /* Where to look for the devices? */
-#ifndef CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS
-#define CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS 0
+#ifndef CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS
+#define CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS 0
 #endif
 
 static unsigned long __initdata doc_locations[] = {
 #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
-#ifdef CONFIG_MTD_DISKONCHIP_PROBE_HIGH
+#ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH
 	0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000,
 	0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
 	0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
@@ -81,11 +81,6 @@
 	struct mtd_info *nextdoc;
 };
 
-/* Max number of eraseblocks to scan (from start of device) for the (I)NFTL
-   MediaHeader.  The spec says to just keep going, I think, but that's just
-   silly. */
-#define MAX_MEDIAHEADER_SCAN 8
-
 /* This is the syndrome computed by the HW ecc generator upon reading an empty
    page, one with all 0xff for data and stored ecc code. */
 static u_char empty_read_syndrome[6] = { 0x26, 0xff, 0x6d, 0x47, 0x73, 0x7a };
@@ -111,10 +106,11 @@
 static int no_ecc_failures=0;
 module_param(no_ecc_failures, int, 0);
 
-#ifdef CONFIG_MTD_PARTITIONS
 static int no_autopart=0;
 module_param(no_autopart, int, 0);
-#endif
+
+static int show_firmware_partition=0;
+module_param(show_firmware_partition, int, 0);
 
 #ifdef MTD_NAND_DISKONCHIP_BBTWRITE
 static int inftl_bbt_write=1;
@@ -123,7 +119,7 @@
 #endif
 module_param(inftl_bbt_write, int, 0);
 
-static unsigned long doc_config_location = CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS;
+static unsigned long doc_config_location = CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS;
 module_param(doc_config_location, ulong, 0);
 MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
 
@@ -411,6 +407,11 @@
 	this->write_byte(mtd, 0);
 	doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
 
+	/* We cant' use dev_ready here, but at least we wait for the
+	 * command to complete 
+	 */
+	udelay(50);
+	
 	ret = this->read_byte(mtd) << 8;
 	ret |= this->read_byte(mtd);
 
@@ -429,6 +430,8 @@
 		doc2000_write_byte(mtd, 0);
 		doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
 
+		udelay(50);
+
 		ident.dword = readl(docptr + DoC_2k_CDSN_IO);
 		if (((ident.byte[0] << 8) | ident.byte[1]) == ret) {
 			printk(KERN_INFO "DiskOnChip 2000 responds to DWORD access\n");
@@ -492,11 +495,11 @@
 	struct doc_priv *doc = this->priv;
 	void __iomem *docptr = doc->virtadr;
 
-	/*ReadDOC(docptr, CDSNSlowIO); */
+	//ReadDOC(docptr, CDSNSlowIO);
 	/* 11.4.5 -- delay twice to allow extended length cycle */
 	DoC_Delay(doc, 2);
 	ReadDOC(docptr, ReadPipeInit);
-	/*return ReadDOC(docptr, Mil_CDSN_IO); */
+	//return ReadDOC(docptr, Mil_CDSN_IO);
 	return ReadDOC(docptr, LastDataRead);
 }
 
@@ -1044,13 +1047,23 @@
 	return ret;
 }
 
-/*u_char mydatabuf[528]; */
+//u_char mydatabuf[528];
 
+/* The strange out-of-order .oobfree list below is a (possibly unneeded)
+ * attempt to retain compatibility.  It used to read:
+ * 	.oobfree = { {8, 8} }
+ * Since that leaves two bytes unusable, it was changed.  But the following
+ * scheme might affect existing jffs2 installs by moving the cleanmarker:
+ * 	.oobfree = { {6, 10} }
+ * jffs2 seems to handle the above gracefully, but the current scheme seems
+ * safer.  The only problem with it is that any code that parses oobfree must
+ * be able to handle out-of-order segments.
+ */
 static struct nand_oobinfo doc200x_oobinfo = {
 	.useecc = MTD_NANDECC_AUTOPLACE,
 	.eccbytes = 6,
 	.eccpos = {0, 1, 2, 3, 4, 5},
-	.oobfree = { {8, 8} }
+        .oobfree = { {8, 8}, {6, 2} }
 };
 
 /* Find the (I)NFTL Media Header, and optionally also the mirror media header.
@@ -1064,12 +1077,11 @@
 {
 	struct nand_chip *this = mtd->priv;
 	struct doc_priv *doc = this->priv;
-	unsigned offs, end = (MAX_MEDIAHEADER_SCAN << this->phys_erase_shift);
+	unsigned offs;
 	int ret;
 	size_t retlen;
 
-	end = min(end, mtd->size); /* paranoia */
-	for (offs = 0; offs < end; offs += mtd->erasesize) {
+	for (offs = 0; offs < mtd->size; offs += mtd->erasesize) {
 		ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf);
 		if (retlen != mtd->oobblock) continue;
 		if (ret) {
@@ -1111,6 +1123,7 @@
 	u_char *buf;
 	struct NFTLMediaHeader *mh;
 	const unsigned psize = 1 << this->page_shift;
+	int numparts = 0;
 	unsigned blocks, maxblocks;
 	int offs, numheaders;
 
@@ -1122,8 +1135,10 @@
 	if (!(numheaders=find_media_headers(mtd, buf, "ANAND", 1))) goto out;
 	mh = (struct NFTLMediaHeader *) buf;
 
-/*#ifdef CONFIG_MTD_DEBUG_VERBOSE */
-/*	if (CONFIG_MTD_DEBUG_VERBOSE >= 2) */
+	mh->NumEraseUnits = le16_to_cpu(mh->NumEraseUnits);
+	mh->FirstPhysicalEUN = le16_to_cpu(mh->FirstPhysicalEUN);
+	mh->FormattedSize = le32_to_cpu(mh->FormattedSize);
+
 	printk(KERN_INFO "    DataOrgID        = %s\n"
 			 "    NumEraseUnits    = %d\n"
 			 "    FirstPhysicalEUN = %d\n"
@@ -1132,7 +1147,6 @@
 		mh->DataOrgID, mh->NumEraseUnits,
 		mh->FirstPhysicalEUN, mh->FormattedSize,
 		mh->UnitSizeFactor);
-/*#endif */
 
 	blocks = mtd->size >> this->phys_erase_shift;
 	maxblocks = min(32768U, mtd->erasesize - psize);
@@ -1175,23 +1189,28 @@
 	offs <<= this->page_shift;
 	offs += mtd->erasesize;
 
-	/*parts[0].name = " DiskOnChip Boot / Media Header partition"; */
-	/*parts[0].offset = 0; */
-	/*parts[0].size = offs; */
-
-	parts[0].name = " DiskOnChip BDTL partition";
-	parts[0].offset = offs;
-	parts[0].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;
+	if (show_firmware_partition == 1) {
+		parts[0].name = " DiskOnChip Firmware / Media Header partition";
+		parts[0].offset = 0;
+		parts[0].size = offs;
+		numparts = 1;
+	}
+
+	parts[numparts].name = " DiskOnChip BDTL partition";
+	parts[numparts].offset = offs;
+	parts[numparts].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;
+
+	offs += parts[numparts].size;
+	numparts++;
 
-	offs += parts[0].size;
 	if (offs < mtd->size) {
-		parts[1].name = " DiskOnChip Remainder partition";
-		parts[1].offset = offs;
-		parts[1].size = mtd->size - offs;
-		ret = 2;
-		goto out;
+		parts[numparts].name = " DiskOnChip Remainder partition";
+		parts[numparts].offset = offs;
+		parts[numparts].size = mtd->size - offs;
+		numparts++;
 	}
-	ret = 1;
+
+	ret = numparts;
 out:
 	kfree(buf);
 	return ret;
@@ -1233,8 +1252,6 @@
 	mh->FormatFlags = le32_to_cpu(mh->FormatFlags);
 	mh->PercentUsed = le32_to_cpu(mh->PercentUsed);
 
-/*#ifdef CONFIG_MTD_DEBUG_VERBOSE */
-/*	if (CONFIG_MTD_DEBUG_VERBOSE >= 2) */
 	printk(KERN_INFO "    bootRecordID          = %s\n"
 			 "    NoOfBootImageBlocks   = %d\n"
 			 "    NoOfBinaryPartitions  = %d\n"
@@ -1252,7 +1269,6 @@
 		((unsigned char *) &mh->OsakVersion)[2] & 0xf,
 		((unsigned char *) &mh->OsakVersion)[3] & 0xf,
 		mh->PercentUsed);
-/*#endif */
 
 	vshift = this->phys_erase_shift + mh->BlockMultiplierBits;
 
@@ -1278,8 +1294,6 @@
 		ip->spareUnits = le32_to_cpu(ip->spareUnits);
 		ip->Reserved0 = le32_to_cpu(ip->Reserved0);
 
-/*#ifdef CONFIG_MTD_DEBUG_VERBOSE */
-/*		if (CONFIG_MTD_DEBUG_VERBOSE >= 2) */
 		printk(KERN_INFO	"    PARTITION[%d] ->\n"
 			"        virtualUnits    = %d\n"
 			"        firstUnit       = %d\n"
@@ -1289,16 +1303,14 @@
 			i, ip->virtualUnits, ip->firstUnit,
 			ip->lastUnit, ip->flags,
 			ip->spareUnits);
-/*#endif */
 
-/*
-		if ((i == 0) && (ip->firstUnit > 0)) {
+		if ((show_firmware_partition == 1) &&
+		    (i == 0) && (ip->firstUnit > 0)) {
 			parts[0].name = " DiskOnChip IPL / Media Header partition";
 			parts[0].offset = 0;
 			parts[0].size = mtd->erasesize * ip->firstUnit;
 			numparts = 1;
 		}
-*/
 
 		if (ip->flags & INFTL_BINARY)
 			parts[numparts].name = " DiskOnChip BDK partition";
@@ -1614,11 +1626,11 @@
 		if (ChipID == DOC_ChipID_DocMilPlus16) {
 			WriteDOC(~newval, virtadr, Mplus_AliasResolution);
 			oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
-			WriteDOC(newval, virtadr, Mplus_AliasResolution); /* restore it */
+			WriteDOC(newval, virtadr, Mplus_AliasResolution); // restore it
 		} else {
 			WriteDOC(~newval, virtadr, AliasResolution);
 			oldval = ReadDOC(doc->virtadr, AliasResolution);
-			WriteDOC(newval, virtadr, AliasResolution); /* restore it */
+			WriteDOC(newval, virtadr, AliasResolution); // restore it
 		}
 		newval = ~newval;
 		if (oldval == newval) {
diff -Naurw drivers/nand/nand_base.c drivers/nand.orig/nand_base.c
--- a/drivers/nand/nand_base.c	2005-11-03 12:42:45.000000000 +0100
+++ b/drivers/nand/nand_base.c	2005-11-03 10:43:21.000000000 +0100
@@ -28,6 +28,24 @@
  *		among multiple independend devices. Suggestions and initial patch
  *		from Ben Dooks <ben-mtd at fluff.org>
  *
+ *  12-05-2004	dmarlin: add workaround for Renesas AG-AND chips "disturb" issue.
+ *		Basically, any block not rewritten may lose data when surrounding blocks
+ *		are rewritten many times.  JFFS2 ensures this doesn't happen for blocks 
+ *		it uses, but the Bad Block Table(s) may not be rewritten.  To ensure they
+ *		do not lose data, force them to be rewritten when some of the surrounding
+ *		blocks are erased.  Rather than tracking a specific nearby block (which 
+ *		could itself go bad), use a page address 'mask' to select several blocks 
+ *		in the same area, and rewrite the BBT when any of them are erased.
+ *
+ *  01-03-2005	dmarlin: added support for the device recovery command sequence for Renesas 
+ *		AG-AND chips.  If there was a sudden loss of power during an erase operation,
+ * 		a "device recovery" operation must be performed when power is restored
+ * 		to ensure correct operation.
+ *
+ *  01-20-2005	dmarlin: added support for optional hardware specific callback routine to 
+ *		perform extra error status checks on erase and write failures.  This required
+ *		adding a wrapper function for nand_read_ecc.
+ *
  * Credits:
  *	David Woodhouse for adding multichip support
  *
@@ -41,7 +59,7 @@
  *	The AG-AND chips have nice features for speed improvement,
  *	which are not supported yet. Read / program 4 pages in one go.
  *
- * $Id: nand_base.c,v 1.126 2004/12/13 11:22:25 lavinen Exp $
+ * $Id: nand_base.c,v 1.147 2005/07/15 07:18:06 gleixner Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -176,18 +194,22 @@
 
 	/* De-select the NAND device */
 	this->select_chip(mtd, -1);
-	/* Do we have a hardware controller ? */
+
 	if (this->controller) {
+		/* Release the controller and the chip */
 		spin_lock(&this->controller->lock);
 		this->controller->active = NULL;
+		this->state = FL_READY;
+		wake_up(&this->controller->wq);
 		spin_unlock(&this->controller->lock);
-	}
+	} else {
 	/* Release the chip */
 	spin_lock (&this->chip_lock);
 	this->state = FL_READY;
 	wake_up (&this->wq);
 	spin_unlock (&this->chip_lock);
 }
+}
 #else
 static void nand_release_device (struct mtd_info *mtd)
 {
@@ -477,6 +499,7 @@
 
 	/* Get block number */
 	block = ((int) ofs) >> this->bbt_erase_shift;
+	if (this->bbt)
 	this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
 
 	/* Do we have a flash based bad block table ? */
@@ -500,7 +523,7 @@
 	struct nand_chip *this = mtd->priv;
 	/* Check the WP bit */
 	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
-	return (this->read_byte(mtd) & 0x80) ? 0 : 1;
+	return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; 
 }
 
 /**
@@ -524,6 +547,39 @@
 	return nand_isbad_bbt (mtd, ofs, allowbbt);
 }
 
+/* 
+ * Wait for the ready pin, after a command
+ * The timeout is catched later.
+ */
+/* XXX U-BOOT XXX */
+#if 0
+static void nand_wait_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *this = mtd->priv;
+	unsigned long	timeo = jiffies + 2;
+
+	/* wait until command is processed or timeout occures */
+	do {
+		if (this->dev_ready(mtd))
+			return;
+		touch_softlockup_watchdog();
+	} while (time_before(jiffies, timeo));	
+}
+#else
+static void nand_wait_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *this = mtd->priv;
+
+	reset_timer_masked();
+
+	/* wait until command is processed or timeout occures */
+	do {
+		if (this->dev_ready(mtd))
+			return;
+	} while (get_timer_masked() < CFG_HZ * 1);
+}
+#endif
+
 /**
  * nand_command - [DEFAULT] Send command to NAND device
  * @mtd:	MTD device structure
@@ -605,7 +661,7 @@
 		this->hwcontrol(mtd, NAND_CTL_SETCLE);
 		this->write_byte(mtd, NAND_CMD_STATUS);
 		this->hwcontrol(mtd, NAND_CTL_CLRCLE);
-		while ( !(this->read_byte(mtd) & 0x40));
+		while ( !(this->read_byte(mtd) & NAND_STATUS_READY));
 		return;
 
 	/* This applies to read commands */
@@ -619,12 +675,11 @@
 			return;
 		}
 	}
-
 	/* Apply this short delay always to ensure that we do wait tWB in
 	 * any case on any machine. */
 	ndelay (100);
-	/* wait until command is processed */
-	while (!this->dev_ready(mtd));
+
+	nand_wait_ready(mtd);
 }
 
 /**
@@ -653,7 +708,7 @@
 	/* Begin command latch cycle */
 	this->hwcontrol(mtd, NAND_CTL_SETCLE);
 	/* Write out the command to the device. */
-	this->write_byte(mtd, command);
+	this->write_byte(mtd, (command & 0xff));
 	/* End command latch cycle */
 	this->hwcontrol(mtd, NAND_CTL_CLRCLE);
 
@@ -681,7 +736,7 @@
 
 	/*
 	 * program and erase have their own busy handlers
-	 * status and sequential in needs no delay
+	 * status, sequential in, and deplete1 need no delay
 	*/
 	switch (command) {
 
@@ -691,8 +746,19 @@
 	case NAND_CMD_ERASE2:
 	case NAND_CMD_SEQIN:
 	case NAND_CMD_STATUS:
+	case NAND_CMD_DEPLETE1:
 		return;
 
+	/* 
+	 * read error status commands require only a short delay
+	 */
+	case NAND_CMD_STATUS_ERROR:
+	case NAND_CMD_STATUS_ERROR0:
+	case NAND_CMD_STATUS_ERROR1:
+	case NAND_CMD_STATUS_ERROR2:
+	case NAND_CMD_STATUS_ERROR3:
+		udelay(this->chip_delay);
+		return;
 
 	case NAND_CMD_RESET:
 		if (this->dev_ready)
@@ -701,7 +767,7 @@
 		this->hwcontrol(mtd, NAND_CTL_SETCLE);
 		this->write_byte(mtd, NAND_CMD_STATUS);
 		this->hwcontrol(mtd, NAND_CTL_CLRCLE);
-		while ( !(this->read_byte(mtd) & 0x40));
+		while ( !(this->read_byte(mtd) & NAND_STATUS_READY));
 		return;
 
 	case NAND_CMD_READ0:
@@ -728,8 +794,8 @@
 	/* Apply this short delay always to ensure that we do wait tWB in
 	 * any case on any machine. */
 	ndelay (100);
-	/* wait until command is processed */
-	while (!this->dev_ready(mtd));
+
+	nand_wait_ready(mtd);
 }
 
 /**
@@ -744,37 +810,34 @@
 #if 0
 static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state)
 {
-	struct nand_chip *active = this;
-
+	struct nand_chip *active;
+	spinlock_t *lock;
+	wait_queue_head_t *wq;
 	DECLARE_WAITQUEUE (wait, current);
 
-	/*
-	 * Grab the lock and see if the device is available
-	*/
+	lock = (this->controller) ? &this->controller->lock : &this->chip_lock;
+	wq = (this->controller) ? &this->controller->wq : &this->wq;
 retry:
+	active = this;
+	spin_lock(lock);
+
 	/* Hardware controller shared among independend devices */
 	if (this->controller) {
-		spin_lock (&this->controller->lock);
 		if (this->controller->active)
 			active = this->controller->active;
 		else
 			this->controller->active = this;
-		spin_unlock (&this->controller->lock);
 	}
-
-	if (active == this) {
-		spin_lock (&this->chip_lock);
-		if (this->state == FL_READY) {
+	if (active == this && this->state == FL_READY) {
 			this->state = new_state;
-			spin_unlock (&this->chip_lock);
+		spin_unlock(lock);
 			return;
 		}
-	}
 	set_current_state (TASK_UNINTERRUPTIBLE);
-	add_wait_queue (&active->wq, &wait);
-	spin_unlock (&active->chip_lock);
+	add_wait_queue(wq, &wait);
+	spin_unlock(lock);
 	schedule ();
-	remove_wait_queue (&active->wq, &wait);
+	remove_wait_queue(wq, &wait);
 	goto retry;
 }
 #else
@@ -825,7 +888,7 @@
 			if (this->read_byte(mtd) & NAND_STATUS_READY)
 				break;
 		}
-		yield ();
+		cond_resched();
 	}
 	status = (int) this->read_byte(mtd);
 	return status;
@@ -946,15 +1009,21 @@
 	if (!cached) {
 		/* call wait ready function */
 		status = this->waitfunc (mtd, this, FL_WRITING);
+
+		/* See if operation failed and additional status checks are available */
+		if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
+			status = this->errstat(mtd, this, FL_WRITING, status, page);
+		}
+
 		/* See if device thinks it succeeded */
-		if (status & 0x01) {
+		if (status & NAND_STATUS_FAIL) {
 			DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
 			return -EIO;
 		}
 	} else {
 		/* FIXME: Implement cached programming ! */
 		/* wait until cache is ready*/
-		/* status = this->waitfunc (mtd, this, FL_CACHEDRPG); */
+		// status = this->waitfunc (mtd, this, FL_CACHEDRPG);
 	}
 	return 0;
 }
@@ -1050,7 +1119,7 @@
 		if (!this->dev_ready)
 			udelay (this->chip_delay);
 		else
-			while (!this->dev_ready(mtd));
+			nand_wait_ready(mtd);
 
 		/* All done, return happy */
 		if (!numpages)
@@ -1072,23 +1141,24 @@
 #endif
 
 /**
- * nand_read - [MTD Interface] MTD compability function for nand_read_ecc
+ * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
  * @mtd:	MTD device structure
  * @from:	offset to read from
  * @len:	number of bytes to read
  * @retlen:	pointer to variable to store the number of read bytes
  * @buf:	the databuffer to put data
  *
- * This function simply calls nand_read_ecc with oob buffer and oobsel = NULL
+ * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL
+ * and flags = 0xff
 */
 static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
 {
-	return nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL);
+	return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff);
 }
 
 
 /**
- * nand_read_ecc - [MTD Interface] Read data with ECC
+ * nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc
  * @mtd:	MTD device structure
  * @from:	offset to read from
  * @len:	number of bytes to read
@@ -1097,11 +1167,39 @@
  * @oob_buf:	filesystem supplied oob data buffer
  * @oobsel:	oob selection structure
  *
- * NAND read with ECC
+ * This function simply calls nand_do_read_ecc with flags = 0xff
  */
 static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
 			  size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel)
 {
+	/* use userspace supplied oobinfo, if zero */
+	if (oobsel == NULL)
+		oobsel = &mtd->oobinfo;
+	return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff);
+}
+
+
+/**
+ * nand_do_read_ecc - [MTD Interface] Read data with ECC
+ * @mtd:	MTD device structure
+ * @from:	offset to read from
+ * @len:	number of bytes to read
+ * @retlen:	pointer to variable to store the number of read bytes
+ * @buf:	the databuffer to put data
+ * @oob_buf:	filesystem supplied oob data buffer (can be NULL)
+ * @oobsel:	oob selection structure
+ * @flags:	flag to indicate if nand_get_device/nand_release_device should be preformed
+ *		and how many corrected error bits are acceptable:
+ *		  bits 0..7 - number of tolerable errors
+ *		  bit  8    - 0 == do not get/release chip, 1 == get/release chip
+ *
+ * NAND read with ECC
+ */
+int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
+			     size_t * retlen, u_char * buf, u_char * oob_buf, 
+			     struct nand_oobinfo *oobsel, int flags)
+{
+
 	int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
 	int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
 	struct nand_chip *this = mtd->priv;
@@ -1126,12 +1224,9 @@
 	}
 
 	/* Grab the lock and see if the device is available */
+	if (flags & NAND_GET_DEVICE)
 	nand_get_device (this, mtd ,FL_READING);
 
-	/* use userspace supplied oobinfo, if zero */
-	if (oobsel == NULL)
-		oobsel = &mtd->oobinfo;
-
 	/* Autoplace of oob data ? Use the default placement scheme */
 	if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)
 		oobsel = this->autooob;
@@ -1208,10 +1303,10 @@
 				printk (KERN_WARNING "Reading data from NAND FLASH without ECC is not recommended\n");
 				lastwhinge = jiffies;
 			}
+			this->read_buf(mtd, data_poi, end);
 #else
 			puts("Reading data from NAND FLASH without ECC is not recommended\n");
 #endif
-			this->read_buf(mtd, data_poi, end);
 			break;
 		}
 
@@ -1236,7 +1331,8 @@
 					/* We calc error correction directly, it checks the hw
 					 * generator for an error, reads back the syndrome and
 					 * does the error correction on the fly */
-					if (this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]) == -1) {
+					ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
+					if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
 						DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: "
 							"Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
 						ecc_failed++;
@@ -1275,7 +1371,7 @@
 				p[i] = ecc_status;
 			}
 
-			if (ecc_status == -1) {
+			if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {	
 				DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
 				ecc_failed++;
 			}
@@ -1289,13 +1385,12 @@
 			case MTD_NANDECC_AUTOPLACE:
 			case MTD_NANDECC_AUTOPL_USR:
 				/* Walk through the autoplace chunks */
-				for (i = 0, j = 0; j < mtd->oobavail; i++) {
+				for (i = 0; oobsel->oobfree[i][1]; i++) {
 					int from = oobsel->oobfree[i][0];
 					int num = oobsel->oobfree[i][1];
 					memcpy(&oob_buf[oob], &oob_data[from], num);
-					j+= num;
+					oob += num;
 				}
-				oob += mtd->oobavail;
 				break;
 			case MTD_NANDECC_PLACE:
 				/* YAFFS1 legacy mode */
@@ -1321,7 +1416,7 @@
 		if (!this->dev_ready)
 			udelay (this->chip_delay);
 		else
-			while (!this->dev_ready(mtd));
+			nand_wait_ready(mtd);
 
 		if (read == len)
 			break;
@@ -1346,6 +1441,7 @@
 	}
 
 	/* Deselect and wake up anyone waiting on the device */
+	if (flags & NAND_GET_DEVICE)
 	nand_release_device(mtd);
 
 	/*
@@ -1411,16 +1507,6 @@
 		this->read_buf(mtd, &buf[i], thislen);
 		i += thislen;
 
-		/* Apply delay or wait for ready/busy pin
-		 * Do this before the AUTOINCR check, so no problems
-		 * arise if a chip which does auto increment
-		 * is marked as NOAUTOINCR by the board driver.
-		*/
-		if (!this->dev_ready)
-			udelay (this->chip_delay);
-		else
-			while (!this->dev_ready(mtd));
-
 		/* Read more ? */
 		if (i < len) {
 			page++;
@@ -1433,6 +1519,16 @@
 				this->select_chip(mtd, chipnr);
 			}
 
+			/* Apply delay or wait for ready/busy pin 
+			 * Do this before the AUTOINCR check, so no problems
+			 * arise if a chip which does auto increment
+			 * is marked as NOAUTOINCR by the board driver.
+			 */
+			if (!this->dev_ready) 
+				udelay (this->chip_delay);
+			else
+				nand_wait_ready(mtd);
+
 			/* Check, if the chip supports auto page increment
 			 * or if we have hit a block boundary.
 			*/
@@ -1499,7 +1595,7 @@
 		if (!this->dev_ready)
 			udelay (this->chip_delay);
 		else
-			while (!this->dev_ready(mtd));
+			nand_wait_ready(mtd);
 
 		/* Check, if the chip supports auto page increment */
 		if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
@@ -1817,7 +1913,7 @@
 	status = this->waitfunc (mtd, this, FL_WRITING);
 
 	/* See if device thinks it succeeded */
-	if (status & 0x01) {
+	if (status & NAND_STATUS_FAIL) {
 		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page);
 		ret = -EIO;
 		goto out;
@@ -2075,6 +2171,7 @@
 	return nand_erase_nand (mtd, instr, 0);
 }
 
+#define BBT_PAGE_MASK	0xffffff3f
 /**
  * nand_erase_intern - [NAND Interface] erase block(s)
  * @mtd:	MTD device structure
@@ -2087,6 +2184,10 @@
 {
 	int page, len, status, pages_per_block, ret, chipnr;
 	struct nand_chip *this = mtd->priv;
+	int rewrite_bbt[NAND_MAX_CHIPS]={0};	/* flags to indicate the page, if bbt needs to be rewritten. */
+	unsigned int bbt_masked_page;		/* bbt mask to compare to page being erased. */
+						/* It is used to see if the current page is in the same */
+						/*   256 block group and the same bank as the bbt. */
 
 	DEBUG (MTD_DEBUG_LEVEL3,
 	       "nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len);
@@ -2132,6 +2233,13 @@
 		goto erase_exit;
 	}
 
+	/* if BBT requires refresh, set the BBT page mask to see if the BBT should be rewritten */
+	if (this->options & BBT_AUTO_REFRESH) {
+		bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
+	} else {
+		bbt_masked_page = 0xffffffff;	/* should not match anything */
+	}
+
 	/* Loop through the pages */
 	len = instr->len;
 
@@ -2154,14 +2262,27 @@
 
 		status = this->waitfunc (mtd, this, FL_ERASING);
 
+		/* See if operation failed and additional status checks are available */
+		if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
+			status = this->errstat(mtd, this, FL_ERASING, status, page);
+		}
+
 		/* See if block erase succeeded */
-		if (status & 0x01) {
+		if (status & NAND_STATUS_FAIL) {
 			DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);
 			instr->state = MTD_ERASE_FAILED;
 			instr->fail_addr = (page << this->page_shift);
 			goto erase_exit;
 		}
 
+		/* if BBT requires refresh, set the BBT rewrite flag to the page being erased */
+		if (this->options & BBT_AUTO_REFRESH) {
+			if (((page & BBT_PAGE_MASK) == bbt_masked_page) && 
+			     (page != this->bbt_td->pages[chipnr])) {
+				rewrite_bbt[chipnr] = (page << this->page_shift);
+			}
+		}
+		
 		/* Increment page address and decrement length */
 		len -= (1 << this->phys_erase_shift);
 		page += pages_per_block;
@@ -2171,6 +2292,13 @@
 			chipnr++;
 			this->select_chip(mtd, -1);
 			this->select_chip(mtd, chipnr);
+
+			/* if BBT requires refresh and BBT-PERCHIP, 
+			 *   set the BBT page mask to see if this BBT should be rewritten */
+			if ((this->options & BBT_AUTO_REFRESH) && (this->bbt_td->options & NAND_BBT_PERCHIP)) {
+				bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
+			}
+
 		}
 	}
 	instr->state = MTD_ERASE_DONE;
@@ -2185,6 +2313,18 @@
 	/* Deselect and wake up anyone waiting on the device */
 	nand_release_device(mtd);
 
+	/* if BBT requires refresh and erase was successful, rewrite any selected bad block tables */
+	if ((this->options & BBT_AUTO_REFRESH) && (!ret)) {
+		for (chipnr = 0; chipnr < this->numchips; chipnr++) {
+			if (rewrite_bbt[chipnr]) {
+				/* update the BBT for chip */
+				DEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n", 
+					chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]);
+				nand_update_bbt (mtd, rewrite_bbt[chipnr]);
+			}
+		}
+	}
+
 	/* Return more or less happy */
 	return ret;
 }
@@ -2256,7 +2396,7 @@
  */
 int nand_scan (struct mtd_info *mtd, int maxchips)
 {
-	int i, j, nand_maf_id, nand_dev_id, busw;
+	int i, nand_maf_id, nand_dev_id, busw, maf_id;
 	struct nand_chip *this = mtd->priv;
 
 	/* Get buswidth to select the correct functions*/
@@ -2344,12 +2484,18 @@
 			busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
 		}
 
+		/* Try to identify manufacturer */
+		for (maf_id = 0; nand_manuf_ids[maf_id].id != 0x0; maf_id++) {
+			if (nand_manuf_ids[maf_id].id == nand_maf_id)
+				break;
+		}
+
 		/* Check, if buswidth is correct. Hardware drivers should set
 		 * this correct ! */
 		if (busw != (this->options & NAND_BUSWIDTH_16)) {
 			printk (KERN_INFO "NAND device: Manufacturer ID:"
 				" 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id,
-				nand_manuf_ids[i].name , mtd->name);
+				nand_manuf_ids[maf_id].name , mtd->name);
 			printk (KERN_WARNING
 				"NAND bus width %d instead %d bit\n",
 					(this->options & NAND_BUSWIDTH_16) ? 16 : 8,
@@ -2388,14 +2534,9 @@
 		if (mtd->oobblock > 512 && this->cmdfunc == nand_command)
 			this->cmdfunc = nand_command_lp;
 
-		/* Try to identify manufacturer */
-		for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
-			if (nand_manuf_ids[j].id == nand_maf_id)
-				break;
-		}
 		printk (KERN_INFO "NAND device: Manufacturer ID:"
 			" 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id,
-			nand_manuf_ids[j].name , nand_flash_ids[i].name);
+			nand_manuf_ids[maf_id].name , nand_flash_ids[i].name);
 		break;
 	}
 
@@ -2470,18 +2611,15 @@
 		default:
 			printk (KERN_WARNING "No oob scheme defined for oobsize %d\n",
 				mtd->oobsize);
-/*			BUG(); */
+			BUG();
 		}
 	}
 
 	/* The number of bytes available for the filesystem to place fs dependend
 	 * oob data */
-	if (this->options & NAND_BUSWIDTH_16) {
-		mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 2);
-		if (this->autooob->eccbytes & 0x01)
-			mtd->oobavail--;
-	} else
-		mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 1);
+	mtd->oobavail = 0;
+	for (i = 0; this->autooob->oobfree[i][1]; i++)
+		mtd->oobavail += this->autooob->oobfree[i][1];
 
 	/*
 	 * check ECC mode, default to software
@@ -2530,7 +2668,7 @@
 
 	default:
 		printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
-/*		BUG(); */
+		BUG();	
 	}
 
 	/* Check hardware ecc function availability and adjust number of ecc bytes per
@@ -2548,7 +2686,7 @@
 		if (this->calculate_ecc && this->correct_data && this->enable_hwecc)
 			break;
 		printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n");
-/*		BUG();	*/
+		BUG();	
 	}
 
 	mtd->eccsize = this->eccsize;
@@ -2623,14 +2761,21 @@
 #if 0
 	mtd->owner = THIS_MODULE;
 #endif
+	/* Check, if we should skip the bad block table scan */
+	if (this->options & NAND_SKIP_BBTSCAN)
+		return 0;
+
 	/* Build bad block table */
 	return this->scan_bbt (mtd);
 }
 
+
 /**
  * nand_release - [NAND Interface] Free resources held by the NAND device
  * @mtd:	MTD device structure
  */
+/* XXX U-BOOT XXX */
+#if 0
 void nand_release (struct mtd_info *mtd)
 {
 	struct nand_chip *this = mtd->priv;
@@ -2640,10 +2785,8 @@
 	del_mtd_partitions (mtd);
 #endif
 	/* Deregister the device */
-/* XXX U-BOOT XXX */
-#if 0
 	del_mtd_device (mtd);
-#endif
+
 	/* Free bad block table memory, if allocated */
 	if (this->bbt)
 		kfree (this->bbt);
@@ -2655,4 +2798,12 @@
 		kfree (this->data_buf);
 }
 
+EXPORT_SYMBOL_GPL (nand_scan);
+EXPORT_SYMBOL_GPL (nand_release);
+
+MODULE_LICENSE ("GPL");
+MODULE_AUTHOR ("Steven J. Hill <sjhill at realitydiluted.com>, Thomas Gleixner <tglx at linutronix.de>");
+MODULE_DESCRIPTION ("Generic NAND flash driver code");
 #endif
+
+#endif	/* CONFIG_COMMANDS & CFG_CMD_NAND */
diff -Naurw drivers/nand/nand_bbt.c drivers/nand.orig/nand_bbt.c
--- a/drivers/nand/nand_bbt.c	2005-11-03 12:42:45.000000000 +0100
+++ b/drivers/nand/nand_bbt.c	2005-11-03 10:27:04.000000000 +0100
@@ -6,7 +6,7 @@
  *
  *  Copyright (C) 2004 Thomas Gleixner (tglx at linutronix.de)
  *
- * $Id: nand_bbt.c,v 1.28 2004/11/13 10:19:09 gleixner Exp $
+ * $Id: nand_bbt.c,v 1.35 2005/07/15 13:53:47 gleixner Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -78,7 +78,7 @@
 */
 static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
 {
-	int i, end;
+	int i, end = 0;
 	uint8_t *p = buf;
 
 	end = paglen + td->offs;
@@ -96,9 +96,9 @@
 			return -1;
 	}
 
+	if (td->options & NAND_BBT_SCANEMPTY) {
 	p += td->len;
 	end += td->len;
-	if (td->options & NAND_BBT_SCANEMPTY) {
 		for (i = end; i < len; i++) {
 			if (*p++ != 0xff)
 				return -1;
@@ -108,6 +108,29 @@
 }
 
 /**
+ * check_short_pattern - [GENERIC] check if a pattern is in the buffer
+ * @buf:	the buffer to search
+ * @td:		search pattern descriptor
+ *
+ * Check for a pattern at the given place. Used to search bad block
+ * tables and good / bad block identifiers. Same as check_pattern, but 
+ * no optional empty check
+ *
+*/
+static int check_short_pattern (uint8_t *buf, struct nand_bbt_descr *td)
+{
+	int i;
+	uint8_t *p = buf;
+
+	/* Compare the pattern */
+	for (i = 0; i < td->len; i++) {
+		if (p[td->offs + i] != td->pattern[i])
+			return -1;
+	}
+	return 0;
+}
+
+/**
  * read_bbt - [GENERIC] Read the bad block table starting from page
  * @mtd:	MTD device structure
  * @buf:	temporary buffer
@@ -253,7 +276,7 @@
  * Create a bad block table by scanning the device
  * for the given good/bad block identify pattern
  */
-static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip)
+static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip)
 {
 	struct nand_chip *this = mtd->priv;
 	int i, j, numblocks, len, scanlen;
@@ -271,9 +294,17 @@
 		else
 			len = 1;
 	}
+
+	if (!(bd->options & NAND_BBT_SCANEMPTY)) {
+		/* We need only read few bytes from the OOB area */
+		scanlen = ooblen = 0;
+		readlen = bd->len;
+	} else {
+		/* Full page content should be read */
 	scanlen	= mtd->oobblock + mtd->oobsize;
 	readlen = len * mtd->oobblock;
 	ooblen = len * mtd->oobsize;
+	}
 
 	if (chip == -1) {
 		/* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it
@@ -285,7 +316,7 @@
 		if (chip >= this->numchips) {
 			printk (KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n",
 				chip + 1, this->numchips);
-			return;
+			return -EINVAL;
 		}
 		numblocks = this->chipsize >> (this->bbt_erase_shift - 1);
 		startblock = chip * numblocks;
@@ -294,8 +325,30 @@
 	}
 
 	for (i = startblock; i < numblocks;) {
-		nand_read_raw (mtd, buf, from, readlen, ooblen);
+		int ret;
+		
+		if (bd->options & NAND_BBT_SCANEMPTY)
+			if ((ret = nand_read_raw (mtd, buf, from, readlen, ooblen)))
+				return ret;
+
 		for (j = 0; j < len; j++) {
+			if (!(bd->options & NAND_BBT_SCANEMPTY)) {
+				size_t retlen;
+				
+				/* Read the full oob until read_oob is fixed to 
+				 * handle single byte reads for 16 bit buswidth */
+				ret = mtd->read_oob(mtd, from + j * mtd->oobblock,
+							mtd->oobsize, &retlen, buf);
+				if (ret)
+					return ret;
+
+				if (check_short_pattern (buf, bd)) {
+					this->bbt[i >> 3] |= 0x03 << (i & 0x6);
+					printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", 
+						i >> 1, (unsigned int) from);
+					break;
+				}
+			} else {
 			if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) {
 				this->bbt[i >> 3] |= 0x03 << (i & 0x6);
 				printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
@@ -303,9 +356,11 @@
 				break;
 			}
 		}
+		}
 		i += 2;
 		from += (1 << this->bbt_erase_shift);
 	}
+	return 0;
 }
 
 /**
@@ -590,14 +645,12 @@
  * The function creates a memory based bbt by scanning the device
  * for manufacturer / software marked good / bad blocks
 */
-static int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
+static inline int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
 {
 	struct nand_chip *this = mtd->priv;
 
-	/* Ensure that we only scan for the pattern and nothing else */
-	bd->options = 0;
-	create_bbt (mtd, this->data_buf, bd, -1);
-	return 0;
+	bd->options &= ~NAND_BBT_SCANEMPTY;
+	return create_bbt (mtd, this->data_buf, bd, -1);
 }
 
 /**
@@ -809,8 +862,14 @@
 	/* If no primary table decriptor is given, scan the device
 	 * to build a memory based bad block table
 	 */
-	if (!td)
-		return nand_memory_bbt(mtd, bd);
+	if (!td) {
+		if ((res = nand_memory_bbt(mtd, bd))) {
+			printk (KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n");
+			kfree (this->bbt);
+			this->bbt = NULL;
+		}
+		return res;
+	}
 
 	/* Allocate a temporary buffer for one eraseblock incl. oob */
 	len = (1 << this->bbt_erase_shift);
@@ -905,14 +964,11 @@
 }
 
 /* Define some generic bad / good block scan pattern which are used
- * while scanning a device for factory marked good / bad blocks
- *
- * The memory based patterns just
- */
+ * while scanning a device for factory marked good / bad blocks. */
 static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
 
 static struct nand_bbt_descr smallpage_memorybased = {
-	.options = 0,
+	.options = NAND_BBT_SCAN2NDPAGE,
 	.offs = 5,
 	.len = 1,
 	.pattern = scan_ff_pattern
@@ -1043,7 +1099,7 @@
 	res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;
 
 	DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
-		(unsigned int)offs, res, block >> 1);
+		(unsigned int)offs, block >> 1, res);
 
 	switch ((int)res) {
 	case 0x00:	return 0;
diff -Naurw drivers/nand/nand_ecc.c drivers/nand.orig/nand_ecc.c
--- a/drivers/nand/nand_ecc.c	2005-11-03 12:42:45.000000000 +0100
+++ b/drivers/nand/nand_ecc.c	2005-11-03 10:42:35.000000000 +0100
@@ -39,6 +39,8 @@
 
 #if (CONFIG_COMMANDS & CFG_CMD_NAND)
 
+#include <linux/mtd/nand_ecc.h>
+
 /*
  * Pre-calculated 256-way 1 byte column parity
  */
@@ -205,7 +207,8 @@
 			a ^= (b << bit);
 			dat[add] = a;
 			return 1;
-		} else {
+		}
+		else {
 			i = 0;
 			while (d1) {
 				if (d1 & 0x01)
@@ -241,3 +244,4 @@
 }
 
 #endif	/* CONFIG_COMMANDS & CFG_CMD_NAND */
+
diff -Naurw drivers/nand/nand_ids.c drivers/nand.orig/nand_ids.c
--- a/drivers/nand/nand_ids.c	2005-11-03 12:42:45.000000000 +0100
+++ b/drivers/nand/nand_ids.c	2005-11-03 10:46:38.000000000 +0100
@@ -3,13 +3,14 @@
  *
  *  Copyright (C) 2002 Thomas Gleixner (tglx at linutronix.de)
   *
- * $Id: nand_ids.c,v 1.10 2004/05/26 13:40:12 gleixner Exp $
+ * $Id: nand_ids.c,v 1.14 2005/06/23 09:38:50 gleixner Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
  */
+
 #include <common.h>
 
 #if (CONFIG_COMMANDS & CFG_CMD_NAND)
@@ -60,17 +61,24 @@
 	{"NAND 64MiB 3,3V 16-bit", 	0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},
 
 	{"NAND 128MiB 1,8V 8-bit", 	0x78, 512, 128, 0x4000, 0},
+	{"NAND 128MiB 1,8V 8-bit", 	0x39, 512, 128, 0x4000, 0},
 	{"NAND 128MiB 3,3V 8-bit", 	0x79, 512, 128, 0x4000, 0},
 	{"NAND 128MiB 1,8V 16-bit", 	0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+	{"NAND 128MiB 1,8V 16-bit", 	0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16},
 	{"NAND 128MiB 3,3V 16-bit", 	0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+	{"NAND 128MiB 3,3V 16-bit", 	0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16},
 
 	{"NAND 256MiB 3,3V 8-bit", 	0x71, 512, 256, 0x4000, 0},
 
-	{"NAND 512MiB 3,3V 8-bit", 	0xDC, 512, 512, 0x4000, 0},
-
 	/* These are the new chips with large page size. The pagesize
 	* and the erasesize is determined from the extended id bytes
 	*/
+	/*512 Megabit */
+	{"NAND 64MiB 1,8V 8-bit", 	0xA2, 0,  64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+	{"NAND 64MiB 3,3V 8-bit", 	0xF2, 0,  64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+	{"NAND 64MiB 1,8V 16-bit", 	0xB2, 0,  64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+	{"NAND 64MiB 3,3V 16-bit", 	0xC2, 0,  64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+	
 	/* 1 Gigabit */
 	{"NAND 128MiB 1,8V 8-bit", 	0xA1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
 	{"NAND 128MiB 3,3V 8-bit", 	0xF1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
@@ -107,7 +115,7 @@
 	 * Anyway JFFS2 would increase the eraseblock size so we chose a combined one which can be erased in one go
 	 * There are more speed improvements for reads and writes possible, but not implemented now
 	 */
-	{"AND 128MiB 3,3V 8-bit",	0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY},
+	{"AND 128MiB 3,3V 8-bit",	0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH},
 
 	{NULL,}
 };
@@ -122,6 +130,9 @@
 	{NAND_MFR_NATIONAL, "National"},
 	{NAND_MFR_RENESAS, "Renesas"},
 	{NAND_MFR_STMICRO, "ST Micro"},
+        {NAND_MFR_HYNIX, "Hynix"},
 	{0x0, "Unknown"}
 };
-#endif
+
+#endif	/* CONFIG_COMMANDS & CFG_CMD_NAND */
+




More information about the U-Boot mailing list