]> git.ipfire.org Git - people/ms/u-boot.git/blobdiff - drivers/mtd/nand/nand_base.c
mtd: nand: Allow caller to pass alternative ID table to nand_scan_ident()
[people/ms/u-boot.git] / drivers / mtd / nand / nand_base.c
index e6ac859e1a52d336767eb06e9d8822cd6f822bd6..3b96b0e2a73264c45c2ca08292b536eb6ce55c43 100644 (file)
  *
  */
 
-/* XXX U-BOOT XXX */
-#if 0
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/compatmac.h>
-#include <linux/interrupt.h>
-#include <linux/bitops.h>
-#include <linux/leds.h>
-#include <asm/io.h>
-
-#ifdef CONFIG_MTD_PARTITIONS
-#include <linux/mtd/partitions.h>
-#endif
-
-#endif
-
 #include <common.h>
 
 #define ENOTSUPP       524     /* Operation is not supported */
 #include <linux/mtd/nand.h>
 #include <linux/mtd/nand_ecc.h>
 
+#ifdef CONFIG_MTD_PARTITIONS
+#include <linux/mtd/partitions.h>
+#endif
+
 #include <asm/io.h>
 #include <asm/errno.h>
 
-#ifdef CONFIG_JFFS2_NAND
-#include <jffs2/jffs2.h>
-#endif
-
 /*
  * CONFIG_SYS_NAND_RESET_CNT is used as a timeout mechanism when resetting
  * a flash.  NAND flash is initialized prior to interrupts so standard timers
@@ -139,44 +115,17 @@ 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);
 
-/*
- * For devices which display every fart in the system on a separate LED. Is
- * compiled away when LED support is disabled.
- */
-/* XXX U-BOOT XXX */
-#if 0
-DEFINE_LED_TRIGGER(nand_led_trigger);
-#endif
-
 /**
  * nand_release_device - [GENERIC] release chip
  * @mtd:       MTD device structure
  *
  * Deselect, release chip lock and wake up anyone waiting on the device
  */
-/* XXX U-BOOT XXX */
-#if 0
-static void nand_release_device(struct mtd_info *mtd)
-{
-       struct nand_chip *chip = mtd->priv;
-
-       /* De-select the NAND device */
-       chip->select_chip(mtd, -1);
-
-       /* Release the controller and the chip */
-       spin_lock(&chip->controller->lock);
-       chip->controller->active = NULL;
-       chip->state = FL_READY;
-       wake_up(&chip->controller->wq);
-       spin_unlock(&chip->controller->lock);
-}
-#else
 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 */
 }
-#endif
 
 /**
  * nand_read_byte - [DEFAULT] read one byte from the chip
@@ -486,39 +435,21 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
  * Wait for the ready pin, after a command
  * The timeout is catched later.
  */
-/* XXX U-BOOT XXX */
-#if 0
-void nand_wait_ready(struct mtd_info *mtd)
-{
-       struct nand_chip *chip = mtd->priv;
-       unsigned long timeo = jiffies + 2;
-
-       led_trigger_event(nand_led_trigger, LED_FULL);
-       /* wait until command is processed or timeout occures */
-       do {
-               if (chip->dev_ready(mtd))
-                       break;
-               touch_softlockup_watchdog();
-       } while (time_before(jiffies, timeo));
-       led_trigger_event(nand_led_trigger, LED_OFF);
-}
-EXPORT_SYMBOL_GPL(nand_wait_ready);
-#else
 void nand_wait_ready(struct mtd_info *mtd)
 {
        struct nand_chip *chip = mtd->priv;
        u32 timeo = (CONFIG_SYS_HZ * 20) / 1000;
+       u32 time_start;
 
-       reset_timer();
+       time_start = get_timer(0);
 
        /* wait until command is processed or timeout occures */
-       while (get_timer(0) < timeo) {
+       while (get_timer(time_start) < timeo) {
                if (chip->dev_ready)
                        if (chip->dev_ready(mtd))
                                break;
        }
 }
-#endif
 
 /**
  * nand_command - [DEFAULT] Send command to NAND device
@@ -755,45 +686,11 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
  *
  * Get the device and lock it for exclusive access
  */
-/* XXX U-BOOT XXX */
-#if 0
-static int
-nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state)
-{
-       spinlock_t *lock = &chip->controller->lock;
-       wait_queue_head_t *wq = &chip->controller->wq;
-       DECLARE_WAITQUEUE(wait, current);
- retry:
-       spin_lock(lock);
-
-       /* Hardware controller shared among independend devices */
-       /* Hardware controller shared among independend devices */
-       if (!chip->controller->active)
-               chip->controller->active = chip;
-
-       if (chip->controller->active == chip && chip->state == FL_READY) {
-               chip->state = new_state;
-               spin_unlock(lock);
-               return 0;
-       }
-       if (new_state == FL_PM_SUSPENDED) {
-               spin_unlock(lock);
-               return (chip->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;
-       }
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       add_wait_queue(wq, &wait);
-       spin_unlock(lock);
-       schedule();
-       remove_wait_queue(wq, &wait);
-       goto retry;
-}
-#else
 static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state)
 {
        this->state = new_state;
        return 0;
 }
