]> git.kernelconcepts.de Git - karo-tx-uboot.git/commitdiff
nand: Merge changes to BBT from Linux nand driver
authorChristian Hitz <christian.hitz@aizo.com>
Wed, 12 Oct 2011 07:32:04 +0000 (09:32 +0200)
committerScott Wood <scottwood@freescale.com>
Thu, 26 Jan 2012 22:09:02 +0000 (16:09 -0600)
[backport from linux commit 02f8c6aee8df3cdc935e9bdd4f2d020306035dbe]

This patch synchronizes the nand driver with the Linux 3.0 state.

Signed-off-by: Christian Hitz <christian.hitz@aizo.com>
Cc: Scott Wood <scottwood@freescale.com>
Signed-off-by: Scott Wood <scottwood@freescale.com>
drivers/mtd/nand/nand_bbt.c
include/linux/mtd/bbm.h

index ded652be345d8059bfbc7c2edaf28a2dc4809bfe..2b730e09c97ade4de292c4c0bc9e3b30f026cc7a 100644 (file)
  * Description:
  *
  * When nand_scan_bbt is called, then it tries to find the bad block table
- * depending on the options in the bbt descriptor(s). If a bbt is found
- * then the contents are read and the memory based bbt is created. If a
- * mirrored bbt is selected then the mirror is searched too and the
- * versions are compared. If the mirror has a greater version number
- * than the mirror bbt is used to build the memory based bbt.
+ * depending on the options in the BBT descriptor(s). If no flash based BBT
+ * (NAND_USE_FLASH_BBT) is specified then the device is scanned for factory
+ * marked good / bad blocks. This information is used to create a memory BBT.
+ * Once a new bad block is discovered then the "factory" information is updated
+ * on the device.
+ * If a flash based BBT is specified then the function first tries to find the
+ * BBT on flash. If a BBT is found then the contents are read and the memory
+ * based BBT is created. If a mirrored BBT is selected then the mirror is
+ * searched too and the versions are compared. If the mirror has a greater
+ * version number than the mirror BBT is used to build the memory based BBT.
  * If the tables are not versioned, then we "or" the bad block information.
- * If one of the bbt's is out of date or does not exist it is (re)created.
- * If no bbt exists at all then the device is scanned for factory marked
+ * If one of the BBTs is out of date or does not exist it is (re)created.
+ * If no BBT exists at all then the device is scanned for factory marked
  * good / bad blocks and the bad block tables are created.
  *
- * For manufacturer created bbts like the one found on M-SYS DOC devices
- * the bbt is searched and read but never created
+ * For manufacturer created BBTs like the one found on M-SYS DOC devices
+ * the BBT is searched and read but never created
  *
- * The autogenerated bad block table is located in the last good blocks
+ * The auto generated bad block table is located in the last good blocks
  * of the device. The table is mirrored, so it can be updated eventually.
- * The table is marked in the oob area with an ident pattern and a version
- * number which indicates which of both tables is more up to date.
+ * The table is marked in the OOB area with an ident pattern and a version
+ * number which indicates which of both tables is more up to date. If the NAND
+ * controller needs the complete OOB area for the ECC information then the
+ * option NAND_USE_FLASH_BBT_NO_OOB should be used: it moves the ident pattern
+ * and the version byte into the data area and the OOB area will remain
+ * untouched.
  *
  * The table uses 2 bits per block
- * 11b:        block is good
- * 00b:        block is factory marked bad
+ * 11b:                block is good
+ * 00b:                block is factory marked bad
  * 01b, 10b:   block is marked bad due to wear
  *
  * The memory bad block table uses the following scheme:
 #include <linux/mtd/compat.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/bitops.h>
 
 #include <asm/errno.h>
 
