nand: Merge changes from Linux nand driver
authorChristian Hitz <christian.hitz@aizo.com>
Wed, 12 Oct 2011 07:32:02 +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>
[scottwood@freescale.com: minor fixes]
Signed-off-by: Scott Wood <scottwood@freescale.com>
drivers/mtd/nand/nand_base.c
include/linux/mtd/bbm.h
include/linux/mtd/nand.h

index 758b53fa29faa81d9ef8725db0905978c6fe7ab1..ed2640c3ef0fdde2e4e18e616ec58c6ee820a74a 100644 (file)
@@ -115,6 +115,35 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
 
 static int nand_wait(struct mtd_info *mtd, struct nand_chip *this);
 
+static int check_offs_len(struct mtd_info *mtd,
+                                       loff_t ofs, uint64_t len)
+{
+       struct nand_chip *chip = mtd->priv;
+       int ret = 0;
+
+       /* Start address must align on block boundary */
+       if (ofs & ((1 << chip->phys_erase_shift) - 1)) {
+               MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Unaligned address\n", __func__);
+               ret = -EINVAL;
+       }
+
+       /* Length must align on block boundary */
+       if (len & ((1 << chip->phys_erase_shift) - 1)) {
+               MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Length not block aligned\n",
+                                       __func__);
+               ret = -EINVAL;
+       }
+
+       /* Do not allow past end of device */
+       if (ofs + len > mtd->size) {
+               MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Past end of device\n",
+                                       __func__);
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
 /**
  * nand_release_device - [GENERIC] release chip
  * @mtd:       MTD device structure
@@ -123,8 +152,10 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this);
  */
 static void nand_release_device(struct mtd_info *mtd)
 {
-       struct nand_chip *this = mtd->priv;
-       this->select_chip(mtd, -1);     /* De-select the NAND device */
+       struct nand_chip *chip = mtd->priv;
+
+       /* De-select the NAND device */
+       chip->select_chip(mtd, -1);
 }
 
 /**
@@ -316,6 +347,9 @@ 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_BBT_SCANLASTPAGE)
+               ofs += mtd->erasesize - mtd->writesize;
+
        page = (int)(ofs >> chip->page_shift) & chip->pagemask;
 
        if (getchip) {
@@ -333,14 +367,18 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
                bad = cpu_to_le16(chip->read_word(mtd));
                if (chip->badblockpos & 0x1)
                        bad >>= 8;
-               if ((bad & 0xFF) != 0xff)
-                       res = 1;
+               else
+                       bad &= 0xFF;
        } else {
                chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page);
-               if (chip->read_byte(mtd) != 0xff)
-                       res = 1;
+               bad = chip->read_byte(mtd);
        }
 
+       if (likely(chip->badblockbits == 8))
+               res = bad != 0xFF;
+       else
+               res = hweight8(bad) < chip->badblockbits;
+
        if (getchip)
                nand_release_device(mtd);
 
@@ -359,7 +397,10 @@ 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_BBT_SCANLASTPAGE)
+               ofs += mtd->erasesize - mtd->writesize;
 
        /* Get block number */
        block = (int)(ofs >> chip->bbt_erase_shift);
@@ -370,17 +411,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)
@@ -399,6 +454,11 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
 static int nand_check_wp(struct mtd_info *mtd)
 {
        struct nand_chip *chip = mtd->priv;
+
+       /* broken xD cards report WP despite being writable */
+       if (chip->options & NAND_BROKEN_XD)
+               return 0;
+
        /* Check the WP bit */
        chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
        return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
@@ -419,11 +479,6 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
 {
        struct nand_chip *chip = mtd->priv;
 
-       if (!(chip->options & NAND_BBT_SCANNED)) {
-               chip->options |= NAND_BBT_SCANNED;
-               chip->scan_bbt(mtd);
-       }
-
        if (!chip->bbt)
                return chip->block_bad(mtd, ofs, getchip);
 
@@ -686,9 +741,10 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
  *
  * Get the device and lock it for exclusive access
  */
-static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state)
+static int
+nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state)
 {
-       this->state = new_state;
+       chip->state = new_state;
        return 0;
 }
 
@@ -701,10 +757,10 @@ static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int ne
  * Erase can take up to 400ms and program up to 20ms according to
  * general NAND and SmartMedia specs
  */
-static int nand_wait(struct mtd_info *mtd, struct nand_chip *this)
+static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
 {
        unsigned long   timeo;
-       int state = this->state;
+       int state = chip->state;
        u32 time_start;
 
        if (state == FL_ERASING)
@@ -712,10 +768,10 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this)
        else
                timeo = (CONFIG_SYS_HZ * 20) / 1000;
 
-       if ((state == FL_ERASING) && (this->options & NAND_IS_AND))
-               this->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1);
+       if ((state == FL_ERASING) && (chip->options & NAND_IS_AND))
+               chip->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1);
        else
-               this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
+               chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
 
        time_start = get_timer(0);
 
@@ -725,11 +781,11 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this)
                        return 0x01;
                }
 
-               if (this->dev_ready) {
-                       if (this->dev_ready(mtd))
+               if (chip->dev_ready) {
+                       if (chip->dev_ready(mtd))
                                break;
                } else {
-                       if (this->read_byte(mtd) & NAND_STATUS_READY)
+                       if (chip->read_byte(mtd) & NAND_STATUS_READY)
                                break;
                }
        }
@@ -739,7 +795,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this)
                ;
 #endif /*  PPCHAMELON_NAND_TIMER_HACK */
 
-       return this->read_byte(mtd);
+       return (int)chip->read_byte(mtd);
 }
 
 /**
@@ -860,6 +916,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
        int data_col_addr, i, gaps = 0;
        int datafrag_len, eccfrag_len, aligned_len, aligned_pos;
        int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1;
+       int index = 0;
 
        /* Column address wihin the page aligned to ECC size (256bytes). */
        start_step = data_offs / chip->ecc.size;