-#endif
 
 /**
  * nand_wait - [DEFAULT]  wait until the command is done
@@ -804,50 +701,11 @@ 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
  */
-/* XXX U-BOOT XXX */
-#if 0
-static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
-{
-
-       unsigned long timeo = jiffies;
-       int status, state = chip->state;
-
-       if (state == FL_ERASING)
-               timeo += (HZ * 400) / 1000;
-       else
-               timeo += (HZ * 20) / 1000;
-
-       led_trigger_event(nand_led_trigger, LED_FULL);
-
-       /* Apply this short delay always to ensure that we do wait tWB in
-        * any case on any machine. */
-       ndelay(100);
-
-       if ((state == FL_ERASING) && (chip->options & NAND_IS_AND))
-               chip->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1);
-       else
-               chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
-
-       while (time_before(jiffies, timeo)) {
-               if (chip->dev_ready) {
-                       if (chip->dev_ready(mtd))
-                               break;
-               } else {
-                       if (chip->read_byte(mtd) & NAND_STATUS_READY)
-                               break;
-               }
-               cond_resched();
-       }
-       led_trigger_event(nand_led_trigger, LED_OFF);
-
-       status = (int)chip->read_byte(mtd);
-       return status;
-}
-#else
 static int nand_wait(struct mtd_info *mtd, struct nand_chip *this)
 {
        unsigned long   timeo;
        int state = this->state;
+       u32 time_start;
 
        if (state == FL_ERASING)
                timeo = (CONFIG_SYS_HZ * 400) / 1000;
@@ -859,10 +717,10 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this)
        else
                this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
 
-       reset_timer();
+       time_start = get_timer(0);
 
        while (1) {
-               if (get_timer(0) > timeo) {
+               if (get_timer(time_start) > timeo) {
                        printf("Timeout!");
                        return 0x01;
                }
@@ -876,36 +734,82 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this)
                }
        }
 #ifdef PPCHAMELON_NAND_TIMER_HACK
-       reset_timer();
-       while (get_timer(0) < 10);
+       time_start = get_timer(0);
+       while (get_timer(time_start) < 10)
+               ;
 #endif /*  PPCHAMELON_NAND_TIMER_HACK */
 
        return this->read_byte(mtd);
 }
-#endif
 
 /**
  * nand_read_page_raw - [Intern] read raw page data without ecc
  * @mtd:       mtd info structure
  * @chip:      nand chip info structure
  * @buf:       buffer to store read data
+ * @page:      page number to read
+ *
+ * Not for syndrome calculating ecc controllers, which use a special oob layout
  */
 static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-                             uint8_t *buf)
+                             uint8_t *buf, int page)
 {
        chip->read_buf(mtd, buf, mtd->writesize);
        chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
        return 0;
 }
 