+static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
+{
+       int ret;
+
+       ret = memcmp(buf, td->pattern, td->len);
+       if (!ret)
+               return ret;
+       return -1;
+}
+
 /**
  * check_pattern - [GENERIC] check if a pattern is in the buffer
  * @buf:       the buffer to search
@@ -76,6 +97,9 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc
        int i, end = 0;
        uint8_t *p = buf;
 
+       if (td->options & NAND_BBT_NO_OOB)
+               return check_pattern_no_oob(buf, td);
+
        end = paglen + td->offs;
        if (td->options & NAND_BBT_SCANEMPTY) {
                for (i = 0; i < end; i++) {
@@ -91,6 +115,28 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc
                        return -1;
        }
 
+       /* Check both positions 1 and 6 for pattern? */
+       if (td->options & NAND_BBT_SCANBYTE1AND6) {
+               if (td->options & NAND_BBT_SCANEMPTY) {
+                       p += td->len;
+                       end += NAND_SMALL_BADBLOCK_POS - td->offs;
+                       /* Check region between positions 1 and 6 */
+                       for (i = 0; i < NAND_SMALL_BADBLOCK_POS - td->offs - td->len;
+                                       i++) {
+                               if (*p++ != 0xff)
+                                       return -1;
+                       }
+               }
+               else {
+                       p += NAND_SMALL_BADBLOCK_POS - td->offs;
+               }
+               /* Compare the pattern */
+               for (i = 0; i < td->len; i++) {
+                       if (p[i] != td->pattern[i])
+                               return -1;
+               }
+       }
+
        if (td->options & NAND_BBT_SCANEMPTY) {
                p += td->len;
                end += td->len;
@@ -122,36 +168,74 @@ static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td)
                if (p[td->offs + i] != td->pattern[i])
                        return -1;
        }
+       /* Need to check location 1 AND 6? */
+       if (td->options & NAND_BBT_SCANBYTE1AND6) {
+               for (i = 0; i < td->len; i++) {
+                       if (p[NAND_SMALL_BADBLOCK_POS + i] != td->pattern[i])
+                               return -1;
+               }
+       }
        return 0;
 }
 
+/**
+ * add_marker_len - compute the length of the marker in data area
+ * @td:                BBT descriptor used for computation
+ *
+ * The length will be 0 if the markeris located in OOB area.
+ */
+static u32 add_marker_len(struct nand_bbt_descr *td)
+{
+       u32 len;
+
+       if (!(td->options & NAND_BBT_NO_OOB))
+               return 0;
+
+       len = td->len;
+       if (td->options & NAND_BBT_VERSION)
+               len++;
+       return len;
+}
+
 /**
  * read_bbt - [GENERIC] Read the bad block table starting from page
  * @mtd:       MTD device structure
  * @buf:       temporary buffer
  * @page:      the starting page
  * @num:       the number of bbt descriptors to read
- * @bits:      number of bits per block
+ * @td:                the bbt describtion table
  * @offs:      offset in the memory table
- * @reserved_block_code:       Pattern to identify reserved blocks
  *
  * Read the bad block table starting from page.
  *
  */
 static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
