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

Generated against testing-NAND branch.
Signed-off-by: Ladislav Michl ladis@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@realitydiluted.com * Thomas Gleixner tglx@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@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@realitydiluted.com, Thomas Gleixner tglx@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@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@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 */ +

In message 20051103120523.GA3894@orphique you wrote:
Generated against testing-NAND branch.
Signed-off-by: Ladislav Michl ladis@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
Sorry, but this patch needs major cleanup. I get:
nand_base.c: In function 'nand_wait_ready': nand_base.c:573: warning: implicit declaration of function 'reset_timer_masked' nand_base.c:579: warning: implicit declaration of function 'get_timer_masked' In file included from nand_ids.c:18: /home/wd/git/u-boot/mailing-list/include/linux/mtd/nand.h:498: warning: 'struct erase_info' declared i nside parameter list /home/wd/git/u-boot/mailing-list/include/linux/mtd/nand.h:498: warning: its scope is only this definit ion or declaration, which is probably not what you want In file included from cmd_jffs2.c:105: /home/wd/git/u-boot/mailing-list/include/linux/mtd/nand.h:498: warning: 'struct erase_info' declared i nside parameter list /home/wd/git/u-boot/mailing-list/include/linux/mtd/nand.h:498: warning: its scope is only this definit ion or declaration, which is probably not what you want drivers/nand/libnand.a(nand_base.o): In function `nand_wait_ready': /.automount/castor-vlab/root/home/wd/git/u-boot/mailing-list/drivers/nand/nand_base.c:573: undefined r eference to `reset_timer_masked' /.automount/castor-vlab/root/home/wd/git/u-boot/mailing-list/drivers/nand/nand_base.c:579: undefined r eference to `get_timer_masked' make: *** [u-boot] Error 1
Note that "reset_timer_masked" and "get_timer_masked" are functions which are architecture-specific and should NOT be used in common code.
Actually, you should never need to use these in the the first place. They are only needed for broken ports.
Please get rid of these, clean up the other errors, and resubmit.
Thanks.
Best regards,
Wolfgang Denk
participants (2)
-
Ladislav Michl
-
Wolfgang Denk