@@ -898,26 +955,30 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
        } else {
                /* send the command to read the particular ecc bytes */
                /* take care about buswidth alignment in read_buf */
-               aligned_pos = eccpos[start_step * chip->ecc.bytes] & ~(busw - 1);
+               index = start_step * chip->ecc.bytes;
+
+               aligned_pos = eccpos[index] & ~(busw - 1);
                aligned_len = eccfrag_len;
-               if (eccpos[start_step * chip->ecc.bytes] & (busw - 1))
+               if (eccpos[index] & (busw - 1))
                        aligned_len++;
-               if (eccpos[(start_step + num_steps) * chip->ecc.bytes] & (busw - 1))
+               if (eccpos[index + (num_steps * chip->ecc.bytes)] & (busw - 1))
                        aligned_len++;
 
-               chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize + aligned_pos, -1);
+               chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
+                                       mtd->writesize + aligned_pos, -1);
                chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len);
        }
 
        for (i = 0; i < eccfrag_len; i++)
-               chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + start_step * chip->ecc.bytes]];
+               chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + index]];
 
        p = bufpoi + data_col_addr;
        for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) {
                int stat;
 
-               stat = chip->ecc.correct(mtd, p, &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);
-               if (stat == -1)
+               stat = chip->ecc.correct(mtd, p,
+                       &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);
+               if (stat < 0)
                        mtd->ecc_stats.failed++;
                else
                        mtd->ecc_stats.corrected += stat;
@@ -1142,6 +1203,9 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
        int ret = 0;
        uint32_t readlen = ops->len;
        uint32_t oobreadlen = ops->ooblen;
+       uint32_t max_oobsize = ops->mode == MTD_OOB_AUTO ?
+               mtd->oobavail : mtd->oobsize;
+
        uint8_t *bufpoi, *oob, *buf;
 
        stats = mtd->ecc_stats;
@@ -1187,7 +1251,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 
                        /* Transfer not aligned data */
                        if (!aligned) {
-                               if (!NAND_SUBPAGE_READ(chip) && !oob)
+                               if (!NAND_SUBPAGE_READ(chip) && !oob &&
+                                   !(mtd->ecc_stats.failed - stats.failed))
                                        chip->pagebuf = realpage;
                                memcpy(buf, chip->buffers->databuf + col, bytes);
                        }
@@ -1195,18 +1260,14 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
                        buf += bytes;
 
                        if (unlikely(oob)) {
-                               /* Raw mode does data:oob:data:oob */
-                               if (ops->mode != MTD_OOB_RAW) {
-                                       int toread = min(oobreadlen,
-                                               chip->ecc.layout->oobavail);
-                                       if (toread) {
-                                               oob = nand_transfer_oob(chip,
-                                                       oob, ops, toread);
-                                               oobreadlen -= toread;
-                                       }
-                               } else
-                                       buf = nand_transfer_oob(chip,
-                                               buf, ops, mtd->oobsize);
+
+                               int toread = min(oobreadlen, max_oobsize);
+
+                               if (toread) {
+                                       oob = nand_transfer_oob(chip,
+                                               oob, ops, toread);
+                                       oobreadlen -= toread;
+                               }
                        }
 
                        if (!(chip->options & NAND_NO_READRDY)) {
@@ -1793,13 +1854,12 @@ 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,
-                                 struct mtd_oob_ops *ops)
+static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len,
+                                               struct mtd_oob_ops *ops)
 {
-       size_t len = ops->ooblen;
-
        switch (ops->mode) {
 
        case MTD_OOB_PLACE:
@@ -1838,7 +1898,7 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
        return NULL;
 }
 
-#define NOTALIGNED(x)  (x & (chip->subpagesize - 1)) != 0
+#define NOTALIGNED(x)  ((x & (chip->subpagesize - 1)) != 0)
 
 /**
  * nand_do_write_ops - [Internal] NAND write with ECC
@@ -1854,6 +1914,11 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
        int chipnr, realpage, page, blockmask, column;
        struct nand_chip *chip = mtd->priv;
        uint32_t writelen = ops->len;
+
+       uint32_t oobwritelen = ops->ooblen;
+       uint32_t oobmaxlen = ops->mode == MTD_OOB_AUTO ?
+                               mtd->oobavail : mtd->oobsize;
+
        uint8_t *oob = ops->oobbuf;
        uint8_t *buf = ops->datbuf;
        int ret, subpage;
@@ -1890,6 +1955,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
        if (likely(!oob))
                memset(chip->oob_poi, 0xff, mtd->oobsize);
 
+       /* Don't allow multipage oob writes with offset */
+       if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen))
+               return -EINVAL;
+
        while (1) {
                WATCHDOG_RESET();
 
@@ -1907,8 +1976,11 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
                        wbuf = chip->buffers->databuf;
                }
 
-               if (unlikely(oob))
-                       oob = nand_fill_oob(chip, oob, ops);
+               if (unlikely(oob)) {
+                       size_t len = min(oobwritelen, oobmaxlen);
+                       oob = nand_fill_oob(chip, oob, len, ops);
+                       oobwritelen -= len;
+               }
 
                ret = chip->write_page(mtd, chip, wbuf, page, cached,
                                       (ops->mode == MTD_OOB_RAW));
@@ -2043,7 +2115,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
                chip->pagebuf = -1;
 
        memset(chip->oob_poi, 0xff, mtd->oobsize);
-       nand_fill_oob(chip, ops->oobbuf, ops);
+       nand_fill_oob(chip, ops->oobbuf, ops->ooblen, ops);
        status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
        memset(chip->oob_poi, 0xff, mtd->oobsize);
 
@@ -2166,27 +2238,10 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
                                __func__, (unsigned long long)instr->addr,
                                (unsigned long long)instr->len);
 
-       /* Start address must align on block boundary */
-       if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) {
-               MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
+       if (check_offs_len(mtd, instr->addr, instr->len))
                return -EINVAL;
-       }
 
-       /* Length must align on block boundary */
-       if (instr->len & ((1 << chip->phys_erase_shift) - 1)) {
-               MTDDEBUG (MTD_DEBUG_LEVEL0,
-                         "nand_erase: Length not block aligned\n");
-               return -EINVAL;
-       }
-
-       /* Do not allow erase past end of device */
-       if ((instr->len + instr->addr) > mtd->size) {
-               MTDDEBUG (MTD_DEBUG_LEVEL0,
-                         "nand_erase: Erase past end of device\n");
-               return -EINVAL;
-       }
-
-       instr->fail_addr = 0xffffffff;
+       instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
 
        /* Grab the lock and see if the device is available */
        nand_get_device(chip, mtd, FL_ERASING);
