Merge git://git.infradead.org/~dwmw2/ideapad-2.6
[sfrench/cifs-2.6.git] / drivers / mtd / nand / nand_base.c
index 4a7b86423ee96fb749537f871cb776a2bc172eb3..a3c7473dd409c51f9dd1b215eb09673a3fd858e8 100644 (file)
@@ -42,7 +42,6 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/compatmac.h>
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
 #include <linux/leds.h>
@@ -347,7 +346,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
        struct nand_chip *chip = mtd->priv;
        u16 bad;
 
-       if (chip->options & NAND_BB_LAST_PAGE)
+       if (chip->options & NAND_BBT_SCANLASTPAGE)
                ofs += mtd->erasesize - mtd->writesize;
 
        page = (int)(ofs >> chip->page_shift) & chip->pagemask;
@@ -397,9 +396,9 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
 {
        struct nand_chip *chip = mtd->priv;
        uint8_t buf[2] = { 0, 0 };
-       int block, ret;
+       int block, ret, i = 0;
 
-       if (chip->options & NAND_BB_LAST_PAGE)
+       if (chip->options & NAND_BBT_SCANLASTPAGE)
                ofs += mtd->erasesize - mtd->writesize;
 
        /* Get block number */
@@ -411,17 +410,31 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
        if (chip->options & NAND_USE_FLASH_BBT)
                ret = nand_update_bbt(mtd, ofs);
        else {
-               /* We write two bytes, so we dont have to mess with 16 bit
-                * access
-                */
                nand_get_device(chip, mtd, FL_WRITING);
-               ofs += mtd->oobsize;
-               chip->ops.len = chip->ops.ooblen = 2;
-               chip->ops.datbuf = NULL;
-               chip->ops.oobbuf = buf;
-               chip->ops.ooboffs = chip->badblockpos & ~0x01;
 
-               ret = nand_do_write_oob(mtd, ofs, &chip->ops);
+               /* Write to first two pages and to byte 1 and 6 if necessary.
+                * If we write to more than one location, the first error
+                * encountered quits the procedure. We write two bytes per
+                * location, so we dont have to mess with 16 bit access.
+                */
+               do {
+                       chip->ops.len = chip->ops.ooblen = 2;
+                       chip->ops.datbuf = NULL;
+                       chip->ops.oobbuf = buf;
+                       chip->ops.ooboffs = chip->badblockpos & ~0x01;
+
+                       ret = nand_do_write_oob(mtd, ofs, &chip->ops);
+
+                       if (!ret && (chip->options & NAND_BBT_SCANBYTE1AND6)) {
+                               chip->ops.ooboffs = NAND_SMALL_BADBLOCK_POS
+                                       & ~0x01;
+                               ret = nand_do_write_oob(mtd, ofs, &chip->ops);
+                       }
+                       i++;
+                       ofs += mtd->writesize;
+               } while (!ret && (chip->options & NAND_BBT_SCAN2NDPAGE) &&
+                               i < 2);
+
                nand_release_device(mtd);
        }
        if (!ret)
@@ -876,17 +889,17 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
 }
 
 /**
- * __nand_unlock - [REPLACABLE] unlocks specified locked blockes
+ * __nand_unlock - [REPLACEABLE] unlocks specified locked blocks
  *
- * @param mtd - mtd info
- * @param ofs - offset to start unlock from
- * @param len - length to unlock
- * @invert -  when = 0, unlock the range of blocks within the lower and
+ * @mtd: mtd info
+ * @ofs: offset to start unlock from
+ * @len: length to unlock
+ * @invert  when = 0, unlock the range of blocks within the lower and
  *                      upper boundary address
- *            whne = 1, unlock the range of blocks outside the boundaries
+ *            when = 1, unlock the range of blocks outside the boundaries
  *                      of the lower and upper boundary address
  *
- * @return - unlock status
+ * return - unlock status
  */
 static int __nand_unlock(struct mtd_info *mtd, loff_t ofs,
                                        uint64_t len, int invert)