+/**
+ * nand_read_page_raw_syndrome - [Intern] read raw page data without ecc
+ * @mtd:       mtd info structure
+ * @chip:      nand chip info structure
+ * @buf:       buffer to store read data
+ * @page:      page number to read
+ *
+ * We need a special oob layout and handling even when OOB isn't used.
+ */
+static int nand_read_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
+                             uint8_t *buf, int page)
+{
+       int eccsize = chip->ecc.size;
+       int eccbytes = chip->ecc.bytes;
+       uint8_t *oob = chip->oob_poi;
+       int steps, size;
+
+       for (steps = chip->ecc.steps; steps > 0; steps--) {
+               chip->read_buf(mtd, buf, eccsize);
+               buf += eccsize;
+
+               if (chip->ecc.prepad) {
+                       chip->read_buf(mtd, oob, chip->ecc.prepad);
+                       oob += chip->ecc.prepad;
+               }
+
+               chip->read_buf(mtd, oob, eccbytes);
+               oob += eccbytes;
+
+               if (chip->ecc.postpad) {
+                       chip->read_buf(mtd, oob, chip->ecc.postpad);
+                       oob += chip->ecc.postpad;
+               }
+       }
+
+       size = mtd->oobsize - (oob - chip->oob_poi);
+       if (size)
+               chip->read_buf(mtd, oob, size);
+
+       return 0;
+}
+
 /**
  * nand_read_page_swecc - [REPLACABLE] software ecc based page read function
  * @mtd:       mtd info structure
  * @chip:      nand chip info structure
  * @buf:       buffer to store read data
+ * @page:      page number to read
  */
 static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
-                               uint8_t *buf)
+                               uint8_t *buf, int page)
 {
        int i, eccsize = chip->ecc.size;
        int eccbytes = chip->ecc.bytes;
@@ -915,7 +819,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
        uint8_t *ecc_code = chip->buffers->ecccode;
        uint32_t *eccpos = chip->ecc.layout->eccpos;
 
-       chip->ecc.read_page_raw(mtd, chip, buf);
+       chip->ecc.read_page_raw(mtd, chip, buf, page);
 
        for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
                chip->ecc.calculate(mtd, p, &ecc_calc[i]);
@@ -942,9 +846,9 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
  * nand_read_subpage - [REPLACABLE] software ecc based sub-page read function
  * @mtd:       mtd info structure
  * @chip:      nand chip info structure
- * @dataofs    offset of requested data within the page
- * @readlen    data length
- * @buf:       buffer to store read data
+ * @data_offs: offset of requested data within the page
+ * @readlen:   data length
+ * @bufpoi:    buffer to store read data
  */
 static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi)
 {
@@ -1011,7 +915,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint3
                int stat;
 
                stat = chip->ecc.correct(mtd, p, &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);
-               if (stat < 0)
+               if (stat == -1)
                        mtd->ecc_stats.failed++;
                else
                        mtd->ecc_stats.corrected += stat;
@@ -1024,11 +928,12 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint3
  * @mtd:       mtd info structure
  * @chip:      nand chip info structure
  * @buf:       buffer to store read data
+ * @page:      page number to read
  *
  * Not for syndrome calculating ecc controllers which need a special oob layout
  */
 static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
-                               uint8_t *buf)
+                               uint8_t *buf, int page)
 {
        int i, eccsize = chip->ecc.size;
        int eccbytes = chip->ecc.bytes;
@@ -1055,7 +960,56 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
                int stat;
 
                stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
-               if (stat == -1)
+               if (stat < 0)
+                       mtd->ecc_stats.failed++;
+               else
+                       mtd->ecc_stats.corrected += stat;
+       }
+       return 0;
+}
+
+/**
+ * nand_read_page_hwecc_oob_first - [REPLACABLE] hw ecc, read oob first
+ * @mtd:       mtd info structure
+ * @chip:      nand chip info structure
+ * @buf:       buffer to store read data
+ * @page:      page number to read
+ *
+ * Hardware ECC for large page chips, require OOB to be read first.
+ * For this ECC mode, the write_page method is re-used from ECC_HW.
+ * These methods read/write ECC from the OOB area, unlike the
+ * ECC_HW_SYNDROME support with multiple ECC steps, follows the
+ * "infix ECC" scheme and reads/writes ECC from the data area, by
+ * overwriting the NAND manufacturer bad block markings.
+ */
+static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
+       struct nand_chip *chip, uint8_t *buf, int page)
+{
+       int i, eccsize = chip->ecc.size;
+       int eccbytes = chip->ecc.bytes;
+       int eccsteps = chip->ecc.steps;
+       uint8_t *p = buf;
+       uint8_t *ecc_code = chip->buffers->ecccode;
+       uint32_t *eccpos = chip->ecc.layout->eccpos;
+       uint8_t *ecc_calc = chip->buffers->ecccalc;
+
+       /* Read the OOB area first */
+       chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+       chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+       chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+
+       for (i = 0; i < chip->ecc.total; i++)
+               ecc_code[i] = chip->oob_poi[eccpos[i]];
+
+       for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+               int stat;
+
+               chip->ecc.hwctl(mtd, NAND_ECC_READ);
+               chip->read_buf(mtd, p, eccsize);
+               chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+
+               stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
+               if (stat < 0)
                        mtd->ecc_stats.failed++;
                else
                        mtd->ecc_stats.corrected += stat;
@@ -1068,12 +1022,13 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
  * @mtd:       mtd info structure
  * @chip:      nand chip info structure
  * @buf:       buffer to store read data
+ * @page:      page number to read
  *
  * The hw generator calculates the error syndrome automatically. Therefor
  * we need a special oob layout and handling.
  */
 static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
-                                  uint8_t *buf)
+                                  uint8_t *buf, int page)
 {
        int i, eccsize = chip->ecc.size;
        int eccbytes = chip->ecc.bytes;
@@ -1215,11 +1170,13 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 
                        /* Now read the page into the buffer */
                        if (unlikely(ops->mode == MTD_OOB_RAW))
-                               ret = chip->ecc.read_page_raw(mtd, chip, bufpoi);
+                               ret = chip->ecc.read_page_raw(mtd, chip,
+                                               bufpoi, page);
                        else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob)
                                ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi);
                        else