-                   int bits, int offs, int reserved_block_code)
+               struct nand_bbt_descr *td, int offs)
 {
        int res, i, j, act = 0;
        struct nand_chip *this = mtd->priv;
        size_t retlen, len, totlen;
        loff_t from;
+       int bits = td->options & NAND_BBT_NRBITS_MSK;
        uint8_t msk = (uint8_t) ((1 << bits) - 1);
+       u32 marker_len;
+       int reserved_block_code = td->reserved_block_code;
 
        totlen = (num * bits) >> 3;
+       marker_len = add_marker_len(td);
        from = ((loff_t) page) << this->page_shift;
 
        while (totlen) {
                len = min(totlen, (size_t) (1 << this->bbt_erase_shift));
+               if (marker_len) {
+                       /*
+                        * In case the BBT marker is not in the OOB area it
+                        * will be just in the first page.
+                        */
+                       len -= marker_len;
+                       from += marker_len;
+                       marker_len = 0;
+               }
                res = mtd->read(mtd, from, len, &retlen, buf);
                if (res < 0) {
                        if (retlen != len) {
@@ -170,9 +254,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
                                        continue;
                                if (reserved_block_code && (tmp == reserved_block_code)) {
                                        printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%012llx\n",
-                                               (loff_t)((offs << 2) +
-                                               (act >> 1)) <<
-                                               this->bbt_erase_shift);
+                                              (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
                                        this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);
                                        mtd->ecc_stats.bbtblocks++;
                                        continue;
@@ -180,8 +262,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
                                /* Leave it for now, if its matured we can move this
                                 * message to MTD_DEBUG_LEVEL0 */
                                printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%012llx\n",
-                                       (loff_t)((offs << 2) + (act >> 1)) <<
-                                       this->bbt_erase_shift);
+                                      (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
                                /* Factory marked bad or worn out ? */
                                if (tmp == 0)
                                        this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
@@ -211,42 +292,86 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 {
        struct nand_chip *this = mtd->priv;
        int res = 0, i;
-       int bits;
 
-       bits = td->options & NAND_BBT_NRBITS_MSK;
        if (td->options & NAND_BBT_PERCHIP) {
                int offs = 0;
                for (i = 0; i < this->numchips; i++) {
                        if (chip == -1 || chip == i)
-                               res = read_bbt (mtd, buf, td->pages[i], this->chipsize >> this->bbt_erase_shift, bits, offs, td->reserved_block_code);
+                               res = read_bbt(mtd, buf, td->pages[i],
+                                       this->chipsize >> this->bbt_erase_shift,
+                                       td, offs);
                        if (res)
                                return res;
                        offs += this->chipsize >> (this->bbt_erase_shift + 2);
                }
        } else {
-               res = read_bbt (mtd, buf, td->pages[0], mtd->size >> this->bbt_erase_shift, bits, 0, td->reserved_block_code);
+               res = read_bbt(mtd, buf, td->pages[0],
+                               mtd->size >> this->bbt_erase_shift, td, 0);
                if (res)
                        return res;
        }
        return 0;
 }
 
+/*
+ * BBT marker is in the first page, no OOB.
+ */
+static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
+                        struct nand_bbt_descr *td)
+{
+       size_t retlen;
+       size_t len;
+
+       len = td->len;
+       if (td->options & NAND_BBT_VERSION)
+               len++;
+
+       return mtd->read(mtd, offs, len, &retlen, buf);
+}
+
 /*
  * Scan read raw data from flash
  */
-static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
+static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
                         size_t len)
 {
        struct mtd_oob_ops ops;
+       int res;
 
        ops.mode = MTD_OOB_RAW;
        ops.ooboffs = 0;
        ops.ooblen = mtd->oobsize;
-       ops.oobbuf = buf;
-       ops.datbuf = buf;
-       ops.len = len;
 
-       return mtd->read_oob(mtd, offs, &ops);
+
+       while (len > 0) {
+               if (len <= mtd->writesize) {
+                       ops.oobbuf = buf + len;
+                       ops.datbuf = buf;
+                       ops.len = len;
+                       return mtd->read_oob(mtd, offs, &ops);
+               } else {
+                       ops.oobbuf = buf + mtd->writesize;
+                       ops.datbuf = buf;
+                       ops.len = mtd->writesize;
+                       res = mtd->read_oob(mtd, offs, &ops);
+
+                       if (res)
+                               return res;
+               }
+
+               buf += mtd->oobsize + mtd->writesize;
+               len -= mtd->writesize;
+       }
+       return 0;
+}
+
+static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
+                        size_t len, struct nand_bbt_descr *td)
+{
+       if (td->options & NAND_BBT_NO_OOB)
+               return scan_read_raw_data(mtd, buf, offs, td);
+       else
+               return scan_read_raw_oob(mtd, buf, offs, len);
 }
 
 /*
@@ -267,6 +392,15 @@ static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,
        return mtd->write_oob(mtd, offs, &ops);
 }
 
+static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td)
+{
+       u32 ver_offs = td->veroffs;
+
+       if (!(td->options & NAND_BBT_NO_OOB))
+               ver_offs += mtd->writesize;
+       return ver_offs;
+}
+
 /**
  * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page
  * @mtd:       MTD device structure
@@ -285,18 +419,18 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
 
        /* Read the primary version, if available */
        if (td->options & NAND_BBT_VERSION) {
-               scan_read_raw(mtd, buf, (loff_t)td->pages[0] <<
-                               this->page_shift, mtd->writesize);
-               td->version[0] = buf[mtd->writesize + td->veroffs];
+               scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift,
+                             mtd->writesize, td);
+               td->version[0] = buf[bbt_get_ver_offs(mtd, td)];
                printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",
                       td->pages[0], td->version[0]);
        }
 
        /* Read the mirror version, if available */
        if (md && (md->options & NAND_BBT_VERSION)) {
-               scan_read_raw(mtd, buf, (loff_t)md->pages[0] <<
-                               this->page_shift, mtd->writesize);
-               md->version[0] = buf[mtd->writesize + md->veroffs];
+               scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift,
+                             mtd->writesize, td);
+               md->version[0] = buf[bbt_get_ver_offs(mtd, md)];
                printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",
                       md->pages[0], md->version[0]);
        }