@@ -2371,7 +2426,8 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
        struct nand_chip *chip = mtd->priv;
        int ret;
 
-       if ((ret = nand_block_isbad(mtd, ofs))) {
+       ret = nand_block_isbad(mtd, ofs);
+       if (ret) {
                /* If it was bad already, return success and do nothing. */
                if (ret > 0)
                        return 0;
@@ -2444,6 +2500,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
        int i;
        int val;
 
+       /* try ONFI for unknow chip or LP */
        chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1);
        if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' ||
                chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I')
@@ -2486,7 +2543,6 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
 
        if (!mtd->name)
                mtd->name = p->model;
-
        mtd->writesize = le32_to_cpu(p->byte_per_page);
        mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize;
        mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
@@ -2495,6 +2551,10 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
        if (le16_to_cpu(p->features) & 1)
                *busw = NAND_BUSWIDTH_16;
 
+       chip->options &= ~NAND_CHIPOPTIONS_MSK;
+       chip->options |= (NAND_NO_READRDY |
+                       NAND_NO_AUTOINCR) & NAND_CHIPOPTIONS_MSK;
+
        return 1;
 }
 #else
@@ -2506,41 +2566,6 @@ static inline int nand_flash_detect_onfi(struct mtd_info *mtd,
 }
 #endif
 
-static void nand_flash_detect_non_onfi(struct mtd_info *mtd,
-                                       struct nand_chip *chip,
-                                       const struct nand_flash_dev *type,
-                                       int *busw)
-{
-       /* Newer devices have all the information in additional id bytes */
-       if (!type->pagesize) {
-               int extid;
-               /* The 3rd id byte holds MLC / multichip data */
-               chip->cellinfo = chip->read_byte(mtd);
-               /* The 4th id byte is the important one */
-               extid = chip->read_byte(mtd);
-               /* Calc pagesize */
-               mtd->writesize = 1024 << (extid & 0x3);
-               extid >>= 2;
-               /* Calc oobsize */
-               mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
-               extid >>= 2;
-               /* Calc blocksize. Blocksize is multiples of 64KiB */
-               mtd->erasesize = (64 * 1024) << (extid & 0x03);
-               extid >>= 2;
-               /* Get buswidth information */
-               *busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
-
-       } else {
-               /*
-                * Old devices have chip data hardcoded in the device id table
-                */
-               mtd->erasesize = type->erasesize;
-               mtd->writesize = type->pagesize;
-               mtd->oobsize = mtd->writesize / 32;
-               *busw = type->options & NAND_BUSWIDTH_16;
-       }
-}
-
 /*
  * Get the flash and manufacturer id and lookup if the type is supported
  */