-                               ret = chip->ecc.read_page(mtd, chip, bufpoi);
+                               ret = chip->ecc.read_page(mtd, chip, bufpoi,
+                                               page);
                        if (ret < 0)
                                break;
 
@@ -1623,6 +1580,8 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
  * @mtd:       mtd info structure
  * @chip:      nand chip info structure
  * @buf:       data buffer
+ *
+ * Not for syndrome calculating ecc controllers, which use a special oob layout
  */
 static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
                                const uint8_t *buf)
@@ -1631,6 +1590,44 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
        chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
 }
 
+/**
+ * nand_write_page_raw_syndrome - [Intern] raw page write function
+ * @mtd:       mtd info structure
+ * @chip:      nand chip info structure
+ * @buf:       data buffer
+ *
+ * We need a special oob layout and handling even when ECC isn't checked.
+ */
+static void nand_write_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
+                               const uint8_t *buf)
+{
+       int eccsize = chip->ecc.size;
+       int eccbytes = chip->ecc.bytes;
+       uint8_t *oob = chip->oob_poi;
+       int steps, size;
+
+       for (steps = chip->ecc.steps; steps > 0; steps--) {
+               chip->write_buf(mtd, buf, eccsize);
+               buf += eccsize;
+
+               if (chip->ecc.prepad) {
+                       chip->write_buf(mtd, oob, chip->ecc.prepad);
+                       oob += chip->ecc.prepad;
+               }
+
+               chip->read_buf(mtd, oob, eccbytes);
+               oob += eccbytes;
+
+               if (chip->ecc.postpad) {
+                       chip->write_buf(mtd, oob, chip->ecc.postpad);
+                       oob += chip->ecc.postpad;
+               }
+       }
+
+       size = mtd->oobsize - (oob - chip->oob_poi);
+       if (size)
+               chip->write_buf(mtd, oob, size);
+}
 /**
  * nand_write_page_swecc - [REPLACABLE] software ecc based page write function
  * @mtd:       mtd info structure
@@ -1858,13 +1855,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
        if (!writelen)
                return 0;
 
-       /* reject writes, which are not page aligned */
-       if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {
-               printk(KERN_NOTICE "nand_write: "
-                      "Attempt to write not page aligned data\n");
-               return -EINVAL;
-       }
-
        column = to & (mtd->writesize - 1);
        subpage = column || (writelen & (mtd->writesize - 1));
 
@@ -2157,13 +2147,15 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
 int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
                    int allowbbt)
 {
-       int page, len, status, pages_per_block, ret, chipnr;
+       int page, status, pages_per_block, ret, chipnr;
        struct nand_chip *chip = mtd->priv;
-       int rewrite_bbt[CONFIG_SYS_NAND_MAX_CHIPS]={0};
+       loff_t rewrite_bbt[CONFIG_SYS_NAND_MAX_CHIPS] = {0};
        unsigned int bbt_masked_page = 0xffffffff;
+       loff_t len;
 
-       MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n",
-                 (unsigned int) instr->addr, (unsigned int) instr->len);
+       MTDDEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%012llx, "
+                "len = %llu\n", (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)) {
@@ -2259,7 +2251,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
                        MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase: "
                                  "Failed erase, page 0x%08x\n", page);
                        instr->state = MTD_ERASE_FAILED;