@@ -312,7 +446,7 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
 {
        int ret, j;
 
-       ret = scan_read_raw(mtd, buf, offs, readlen);
+       ret = scan_read_raw_oob(mtd, buf, offs, readlen);
        if (ret)
                return ret;
 
@@ -376,16 +510,14 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
        loff_t from;
        size_t readlen;
 
-       MTDDEBUG (MTD_DEBUG_LEVEL0, "Scanning device for bad blocks\n");
+       MTDDEBUG(MTD_DEBUG_LEVEL0, "Scanning device for bad blocks\n");
 
        if (bd->options & NAND_BBT_SCANALLPAGES)
                len = 1 << (this->bbt_erase_shift - this->page_shift);
-       else {
-               if (bd->options & NAND_BBT_SCAN2NDPAGE)
-                       len = 2;
-               else
-                       len = 1;
-       }
+       else if (bd->options & NAND_BBT_SCAN2NDPAGE)
+               len = 2;
+       else
+               len = 1;
 
        if (!(bd->options & NAND_BBT_SCANEMPTY)) {
                /* We need only read few bytes from the OOB area */
@@ -415,9 +547,14 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
                from = (loff_t)startblock << (this->bbt_erase_shift - 1);
        }
 
+       if (this->options & NAND_BBT_SCANLASTPAGE)
+               from += mtd->erasesize - (mtd->writesize * len);
+
        for (i = startblock; i < numblocks;) {
                int ret;
 
+               BUG_ON(bd->options & NAND_BBT_NO_OOB);
+
                if (bd->options & NAND_BBT_SCANALLPAGES)
                        ret = scan_block_full(mtd, bd, from, buf, readlen,
                                              scanlen, len);
@@ -429,7 +566,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
 
                if (ret) {
                        this->bbt[i >> 3] |= 0x03 << (i & 0x6);
-                       MTDDEBUG (MTD_DEBUG_LEVEL0,
+                       MTDDEBUG(MTD_DEBUG_LEVEL0,
                                  "Bad eraseblock %d at 0x%012llx\n",
                                  i >> 1, (unsigned long long)from);
                        mtd->ecc_stats.badblocks++;
@@ -497,11 +634,12 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
                        loff_t offs = (loff_t)actblock << this->bbt_erase_shift;
 
                        /* Read first page */
-                       scan_read_raw(mtd, buf, offs, mtd->writesize);
+                       scan_read_raw(mtd, buf, offs, mtd->writesize, td);
                        if (!check_pattern(buf, scanlen, mtd->writesize, td)) {
                                td->pages[i] = actblock << blocktopage;
                                if (td->options & NAND_BBT_VERSION) {
-                                       td->version[i] = buf[mtd->writesize + td->veroffs];
+                                       offs = bbt_get_ver_offs(mtd, td);
+                                       td->version[i] = buf[offs];
                                }
                                break;
                        }
@@ -685,12 +823,26 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
                        memset(&buf[offs], 0xff, (size_t) (numblocks >> sft));
                        ooboffs = len + (pageoffs * mtd->oobsize);
 
+               } else if (td->options & NAND_BBT_NO_OOB) {
+                       ooboffs = 0;
+                       offs = td->len;
+                       /* the version byte */
+                       if (td->options & NAND_BBT_VERSION)
+                               offs++;
+                       /* Calc length */
+                       len = (size_t) (numblocks >> sft);
+                       len += offs;
+                       /* Make it page aligned ! */
+                       len = ALIGN(len, mtd->writesize);
+                       /* Preset the buffer with 0xff */
+                       memset(buf, 0xff, len);
+                       /* Pattern is located at the begin of first page */
+                       memcpy(buf, td->pattern, td->len);
                } else {
                        /* Calc length */
                        len = (size_t) (numblocks >> sft);
                        /* Make it page aligned ! */
-                       len = (len + (mtd->writesize - 1)) &
-                               ~(mtd->writesize - 1);
+                       len = ALIGN(len, mtd->writesize);
                        /* Preset the buffer with 0xff */
                        memset(buf, 0xff, len +
                               (len >> this->page_shift)* mtd->oobsize);
@@ -724,13 +876,14 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
                if (res < 0)
                        goto outerr;
 
-               res = scan_write_bbt(mtd, to, len, buf, &buf[len]);
+               res = scan_write_bbt(mtd, to, len, buf,
+                               td->options & NAND_BBT_NO_OOB ? NULL :
+                               &buf[len]);
                if (res < 0)
                        goto outerr;
 
-               printk(KERN_DEBUG "Bad block table written to 0x%012llx, "
-                      "version 0x%02X\n", (unsigned long long)to,
-                      td->version[chip]);
+               printk(KERN_DEBUG "Bad block table written to 0x%012llx, version "
+                      "0x%02X\n", (unsigned long long)to, td->version[chip]);
 
                /* Mark it as used */
                td->pages[chip] = page;
@@ -791,7 +944,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
                rd2 = NULL;
                /* Per chip or per device ? */
                chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1;
-               /* Mirrored table avilable ? */
+               /* Mirrored table available ? */
                if (md) {
                        if (td->pages[i] == -1 && md->pages[i] == -1) {
                                writeops = 0x03;
@@ -845,7 +998,8 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
                        continue;
 
                /* Create the table in memory by scanning the chip(s) */
-               create_bbt(mtd, buf, bd, chipsel);
+               if (!(this->options & NAND_CREATE_EMPTY_BBT))
+                       create_bbt(mtd, buf, bd, chipsel);
 
                td->version[i] = 1;
                if (md)
@@ -910,8 +1064,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
                        newval = oldval | (0x2 << (block & 0x06));
                        this->bbt[(block >> 3)] = newval;
                        if ((oldval != newval) && td->reserved_block_code)
-                               nand_update_bbt(mtd, (loff_t)block <<
-                                       (this->bbt_erase_shift - 1));
+                               nand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 1));
                        continue;
                }
                update = 0;
@@ -932,11 +1085,58 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
                   new ones have been marked, then we need to update the stored
                   bbts.  This should only happen once. */
                if (update && td->reserved_block_code)
-                       nand_update_bbt(mtd, (loff_t)(block - 2) <<
-                               (this->bbt_erase_shift - 1));
+                       nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1));
        }
 }
 