@@ -2550,8 +2575,9 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
                                                  int *maf_id, int *dev_id,
                                                  const struct nand_flash_dev *type)
 {
-       int ret, maf_idx;
-       int tmp_id, tmp_manf;
+       int i, maf_idx;
+       u8 id_data[8];
+       int ret;
 
        /* Select the device */
        chip->select_chip(mtd, 0);
@@ -2577,15 +2603,13 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
 
        chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
 
-       /* Read manufacturer and device IDs */
-
-       tmp_manf = chip->read_byte(mtd);
-       tmp_id = chip->read_byte(mtd);
+       for (i = 0; i < 2; i++)
+               id_data[i] = chip->read_byte(mtd);
 
-       if (tmp_manf != *maf_id || tmp_id != *dev_id) {
+       if (id_data[0] != *maf_id || id_data[1] != *dev_id) {
                printk(KERN_INFO "%s: second ID read did not match "
                       "%02x,%02x against %02x,%02x\n", __func__,
-                      *maf_id, *dev_id, tmp_manf, tmp_id);
+                      *maf_id, *dev_id, id_data[0], id_data[1]);
                return ERR_PTR(-ENODEV);
        }
 
@@ -2596,30 +2620,121 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
                if (*dev_id == type->id)
                        break;
 
-       if (!type->name) {
-               /* supress warning if there is no nand */
-               if (*maf_id != 0x00 && *maf_id != 0xff &&
-                   *dev_id  != 0x00 && *dev_id  != 0xff)
-                       printk(KERN_INFO "%s: unknown NAND device: "
-                               "Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
-                               __func__, *maf_id, *dev_id);
-               return ERR_PTR(-ENODEV);
+       chip->onfi_version = 0;
+       if (!type->name || !type->pagesize) {
+               /* Check is chip is ONFI compliant */
+               ret = nand_flash_detect_onfi(mtd, chip, &busw);
+               if (ret)
+                       goto ident_done;
        }
 
+       chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
+
+       /* Read entire ID string */
+
+       for (i = 0; i < 8; i++)
+               id_data[i] = chip->read_byte(mtd);
+
+       if (!type->name)
+               return ERR_PTR(-ENODEV);
+
        if (!mtd->name)
                mtd->name = type->name;
 
        chip->chipsize = (uint64_t)type->chipsize << 20;
-       chip->onfi_version = 0;
 
-       ret = nand_flash_detect_onfi(mtd, chip, &busw);
-       if (!ret)
-               nand_flash_detect_non_onfi(mtd, chip, type, &busw);
+       if (!type->pagesize && chip->init_size) {
+               /* set the pagesize, oobsize, erasesize by the driver*/
+               busw = chip->init_size(mtd, chip, id_data);
+       } else if (!type->pagesize) {
+               int extid;
+               /* The 3rd id byte holds MLC / multichip data */
+               chip->cellinfo = id_data[2];
+               /* The 4th id byte is the important one */
+               extid = id_data[3];
+
+               /*
+                * Field definitions are in the following datasheets:
+                * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32)
+                * New style   (6 byte ID): Samsung K9GBG08U0M (p.40)
+                *
+                * Check for wraparound + Samsung ID + nonzero 6th byte
+                * to decide what to do.
+                */
+               if (id_data[0] == id_data[6] && id_data[1] == id_data[7] &&
+                               id_data[0] == NAND_MFR_SAMSUNG &&
+                               (chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
+                               id_data[5] != 0x00) {
+                       /* Calc pagesize */
+                       mtd->writesize = 2048 << (extid & 0x03);
+                       extid >>= 2;
+                       /* Calc oobsize */
+                       switch (extid & 0x03) {
+                       case 1:
+                               mtd->oobsize = 128;
+                               break;
+                       case 2:
+                               mtd->oobsize = 218;
+                               break;
+                       case 3:
+                               mtd->oobsize = 400;
+                               break;
+                       default:
+                               mtd->oobsize = 436;
+                               break;
+                       }
+                       extid >>= 2;
+                       /* Calc blocksize */
+                       mtd->erasesize = (128 * 1024) <<
+                               (((extid >> 1) & 0x04) | (extid & 0x03));
+                       busw = 0;
+               } else {
+                       /* Calc pagesize */
+                       mtd->writesize = 1024 << (extid & 0x03);
+                       extid >>= 2;
+                       /* Calc oobsize */
+                       mtd->oobsize = (8 << (extid & 0x01)) *
+                               (mtd->writesize >> 9);
+                       extid >>= 2;
+                       /* Calc blocksize. Blocksize is multiples of 64KiB */
+                       mtd->erasesize = (64 * 1024) << (extid & 0x03);
+                       extid >>= 2;
+                       /* Get buswidth information */
+                       busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
+               }
+       } else {
+               /*
+                * Old devices have chip data hardcoded in the device id table
+                */
+               mtd->erasesize = type->erasesize;
+               mtd->writesize = type->pagesize;
+               mtd->oobsize = mtd->writesize / 32;
+               busw = type->options & NAND_BUSWIDTH_16;
 
+               /*
+                * Check for Spansion/AMD ID + repeating 5th, 6th byte since
+                * some Spansion chips have erasesize that conflicts with size
+                * listed in nand_ids table
+                * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
+                */
+               if (*maf_id == NAND_MFR_AMD && id_data[4] != 0x00 &&
+                               id_data[5] == 0x00 && id_data[6] == 0x00 &&
+                               id_data[7] == 0x00 && mtd->writesize == 512) {
+                       mtd->erasesize = 128 * 1024;
+                       mtd->erasesize <<= ((id_data[3] & 0x03) << 1);
+               }
+       }
        /* Get chip options, preserve non chip based options */
        chip->options &= ~NAND_CHIPOPTIONS_MSK;
        chip->options |= type->options & NAND_CHIPOPTIONS_MSK;
 
+       /* Check if chip is a not a samsung device. Do not clear the
+        * options for chips which are not having an extended id.
+        */
+       if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
+               chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
+ident_done:
+
        /*
         * Set chip as a default. Board drivers can override it, if necessary
         */
@@ -2654,18 +2769,48 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
                ffs(mtd->erasesize) - 1;
        if (chip->chipsize & 0xffffffff)
                chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
-       else
-               chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 31;
+       else {
+               chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32));
+               chip->chip_shift += 32 - 1;
+       }
+
+       chip->badblockbits = 8;
 
        /* Set the bad block position */
-       chip->badblockpos = mtd->writesize > 512 ?
-               NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
+       if (mtd->writesize > 512 || (busw & NAND_BUSWIDTH_16))
+               chip->badblockpos = NAND_LARGE_BADBLOCK_POS;
+       else
+               chip->badblockpos = NAND_SMALL_BADBLOCK_POS;
 
-       /* Check if chip is a not a samsung device. Do not clear the
-        * options for chips which are not having an extended id.
+       /*
+        * Bad block marker is stored in the last page of each block
+        * 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, Toshiba and AMD/Spansion. All others scan
+        * only the first page.
         */
-       if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
-               chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
+       if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
+                       (*maf_id == NAND_MFR_SAMSUNG ||
+                        *maf_id == NAND_MFR_HYNIX))
+               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_TOSHIBA ||
+                                *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)
@@ -2677,9 +2822,15 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
        if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
                chip->cmdfunc = nand_command_lp;
 
+       /* TODO onfi flash name */
        MTDDEBUG (MTD_DEBUG_LEVEL0, "NAND device: Manufacturer ID:"
-                 " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id,
-                 nand_manuf_ids[maf_idx].name, type->name);
+               " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id,
+               nand_manuf_ids[maf_idx].name,
+#ifdef CONFIG_SYS_NAND_ONFI_DETECTION
+               chip->onfi_version ? chip->onfi_params.model : type->name);
+#else
+               type->name);
+#endif
 
        return type;
 }
@@ -2865,7 +3016,8 @@ int nand_scan_tail(struct mtd_info *mtd)
                chip->ecc.write_page_raw = nand_write_page_raw;
                chip->ecc.read_oob = nand_read_oob_std;
                chip->ecc.write_oob = nand_write_oob_std;
-               chip->ecc.size = 256;
+               if (!chip->ecc.size)
+                       chip->ecc.size = 256;
                chip->ecc.bytes = 3;
                break;
 
@@ -2973,7 +3125,8 @@ int nand_scan_tail(struct mtd_info *mtd)
 
        /* Fill in remaining MTD driver data */
        mtd->type = MTD_NANDFLASH;
-       mtd->flags = MTD_CAP_NANDFLASH;
+       mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :
+                                               MTD_CAP_NANDFLASH;
        mtd->erase = nand_erase;
        mtd->point = NULL;
        mtd->unpoint = NULL;
@@ -2992,9 +3145,10 @@ int nand_scan_tail(struct mtd_info *mtd)
 
        /* Check, if we should skip the bad block table scan */
        if (chip->options & NAND_SKIP_BBTSCAN)
-               chip->options |= NAND_BBT_SCANNED;
+               return 0;
 