-                       instr->fail_addr = (page << chip->page_shift);
+                       instr->fail_addr = ((loff_t)page << chip->page_shift);
                        goto erase_exit;
                }
 
@@ -2269,7 +2261,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
                 */
                if (bbt_masked_page != 0xffffffff &&
                    (page & BBT_PAGE_MASK) == bbt_masked_page)
-                           rewrite_bbt[chipnr] = (page << chip->page_shift);
+                       rewrite_bbt[chipnr] =
+                               ((loff_t)page << chip->page_shift);
 
                /* Increment page address and decrement length */
                len -= (1 << chip->phys_erase_shift);
@@ -2316,8 +2309,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
                        continue;
                /* update the BBT for chip */
                MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt "
-                         "(%d:0x%0x 0x%0x)\n", chipnr, rewrite_bbt[chipnr],
-                         chip->bbt_td->pages[chipnr]);
+                         "(%d:0x%0llx 0x%0x)\n", chipnr, rewrite_bbt[chipnr],
+                         chip->bbt_td->pages[chipnr]);
                nand_update_bbt(mtd, rewrite_bbt[chipnr]);
        }
 
@@ -2377,32 +2370,6 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
        return chip->block_markbad(mtd, ofs);
 }
 
-/**
- * nand_suspend - [MTD Interface] Suspend the NAND flash
- * @mtd:       MTD device structure
- */
-static int nand_suspend(struct mtd_info *mtd)
-{
-       struct nand_chip *chip = mtd->priv;
-
-       return nand_get_device(chip, mtd, FL_PM_SUSPENDED);
-}
-
-/**
- * nand_resume - [MTD Interface] Resume the NAND flash
- * @mtd:       MTD device structure
- */
-static void nand_resume(struct mtd_info *mtd)
-{
-       struct nand_chip *chip = mtd->priv;
-
-       if (chip->state == FL_PM_SUSPENDED)
-               nand_release_device(mtd);
-       else
-               printk(KERN_ERR "nand_resume() called for a chip which is not "
-                      "in suspended state\n");
-}
-
 /*
  * Set default functions
  */
@@ -2438,28 +2405,19 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
                chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
        if (!chip->scan_bbt)
                chip->scan_bbt = nand_default_bbt;
-
-       if (!chip->controller) {
+       if (!chip->controller)
                chip->controller = &chip->hwcontrol;
-
-               /* XXX U-BOOT XXX */
-#if 0
-               spin_lock_init(&chip->controller->lock);
-               init_waitqueue_head(&chip->controller->wq);
-#endif
-       }
-
 }
 
 /*
  * Get the flash and manufacturer id and lookup if the type is supported
  */
-static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
+static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
                                                  struct nand_chip *chip,
-                                                 int busw, int *maf_id)
+                                                 int busw, int *maf_id,
+                                                 const struct nand_flash_dev *type)
 {
-       struct nand_flash_dev *type = NULL;
-       int i, dev_id, maf_idx;
+       int dev_id, maf_idx;
        int tmp_id, tmp_manf;
 
        /* Select the device */
@@ -2498,21 +2456,27 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
                return ERR_PTR(-ENODEV);
        }
 
-       /* Lookup the flash id */
-       for (i = 0; nand_flash_ids[i].name != NULL; i++) {
-               if (dev_id == nand_flash_ids[i].id) {
-                       type =  &nand_flash_ids[i];
-                       break;
-               }
-       }
-
        if (!type)
+               type = nand_flash_ids;
+
+       for (; type->name != NULL; type++)
+               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);
+       }
 
        if (!mtd->name)
                mtd->name = type->name;
 