+/**
+ * verify_bbt_descr - verify the bad block description
+ * @mtd:       MTD device structure
+ * @bd:                the table to verify
+ *
+ * This functions performs a few sanity checks on the bad block description
+ * table.
+ */
+static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
+{
+       struct nand_chip *this = mtd->priv;
+       u32 pattern_len;
+       u32 bits;
+       u32 table_size;
+
+       if (!bd)
+               return;
+
+       pattern_len = bd->len;
+       bits = bd->options & NAND_BBT_NRBITS_MSK;
+
+       BUG_ON((this->options & NAND_USE_FLASH_BBT_NO_OOB) &&
+                       !(this->options & NAND_USE_FLASH_BBT));
+       BUG_ON(!bits);
+
+       if (bd->options & NAND_BBT_VERSION)
+               pattern_len++;
+
+       if (bd->options & NAND_BBT_NO_OOB) {
+               BUG_ON(!(this->options & NAND_USE_FLASH_BBT));
+               BUG_ON(!(this->options & NAND_USE_FLASH_BBT_NO_OOB));
+               BUG_ON(bd->offs);
+               if (bd->options & NAND_BBT_VERSION)
+                       BUG_ON(bd->veroffs != bd->len);
+               BUG_ON(bd->options & NAND_BBT_SAVECONTENT);
+       }
+
+       if (bd->options & NAND_BBT_PERCHIP)
+               table_size = this->chipsize >> this->bbt_erase_shift;
+       else
+               table_size = mtd->size >> this->bbt_erase_shift;
+       table_size >>= 3;
+       table_size *= bits;
+       if (bd->options & NAND_BBT_NO_OOB)
+               table_size += pattern_len;
+       BUG_ON(table_size > (1 << this->bbt_erase_shift));
+}
+
 /**
  * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s)
  * @mtd:       MTD device structure
@@ -978,6 +1178,8 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
                }
                return res;
        }
+       verify_bbt_descr(mtd, td);
+       verify_bbt_descr(mtd, md);
 
        /* Allocate a temporary buffer for one eraseblock incl. oob */
        len = (1 << this->bbt_erase_shift);