-       return 0;
+       /* Build bad block table */
+       return chip->scan_bbt(mtd);
 }
 
 /**
@@ -3039,4 +3193,9 @@ 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);
 }
index 7db25465df1a4a5c06b2ef0ead78d778cfbaad85..2fb36177ab97ed91e24bc2bcf5e80725b40f656c 100644 (file)
  *  Thomas Gleixner <tglx@linuxtronix.de>
  *
  * 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.
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
  */
 #ifndef __LINUX_MTD_BBM_H
 #define __LINUX_MTD_BBM_H
@@ -76,7 +87,7 @@ struct nand_bbt_descr {
 #define NAND_BBT_PERCHIP       0x00000080
 /* bbt has a version counter at offset veroffs */
 #define NAND_BBT_VERSION       0x00000100
-/* Create a bbt if none axists */
+/* Create a bbt if none exists */
 #define NAND_BBT_CREATE                0x00000200
 /* Search good / bad pattern through all pages of a block */
 #define NAND_BBT_SCANALLPAGES  0x00000400
@@ -88,6 +99,12 @@ struct nand_bbt_descr {
 #define NAND_BBT_SAVECONTENT   0x00002000
 /* Search good / bad pattern on the first and the second page */
 #define NAND_BBT_SCAN2NDPAGE   0x00004000
+/* Search good / bad pattern on the last page of the eraseblock */
+#define NAND_BBT_SCANLASTPAGE  0x00008000
+/* Chip stores bad block marker on BOTH 1st and 6th bytes of OOB */
+#define NAND_BBT_SCANBYTE1AND6 0x00100000
+/* The nand_bbt_descr was created dynamicaly and must be freed */
+#define NAND_BBT_DYNAMICSTRUCT 0x00200000
 
 /* The maximum number of blocks to scan for a bbt */
 #define NAND_BBT_SCAN_MAXBLOCKS        4
index 527d9ae03f8b2b226d06f77b426885db5e2af762..99668d552e22ac37e8af6c124ec2bfe25fdd6e25 100644 (file)
@@ -1,9 +1,9 @@
 /*
  *  linux/include/linux/mtd/nand.h
  *
- *  Copyright (c) 2000 David Woodhouse <dwmw2@infradead.org>
- *                     Steven J. Hill <sjhill@realitydiluted.com>
- *                    Thomas Gleixner <tglx@linutronix.de>
+ *  Copyright Â© 2000-2010 David Woodhouse <dwmw2@infradead.org>
+ *                        Steven J. Hill <sjhill@realitydiluted.com>
+ *                       Thomas Gleixner <tglx@linutronix.de>
  *
  * 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
@@ -36,17 +36,18 @@ extern int nand_scan_ident(struct mtd_info *mtd, int max_chips,
 extern int nand_scan_tail(struct mtd_info *mtd);
 
 /* Free resources held by the NAND device */
-extern void nand_release (struct mtd_info *mtd);
+extern void nand_release(struct mtd_info *mtd);
 
 /* Internal helper for board drivers which need to override command function */
 extern void nand_wait_ready(struct mtd_info *mtd);
 
-/* This constant declares the max. oobsize / page, which
+/*
+ * This constant declares the max. oobsize / page, which
  * is supported now. If you add a chip with bigger oobsize/page
  * adjust this accordingly.
  */
-#define NAND_MAX_OOBSIZE       218
-#define NAND_MAX_PAGESIZE      4096
+#define NAND_MAX_OOBSIZE       576
+#define NAND_MAX_PAGESIZE      8192
 
 /*
  * Constants for hardware specific CLE/ALE/NCE function
@@ -79,10 +80,14 @@ extern void nand_wait_ready(struct mtd_info *mtd);
 #define NAND_CMD_SEQIN         0x80
 #define NAND_CMD_RNDIN         0x85
 #define NAND_CMD_READID                0x90
-#define NAND_CMD_PARAM         0xec
 #define NAND_CMD_ERASE2                0xd0
+#define NAND_CMD_PARAM         0xec
 #define NAND_CMD_RESET         0xff
 
+#define NAND_CMD_LOCK          0x2a
+#define NAND_CMD_UNLOCK1       0x23
+#define NAND_CMD_UNLOCK2       0x24
+
 /* Extended commands for large page devices */
 #define NAND_CMD_READSTART     0x30
 #define NAND_CMD_RNDOUTSTART   0xE0
@@ -142,9 +147,10 @@ typedef enum {
 #define NAND_GET_DEVICE                0x80
 
 
-/* Option constants for bizarre disfunctionality and real
-*  features
-*/
+/*
+ * Option constants for bizarre disfunctionality and real
+ * features.
+ */
 /* Chip can not auto increment pages */
 #define NAND_NO_AUTOINCR       0x00000001
 /* Buswitdh is 16 bit */
@@ -155,23 +161,36 @@ typedef enum {
 #define NAND_CACHEPRG          0x00000008
 /* Chip has copy back function */
 #define NAND_COPYBACK          0x00000010
-/* AND Chip which has 4 banks and a confusing page / block
- * assignment. See Renesas datasheet for further information */
+/*
+ * AND Chip which has 4 banks and a confusing page / block
+ * assignment. See Renesas datasheet for further information.
+ */
 #define NAND_IS_AND            0x00000020
-/* Chip has a array of 4 pages which can be read without
- * additional ready /busy waits */
+/*
+ * 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
+/*
+ * 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.  */
+ * This happens with the Renesas AG-AND chips, possibly others.
+ */
 #define BBT_AUTO_REFRESH       0x00000080
-/* Chip does not require ready check on read. True
+/*
+ * Chip does not require ready check on read. True
  * for all large page devices, as they do not support
- * autoincrement.*/
+ * autoincrement.
+ */
 #define NAND_NO_READRDY                0x00000100
 /* Chip does not allow subpage writes */
 #define NAND_NO_SUBPAGE_WRITE  0x00000200
 
+/* Device is one of 'new' xD cards that expose fake nand command set */
+#define NAND_BROKEN_XD         0x00000400
+
+/* Device behaves just like nand, but is readonly */
+#define NAND_ROM               0x00000800
 
 /* Options valid for Samsung large page devices */
 #define NAND_SAMSUNG_LP_OPTIONS \
@@ -190,17 +209,29 @@ typedef enum {
 #define NAND_CHIPOPTIONS_MSK   (0x0000ffff & ~NAND_NO_AUTOINCR)
 
 /* Non chip related options */
-/* Use a flash based bad block table. This option is passed to the
- * default bad block table function. */
+/*
+ * Use a flash based bad block table. OOB identifier is saved in OOB area.
+ * This option is passed to the default bad block table function.
+ */
 #define NAND_USE_FLASH_BBT     0x00010000
 /* This option skips the bbt scan during initialization. */
 #define NAND_SKIP_BBTSCAN      0x00020000
-/* This option is defined if the board driver allocates its own buffers
-   (e.g. because it needs them DMA-coherent */
+/*
+ * This option is defined if the board driver allocates its own buffers
+ * (e.g. because it needs them DMA-coherent).
+ */
 #define NAND_OWN_BUFFERS       0x00040000
+/* Chip may not exist, so silence any errors in scan */
+#define NAND_SCAN_SILENT_NODEV 0x00080000
+/*
+ * If passed additionally to NAND_USE_FLASH_BBT then BBT code will not touch
+ * the OOB area.
+ */
+#define NAND_USE_FLASH_BBT_NO_OOB      0x00800000
+/* Create an empty BBT with no vendor information if the BBT is available */
+#define NAND_CREATE_EMPTY_BBT          0x01000000
+
 /* Options set by nand scan */
-/* bbt has already been read */
-#define NAND_BBT_SCANNED       0x40000000
 /* Nand scan has allocated controller struct */
 #define NAND_CONTROLLER_ALLOC  0x80000000
 
@@ -275,13 +306,13 @@ struct nand_onfi_params {
 
 #define ONFI_CRC_BASE  0x4F4E
 
-
 /**
  * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent 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
+ * @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.
  */
 struct nand_hw_control {
 /* XXX U-BOOT XXX */
@@ -302,58 +333,50 @@ struct nand_hw_control {
  * @prepad:    padding information for syndrome based ecc generators
  * @postpad:   padding information for syndrome based ecc generators
  * @layout:    ECC layout control struct pointer
- * @priv:       pointer to private ecc control data
+ * @priv:      pointer to private ecc control data
  * @hwctl:     function to control hardware ecc generator. Must only
  *             be provided if an hardware ECC is available
  * @calculate: function for ecc calculation or readback from ecc hardware
  * @correct:   function for ecc correction, matching to ecc generator (sw/hw)
  * @read_page_raw:     function to read a raw page without ECC
  * @write_page_raw:    function to write a raw page without ECC
- * @read_page: function to read a page according to the ecc generator requirements
- * @write_page:        function to write a page according to the ecc generator requirements
+ * @read_page: function to read a page according to the ecc generator
+ *             requirements.
+ * @read_subpage:      function to read parts of the page covered by ECC.
+ * @write_page:        function to write a page according to the ecc generator
+ *             requirements.
  * @read_oob:  function to read chip OOB data
  * @write_oob: function to write chip OOB data
  */
 struct nand_ecc_ctrl {
-       nand_ecc_modes_t        mode;
-       int                     steps;
-       int                     size;
-       int                     bytes;
-       int                     total;
-       int                     prepad;
-       int                     postpad;
+       nand_ecc_modes_t mode;
+       int steps;
+       int size;
+       int bytes;
+       int total;
+       int prepad;
+       int postpad;
        struct nand_ecclayout   *layout;
-       void                    *priv;
-       void                    (*hwctl)(struct mtd_info *mtd, int mode);
-       int                     (*calculate)(struct mtd_info *mtd,
-                                            const uint8_t *dat,
-                                            uint8_t *ecc_code);
-       int                     (*correct)(struct mtd_info *mtd, uint8_t *dat,
-                                          uint8_t *read_ecc,
-                                          uint8_t *calc_ecc);
-       int                     (*read_page_raw)(struct mtd_info *mtd,
-                                                struct nand_chip *chip,
-                                                uint8_t *buf, int page);
-       void                    (*write_page_raw)(struct mtd_info *mtd,
-                                                 struct nand_chip *chip,
-                                                 const uint8_t *buf);
-       int                     (*read_page)(struct mtd_info *mtd,
-                                            struct nand_chip *chip,
-                                            uint8_t *buf, int page);
-       int                     (*read_subpage)(struct mtd_info *mtd,
-                                            struct nand_chip *chip,
-                                            uint32_t offs, uint32_t len,
-                                            uint8_t *buf);
-       void                    (*write_page)(struct mtd_info *mtd,
-                                             struct nand_chip *chip,
-                                             const uint8_t *buf);
-       int                     (*read_oob)(struct mtd_info *mtd,
-                                           struct nand_chip *chip,
-                                           int page,
-                                           int sndcmd);
-       int                     (*write_oob)(struct mtd_info *mtd,
-                                            struct nand_chip *chip,
-                                            int page);
+       void *priv;
+       void (*hwctl)(struct mtd_info *mtd, int mode);
+       int (*calculate)(struct mtd_info *mtd, const uint8_t *dat,
+                       uint8_t *ecc_code);
+       int (*correct)(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc,
+                       uint8_t *calc_ecc);
+       int (*read_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
+                       uint8_t *buf, int page);
+       void (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
+                       const uint8_t *buf);
+       int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip,
+                       uint8_t *buf, int page);
+       int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip,
+                       uint32_t offs, uint32_t len, uint8_t *buf);
+       void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
+                       const uint8_t *buf);
+       int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page,
+                       int sndcmd);
+       int (*write_oob)(struct mtd_info *mtd, struct nand_chip *chip,
+                       int page);
 };
 
 /**
@@ -373,125 +396,150 @@ struct nand_buffers {
 
 /**
  * struct nand_chip - NAND Private Flash Chip Data
- * @IO_ADDR_R:         [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device
- * @IO_ADDR_W:         [BOARDSPECIFIC] address to write the 8 I/O lines of the flash device
+ * @IO_ADDR_R:         [BOARDSPECIFIC] address to read the 8 I/O lines of the
+ *                     flash device
+ * @IO_ADDR_W:         [BOARDSPECIFIC] address to write the 8 I/O lines of the
+ *                     flash device.
  * @read_byte:         [REPLACEABLE] read one byte from the chip
  * @read_word:         [REPLACEABLE] read one word from the chip
  * @write_buf:         [REPLACEABLE] write data from the buffer to the chip
  * @read_buf:          [REPLACEABLE] read data from the chip into the buffer
- * @verify_buf:                [REPLACEABLE] verify buffer contents against the chip data
+ * @verify_buf:                [REPLACEABLE] verify buffer contents against the chip
+ *                     data.
  * @select_chip:       [REPLACEABLE] select chip nr
  * @block_bad:         [REPLACEABLE] check, if the block is bad
  * @block_markbad:     [REPLACEABLE] mark the block bad
- * @cmd_ctrl:          [BOARDSPECIFIC] hardwarespecific funtion for controlling
+ * @cmd_ctrl:          [BOARDSPECIFIC] hardwarespecific function for controlling
  *                     ALE/CLE/nCE. Also used to write command and address
- * @dev_ready:         [BOARDSPECIFIC] hardwarespecific function for accesing device ready/busy line
- *                     If set to NULL no access to ready/busy is available and the ready/busy information
- *                     is read from the chip status register
- * @cmdfunc:           [REPLACEABLE] hardwarespecific function for writing commands to the chip
- * @waitfunc:          [REPLACEABLE] hardwarespecific function for wait on ready
+ * @init_size:         [BOARDSPECIFIC] hardwarespecific function for setting
+ *                     mtd->oobsize, mtd->writesize and so on.
+ *                     @id_data contains the 8 bytes values of NAND_CMD_READID.
+ *                     Return with the bus width.
+ * @dev_ready:         [BOARDSPECIFIC] hardwarespecific function for accesing
+ *                     device ready/busy line. If set to NULL no access to
+ *                     ready/busy is available and the ready/busy information
+ *                     is read from the chip status register.
+ * @cmdfunc:           [REPLACEABLE] hardwarespecific function for writing
+ *                     commands to the chip.
+ * @waitfunc:          [REPLACEABLE] hardwarespecific function for wait on
+ *                     ready.
  * @ecc:               [BOARDSPECIFIC] ecc control ctructure
  * @buffers:           buffer structure for read/write
  * @hwcontrol:         platform-specific hardware control structure
  * @ops:               oob operation operands
- * @erase_cmd:         [INTERN] erase command write function, selectable due to AND support
+ * @erase_cmd:         [INTERN] erase command write function, selectable due
+ *                     to AND support.
  * @scan_bbt:          [REPLACEABLE] function to scan bad block table
- * @chip_delay:                [BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR)
- * @wq:                        [INTERN] wait queue to sleep on if a NAND operation is in progress
+ * @chip_delay:                [BOARDSPECIFIC] chip dependent delay for transferring
+ *                     data from array to read regs (tR).
  * @state:             [INTERN] the current state of the NAND device
  * @oob_poi:           poison value buffer
- * @page_shift:                [INTERN] number of address bits in a page (column address bits)
+ * @page_shift:                [INTERN] number of address bits in a page (column
+ *                     address bits).
  * @phys_erase_shift:  [INTERN] number of address bits in a physical eraseblock
  * @bbt_erase_shift:   [INTERN] number of address bits in a bbt entry
  * @chip_shift:                [INTERN] number of address bits in one chip
- * @datbuf:            [INTERN] internal buffer for one page + oob
- * @oobbuf:            [INTERN] oob buffer for one eraseblock
- * @oobdirty:          [INTERN] indicates that oob_buf must be reinitialized
- * @data_poi:          [INTERN] pointer to a data buffer
- * @options:           [BOARDSPECIFIC] various chip options. They can partly be set to inform nand_scan about
- *                     special functionality. See the defines for further explanation
- * @badblockpos:       [INTERN] position of the bad block marker in the oob area
+ * @options:           [BOARDSPECIFIC] various chip options. They can partly
+ *                     be set to inform nand_scan about special functionality.
+ *                     See the defines for further explanation.
+ * @badblockpos:       [INTERN] position of the bad block marker in the oob
+ *                     area.
+ * @badblockbits:      [INTERN] number of bits to left-shift the bad block
+ *                     number
  * @cellinfo:          [INTERN] MLC/multichip data from chip ident
  * @numchips:          [INTERN] number of physical chips
  * @chipsize:          [INTERN] the size of one chip for multichip arrays
  * @pagemask:          [INTERN] page number mask = number of (pages / chip) - 1
- * @pagebuf:           [INTERN] holds the pagenumber which is currently in data_buf
+ * @pagebuf:           [INTERN] holds the pagenumber which is currently in
+ *                     data_buf.
  * @subpagesize:       [INTERN] holds the subpagesize
+ * @onfi_version:      [INTERN] holds the chip ONFI version (BCD encoded),
+ *                     non 0 if ONFI supported.
+ * @onfi_params:       [INTERN] holds the ONFI page parameter when ONFI is
+ *                     supported, 0 otherwise.
  * @ecclayout:         [REPLACEABLE] the default ecc placement scheme
  * @bbt:               [INTERN] bad block table pointer
- * @bbt_td:            [REPLACEABLE] bad block table descriptor for flash lookup
+ * @bbt_td:            [REPLACEABLE] bad block table descriptor for flash
+ *                     lookup.
  * @bbt_md:            [REPLACEABLE] bad block table mirror descriptor
- * @badblock_pattern:  [REPLACEABLE] bad block scan pattern used for initial bad block scan
- * @controller:                [REPLACEABLE] a pointer to a hardware controller structure
- *                     which is shared among multiple independend devices
+ * @badblock_pattern:  [REPLACEABLE] bad block scan pattern used for initial
+ *                     bad block scan.
+ * @controller:                [REPLACEABLE] 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)
+ * @errstat:           [OPTIONAL] hardware specific function to perform
+ *                     additional error status checks (determine if errors are
+ *                     correctable).
  * @write_page:                [REPLACEABLE] High-level page write function
  */
 
 struct nand_chip {
-       void  __iomem   *IO_ADDR_R;
-       void  __iomem   *IO_ADDR_W;
-
-       uint8_t         (*read_byte)(struct mtd_info *mtd);
-       u16             (*read_word)(struct mtd_info *mtd);
-       void            (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
-       void            (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
-       int             (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
-       void            (*select_chip)(struct mtd_info *mtd, int chip);
-       int             (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
-       int             (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
-       void            (*cmd_ctrl)(struct mtd_info *mtd, int dat,
-                                   unsigned int ctrl);
-       int             (*dev_ready)(struct mtd_info *mtd);
-       void            (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);
-       int             (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);
-       void            (*erase_cmd)(struct mtd_info *mtd, int page);
-       int             (*scan_bbt)(struct mtd_info *mtd);
-       int             (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page);
-       int             (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
-                                     const uint8_t *buf, int page, int cached, int raw);
-
-       int             chip_delay;
-       unsigned int    options;
-
-       int             page_shift;
-       int             phys_erase_shift;
-       int             bbt_erase_shift;
-       int             chip_shift;
-       int             numchips;
-       uint64_t        chipsize;
-       int             pagemask;
-       int             pagebuf;
-       int             subpagesize;
-       uint8_t         cellinfo;
-       int             badblockpos;
-       int             onfi_version;
+       void __iomem *IO_ADDR_R;
+       void __iomem *IO_ADDR_W;
+
+       uint8_t (*read_byte)(struct mtd_info *mtd);
+       u16 (*read_word)(struct mtd_info *mtd);
+       void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
+       void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
+       int (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
+       void (*select_chip)(struct mtd_info *mtd, int chip);
+       int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
+       int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
+       void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
+       int (*init_size)(struct mtd_info *mtd, struct nand_chip *this,
+                       u8 *id_data);
+       int (*dev_ready)(struct mtd_info *mtd);
+       void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column,
+                       int page_addr);
+       int(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);
+       void (*erase_cmd)(struct mtd_info *mtd, int page);
+       int (*scan_bbt)(struct mtd_info *mtd);
+       int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state,
+                       int status, int page);
+       int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
+                       const uint8_t *buf, int page, int cached, int raw);
+
+       int chip_delay;
+       unsigned int options;
+
+       int page_shift;
+       int phys_erase_shift;
+       int bbt_erase_shift;
+       int chip_shift;
+       int numchips;
+       uint64_t chipsize;
+       int pagemask;
+       int pagebuf;
+       int subpagesize;
+       uint8_t cellinfo;
+       int badblockpos;
+       int badblockbits;
+
+       int onfi_version;
 #ifdef CONFIG_SYS_NAND_ONFI_DETECTION
        struct nand_onfi_params onfi_params;
 #endif
 
-       int             state;
+       int state;
 
-       uint8_t         *oob_poi;
-       struct nand_hw_control  *controller;
-       struct nand_ecclayout   *ecclayout;
+       uint8_t *oob_poi;
+       struct nand_hw_control *controller;
+       struct nand_ecclayout *ecclayout;
 
        struct nand_ecc_ctrl ecc;
        struct nand_buffers *buffers;
-
        struct nand_hw_control hwcontrol;
 
        struct mtd_oob_ops ops;
 
-       uint8_t         *bbt;
-       struct nand_bbt_descr   *bbt_td;
-       struct nand_bbt_descr   *bbt_md;
+       uint8_t *bbt;
+       struct nand_bbt_descr *bbt_td;
+       struct nand_bbt_descr *bbt_md;
 
-       struct nand_bbt_descr   *badblock_pattern;
+       struct nand_bbt_descr *badblock_pattern;
 
-       void            *priv;
+       void *priv;
 };
 
 /*
@@ -535,7 +583,7 @@ struct nand_flash_dev {
 */
 struct nand_manufacturers {
        int id;
-       char * name;
+       char *name;
 };
 
 extern const struct nand_flash_dev nand_flash_ids[];
@@ -548,7 +596,7 @@ 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(struct mtd_info *mtd, loff_t from, size_t len,
-                       size_t * retlen, uint8_t * buf);
+                       size_t *retlen, uint8_t *buf);
 
 /*
 * Constants for oob configuration
@@ -569,17 +617,20 @@ extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
  * @priv:              hardware controller specific settings
  */
 struct platform_nand_chip {
-       int                     nr_chips;
-       int                     chip_offset;
-       int                     nr_partitions;
-       struct mtd_partition    *partitions;
-       struct nand_ecclayout   *ecclayout;
-       int                     chip_delay;
-       unsigned int            options;
-       const char              **part_probe_types;
-       void                    *priv;
+       int nr_chips;
+       int chip_offset;
+       int nr_partitions;
+       struct mtd_partition *partitions;
+       struct nand_ecclayout *ecclayout;
+       int chip_delay;
+       unsigned int options;
+       const char **part_probe_types;
+       void *priv;
 };
 
+/* Keep gcc happy */
+struct platform_device;
+
 /**
  * struct platform_nand_ctrl - controller level device structure
  * @hwcontrol:         platform specific hardware control structure
@@ -592,12 +643,11 @@ struct platform_nand_chip {
  * All fields are optional and depend on the hardware driver requirements
  */
 struct platform_nand_ctrl {
-       void            (*hwcontrol)(struct mtd_info *mtd, int cmd);
-       int             (*dev_ready)(struct mtd_info *mtd);
-       void            (*select_chip)(struct mtd_info *mtd, int chip);
-       void            (*cmd_ctrl)(struct mtd_info *mtd, int dat,
-                                   unsigned int ctrl);
-       void            *priv;
+       void (*hwcontrol)(struct mtd_info *mtd, int cmd);
+       int (*dev_ready)(struct mtd_info *mtd);
+       void (*select_chip)(struct mtd_info *mtd, int chip);
+       void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
+       void *priv;
 };
 
 /**
@@ -606,8 +656,8 @@ struct platform_nand_ctrl {
  * @ctrl:              controller level device structure
  */
 struct platform_nand_data {
-       struct platform_nand_chip       chip;
-       struct platform_nand_ctrl       ctrl;
+       struct platform_nand_chip chip;
+       struct platform_nand_ctrl ctrl;
 };
 
 /* Some helpers to access the data structures */