-       chip->chipsize = type->chipsize << 20;
+       chip->chipsize = (uint64_t)type->chipsize << 20;
 
        /* Newer devices have all the information in additional id bytes */
        if (!type->pagesize) {
@@ -2570,7 +2534,10 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
 
        chip->bbt_erase_shift = chip->phys_erase_shift =
                ffs(mtd->erasesize) - 1;
-       chip->chip_shift = ffs(chip->chipsize) - 1;
+       if (chip->chipsize & 0xffffffff)
+               chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
+       else
+               chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 31;
 
        /* Set the bad block position */
        chip->badblockpos = mtd->writesize > 512 ?
@@ -2612,17 +2579,19 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
  * nand_scan_ident - [NAND Interface] Scan for the NAND device
  * @mtd:            MTD device structure
  * @maxchips:       Number of chips to scan for
+ * @table:          Alternative NAND ID table
  *
  * This is the first phase of the normal nand_scan() function. It
  * reads the flash ID and sets up MTD fields accordingly.
  *
  * The mtd->owner field must be set to the module of the caller.
  */
-int nand_scan_ident(struct mtd_info *mtd, int maxchips)
+int nand_scan_ident(struct mtd_info *mtd, int maxchips,
+                   const struct nand_flash_dev *table)
 {
        int i, busw, nand_maf_id;
        struct nand_chip *chip = mtd->priv;
-       struct nand_flash_dev *type;
+       const struct nand_flash_dev *type;
 
        /* Get buswidth to select the correct functions */
        busw = chip->options & NAND_BUSWIDTH_16;
@@ -2630,7 +2599,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips)
        nand_set_defaults(chip, busw);
 
        /* Read the flash type */
-       type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id);
+       type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id, table);
 
        if (IS_ERR(type)) {
 #ifndef CONFIG_SYS_NAND_QUIET_TEST
@@ -2668,7 +2637,6 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips)
 /**
  * nand_scan_tail - [NAND Interface] Scan for the NAND device
  * @mtd:           MTD device structure
- * @maxchips:      Number of chips to scan for
  *
  * This is the second phase of the normal nand_scan() function. It
  * fills out all the uninitialized function pointers with the defaults
@@ -2707,7 +2675,6 @@ int nand_scan_tail(struct mtd_info *mtd)
                default:
                        printk(KERN_WARNING "No oob scheme defined for "
                               "oobsize %d\n", mtd->oobsize);
-/*                     BUG(); */
                }
        }
 
@@ -2718,18 +2685,29 @@ int nand_scan_tail(struct mtd_info *mtd)
         * check ECC mode, default to software if 3byte/512byte hardware ECC is
         * selected and we have 256 byte pagesize fallback to software ECC
         */
-       if (!chip->ecc.read_page_raw)
-               chip->ecc.read_page_raw = nand_read_page_raw;
-       if (!chip->ecc.write_page_raw)
-               chip->ecc.write_page_raw = nand_write_page_raw;
 
        switch (chip->ecc.mode) {
+       case NAND_ECC_HW_OOB_FIRST:
+               /* Similar to NAND_ECC_HW, but a separate read_page handle */
+               if (!chip->ecc.calculate || !chip->ecc.correct ||
+                    !chip->ecc.hwctl) {
+                       printk(KERN_WARNING "No ECC functions supplied, "
+                              "Hardware ECC not possible\n");
+                       BUG();
+               }
+               if (!chip->ecc.read_page)
+                       chip->ecc.read_page = nand_read_page_hwecc_oob_first;
+
        case NAND_ECC_HW:
                /* Use standard hwecc read page function ? */
                if (!chip->ecc.read_page)
                        chip->ecc.read_page = nand_read_page_hwecc;
                if (!chip->ecc.write_page)
                        chip->ecc.write_page = nand_write_page_hwecc;
+               if (!chip->ecc.read_page_raw)
+                       chip->ecc.read_page_raw = nand_read_page_raw;
+               if (!chip->ecc.write_page_raw)
+                       chip->ecc.write_page_raw = nand_write_page_raw;
                if (!chip->ecc.read_oob)
                        chip->ecc.read_oob = nand_read_oob_std;
                if (!chip->ecc.write_oob)
@@ -2751,6 +2729,10 @@ int nand_scan_tail(struct mtd_info *mtd)
                        chip->ecc.read_page = nand_read_page_syndrome;
                if (!chip->ecc.write_page)
                        chip->ecc.write_page = nand_write_page_syndrome;
+               if (!chip->ecc.read_page_raw)
+                       chip->ecc.read_page_raw = nand_read_page_raw_syndrome;
+               if (!chip->ecc.write_page_raw)
+                       chip->ecc.write_page_raw = nand_write_page_raw_syndrome;
                if (!chip->ecc.read_oob)
                        chip->ecc.read_oob = nand_read_oob_syndrome;
                if (!chip->ecc.write_oob)
@@ -2769,6 +2751,8 @@ int nand_scan_tail(struct mtd_info *mtd)
                chip->ecc.read_page = nand_read_page_swecc;
                chip->ecc.read_subpage = nand_read_subpage;
                chip->ecc.write_page = nand_write_page_swecc;
+               chip->ecc.read_page_raw = nand_read_page_raw;
+               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;
@@ -2781,6 +2765,8 @@ int nand_scan_tail(struct mtd_info *mtd)
                chip->ecc.read_page = nand_read_page_raw;
                chip->ecc.write_page = nand_write_page_raw;
                chip->ecc.read_oob = nand_read_oob_std;
+               chip->ecc.read_page_raw = nand_read_page_raw;
+               chip->ecc.write_page_raw = nand_write_page_raw;
                chip->ecc.write_oob = nand_write_oob_std;
                chip->ecc.size = mtd->writesize;
                chip->ecc.bytes = 0;
@@ -2797,7 +2783,8 @@ int nand_scan_tail(struct mtd_info *mtd)
         * the out of band area
         */
        chip->ecc.layout->oobavail = 0;
-       for (i = 0; chip->ecc.layout->oobfree[i].length; i++)
+       for (i = 0; chip->ecc.layout->oobfree[i].length
+                       && i < ARRAY_SIZE(chip->ecc.layout->oobfree); i++)
                chip->ecc.layout->oobavail +=
                        chip->ecc.layout->oobfree[i].length;
        mtd->oobavail = chip->ecc.layout->oobavail;
@@ -2825,6 +2812,7 @@ int nand_scan_tail(struct mtd_info *mtd)
                        break;
                case 4:
                case 8:
+               case 16:
                        mtd->subpage_sft = 2;
                        break;
                }