@@ -1073,34 +1275,6 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
  * 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 = NAND_BBT_SCAN2NDPAGE,
-       .offs = 5,
-       .len = 1,
-       .pattern = scan_ff_pattern
-};
-
-static struct nand_bbt_descr largepage_memorybased = {
-       .options = 0,
-       .offs = 0,
-       .len = 2,
-       .pattern = scan_ff_pattern
-};
-
-static struct nand_bbt_descr smallpage_flashbased = {
-       .options = NAND_BBT_SCAN2NDPAGE,
-       .offs = 5,
-       .len = 1,
-       .pattern = scan_ff_pattern
-};
-
-static struct nand_bbt_descr largepage_flashbased = {
-       .options = NAND_BBT_SCAN2NDPAGE,
-       .offs = 0,
-       .len = 2,
-       .pattern = scan_ff_pattern
-};
-
 static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 };
 
 static struct nand_bbt_descr agand_flashbased = {
@@ -1135,6 +1309,59 @@ static struct nand_bbt_descr bbt_mirror_descr = {
        .pattern = mirror_pattern
 };
 
+static struct nand_bbt_descr bbt_main_no_bbt_descr = {
+       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+               | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
+               | NAND_BBT_NO_OOB,
+       .len = 4,
+       .veroffs = 4,
+       .maxblocks = 4,
+       .pattern = bbt_pattern
+};
+
+static struct nand_bbt_descr bbt_mirror_no_bbt_descr = {
+       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+               | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
+               | NAND_BBT_NO_OOB,
+       .len = 4,
+       .veroffs = 4,
+       .maxblocks = 4,
+       .pattern = mirror_pattern
+};
+
+#define BBT_SCAN_OPTIONS (NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE | \
+               NAND_BBT_SCANBYTE1AND6)
+/**
+ * nand_create_default_bbt_descr - [Internal] Creates a BBT descriptor structure
+ * @this:      NAND chip to create descriptor for
+ *
+ * This function allocates and initializes a nand_bbt_descr for BBM detection
+ * based on the properties of "this". The new descriptor is stored in
+ * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when
+ * passed to this function.
+ *
+ */
+static int nand_create_default_bbt_descr(struct nand_chip *this)
+{
+       struct nand_bbt_descr *bd;
+       if (this->badblock_pattern) {
+               printk(KERN_WARNING "BBT descr already allocated; not replacing.\n");
+               return -EINVAL;
+       }
+       bd = kzalloc(sizeof(*bd), GFP_KERNEL);
+       if (!bd) {
+               printk(KERN_ERR "nand_create_default_bbt_descr: Out of memory\n");
+               return -ENOMEM;
+       }
+       bd->options = this->options & BBT_SCAN_OPTIONS;
+       bd->offs = this->badblockpos;
+       bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1;
+       bd->pattern = scan_ff_pattern;
+       bd->options |= NAND_BBT_DYNAMICSTRUCT;
+       this->badblock_pattern = bd;
+       return 0;
+}
+
 /**
  * nand_default_bbt - [NAND Interface] Select a default bad block table for the device
  * @mtd:       MTD device structure
@@ -1168,20 +1395,22 @@ int nand_default_bbt(struct mtd_info *mtd)
        if (this->options & NAND_USE_FLASH_BBT) {
                /* Use the default pattern descriptors */
                if (!this->bbt_td) {
-                       this->bbt_td = &bbt_main_descr;
-                       this->bbt_md = &bbt_mirror_descr;
-               }
-               if (!this->badblock_pattern) {
-                       this->badblock_pattern = (mtd->writesize > 512) ? &largepage_flashbased : &smallpage_flashbased;
+                       if (this->options & NAND_USE_FLASH_BBT_NO_OOB) {
+                               this->bbt_td = &bbt_main_no_bbt_descr;
+                               this->bbt_md = &bbt_mirror_no_bbt_descr;
+                       } else {
+                               this->bbt_td = &bbt_main_descr;
+                               this->bbt_md = &bbt_mirror_descr;
+                       }
                }
        } else {
                this->bbt_td = NULL;
                this->bbt_md = NULL;
-               if (!this->badblock_pattern) {
-                       this->badblock_pattern = (mtd->writesize > 512) ?
-                           &largepage_memorybased : &smallpage_memorybased;
-               }
        }
+
+       if (!this->badblock_pattern)
+               nand_create_default_bbt_descr(this);
+
        return nand_scan_bbt(mtd, this->badblock_pattern);
 }
 
@@ -1202,8 +1431,8 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
        block = (int)(offs >> (this->bbt_erase_shift - 1));
        res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;
 
-       MTDDEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: "
-                 "(block %d) 0x%02x\n", (unsigned int)offs, res, block >> 1);
+       MTDDEBUG(MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
+             (unsigned int)offs, block >> 1, res);
 
        switch ((int)res) {
        case 0x00:
index 2fb36177ab97ed91e24bc2bcf5e80725b40f656c..8cbcdae1143fa28ef406ce7dc795c8c0b6f8f7b8 100644 (file)
@@ -105,6 +105,8 @@ struct nand_bbt_descr {
 #define NAND_BBT_SCANBYTE1AND6 0x00100000
 /* The nand_bbt_descr was created dynamicaly and must be freed */
 #define NAND_BBT_DYNAMICSTRUCT 0x00200000
+/* The bad block table does not OOB for marker */
+#define NAND_BBT_NO_OOB                0x00400000
 
 /* The maximum number of blocks to scan for a bbt */
 #define NAND_BBT_SCAN_MAXBLOCKS        4