@@ -918,13 +931,13 @@ static int __nand_unlock(struct mtd_info *mtd, loff_t ofs,
 }
 
 /**
- * nand_unlock - [REPLACABLE] unlocks specified locked blockes
+ * nand_unlock - [REPLACEABLE] unlocks specified locked blocks
  *
- * @param mtd - mtd info
- * @param ofs - offset to start unlock from
- * @param len - length to unlock
+ * @mtd: mtd info
+ * @ofs: offset to start unlock from
+ * @len: length to unlock
  *
- * @return - unlock status
+ * return - unlock status
  */
 int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 {
@@ -969,16 +982,16 @@ out:
 }
 
 /**
- * nand_lock - [REPLACABLE] locks all blockes present in the device
+ * nand_lock - [REPLACEABLE] locks all blocks present in the device
  *
- * @param mtd - mtd info
- * @param ofs - offset to start unlock from
- * @param len - length to unlock
+ * @mtd: mtd info
+ * @ofs: offset to start unlock from
+ * @len: length to unlock
  *
- * @return - lock status
+ * return - lock status
  *
- * This feature is not support in many NAND parts. 'Micron' NAND parts
- * do have this feature, but it allows only to lock all blocks not for
+ * This feature is not supported in many NAND parts. 'Micron' NAND parts
+ * do have this feature, but it allows only to lock all blocks, not for
  * specified range for block.
  *
  * Implementing 'lock' feature by making use of 'unlock', for now.
@@ -2080,6 +2093,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
  * nand_fill_oob - [Internal] Transfer client buffer to oob
  * @chip:      nand chip structure
  * @oob:       oob data buffer
+ * @len:       oob data write length
  * @ops:       oob ops structure
  */
 static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len,
@@ -2920,9 +2934,14 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
                chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 32 - 1;
 
        /* Set the bad block position */
-       chip->badblockpos = mtd->writesize > 512 ?
-               NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
-       chip->badblockbits = 8;
+       if (!(busw & NAND_BUSWIDTH_16) && (*maf_id == NAND_MFR_STMICRO ||
+                               (*maf_id == NAND_MFR_SAMSUNG &&
+                                mtd->writesize == 512) ||
+                               *maf_id == NAND_MFR_AMD))
+               chip->badblockpos = NAND_SMALL_BADBLOCK_POS;
+       else
+               chip->badblockpos = NAND_LARGE_BADBLOCK_POS;
+
 
        /* Get chip options, preserve non chip based options */
        chip->options &= ~NAND_CHIPOPTIONS_MSK;
@@ -2941,12 +2960,32 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
 
        /*
         * Bad block marker is stored in the last page of each block
-        * on Samsung and Hynix MLC devices
+        * on Samsung and Hynix MLC devices; stored in first two pages
+        * of each block on Micron devices with 2KiB pages and on
+        * SLC Samsung, Hynix, and AMD/Spansion. All others scan only
+        * the first page.
         */
        if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
                        (*maf_id == NAND_MFR_SAMSUNG ||
                         *maf_id == NAND_MFR_HYNIX))
-               chip->options |= NAND_BB_LAST_PAGE;
+               chip->options |= NAND_BBT_SCANLASTPAGE;
+       else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
+                               (*maf_id == NAND_MFR_SAMSUNG ||
+                                *maf_id == NAND_MFR_HYNIX ||
+                                *maf_id == NAND_MFR_AMD)) ||
+                       (mtd->writesize == 2048 &&
+                        *maf_id == NAND_MFR_MICRON))
+               chip->options |= NAND_BBT_SCAN2NDPAGE;
+
+       /*
+        * Numonyx/ST 2K pages, x8 bus use BOTH byte 1 and 6
+        */
+       if (!(busw & NAND_BUSWIDTH_16) &&
+                       *maf_id == NAND_MFR_STMICRO &&
+                       mtd->writesize == 2048) {
+               chip->options |= NAND_BBT_SCANBYTE1AND6;
+               chip->badblockpos = 0;
+       }
 
        /* Check for AND chips with 4 page planes */
        if (chip->options & NAND_4PAGE_ARRAY)
@@ -3306,6 +3345,11 @@ void nand_release(struct mtd_info *mtd)
        kfree(chip->bbt);
        if (!(chip->options & NAND_OWN_BUFFERS))
                kfree(chip->buffers);
+
+       /* Free bad block descriptor memory */
+       if (chip->badblock_pattern && chip->badblock_pattern->options
+                       & NAND_BBT_DYNAMICSTRUCT)
+               kfree(chip->badblock_pattern);
 }
 
 EXPORT_SYMBOL_GPL(nand_lock);