@@ -2853,8 +2841,6 @@ int nand_scan_tail(struct mtd_info *mtd)
        mtd->sync = nand_sync;
        mtd->lock = NULL;
        mtd->unlock = NULL;
-       mtd->suspend = nand_suspend;
-       mtd->resume = nand_resume;
        mtd->block_isbad = nand_block_isbad;
        mtd->block_markbad = nand_block_markbad;
 
@@ -2868,16 +2854,6 @@ int nand_scan_tail(struct mtd_info *mtd)
        return 0;
 }
 
-/* module_text_address() isn't exported, and it's mostly a pointless
-   test if this is a module _anyway_ -- they'd have to try _really_ hard
-   to call us from in-kernel code if the core NAND support is modular. */
-#ifdef MODULE
-#define caller_is_module() (1)
-#else
-#define caller_is_module() \
-       module_text_address((unsigned long)__builtin_return_address(0))
-#endif
-
 /**
  * nand_scan - [NAND Interface] Scan for the NAND device
  * @mtd:       MTD device structure
@@ -2894,16 +2870,7 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
 {
        int ret;
 
-       /* Many callers got this wrong, so check for it for a while... */
-       /* XXX U-BOOT XXX */
-#if 0
-       if (!mtd->owner && caller_is_module()) {
-               printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n");
-               BUG();
-       }
-#endif
-
-       ret = nand_scan_ident(mtd, maxchips);
+       ret = nand_scan_ident(mtd, maxchips, NULL);
        if (!ret)
                ret = nand_scan_tail(mtd);
        return ret;
@@ -2921,40 +2888,9 @@ void nand_release(struct mtd_info *mtd)
        /* Deregister partitions */
        del_mtd_partitions(mtd);
 #endif
-       /* Deregister the device */
-       /* XXX U-BOOT XXX */
-#if 0
-       del_mtd_device(mtd);
-#endif
 
        /* Free bad block table memory */
        kfree(chip->bbt);
        if (!(chip->options & NAND_OWN_BUFFERS))
                kfree(chip->buffers);
 }
-
-/* XXX U-BOOT XXX */
-#if 0
-EXPORT_SYMBOL_GPL(nand_scan);
-EXPORT_SYMBOL_GPL(nand_scan_ident);
-EXPORT_SYMBOL_GPL(nand_scan_tail);
-EXPORT_SYMBOL_GPL(nand_release);
-
-static int __init nand_base_init(void)
-{
-       led_trigger_register_simple("nand-disk", &nand_led_trigger);
-       return 0;
-}
-
-static void __exit nand_base_exit(void)
-{
-       led_trigger_unregister_simple(nand_led_trigger);
-}
-
-module_init(nand_base_init);
-module_exit(nand_base_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>");
-MODULE_DESCRIPTION("Generic NAND flash driver code");
-#endif