]> git.ipfire.org Git - people/ms/u-boot.git/commitdiff
Merge branch 'master' of git://git.denx.de/u-boot-cfi-flash
authorWolfgang Denk <wd@denx.de>
Sat, 11 Feb 2012 21:16:47 +0000 (22:16 +0100)
committerWolfgang Denk <wd@denx.de>
Sat, 11 Feb 2012 21:16:47 +0000 (22:16 +0100)
* 'master' of git://git.denx.de/u-boot-cfi-flash:
  add STM29F400BB to table of supported legacy flashs
  * Fix: watchdog timed out, if flash blank (0xFF) blocks

75 files changed:
arch/arm/cpu/armv7/am33xx/clock.c
arch/arm/include/asm/arch-am33xx/common_def.h
arch/arm/include/asm/arch-am33xx/cpu.h
arch/arm/include/asm/arch-am33xx/i2c.h [new file with mode: 0644]
board/ti/am335x/evm.c
board/ti/am335x/mux.c
doc/README.nand
drivers/i2c/omap24xx_i2c.c
drivers/i2c/omap24xx_i2c.h
drivers/mtd/nand/Makefile
drivers/mtd/nand/fsl_elbc_nand.c
drivers/mtd/nand/nand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_bbt.c
drivers/mtd/nand/nand_bch.c [new file with mode: 0644]
drivers/mtd/nand/nand_ids.c
drivers/mtd/nand/nand_spl_simple.c
include/configs/P1_P2_RDB.h
include/configs/PMC440.h
include/configs/SIMPC8313.h
include/configs/VCMA9.h
include/configs/acadia.h
include/configs/am335x_evm.h
include/configs/am3517_crane.h
include/configs/am3517_evm.h
include/configs/aria.h
include/configs/at91sam9m10g45ek.h
include/configs/bamboo.h
include/configs/bf526-ezbrd.h
include/configs/bf527-ad7160-eval.h
include/configs/bf527-ezkit.h
include/configs/bf548-ezkit.h
include/configs/cam_enc_4xx.h
include/configs/canyonlands.h
include/configs/cm-bf527.h
include/configs/cpu9260.h
include/configs/da830evm.h
include/configs/da850evm.h
include/configs/davinci_dm355leopard.h
include/configs/devkit8000.h
include/configs/ea20.h
include/configs/eb_cpux9k2.h
include/configs/enbw_cmc.h
include/configs/hawkboard.h
include/configs/kilauea.h
include/configs/km/km_arm.h
include/configs/m28evk.h
include/configs/mecp5123.h
include/configs/mpc5121ads.h
include/configs/mv-common.h
include/configs/omap3_beagle.h
include/configs/omap3_evm.h
include/configs/omap3_evm_quick_nand.h
include/configs/pdm360ng.h
include/configs/pm9261.h
include/configs/pm9263.h
include/configs/pm9g45.h
include/configs/qi_lb60.h
include/configs/sequoia.h
include/configs/smdk2410.h
include/configs/smdk6400.h
include/configs/tam3517-common.h
include/configs/tnetv107x_evm.h
include/configs/tt01.h
include/linux/bch.h [new file with mode: 0644]
include/linux/mtd/bbm.h
include/linux/mtd/nand.h
include/linux/mtd/nand_bch.h [new file with mode: 0644]
include/linux/mtd/nand_ecc.h
include/linux/string.h
include/nand.h
lib/Makefile
lib/bch.c [new file with mode: 0644]
lib/string.c
nand_spl/nand_boot.c

index 98cfd938140d219c3e098d7267f46a5f62900024..bbb9c1353f211fd563c8bf1807c087f8662a60cc 100644 (file)
@@ -113,6 +113,11 @@ static void enable_per_clocks(void)
        writel(PRCM_MOD_EN, &cmper->mmc0clkctrl);
        while (readl(&cmper->mmc0clkctrl) != PRCM_MOD_EN)
                ;
+
+       /* i2c0 */
+       writel(PRCM_MOD_EN, &cmwkup->wkup_i2c0ctrl);
+       while (readl(&cmwkup->wkup_i2c0ctrl) != PRCM_MOD_EN)
+               ;
 }
 
 static void mpu_pll_config(void)
index 767932daea8eba292a021eec527c3d68b4728bb5..aa3b554536889ec10e10be64034600970f64e8b2 100644 (file)
@@ -18,5 +18,6 @@
 
 extern void enable_uart0_pin_mux(void);
 extern void enable_mmc0_pin_mux(void);
+extern void enable_i2c0_pin_mux(void);
 
 #endif/*__COMMON_DEF_H__ */
index 25558a2b2c8aa93be773d9108d118f312a04f369..cd002e632d22383ee9b96f2d6e9ac26fa41f1a6e 100644 (file)
@@ -95,7 +95,8 @@ struct cm_wkuppll {
        unsigned int divm2dpllper;      /* offset 0xAC */
        unsigned int resv11[1];
        unsigned int wkup_uart0ctrl;    /* offset 0xB4 */
-       unsigned int resv12[8];
+       unsigned int wkup_i2c0ctrl;     /* offset 0xB8 */
+       unsigned int resv12[7];
        unsigned int divm6dpllcore;     /* offset 0xD8 */
 };
 
diff --git a/arch/arm/include/asm/arch-am33xx/i2c.h b/arch/arm/include/asm/arch-am33xx/i2c.h
new file mode 100644 (file)
index 0000000..366e2bb
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * (C) Copyright 2012
+ * Texas Instruments, <www.ti.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#ifndef _I2C_H_
+#define _I2C_H_
+
+#define  I2C_BASE1             0x44E0B000
+#define  I2C_BASE2             0x4802A000
+#define  I2C_BASE3             0x4819C000
+#define         I2C_BUS_MAX            3
+
+#define I2C_DEFAULT_BASE               I2C_BASE1
+
+struct i2c {
+       unsigned short revnb_lo;        /* 0x00 */
+       unsigned short res1;
+       unsigned short revnb_hi;        /* 0x04 */
+       unsigned short res2[13];
+       unsigned short sysc;            /* 0x20 */
+       unsigned short res3;
+       unsigned short irqstatus_raw;   /* 0x24 */
+       unsigned short res4;
+       unsigned short stat;            /* 0x28 */
+       unsigned short res5;
+       unsigned short ie;              /* 0x2C */
+       unsigned short res6;
+       unsigned short irqenable_clr;   /* 0x30 */
+       unsigned short res7;
+       unsigned short iv;              /* 0x34 */
+       unsigned short res8[45];
+       unsigned short syss;            /* 0x90 */
+       unsigned short res9;
+       unsigned short buf;             /* 0x94 */
+       unsigned short res10;
+       unsigned short cnt;             /* 0x98 */
+       unsigned short res11;
+       unsigned short data;            /* 0x9C */
+       unsigned short res13;
+       unsigned short res14;           /* 0xA0 */
+       unsigned short res15;
+       unsigned short con;             /* 0xA4 */
+       unsigned short res16;
+       unsigned short oa;              /* 0xA8 */
+       unsigned short res17;
+       unsigned short sa;              /* 0xAC */
+       unsigned short res18;
+       unsigned short psc;             /* 0xB0 */
+       unsigned short res19;
+       unsigned short scll;            /* 0xB4 */
+       unsigned short res20;
+       unsigned short sclh;            /* 0xB8 */
+       unsigned short res21;
+       unsigned short systest;         /* 0xBC */
+       unsigned short res22;
+       unsigned short bufstat;         /* 0xC0 */
+       unsigned short res23;
+};
+
+#define I2C_IP_CLK                     48000000
+#define I2C_INTERNAL_SAMLPING_CLK      12000000
+
+#endif /* _I2C_H_ */
index 6a9f788299f818cefde1f99107cb0f7e584d53d8..13dc60361a272281439be39c85795f7e54a77a3e 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/arch/hardware.h>
 #include <asm/arch/common_def.h>
 #include <serial.h>
+#include <i2c.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -42,6 +43,12 @@ int init_basic_setup(void)
 int board_init(void)
 {
        enable_uart0_pin_mux();
+
+#ifdef CONFIG_I2C
+       enable_i2c0_pin_mux();
+       i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+#endif
+
        init_basic_setup();
 
        return 0;
index 4cb0cdf361a8a8782e77930ab48bdc483e214cc2..9ccb43642b38cc44960a7893f7af8de161f52539 100644 (file)
@@ -272,6 +272,14 @@ static struct module_pin_mux mmc0_pin_mux[] = {
 };
 #endif
 
+static struct module_pin_mux i2c0_pin_mux[] = {
+       {OFFSET(i2c0_sda), (MODE(0) | RXACTIVE |
+                       PULLUDEN | SLEWCTRL)}, /* I2C_DATA */
+       {OFFSET(i2c0_scl), (MODE(0) | RXACTIVE |
+                       PULLUDEN | SLEWCTRL)}, /* I2C_SCLK */
+       {-1},
+};
+
 /*
  * Configure the pin mux for the module
  */
@@ -297,3 +305,8 @@ void enable_mmc0_pin_mux(void)
        configure_module_pin_mux(mmc0_pin_mux);
 }
 #endif
+
+void enable_i2c0_pin_mux(void)
+{
+       configure_module_pin_mux(i2c0_pin_mux);
+}
index 023740e1d364452f77316cf97968be48faf9cd40..04a87c99184be6e229cfbe3d5a8d035adfd6894d 100644 (file)
@@ -120,6 +120,68 @@ Configuration Options:
    CONFIG_SYS_NAND_MAX_CHIPS
       The maximum number of NAND chips per device to be supported.
 
+   CONFIG_SYS_NAND_SELF_INIT
+      Traditionally, glue code in drivers/mtd/nand/nand.c has driven
+      the initialization process -- it provides the mtd and nand
+      structs, calls a board init function for a specific device,
+      calls nand_scan(), and registers with mtd.
+
+      This arrangement does not provide drivers with the flexibility to
+      run code between nand_scan_ident() and nand_scan_tail(), or other
+      deviations from the "normal" flow.
+
+      If a board defines CONFIG_SYS_NAND_SELF_INIT, drivers/mtd/nand/nand.c
+      will make one call to board_nand_init(), with no arguments.  That
+      function is responsible for calling a driver init function for
+      each NAND device on the board, that performs all initialization
+      tasks except setting mtd->name, and registering with the rest of
+      U-Boot.  Those last tasks are accomplished by calling  nand_register()
+      on the new mtd device.
+
+      Example of new init to be added to the end of an existing driver
+      init:
+
+       /*
+        * devnum is the device number to be used in nand commands
+        * and in mtd->name.  Must be less than
+        * CONFIG_SYS_NAND_MAX_DEVICE.
+        */
+       mtd = &nand_info[devnum];
+
+       /* chip is struct nand_chip, and is now provided by the driver. */
+       mtd->priv = &chip;
+
+       /*
+        * Fill in appropriate values if this driver uses these fields,
+        * or uses the standard read_byte/write_buf/etc. functions from
+        * nand_base.c that use these fields.
+        */
+       chip.IO_ADDR_R = ...;
+       chip.IO_ADDR_W = ...;
+
+       if (nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_CHIPS, NULL))
+               error out
+
+       /*
+        * Insert here any code you wish to run after the chip has been
+        * identified, but before any other I/O is done.
+        */
+
+       if (nand_scan_tail(mtd))
+               error out
+
+       if (nand_register(devnum))
+               error out
+
+      In addition to providing more flexibility to the driver, it reduces
+      the difference between a U-Boot driver and its Linux counterpart.
+      nand_init() is now reduced to calling board_nand_init() once, and
+      printing a size summary.  This should also make it easier to
+      transition to delayed NAND initialization.
+
+      Please convert your driver even if you don't need the extra
+      flexibility, so that one day we can eliminate the old mechanism.
+
 NOTE:
 =====
 
index a7ffd95d5d7f4d19d82a5041d88774e66f21ce1a..f06af02ba31336954ace8cd312a0da07b93c000e 100644 (file)
 
 DECLARE_GLOBAL_DATA_PTR;
 
-#define I2C_TIMEOUT    1000
+#define I2C_STAT_TIMEO (1 << 31)
+#define I2C_TIMEOUT    10
 
-static void wait_for_bb(void);
-static u16 wait_for_pin(void);
+static u32 wait_for_bb(void);
+static u32 wait_for_status_mask(u16 mask);
 static void flush_fifo(void);
 
 /*
@@ -50,7 +51,6 @@ void i2c_init(int speed, int slaveadd)
        int psc, fsscll, fssclh;
        int hsscll = 0, hssclh = 0;
        u32 scll, sclh;
-       int timeout = I2C_TIMEOUT;
 
        /* Only handle standard, fast and high speeds */
        if ((speed != OMAP_I2C_STANDARD) &&
@@ -112,24 +112,14 @@ void i2c_init(int speed, int slaveadd)
                sclh = (unsigned int)fssclh;
        }
 
+       if (gd->flags & GD_FLG_RELOC)
+               bus_initialized[current_bus] = 1;
+
        if (readw(&i2c_base->con) & I2C_CON_EN) {
                writew(0, &i2c_base->con);
                udelay(50000);
        }
 
-       writew(0x2, &i2c_base->sysc); /* for ES2 after soft reset */
-       udelay(1000);
-
-       writew(I2C_CON_EN, &i2c_base->con);
-       while (!(readw(&i2c_base->syss) & I2C_SYSS_RDONE) && timeout--) {
-               if (timeout <= 0) {
-                       puts("ERROR: Timeout in soft-reset\n");
-                       return;
-               }
-               udelay(1000);
-       }
-
-       writew(0, &i2c_base->con);
        writew(psc, &i2c_base->psc);
        writew(scll, &i2c_base->scll);
        writew(sclh, &i2c_base->sclh);
@@ -145,81 +135,6 @@ void i2c_init(int speed, int slaveadd)
        flush_fifo();
        writew(0xFFFF, &i2c_base->stat);
        writew(0, &i2c_base->cnt);
-
-       if (gd->flags & GD_FLG_RELOC)
-               bus_initialized[current_bus] = 1;
-}
-
-static int i2c_read_byte(u8 devaddr, u8 regoffset, u8 *value)
-{
-       int i2c_error = 0;
-       u16 status;
-
-       /* wait until bus not busy */
-       wait_for_bb();
-
-       /* one byte only */
-       writew(1, &i2c_base->cnt);
-       /* set slave address */
-       writew(devaddr, &i2c_base->sa);
-       /* no stop bit needed here */
-       writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT |
-             I2C_CON_TRX, &i2c_base->con);
-
-       /* send register offset */
-       while (1) {
-               status = wait_for_pin();
-               if (status == 0 || status & I2C_STAT_NACK) {
-                       i2c_error = 1;
-                       goto read_exit;
-               }
-               if (status & I2C_STAT_XRDY) {
-                       /* Important: have to use byte access */
-                       writeb(regoffset, &i2c_base->data);
-                       writew(I2C_STAT_XRDY, &i2c_base->stat);
-               }
-               if (status & I2C_STAT_ARDY) {
-                       writew(I2C_STAT_ARDY, &i2c_base->stat);
-                       break;
-               }
-       }
-
-       /* set slave address */
-       writew(devaddr, &i2c_base->sa);
-       /* read one byte from slave */
-       writew(1, &i2c_base->cnt);
-       /* need stop bit here */
-       writew(I2C_CON_EN | I2C_CON_MST |
-               I2C_CON_STT | I2C_CON_STP,
-               &i2c_base->con);
-
-       /* receive data */
-       while (1) {
-               status = wait_for_pin();
-               if (status == 0 || status & I2C_STAT_NACK) {
-                       i2c_error = 1;
-                       goto read_exit;
-               }
-               if (status & I2C_STAT_RRDY) {
-#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
-       defined(CONFIG_OMAP44XX)
-                       *value = readb(&i2c_base->data);
-#else
-                       *value = readw(&i2c_base->data);
-#endif
-                       writew(I2C_STAT_RRDY, &i2c_base->stat);
-               }
-               if (status & I2C_STAT_ARDY) {
-                       writew(I2C_STAT_ARDY, &i2c_base->stat);
-                       break;
-               }
-       }
-
-read_exit:
-       flush_fifo();
-       writew(0xFFFF, &i2c_base->stat);
-       writew(0, &i2c_base->cnt);
-       return i2c_error;
 }
 
 static void flush_fifo(void)
@@ -232,7 +147,7 @@ static void flush_fifo(void)
                stat = readw(&i2c_base->stat);
                if (stat == I2C_STAT_RRDY) {
 #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
-       defined(CONFIG_OMAP44XX)
+       defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX)
                        readb(&i2c_base->data);
 #else
                        readw(&i2c_base->data);
@@ -246,32 +161,42 @@ static void flush_fifo(void)
 
 int i2c_probe(uchar chip)
 {
-       u16 status;
+       u32 status;
        int res = 1; /* default = fail */
 
        if (chip == readw(&i2c_base->oa))
                return res;
 
        /* wait until bus not busy */
-       wait_for_bb();
+       status = wait_for_bb();
+       /* exit on BUS busy */
+       if (status & I2C_STAT_TIMEO)
+               return res;
 
        /* try to write one byte */
        writew(1, &i2c_base->cnt);
        /* set slave address */
        writew(chip, &i2c_base->sa);
        /* stop bit needed here */
-       writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
-              I2C_CON_STP, &i2c_base->con);
-
-       status = wait_for_pin();
-
-       /* check for ACK (!NAK) */
-       if (!(status & I2C_STAT_NACK))
-               res = 0;
-
-       /* abort transfer (force idle state) */
-       writew(0, &i2c_base->con);
-
+       writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT
+                       | I2C_CON_STP, &i2c_base->con);
+       /* enough delay for the NACK bit set */
+       udelay(9000);
+
+       if (!(readw(&i2c_base->stat) & I2C_STAT_NACK)) {
+               res = 0;      /* success case */
+               flush_fifo();
+               writew(0xFFFF, &i2c_base->stat);
+       } else {
+               /* failure, clear sources*/
+               writew(0xFFFF, &i2c_base->stat);
+               /* finish up xfer */
+               writew(readw(&i2c_base->con) | I2C_CON_STP, &i2c_base->con);
+               status = wait_for_bb();
+               /* exit on BUS busy */
+               if (status & I2C_STAT_TIMEO)
+                       return res;
+       }
        flush_fifo();
        /* don't allow any more data in... we don't want it. */
        writew(0, &i2c_base->cnt);
@@ -281,111 +206,315 @@ int i2c_probe(uchar chip)
 
 int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
 {
-       int i;
+       int i2c_error = 0, i;
+       u32 status;
 
-       if (alen > 1) {
-               printf("I2C read: addr len %d not supported\n", alen);
+       if ((alen > 2) || (alen < 0))
+               return 1;
+
+       if (alen < 2) {
+               if (addr + len > 256)
+                       return 1;
+       } else if (addr + len > 0xFFFF) {
                return 1;
        }
 
-       if (addr + len > 256) {
-               puts("I2C read: address out of range\n");
+       /* wait until bus not busy */
+       status = wait_for_bb();
+
+       /* exit on BUS busy */
+       if (status & I2C_STAT_TIMEO)
                return 1;
+
+       writew((alen & 0xFF), &i2c_base->cnt);
+       /* set slave address */
+       writew(chip, &i2c_base->sa);
+       /* Clear the Tx & Rx FIFOs */
+       writew((readw(&i2c_base->buf) | I2C_RXFIFO_CLEAR |
+               I2C_TXFIFO_CLEAR), &i2c_base->buf);
+       /* no stop bit needed here */
+       writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_TRX |
+               I2C_CON_STT, &i2c_base->con);
+
+       /* wait for Transmit ready condition */
+       status = wait_for_status_mask(I2C_STAT_XRDY | I2C_STAT_NACK);
+
+       if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO))
+               i2c_error = 1;
+
+       if (!i2c_error) {
+               if (status & I2C_STAT_XRDY) {
+                       switch (alen) {
+                       case 2:
+                               /* Send address MSByte */
+#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
+                       defined(CONFIG_AM33XX)
+                               writew(((addr >> 8) & 0xFF), &i2c_base->data);
+
+                               /* Clearing XRDY event */
+                               writew((status & I2C_STAT_XRDY),
+                                               &i2c_base->stat);
+                               /* wait for Transmit ready condition */
+                               status = wait_for_status_mask(I2C_STAT_XRDY |
+                                               I2C_STAT_NACK);
+
+                               if (status & (I2C_STAT_NACK |
+                                               I2C_STAT_TIMEO)) {
+                                       i2c_error = 1;
+                                       break;
+                               }
+#endif
+                       case 1:
+#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
+                       defined(CONFIG_AM33XX)
+                               /* Send address LSByte */
+                               writew((addr & 0xFF), &i2c_base->data);
+#else
+                               /* Send address Short word */
+                               writew((addr & 0xFFFF), &i2c_base->data);
+#endif
+                               /* Clearing XRDY event */
+                               writew((status & I2C_STAT_XRDY),
+                                       &i2c_base->stat);
+                               /*wait for Transmit ready condition */
+                               status = wait_for_status_mask(I2C_STAT_ARDY |
+                                               I2C_STAT_NACK);
+
+                               if (status & (I2C_STAT_NACK |
+                                       I2C_STAT_TIMEO)) {
+                                       i2c_error = 1;
+                                       break;
+                               }
+                       }
+               } else
+                       i2c_error = 1;
        }
 
-       for (i = 0; i < len; i++) {
-               if (i2c_read_byte(chip, addr + i, &buffer[i])) {
-                       puts("I2C read: I/O error\n");
-                       i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
-                       return 1;
+       /* Wait for ARDY to set */
+       status = wait_for_status_mask(I2C_STAT_ARDY | I2C_STAT_NACK
+                       | I2C_STAT_AL);
+
+       if (!i2c_error) {
+               /* set slave address */
+               writew(chip, &i2c_base->sa);
+               writew((len & 0xFF), &i2c_base->cnt);
+               /* Clear the Tx & Rx FIFOs */
+               writew((readw(&i2c_base->buf) | I2C_RXFIFO_CLEAR |
+                       I2C_TXFIFO_CLEAR), &i2c_base->buf);
+               /* need stop bit here */
+               writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP,
+                       &i2c_base->con);
+
+               for (i = 0; i < len; i++) {
+                       /* wait for Receive condition */
+                       status = wait_for_status_mask(I2C_STAT_RRDY |
+                               I2C_STAT_NACK);
+                       if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO)) {
+                               i2c_error = 1;
+                               break;
+                       }
+
+                       if (status & I2C_STAT_RRDY) {
+#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
+                       defined(CONFIG_AM33XX)
+                               buffer[i] = readb(&i2c_base->data);
+#else
+                               *((u16 *)&buffer[i]) =
+                                       readw(&i2c_base->data) & 0xFFFF;
+                               i++;
+#endif
+                               writew((status & I2C_STAT_RRDY),
+                                       &i2c_base->stat);
+                               udelay(1000);
+                       } else {
+                               i2c_error = 1;
+                       }
                }
        }
 
+       /* Wait for ARDY to set */
+       status = wait_for_status_mask(I2C_STAT_ARDY | I2C_STAT_NACK
+                       | I2C_STAT_AL);
+
+       if (i2c_error) {
+               writew(0, &i2c_base->con);
+               return 1;
+       }
+
+       writew(I2C_CON_EN, &i2c_base->con);
+
+       while (readw(&i2c_base->stat)
+               || (readw(&i2c_base->con) & I2C_CON_MST)) {
+               udelay(10000);
+               writew(0xFFFF, &i2c_base->stat);
+       }
+
+       writew(I2C_CON_EN, &i2c_base->con);
+       flush_fifo();
+       writew(0xFFFF, &i2c_base->stat);
+       writew(0, &i2c_base->cnt);
+
        return 0;
 }
 
 int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
 {
-       int i;
-       u16 status;
-       int i2c_error = 0;
 
-       if (alen > 1) {
-               printf("I2C write: addr len %d not supported\n", alen);
+       int i, i2c_error = 0;
+       u32 status;
+       u16 writelen;
+
+       if (alen > 2)
                return 1;
-       }
 
-       if (addr + len > 256) {
-               printf("I2C write: address 0x%x + 0x%x out of range\n",
-                               addr, len);
+       if (alen < 2) {
+               if (addr + len > 256)
+                       return 1;
+       } else if (addr + len > 0xFFFF) {
                return 1;
        }
 
        /* wait until bus not busy */
-       wait_for_bb();
+       status = wait_for_bb();
 
-       /* start address phase - will write regoffset + len bytes data */
-       /* TODO consider case when !CONFIG_OMAP243X/34XX/44XX */
-       writew(alen + len, &i2c_base->cnt);
+       /* exiting on BUS busy */
+       if (status & I2C_STAT_TIMEO)
+               return 1;
+
+       writelen = (len & 0xFFFF) + alen;
+
+       /* two bytes */
+       writew((writelen & 0xFFFF), &i2c_base->cnt);
+       /* Clear the Tx & Rx FIFOs */
+       writew((readw(&i2c_base->buf) | I2C_RXFIFO_CLEAR |
+                       I2C_TXFIFO_CLEAR), &i2c_base->buf);
        /* set slave address */
        writew(chip, &i2c_base->sa);
        /* stop bit needed here */
        writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
                I2C_CON_STP, &i2c_base->con);
 
-       /* Send address byte */
-       status = wait_for_pin();
+       /* wait for Transmit ready condition */
+       status = wait_for_status_mask(I2C_STAT_XRDY | I2C_STAT_NACK);
 
-       if (status == 0 || status & I2C_STAT_NACK) {
+       if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO))
                i2c_error = 1;
-               printf("error waiting for i2c address ACK (status=0x%x)\n",
-                     status);
-               goto write_exit;
-       }
 
-       if (status & I2C_STAT_XRDY) {
-               writeb(addr & 0xFF, &i2c_base->data);
-               writew(I2C_STAT_XRDY, &i2c_base->stat);
-       } else {
-               i2c_error = 1;
-               printf("i2c bus not ready for transmit (status=0x%x)\n",
-                     status);
-               goto write_exit;
-       }
+       if (!i2c_error) {
+               if (status & I2C_STAT_XRDY) {
+                       switch (alen) {
+#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
+                       defined(CONFIG_AM33XX)
+                       case 2:
+                               /* send out MSB byte */
+                               writeb(((addr >> 8) & 0xFF), &i2c_base->data);
+#else
+                               writeb((addr  & 0xFFFF), &i2c_base->data);
+                               break;
+#endif
+                               /* Clearing XRDY event */
+                               writew((status & I2C_STAT_XRDY),
+                                       &i2c_base->stat);
+                               /*waiting for Transmit ready * condition */
+                               status = wait_for_status_mask(I2C_STAT_XRDY |
+                                               I2C_STAT_NACK);
+
+                               if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO)) {
+                                       i2c_error = 1;
+                                       break;
+                               }
+                       case 1:
+#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
+                       defined(CONFIG_AM33XX)
+                               /* send out MSB byte */
+                               writeb((addr  & 0xFF), &i2c_base->data);
+#else
+                               writew(((buffer[0] << 8) | (addr & 0xFF)),
+                                       &i2c_base->data);
+#endif
+                       }
 
-       /* address phase is over, now write data */
-       for (i = 0; i < len; i++) {
-               status = wait_for_pin();
+                       /* Clearing XRDY event */
+                       writew((status & I2C_STAT_XRDY), &i2c_base->stat);
+               }
+
+               /* waiting for Transmit ready condition */
+               status = wait_for_status_mask(I2C_STAT_XRDY | I2C_STAT_NACK);
 
-               if (status == 0 || status & I2C_STAT_NACK) {
+               if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO))
                        i2c_error = 1;
-                       printf("i2c error waiting for data ACK (status=0x%x)\n",
-                                       status);
-                       goto write_exit;
+
+               if (!i2c_error) {
+                       for (i = ((alen > 1) ? 0 : 1); i < len; i++) {
+                               if (status & I2C_STAT_XRDY) {
+#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
+                               defined(CONFIG_AM33XX)
+                                       writeb((buffer[i] & 0xFF),
+                                               &i2c_base->data);
+#else
+                                       writew((((buffer[i] << 8) |
+                                       buffer[i + 1]) & 0xFFFF),
+                                               &i2c_base->data);
+                                       i++;
+#endif
+                               } else
+                                       i2c_error = 1;
+                                       /* Clearing XRDY event */
+                                       writew((status & I2C_STAT_XRDY),
+                                               &i2c_base->stat);
+                                       /* waiting for XRDY condition */
+                                       status = wait_for_status_mask(
+                                               I2C_STAT_XRDY |
+                                               I2C_STAT_ARDY |
+                                               I2C_STAT_NACK);
+                                       if (status & (I2C_STAT_NACK |
+                                               I2C_STAT_TIMEO)) {
+                                               i2c_error = 1;
+                                               break;
+                                       }
+                                       if (status & I2C_STAT_ARDY)
+                                               break;
+                       }
                }
+       }
 
-               if (status & I2C_STAT_XRDY) {
-                       writeb(buffer[i], &i2c_base->data);
-                       writew(I2C_STAT_XRDY, &i2c_base->stat);
-               } else {
-                       i2c_error = 1;
-                       printf("i2c bus not ready for Tx (i=%d)\n", i);
-                       goto write_exit;
+       status = wait_for_status_mask(I2C_STAT_ARDY | I2C_STAT_NACK |
+                               I2C_STAT_AL);
+
+       if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO))
+               i2c_error = 1;
+
+       if (i2c_error) {
+               writew(0, &i2c_base->con);
+               return 1;
+       }
+
+       if (!i2c_error) {
+               int eout = 200;
+
+               writew(I2C_CON_EN, &i2c_base->con);
+               while ((status = readw(&i2c_base->stat)) ||
+                               (readw(&i2c_base->con) & I2C_CON_MST)) {
+                       udelay(1000);
+                       /* have to read to clear intrrupt */
+                       writew(0xFFFF, &i2c_base->stat);
+                       if (--eout == 0)
+                               /* better leave with error than hang */
+                               break;
                }
        }
 
-write_exit:
        flush_fifo();
        writew(0xFFFF, &i2c_base->stat);
-       return i2c_error;
+       writew(0, &i2c_base->cnt);
+       return 0;
 }
 
-static void wait_for_bb(void)
+static u32 wait_for_bb(void)
 {
        int timeout = I2C_TIMEOUT;
-       u16 stat;
+       u32 stat;
 
-       writew(0xFFFF, &i2c_base->stat);        /* clear current interrupts...*/
        while ((stat = readw(&i2c_base->stat) & I2C_STAT_BB) && timeout--) {
                writew(stat, &i2c_base->stat);
                udelay(1000);
@@ -394,30 +523,28 @@ static void wait_for_bb(void)
        if (timeout <= 0) {
                printf("timed out in wait_for_bb: I2C_STAT=%x\n",
                        readw(&i2c_base->stat));
+               stat |= I2C_STAT_TIMEO;
        }
        writew(0xFFFF, &i2c_base->stat);         /* clear delayed stuff*/
+       return stat;
 }
 
-static u16 wait_for_pin(void)
+static u32 wait_for_status_mask(u16 mask)
 {
-       u16 status;
+       u32 status;
        int timeout = I2C_TIMEOUT;
 
        do {
                udelay(1000);
                status = readw(&i2c_base->stat);
-       } while (!(status &
-                  (I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY |
-                   I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK |
-                   I2C_STAT_AL)) && timeout--);
+       } while (!(status & mask) && timeout--);
 
        if (timeout <= 0) {
-               printf("timed out in wait_for_pin: I2C_STAT=%x\n",
+               printf("timed out in wait_for_status_mask: I2C_STAT=%x\n",
                        readw(&i2c_base->stat));
                writew(0xFFFF, &i2c_base->stat);
-               status = 0;
+               status |= I2C_STAT_TIMEO;
        }
-
        return status;
 }
 
index 1f38c232d16461c8f077c40573f637a8957ab2b3..9a0b126b387825c9f7d8d20f2dcacc79a07ab0b9 100644 (file)
@@ -60,7 +60,9 @@
 /* I2C Buffer Configuration Register (I2C_BUF): */
 
 #define I2C_BUF_RDMA_EN                (1 << 15) /* Receive DMA channel enable */
+#define I2C_RXFIFO_CLEAR       (1 << 14) /* RX FIFO Clear */
 #define I2C_BUF_XDMA_EN                (1 << 7)  /* Transmit DMA channel enable */
+#define I2C_TXFIFO_CLEAR       (1 << 6)  /* TX FIFO clear */
 
 /* I2C Configuration Register (I2C_CON): */
 
index 36ee454304351358dcddd36b756f4d87654c3dc1..998fc73497caf4ca33e125ffafbb7b1d08b7d615 100644 (file)
@@ -39,8 +39,9 @@ COBJS-y += nand_bbt.o
 COBJS-y += nand_ids.o
 COBJS-y += nand_util.o
 endif
-COBJS-y += nand_ecc.o
+COBJS-$(CONFIG_MTD_ECC_SOFT) += nand_ecc.o
 COBJS-y += nand_base.o
+COBJS-$(CONFIG_NAND_ECC_BCH) += nand_bch.o
 
 COBJS-$(CONFIG_NAND_ATMEL) += atmel_nand.o
 COBJS-$(CONFIG_DRIVER_NAND_BFIN) += bfin_nand.o
index 4d1e527db103f54359f6744fa9df601007ca5ce6..9076ad4cdc36ac517ef1658f91a0955c2223ab16 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <common.h>
 #include <malloc.h>
+#include <nand.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
@@ -57,7 +58,6 @@ struct fsl_elbc_ctrl;
 /* mtd information per set */
 
 struct fsl_elbc_mtd {
-       struct mtd_info mtd;
        struct nand_chip chip;
        struct fsl_elbc_ctrl *ctrl;
 
@@ -340,18 +340,21 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
 
        /* READID must read all 5 possible bytes while CEB is active */
        case NAND_CMD_READID:
-               vdbg("fsl_elbc_cmdfunc: NAND_CMD_READID.\n");
+       case NAND_CMD_PARAM:
+               vdbg("fsl_elbc_cmdfunc: NAND_CMD 0x%x.\n", command);
 
                out_be32(&lbc->fir, (FIR_OP_CW0 << FIR_OP0_SHIFT) |
                                    (FIR_OP_UA  << FIR_OP1_SHIFT) |
                                    (FIR_OP_RBW << FIR_OP2_SHIFT));
-               out_be32(&lbc->fcr, NAND_CMD_READID << FCR_CMD0_SHIFT);
-               /* 5 bytes for manuf, device and exts */
-               out_be32(&lbc->fbcr, 5);
-               ctrl->read_bytes = 5;
+               out_be32(&lbc->fcr, command << FCR_CMD0_SHIFT);
+               /*
+                * although currently it's 8 bytes for READID, we always read
+                * the maximum 256 bytes(for PARAM)
+                */
+               out_be32(&lbc->fbcr, 256);
+               ctrl->read_bytes = 256;
                ctrl->use_mdr = 1;
-               ctrl->mdr = 0;
-
+               ctrl->mdr = column;
                set_addr(mtd, 0, 0, 0);
                fsl_elbc_run_command(mtd);
                return;
@@ -683,10 +686,13 @@ static void fsl_elbc_ctrl_init(void)
        elbc_ctrl->addr = NULL;
 }
 
-int board_nand_init(struct nand_chip *nand)
+static int fsl_elbc_chip_init(int devnum, u8 *addr)
 {
+       struct mtd_info *mtd = &nand_info[devnum];
+       struct nand_chip *nand;
        struct fsl_elbc_mtd *priv;
        uint32_t br = 0, or = 0;
+       int ret;
 
        if (!elbc_ctrl) {
                fsl_elbc_ctrl_init();
@@ -699,19 +705,19 @@ int board_nand_init(struct nand_chip *nand)
                return -ENOMEM;
 
        priv->ctrl = elbc_ctrl;
-       priv->vbase = nand->IO_ADDR_R;
+       priv->vbase = addr;
 
        /* Find which chip select it is connected to.  It'd be nice
         * if we could pass more than one datum to the NAND driver...
         */
        for (priv->bank = 0; priv->bank < MAX_BANKS; priv->bank++) {
-               phys_addr_t base_addr = virt_to_phys(nand->IO_ADDR_R);
+               phys_addr_t phys_addr = virt_to_phys(addr);
 
                br = in_be32(&elbc_ctrl->regs->bank[priv->bank].br);
                or = in_be32(&elbc_ctrl->regs->bank[priv->bank].or);
 
                if ((br & BR_V) && (br & BR_MSEL) == BR_MS_FCM &&
-                   (br & or & BR_BA) == BR_PHYS_ADDR(base_addr))
+                   (br & or & BR_BA) == BR_PHYS_ADDR(phys_addr))
                        break;
        }
 
@@ -721,6 +727,9 @@ int board_nand_init(struct nand_chip *nand)
                return -ENODEV;
        }
 
+       nand = &priv->chip;
+       mtd->priv = nand;
+
        elbc_ctrl->chips[priv->bank] = priv;
 
        /* fill in nand_chip structure */
@@ -791,5 +800,32 @@ int board_nand_init(struct nand_chip *nand)
                }
        }
 
+       ret = nand_scan_ident(mtd, 1, NULL);
+       if (ret)
+               return ret;
+
+       ret = nand_scan_tail(mtd);
+       if (ret)
+               return ret;
+
+       ret = nand_register(devnum);
+       if (ret)
+               return ret;
+
        return 0;
 }
+
+#ifndef CONFIG_SYS_NAND_BASE_LIST
+#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE }
+#endif
+
+static unsigned long base_address[CONFIG_SYS_MAX_NAND_DEVICE] =
+       CONFIG_SYS_NAND_BASE_LIST;
+
+void board_nand_init(void)
+{
+       int i;
+
+       for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
+               fsl_elbc_chip_init(i, (u8 *)base_address[i]);
+}
index d987f4c85c83539fe47ecf82b23650c1f8dbfab9..4cf4c1c7076c1f933bb77086f68fd3894e98a6f3 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <common.h>
 #include <nand.h>
+#include <errno.h>
 
 #ifndef CONFIG_SYS_NAND_BASE_LIST
 #define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE }
 DECLARE_GLOBAL_DATA_PTR;
 
 int nand_curr_device = -1;
+
+
 nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE];
 
+#ifndef CONFIG_SYS_NAND_SELF_INIT
 static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE];
 static ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LIST;
+#endif
+
+static char dev_name[CONFIG_SYS_MAX_NAND_DEVICE][8];
+
+static unsigned long total_nand_size; /* in kiB */
+
+/* Register an initialized NAND mtd device with the U-Boot NAND command. */
+int nand_register(int devnum)
+{
+       struct mtd_info *mtd;
+
+       if (devnum >= CONFIG_SYS_MAX_NAND_DEVICE)
+               return -EINVAL;
+
+       mtd = &nand_info[devnum];
+
+       sprintf(dev_name[devnum], "nand%d", devnum);
+       mtd->name = dev_name[devnum];
+
+#ifdef CONFIG_MTD_DEVICE
+       /*
+        * Add MTD device so that we can reference it later
+        * via the mtdcore infrastructure (e.g. ubi).
+        */
+       add_mtd_device(mtd);
+#endif
+
+       total_nand_size += mtd->size / 1024;
 
-static const char default_nand_name[] = "nand";
-static __attribute__((unused)) char dev_name[CONFIG_SYS_MAX_NAND_DEVICE][8];
+       if (nand_curr_device == -1)
+               nand_curr_device = devnum;
+
+       return 0;
+}
 
-static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand,
-                          ulong base_addr)
+#ifndef CONFIG_SYS_NAND_SELF_INIT
+static void nand_init_chip(int i)
 {
+       struct mtd_info *mtd = &nand_info[i];
+       struct nand_chip *nand = &nand_chip[i];
+       ulong base_addr = base_address[i];
        int maxchips = CONFIG_SYS_NAND_MAX_CHIPS;
-       static int __attribute__((unused)) i = 0;
 
        if (maxchips < 1)
                maxchips = 1;
-       mtd->priv = nand;
 
+       mtd->priv = nand;
        nand->IO_ADDR_R = nand->IO_ADDR_W = (void  __iomem *)base_addr;
-       if (board_nand_init(nand) == 0) {
-               if (nand_scan(mtd, maxchips) == 0) {
-                       if (!mtd->name)
-                               mtd->name = (char *)default_nand_name;
-#ifdef CONFIG_NEEDS_MANUAL_RELOC
-                       else
-                               mtd->name += gd->reloc_off;
-#endif
 
-#ifdef CONFIG_MTD_DEVICE
-                       /*
-                        * Add MTD device so that we can reference it later
-                        * via the mtdcore infrastructure (e.g. ubi).
-                        */
-                       sprintf(dev_name[i], "nand%d", i);
-                       mtd->name = dev_name[i++];
-                       add_mtd_device(mtd);
-#endif
-               } else
-                       mtd->name = NULL;
-       } else {
-               mtd->name = NULL;
-               mtd->size = 0;
-       }
+       if (board_nand_init(nand))
+               return;
 
+       if (nand_scan(mtd, maxchips))
+               return;
+
+       nand_register(i);
 }
+#endif
 
 void nand_init(void)
 {
+#ifdef CONFIG_SYS_NAND_SELF_INIT
+       board_nand_init();
+#else
        int i;
-       unsigned int size = 0;
-       for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
-               nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]);
-               size += nand_info[i].size / 1024;
-               if (nand_curr_device == -1)
-                       nand_curr_device = i;
-       }
-       printf("%u MiB\n", size / 1024);
+
+       for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
+               nand_init_chip(i);
+#endif
+
+       printf("%lu MiB\n", total_nand_size / 1024);
 
 #ifdef CONFIG_SYS_NAND_SELECT_DEVICE
        /*
index 27f6c776b04d6649992cef0ec79e6552db14c59f..12b960fdb907ba44e3957b02a7b0e7a5f817dbf9 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand_bch.h>
 
 #ifdef CONFIG_MTD_PARTITIONS
 #include <linux/mtd/partitions.h>
@@ -70,7 +71,7 @@ static struct nand_ecclayout nand_oob_8 = {
                {.offset = 3,
                 .length = 2},
                {.offset = 6,
-                .length = 2}}
+                .length = 2} }
 };
 
 static struct nand_ecclayout nand_oob_16 = {
@@ -78,7 +79,7 @@ static struct nand_ecclayout nand_oob_16 = {
        .eccpos = {0, 1, 2, 3, 6, 7},
        .oobfree = {
                {.offset = 8,
-                . length = 8}}
+                . length = 8} }
 };
 
 static struct nand_ecclayout nand_oob_64 = {
@@ -89,24 +90,23 @@ static struct nand_ecclayout nand_oob_64 = {
                   56, 57, 58, 59, 60, 61, 62, 63},
        .oobfree = {
                {.offset = 2,
-                .length = 38}}
+                .length = 38} }
 };
 
 static struct nand_ecclayout nand_oob_128 = {
        .eccbytes = 48,
        .eccpos = {
-                   80,  81,  82,  83,  84,  85,  86,  87,
-                   88,  89,  90,  91,  92,  93,  94,  95,
-                   96,  97,  98,  99, 100, 101, 102, 103,
+                  80, 81, 82, 83, 84, 85, 86, 87,
+                  88, 89, 90, 91, 92, 93, 94, 95,
+                  96, 97, 98, 99, 100, 101, 102, 103,
                   104, 105, 106, 107, 108, 109, 110, 111,
                   112, 113, 114, 115, 116, 117, 118, 119,
                   120, 121, 122, 123, 124, 125, 126, 127},
        .oobfree = {
                {.offset = 2,
-                .length = 78}}
+                .length = 78} }
 };
 
-
 static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd,
                           int new_state);
 
@@ -115,16 +115,47 @@ 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
  *
  * Deselect, release chip lock and wake up anyone waiting on the device
  */
-static void nand_release_device (struct mtd_info *mtd)
+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);
 }
 
 /**
@@ -768,8 +824,9 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
  *
  * 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)
+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;
@@ -850,7 +907,8 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
  * @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)
+static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
+                       uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi)
 {
        int start_step, end_step, num_steps;
        uint32_t *eccpos = chip->ecc.layout->eccpos;
@@ -858,6 +916,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint3
        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;
@@ -896,26 +955,30 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint3
        } 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;
@@ -1082,7 +1145,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
 static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
                                  struct mtd_oob_ops *ops, size_t len)
 {
-       switch(ops->mode) {
+       switch (ops->mode) {
 
        case MTD_OOB_PLACE:
        case MTD_OOB_RAW:
@@ -1094,7 +1157,7 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
                uint32_t boffs = 0, roffs = ops->ooboffs;
                size_t bytes = 0;
 
-               for(; free->length && len; free++, len -= bytes) {
+               for (; free->length && len; free++, len -= bytes) {
                        /* Read request not from offset 0 ? */
                        if (unlikely(roffs)) {
                                if (roffs >= free->length) {
@@ -1140,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;
@@ -1155,7 +1221,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
        buf = ops->datbuf;
        oob = ops->oobbuf;
 
-       while(1) {
+       while (1) {
                WATCHDOG_RESET();
 
                bytes = min(mtd->writesize - col, readlen);
@@ -1173,18 +1239,20 @@ 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, page);
+                                                             bufpoi, page);
                        else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob)
-                               ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi);
+                               ret = chip->ecc.read_subpage(mtd, chip,
+                                                       col, bytes, bufpoi);
                        else
                                ret = chip->ecc.read_page(mtd, chip, bufpoi,
-                                               page);
+                                                         page);
                        if (ret < 0)
                                break;
 
                        /* 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);
                        }
@@ -1192,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)) {
@@ -1259,11 +1323,11 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
        if (mtd->ecc_stats.failed - stats.failed)
                return -EBADMSG;
 
-       return  mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
+       return  mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
 }
 
 /**
- * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
+ * nand_read - [MTD Interface] MTD compatibility function for nand_do_read_ecc
  * @mtd:       MTD device structure
  * @from:      offset to read from
  * @len:       number of bytes to read
@@ -1456,8 +1520,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
        int len;
        uint8_t *buf = ops->oobbuf;
 
-       MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n",
-                 (unsigned long long)from, readlen);
+       MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08Lx, len = %i\n",
+                       __func__, (unsigned long long)from, readlen);
 
        if (ops->mode == MTD_OOB_AUTO)
                len = chip->ecc.layout->oobavail;
@@ -1465,8 +1529,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
                len = mtd->oobsize;
 
        if (unlikely(ops->ooboffs >= len)) {
-               MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: "
-                         "Attempt to start read outside oob\n");
+               MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to start read "
+                                       "outside oob\n", __func__);
                return -EINVAL;
        }
 
@@ -1474,8 +1538,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
        if (unlikely(from >= mtd->size ||
                     ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) -
                                        (from >> chip->page_shift)) * len)) {
-               MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: "
-                         "Attempt read beyond end of device\n");
+               MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt read beyond end "
+                                       "of device\n", __func__);
                return -EINVAL;
        }
 
@@ -1486,7 +1550,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
        realpage = (int)(from >> chip->page_shift);
        page = realpage & chip->pagemask;
 
-       while(1) {
+       while (1) {
                WATCHDOG_RESET();
                sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);
 
@@ -1550,14 +1614,14 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
 
        /* Do not allow reads past end of device */
        if (ops->datbuf && (from + ops->len) > mtd->size) {
-               MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: "
-                         "Attempt read beyond end of device\n");
+               MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt read "
+                               "beyond end of device\n", __func__);
                return -EINVAL;
        }
 
        nand_get_device(chip, mtd, FL_READING);
 
-       switch(ops->mode) {
+       switch (ops->mode) {
        case MTD_OOB_PLACE:
        case MTD_OOB_AUTO:
        case MTD_OOB_RAW:
@@ -1572,7 +1636,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
        else
                ret = nand_do_read_ops(mtd, from, ops);
 
- out:
+out:
        nand_release_device(mtd);
        return ret;
 }
@@ -1601,8 +1665,9 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
  *
  * 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)
+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;
@@ -1789,14 +1854,13 @@ 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) {
+       switch (ops->mode) {
 
        case MTD_OOB_PLACE:
        case MTD_OOB_RAW:
@@ -1808,7 +1872,7 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
                uint32_t boffs = 0, woffs = ops->ooboffs;
                size_t bytes = 0;
 
-               for(; free->length && len; free++, len -= bytes) {
+               for (; free->length && len; free++, len -= bytes) {
                        /* Write request not from offset 0 ? */
                        if (unlikely(woffs)) {
                                if (woffs >= free->length) {
@@ -1834,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
@@ -1850,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;
@@ -1886,7 +1955,11 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
        if (likely(!oob))
                memset(chip->oob_poi, 0xff, mtd->oobsize);
 
-       while(1) {
+       /* Don't allow multipage oob writes with offset */
+       if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen))
+               return -EINVAL;
+
+       while (1) {
                WATCHDOG_RESET();
 
                int bytes = mtd->writesize;
@@ -1903,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));
@@ -1985,8 +2061,8 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
        int chipnr, page, status, len;
        struct nand_chip *chip = mtd->priv;
 
-       MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n",
-                 (unsigned int)to, (int)ops->ooblen);
+       MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n",
+                        __func__, (unsigned int)to, (int)ops->ooblen);
 
        if (ops->mode == MTD_OOB_AUTO)
                len = chip->ecc.layout->oobavail;
@@ -1995,24 +2071,24 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
 
        /* Do not allow write past end of page */
        if ((ops->ooboffs + ops->ooblen) > len) {
-               MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: "
-                         "Attempt to write past end of page\n");
+               MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to write "
+                               "past end of page\n", __func__);
                return -EINVAL;
        }
 
        if (unlikely(ops->ooboffs >= len)) {
-               MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: "
-                         "Attempt to start write outside oob\n");
+               MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to start "
+                               "write outside oob\n", __func__);
                return -EINVAL;
        }
 
-       /* Do not allow reads past end of device */
+       /* Do not allow write past end of device */
        if (unlikely(to >= mtd->size ||
                     ops->ooboffs + ops->ooblen >
                        ((mtd->size >> chip->page_shift) -
                         (to >> chip->page_shift)) * len)) {
-               MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: "
-                         "Attempt write beyond end of device\n");
+               MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt write beyond "
+                               "end of device\n", __func__);
                return -EINVAL;
        }
 
@@ -2039,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);
 
@@ -2067,14 +2143,14 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
 
        /* Do not allow writes past end of device */
        if (ops->datbuf && (to + ops->len) > mtd->size) {
-               MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: "
-                         "Attempt read beyond end of device\n");
+               MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt write beyond "
+                               "end of device\n", __func__);
                return -EINVAL;
        }
 
        nand_get_device(chip, mtd, FL_WRITING);
 
-       switch(ops->mode) {
+       switch (ops->mode) {
        case MTD_OOB_PLACE:
        case MTD_OOB_AUTO:
        case MTD_OOB_RAW:
@@ -2089,7 +2165,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
        else
                ret = nand_do_write_ops(mtd, to, ops);
 
- out:
+out:
        nand_release_device(mtd);
        return ret;
 }
@@ -2158,31 +2234,14 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
        unsigned int bbt_masked_page = 0xffffffff;
        loff_t 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)) {
-               MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
-               return -EINVAL;
-       }
+       MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: start = 0x%012llx, len = %llu\n",
+                               __func__, (unsigned long long)instr->addr,
+                               (unsigned long long)instr->len);
 
-       /* 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");
+       if (check_offs_len(mtd, instr->addr, instr->len))
                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);
@@ -2199,8 +2258,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
 
        /* Check, if it is write protected */
        if (nand_check_wp(mtd)) {
-               MTDDEBUG (MTD_DEBUG_LEVEL0,
-                         "nand_erase: Device is write protected!!!\n");
+               MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Device is write protected!!!\n",
+                                       __func__);
                instr->state = MTD_ERASE_FAILED;
                goto erase_exit;
        }
@@ -2226,8 +2285,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
                 */
                if (!instr->scrub && nand_block_checkbad(mtd, ((loff_t) page) <<
                                        chip->page_shift, 0, allowbbt)) {
-                       printk(KERN_WARNING "nand_erase: attempt to erase a "
-                              "bad block at page 0x%08x\n", page);
+                       printk(KERN_WARNING "%s: attempt to erase a bad block "
+                                       "at page 0x%08x\n", __func__, page);
                        instr->state = MTD_ERASE_FAILED;
                        goto erase_exit;
                }
@@ -2254,10 +2313,11 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
 
                /* See if block erase succeeded */
                if (status & NAND_STATUS_FAIL) {
-                       MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase: "
-                                 "Failed erase, page 0x%08x\n", page);
+                       MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Failed erase, "
+                                       "page 0x%08x\n", __func__, page);
                        instr->state = MTD_ERASE_FAILED;
-                       instr->fail_addr = ((loff_t)page << chip->page_shift);
+                       instr->fail_addr =
+                               ((loff_t)page << chip->page_shift);
                        goto erase_exit;
                }
 
@@ -2292,7 +2352,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
        }
        instr->state = MTD_ERASE_DONE;
 
- erase_exit:
+erase_exit:
 
        ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
 
@@ -2314,9 +2374,9 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
                if (!rewrite_bbt[chipnr])
                        continue;
                /* update the BBT for chip */
-               MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt "
-                         "(%d:0x%0llx 0x%0x)\n", chipnr, rewrite_bbt[chipnr],
-                         chip->bbt_td->pages[chipnr]);
+               MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: nand_update_bbt "
+                       "(%d:0x%0llx 0x%0x)\n", __func__, chipnr,
+                       rewrite_bbt[chipnr], chip->bbt_td->pages[chipnr]);
                nand_update_bbt(mtd, rewrite_bbt[chipnr]);
        }
 
@@ -2334,7 +2394,7 @@ static void nand_sync(struct mtd_info *mtd)
 {
        struct nand_chip *chip = mtd->priv;
 
-       MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n");
+       MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: called\n", __func__);
 
        /* Grab the lock and see if the device is available */
        nand_get_device(chip, mtd, FL_SYNCING);
@@ -2366,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;
@@ -2416,10 +2477,29 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
 }
 
 #ifdef CONFIG_SYS_NAND_ONFI_DETECTION
+/*
+ * sanitize ONFI strings so we can safely print them
+ */
+static void sanitize_string(char *s, size_t len)
+{
+       ssize_t i;
+
+       /* null terminate */
+       s[len - 1] = 0;
+
+       /* remove non printable chars */
+       for (i = 0; i < len - 1; i++) {
+               if (s[i] < ' ' || s[i] > 127)
+                       s[i] = '?';
+       }
+
+       /* remove trailing spaces */
+       strim(s);
+}
+
 static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
 {
        int i;
-
        while (len--) {
                crc ^= *p++ << 8;
                for (i = 0; i < 8; i++)
@@ -2432,14 +2512,14 @@ static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
 /*
  * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise
  */
-static int nand_flash_detect_onfi(struct mtd_info *mtd,
-                                       struct nand_chip *chip,
+static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
                                        int *busw)
 {
        struct nand_onfi_params *p = &chip->onfi_params;
        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')
@@ -2450,7 +2530,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd,
        for (i = 0; i < 3; i++) {
                chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));
                if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) ==
-                                               le16_to_cpu(p->crc)) {
+                               le16_to_cpu(p->crc)) {
                        printk(KERN_INFO "ONFI param page %d valid\n", i);
                        break;
                }
@@ -2475,14 +2555,15 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd,
                chip->onfi_version = 0;
 
        if (!chip->onfi_version) {
-               printk(KERN_INFO "%s: unsupported ONFI "
-                                       "version: %d\n", __func__, val);
+               printk(KERN_INFO "%s: unsupported ONFI version: %d\n",
+                                                               __func__, val);
                return 0;
        }
 
+       sanitize_string(p->manufacturer, sizeof(p->manufacturer));
+       sanitize_string(p->model, sizeof(p->model));
        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);
@@ -2491,6 +2572,10 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd,
        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
@@ -2502,41 +2587,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
  */
@@ -2546,8 +2596,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);
@@ -2573,15 +2624,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 */
+       for (i = 0; i < 2; i++)
+               id_data[i] = chip->read_byte(mtd);
 
-       tmp_manf = chip->read_byte(mtd);
-       tmp_id = 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);
        }
 
@@ -2592,30 +2641,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
         */
@@ -2650,18 +2790,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)
@@ -2673,9 +2843,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;
 }
@@ -2704,7 +2880,8 @@ 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, &nand_dev_id, table);
+       type = nand_get_flash_type(mtd, chip, busw,
+                               &nand_maf_id, &nand_dev_id, table);
 
        if (IS_ERR(type)) {
 #ifndef CONFIG_SYS_NAND_QUIET_TEST
@@ -2763,7 +2940,7 @@ int nand_scan_tail(struct mtd_info *mtd)
        /*
         * If no default placement scheme is given, select an appropriate one
         */
-       if (!chip->ecc.layout) {
+       if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH)) {
                switch (mtd->oobsize) {
                case 8:
                        chip->ecc.layout = &nand_oob_8;
@@ -2796,7 +2973,7 @@ int nand_scan_tail(struct mtd_info *mtd)
                /* 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, "
+                       printk(KERN_WARNING "No ECC functions supplied; "
                               "Hardware ECC not possible\n");
                        BUG();
                }
@@ -2825,7 +3002,7 @@ int nand_scan_tail(struct mtd_info *mtd)
                     chip->ecc.read_page == nand_read_page_hwecc ||
                     !chip->ecc.write_page ||
                     chip->ecc.write_page == nand_write_page_hwecc)) {
-                       printk(KERN_WARNING "No ECC functions supplied, "
+                       printk(KERN_WARNING "No ECC functions supplied; "
                               "Hardware ECC not possible\n");
                        BUG();
                }
@@ -2851,6 +3028,10 @@ int nand_scan_tail(struct mtd_info *mtd)
                chip->ecc.mode = NAND_ECC_SOFT;
 
        case NAND_ECC_SOFT:
+               if (!mtd_nand_has_ecc_soft()) {
+                       printk(KERN_WARNING "CONFIG_MTD_ECC_SOFT not enabled\n");
+                       return -EINVAL;
+               }
                chip->ecc.calculate = nand_calculate_ecc;
                chip->ecc.correct = nand_correct_data;
                chip->ecc.read_page = nand_read_page_swecc;
@@ -2860,10 +3041,44 @@ 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;
 
+       case NAND_ECC_SOFT_BCH:
+               if (!mtd_nand_has_bch()) {
+                       printk(KERN_WARNING "CONFIG_MTD_ECC_BCH not enabled\n");
+                       return -EINVAL;
+               }
+               chip->ecc.calculate = nand_bch_calculate_ecc;
+               chip->ecc.correct = nand_bch_correct_data;
+               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;
+               /*
+                * Board driver should supply ecc.size and ecc.bytes values to
+                * select how many bits are correctable; see nand_bch_init()
+                * for details.
+                * Otherwise, default to 4 bits for large page devices
+                */
+               if (!chip->ecc.size && (mtd->oobsize >= 64)) {
+                       chip->ecc.size = 512;
+                       chip->ecc.bytes = 7;
+               }
+               chip->ecc.priv = nand_bch_init(mtd,
+                                              chip->ecc.size,
+                                              chip->ecc.bytes,
+                                              &chip->ecc.layout);
+               if (!chip->ecc.priv)
+                       printk(KERN_WARNING "BCH ECC initialization failed!\n");
+
+               break;
+
        case NAND_ECC_NONE:
                printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
                       "This is not recommended !!\n");
@@ -2899,7 +3114,7 @@ int nand_scan_tail(struct mtd_info *mtd)
         * mode
         */
        chip->ecc.steps = mtd->writesize / chip->ecc.size;
-       if(chip->ecc.steps * chip->ecc.size != mtd->writesize) {
+       if (chip->ecc.steps * chip->ecc.size != mtd->writesize) {
                printk(KERN_WARNING "Invalid ecc parameters\n");
                BUG();
        }
@@ -2911,7 +3126,7 @@ int nand_scan_tail(struct mtd_info *mtd)
         */
        if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
            !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
-               switch(chip->ecc.steps) {
+               switch (chip->ecc.steps) {
                case 2:
                        mtd->subpage_sft = 1;
                        break;
@@ -2935,7 +3150,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;
@@ -2954,9 +3170,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);
 }
 
 /**
@@ -2989,6 +3206,9 @@ void nand_release(struct mtd_info *mtd)
 {
        struct nand_chip *chip = mtd->priv;
 
+       if (chip->ecc.mode == NAND_ECC_SOFT_BCH)
+               nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
+
 #ifdef CONFIG_MTD_PARTITIONS
        /* Deregister partitions */
        del_mtd_partitions(mtd);
@@ -2998,4 +3218,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 ded652be345d8059bfbc7c2edaf28a2dc4809bfe..2b730e09c97ade4de292c4c0bc9e3b30f026cc7a 100644 (file)
  * Description:
  *
  * When nand_scan_bbt is called, then it tries to find the bad block table
- * depending on the options in the bbt descriptor(s). If a bbt is found
- * then the contents are read and the memory based bbt is created. If a
- * mirrored bbt is selected then the mirror is searched too and the
- * versions are compared. If the mirror has a greater version number
- * than the mirror bbt is used to build the memory based bbt.
+ * depending on the options in the BBT descriptor(s). If no flash based BBT
+ * (NAND_USE_FLASH_BBT) is specified then the device is scanned for factory
+ * marked good / bad blocks. This information is used to create a memory BBT.
+ * Once a new bad block is discovered then the "factory" information is updated
+ * on the device.
+ * If a flash based BBT is specified then the function first tries to find the
+ * BBT on flash. If a BBT is found then the contents are read and the memory
+ * based BBT is created. If a mirrored BBT is selected then the mirror is
+ * searched too and the versions are compared. If the mirror has a greater
+ * version number than the mirror BBT is used to build the memory based BBT.
  * If the tables are not versioned, then we "or" the bad block information.
- * If one of the bbt's is out of date or does not exist it is (re)created.
- * If no bbt exists at all then the device is scanned for factory marked
+ * If one of the BBTs is out of date or does not exist it is (re)created.
+ * If no BBT exists at all then the device is scanned for factory marked
  * good / bad blocks and the bad block tables are created.
  *
- * For manufacturer created bbts like the one found on M-SYS DOC devices
- * the bbt is searched and read but never created
+ * For manufacturer created BBTs like the one found on M-SYS DOC devices
+ * the BBT is searched and read but never created
  *
- * The autogenerated bad block table is located in the last good blocks
+ * The auto generated bad block table is located in the last good blocks
  * of the device. The table is mirrored, so it can be updated eventually.
- * The table is marked in the oob area with an ident pattern and a version
- * number which indicates which of both tables is more up to date.
+ * The table is marked in the OOB area with an ident pattern and a version
+ * number which indicates which of both tables is more up to date. If the NAND
+ * controller needs the complete OOB area for the ECC information then the
+ * option NAND_USE_FLASH_BBT_NO_OOB should be used: it moves the ident pattern
+ * and the version byte into the data area and the OOB area will remain
+ * untouched.
  *
  * The table uses 2 bits per block
- * 11b:        block is good
- * 00b:        block is factory marked bad
+ * 11b:                block is good
+ * 00b:                block is factory marked bad
  * 01b, 10b:   block is marked bad due to wear
  *
  * The memory bad block table uses the following scheme:
 #include <linux/mtd/compat.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/bitops.h>
 
 #include <asm/errno.h>
 
+static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
+{
+       int ret;
+
+       ret = memcmp(buf, td->pattern, td->len);
+       if (!ret)
+               return ret;
+       return -1;
+}
+
 /**
  * check_pattern - [GENERIC] check if a pattern is in the buffer
  * @buf:       the buffer to search
@@ -76,6 +97,9 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc
        int i, end = 0;
        uint8_t *p = buf;
 
+       if (td->options & NAND_BBT_NO_OOB)
+               return check_pattern_no_oob(buf, td);
+
        end = paglen + td->offs;
        if (td->options & NAND_BBT_SCANEMPTY) {
                for (i = 0; i < end; i++) {
@@ -91,6 +115,28 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc
                        return -1;
        }
 
+       /* Check both positions 1 and 6 for pattern? */
+       if (td->options & NAND_BBT_SCANBYTE1AND6) {
+               if (td->options & NAND_BBT_SCANEMPTY) {
+                       p += td->len;
+                       end += NAND_SMALL_BADBLOCK_POS - td->offs;
+                       /* Check region between positions 1 and 6 */
+                       for (i = 0; i < NAND_SMALL_BADBLOCK_POS - td->offs - td->len;
+                                       i++) {
+                               if (*p++ != 0xff)
+                                       return -1;
+                       }
+               }
+               else {
+                       p += NAND_SMALL_BADBLOCK_POS - td->offs;
+               }
+               /* Compare the pattern */
+               for (i = 0; i < td->len; i++) {
+                       if (p[i] != td->pattern[i])
+                               return -1;
+               }
+       }
+
        if (td->options & NAND_BBT_SCANEMPTY) {
                p += td->len;
                end += td->len;
@@ -122,36 +168,74 @@ static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td)
                if (p[td->offs + i] != td->pattern[i])
                        return -1;
        }
+       /* Need to check location 1 AND 6? */
+       if (td->options & NAND_BBT_SCANBYTE1AND6) {
+               for (i = 0; i < td->len; i++) {
+                       if (p[NAND_SMALL_BADBLOCK_POS + i] != td->pattern[i])
+                               return -1;
+               }
+       }
        return 0;
 }
 
+/**
+ * add_marker_len - compute the length of the marker in data area
+ * @td:                BBT descriptor used for computation
+ *
+ * The length will be 0 if the markeris located in OOB area.
+ */
+static u32 add_marker_len(struct nand_bbt_descr *td)
+{
+       u32 len;
+
+       if (!(td->options & NAND_BBT_NO_OOB))
+               return 0;
+
+       len = td->len;
+       if (td->options & NAND_BBT_VERSION)
+               len++;
+       return len;
+}
+
 /**
  * read_bbt - [GENERIC] Read the bad block table starting from page
  * @mtd:       MTD device structure
  * @buf:       temporary buffer
  * @page:      the starting page
  * @num:       the number of bbt descriptors to read
- * @bits:      number of bits per block
+ * @td:                the bbt describtion table
  * @offs:      offset in the memory table
- * @reserved_block_code:       Pattern to identify reserved blocks
  *
  * Read the bad block table starting from page.
  *
  */
 static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
-                   int bits, int offs, int reserved_block_code)
+               struct nand_bbt_descr *td, int offs)
 {
        int res, i, j, act = 0;
        struct nand_chip *this = mtd->priv;
        size_t retlen, len, totlen;
        loff_t from;
+       int bits = td->options & NAND_BBT_NRBITS_MSK;
        uint8_t msk = (uint8_t) ((1 << bits) - 1);
+       u32 marker_len;
+       int reserved_block_code = td->reserved_block_code;
 
        totlen = (num * bits) >> 3;
+       marker_len = add_marker_len(td);
        from = ((loff_t) page) << this->page_shift;
 
        while (totlen) {
                len = min(totlen, (size_t) (1 << this->bbt_erase_shift));
+               if (marker_len) {
+                       /*
+                        * In case the BBT marker is not in the OOB area it
+                        * will be just in the first page.
+                        */
+                       len -= marker_len;
+                       from += marker_len;
+                       marker_len = 0;
+               }
                res = mtd->read(mtd, from, len, &retlen, buf);
                if (res < 0) {
                        if (retlen != len) {
@@ -170,9 +254,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
                                        continue;
                                if (reserved_block_code && (tmp == reserved_block_code)) {
                                        printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%012llx\n",
-                                               (loff_t)((offs << 2) +
-                                               (act >> 1)) <<
-                                               this->bbt_erase_shift);
+                                              (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
                                        this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);
                                        mtd->ecc_stats.bbtblocks++;
                                        continue;
@@ -180,8 +262,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
                                /* Leave it for now, if its matured we can move this
                                 * message to MTD_DEBUG_LEVEL0 */
                                printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%012llx\n",
-                                       (loff_t)((offs << 2) + (act >> 1)) <<
-                                       this->bbt_erase_shift);
+                                      (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
                                /* Factory marked bad or worn out ? */
                                if (tmp == 0)
                                        this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
@@ -211,42 +292,86 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 {
        struct nand_chip *this = mtd->priv;
        int res = 0, i;
-       int bits;
 
-       bits = td->options & NAND_BBT_NRBITS_MSK;
        if (td->options & NAND_BBT_PERCHIP) {
                int offs = 0;
                for (i = 0; i < this->numchips; i++) {
                        if (chip == -1 || chip == i)
-                               res = read_bbt (mtd, buf, td->pages[i], this->chipsize >> this->bbt_erase_shift, bits, offs, td->reserved_block_code);
+                               res = read_bbt(mtd, buf, td->pages[i],
+                                       this->chipsize >> this->bbt_erase_shift,
+                                       td, offs);
                        if (res)
                                return res;
                        offs += this->chipsize >> (this->bbt_erase_shift + 2);
                }
        } else {
-               res = read_bbt (mtd, buf, td->pages[0], mtd->size >> this->bbt_erase_shift, bits, 0, td->reserved_block_code);
+               res = read_bbt(mtd, buf, td->pages[0],
+                               mtd->size >> this->bbt_erase_shift, td, 0);
                if (res)
                        return res;
        }
        return 0;
 }
 
+/*
+ * BBT marker is in the first page, no OOB.
+ */
+static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
+                        struct nand_bbt_descr *td)
+{
+       size_t retlen;
+       size_t len;
+
+       len = td->len;
+       if (td->options & NAND_BBT_VERSION)
+               len++;
+
+       return mtd->read(mtd, offs, len, &retlen, buf);
+}
+
 /*
  * Scan read raw data from flash
  */
-static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
+static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
                         size_t len)
 {
        struct mtd_oob_ops ops;
+       int res;
 
        ops.mode = MTD_OOB_RAW;
        ops.ooboffs = 0;
        ops.ooblen = mtd->oobsize;
-       ops.oobbuf = buf;
-       ops.datbuf = buf;
-       ops.len = len;
 
-       return mtd->read_oob(mtd, offs, &ops);
+
+       while (len > 0) {
+               if (len <= mtd->writesize) {
+                       ops.oobbuf = buf + len;
+                       ops.datbuf = buf;
+                       ops.len = len;
+                       return mtd->read_oob(mtd, offs, &ops);
+               } else {
+                       ops.oobbuf = buf + mtd->writesize;
+                       ops.datbuf = buf;
+                       ops.len = mtd->writesize;
+                       res = mtd->read_oob(mtd, offs, &ops);
+
+                       if (res)
+                               return res;
+               }
+
+               buf += mtd->oobsize + mtd->writesize;
+               len -= mtd->writesize;
+       }
+       return 0;
+}
+
+static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
+                        size_t len, struct nand_bbt_descr *td)
+{
+       if (td->options & NAND_BBT_NO_OOB)
+               return scan_read_raw_data(mtd, buf, offs, td);
+       else
+               return scan_read_raw_oob(mtd, buf, offs, len);
 }
 
 /*
@@ -267,6 +392,15 @@ static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,
        return mtd->write_oob(mtd, offs, &ops);
 }
 
+static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td)
+{
+       u32 ver_offs = td->veroffs;
+
+       if (!(td->options & NAND_BBT_NO_OOB))
+               ver_offs += mtd->writesize;
+       return ver_offs;
+}
+
 /**
  * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page
  * @mtd:       MTD device structure
@@ -285,18 +419,18 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
 
        /* Read the primary version, if available */
        if (td->options & NAND_BBT_VERSION) {
-               scan_read_raw(mtd, buf, (loff_t)td->pages[0] <<
-                               this->page_shift, mtd->writesize);
-               td->version[0] = buf[mtd->writesize + td->veroffs];
+               scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift,
+                             mtd->writesize, td);
+               td->version[0] = buf[bbt_get_ver_offs(mtd, td)];
                printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",
                       td->pages[0], td->version[0]);
        }
 
        /* Read the mirror version, if available */
        if (md && (md->options & NAND_BBT_VERSION)) {
-               scan_read_raw(mtd, buf, (loff_t)md->pages[0] <<
-                               this->page_shift, mtd->writesize);
-               md->version[0] = buf[mtd->writesize + md->veroffs];
+               scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift,
+                             mtd->writesize, td);
+               md->version[0] = buf[bbt_get_ver_offs(mtd, md)];
                printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",
                       md->pages[0], md->version[0]);
        }
@@ -312,7 +446,7 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
 {
        int ret, j;
 
-       ret = scan_read_raw(mtd, buf, offs, readlen);
+       ret = scan_read_raw_oob(mtd, buf, offs, readlen);
        if (ret)
                return ret;
 
@@ -376,16 +510,14 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
        loff_t from;
        size_t readlen;
 
-       MTDDEBUG (MTD_DEBUG_LEVEL0, "Scanning device for bad blocks\n");
+       MTDDEBUG(MTD_DEBUG_LEVEL0, "Scanning device for bad blocks\n");
 
        if (bd->options & NAND_BBT_SCANALLPAGES)
                len = 1 << (this->bbt_erase_shift - this->page_shift);
-       else {
-               if (bd->options & NAND_BBT_SCAN2NDPAGE)
-                       len = 2;
-               else
-                       len = 1;
-       }
+       else if (bd->options & NAND_BBT_SCAN2NDPAGE)
+               len = 2;
+       else
+               len = 1;
 
        if (!(bd->options & NAND_BBT_SCANEMPTY)) {
                /* We need only read few bytes from the OOB area */
@@ -415,9 +547,14 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
                from = (loff_t)startblock << (this->bbt_erase_shift - 1);
        }
 
+       if (this->options & NAND_BBT_SCANLASTPAGE)
+               from += mtd->erasesize - (mtd->writesize * len);
+
        for (i = startblock; i < numblocks;) {
                int ret;
 
+               BUG_ON(bd->options & NAND_BBT_NO_OOB);
+
                if (bd->options & NAND_BBT_SCANALLPAGES)
                        ret = scan_block_full(mtd, bd, from, buf, readlen,
                                              scanlen, len);
@@ -429,7 +566,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
 
                if (ret) {
                        this->bbt[i >> 3] |= 0x03 << (i & 0x6);
-                       MTDDEBUG (MTD_DEBUG_LEVEL0,
+                       MTDDEBUG(MTD_DEBUG_LEVEL0,
                                  "Bad eraseblock %d at 0x%012llx\n",
                                  i >> 1, (unsigned long long)from);
                        mtd->ecc_stats.badblocks++;
@@ -497,11 +634,12 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
                        loff_t offs = (loff_t)actblock << this->bbt_erase_shift;
 
                        /* Read first page */
-                       scan_read_raw(mtd, buf, offs, mtd->writesize);
+                       scan_read_raw(mtd, buf, offs, mtd->writesize, td);
                        if (!check_pattern(buf, scanlen, mtd->writesize, td)) {
                                td->pages[i] = actblock << blocktopage;
                                if (td->options & NAND_BBT_VERSION) {
-                                       td->version[i] = buf[mtd->writesize + td->veroffs];
+                                       offs = bbt_get_ver_offs(mtd, td);
+                                       td->version[i] = buf[offs];
                                }
                                break;
                        }
@@ -685,12 +823,26 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
                        memset(&buf[offs], 0xff, (size_t) (numblocks >> sft));
                        ooboffs = len + (pageoffs * mtd->oobsize);
 
+               } else if (td->options & NAND_BBT_NO_OOB) {
+                       ooboffs = 0;
+                       offs = td->len;
+                       /* the version byte */
+                       if (td->options & NAND_BBT_VERSION)
+                               offs++;
+                       /* Calc length */
+                       len = (size_t) (numblocks >> sft);
+                       len += offs;
+                       /* Make it page aligned ! */
+                       len = ALIGN(len, mtd->writesize);
+                       /* Preset the buffer with 0xff */
+                       memset(buf, 0xff, len);
+                       /* Pattern is located at the begin of first page */
+                       memcpy(buf, td->pattern, td->len);
                } else {
                        /* Calc length */
                        len = (size_t) (numblocks >> sft);
                        /* Make it page aligned ! */
-                       len = (len + (mtd->writesize - 1)) &
-                               ~(mtd->writesize - 1);
+                       len = ALIGN(len, mtd->writesize);
                        /* Preset the buffer with 0xff */
                        memset(buf, 0xff, len +
                               (len >> this->page_shift)* mtd->oobsize);
@@ -724,13 +876,14 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
                if (res < 0)
                        goto outerr;
 
-               res = scan_write_bbt(mtd, to, len, buf, &buf[len]);
+               res = scan_write_bbt(mtd, to, len, buf,
+                               td->options & NAND_BBT_NO_OOB ? NULL :
+                               &buf[len]);
                if (res < 0)
                        goto outerr;
 
-               printk(KERN_DEBUG "Bad block table written to 0x%012llx, "
-                      "version 0x%02X\n", (unsigned long long)to,
-                      td->version[chip]);
+               printk(KERN_DEBUG "Bad block table written to 0x%012llx, version "
+                      "0x%02X\n", (unsigned long long)to, td->version[chip]);
 
                /* Mark it as used */
                td->pages[chip] = page;
@@ -791,7 +944,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
                rd2 = NULL;
                /* Per chip or per device ? */
                chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1;
-               /* Mirrored table avilable ? */
+               /* Mirrored table available ? */
                if (md) {
                        if (td->pages[i] == -1 && md->pages[i] == -1) {
                                writeops = 0x03;
@@ -845,7 +998,8 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
                        continue;
 
                /* Create the table in memory by scanning the chip(s) */
-               create_bbt(mtd, buf, bd, chipsel);
+               if (!(this->options & NAND_CREATE_EMPTY_BBT))
+                       create_bbt(mtd, buf, bd, chipsel);
 
                td->version[i] = 1;
                if (md)
@@ -910,8 +1064,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
                        newval = oldval | (0x2 << (block & 0x06));
                        this->bbt[(block >> 3)] = newval;
                        if ((oldval != newval) && td->reserved_block_code)
-                               nand_update_bbt(mtd, (loff_t)block <<
-                                       (this->bbt_erase_shift - 1));
+                               nand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 1));
                        continue;
                }
                update = 0;
@@ -932,11 +1085,58 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
                   new ones have been marked, then we need to update the stored
                   bbts.  This should only happen once. */
                if (update && td->reserved_block_code)
-                       nand_update_bbt(mtd, (loff_t)(block - 2) <<
-                               (this->bbt_erase_shift - 1));
+                       nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1));
        }
 }
 
+/**
+ * verify_bbt_descr - verify the bad block description
+ * @mtd:       MTD device structure
+ * @bd:                the table to verify
+ *
+ * This functions performs a few sanity checks on the bad block description
+ * table.
+ */
+static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
+{
+       struct nand_chip *this = mtd->priv;
+       u32 pattern_len;
+       u32 bits;
+       u32 table_size;
+
+       if (!bd)
+               return;
+
+       pattern_len = bd->len;
+       bits = bd->options & NAND_BBT_NRBITS_MSK;
+
+       BUG_ON((this->options & NAND_USE_FLASH_BBT_NO_OOB) &&
+                       !(this->options & NAND_USE_FLASH_BBT));
+       BUG_ON(!bits);
+
+       if (bd->options & NAND_BBT_VERSION)
+               pattern_len++;
+
+       if (bd->options & NAND_BBT_NO_OOB) {
+               BUG_ON(!(this->options & NAND_USE_FLASH_BBT));
+               BUG_ON(!(this->options & NAND_USE_FLASH_BBT_NO_OOB));
+               BUG_ON(bd->offs);
+               if (bd->options & NAND_BBT_VERSION)
+                       BUG_ON(bd->veroffs != bd->len);
+               BUG_ON(bd->options & NAND_BBT_SAVECONTENT);
+       }
+
+       if (bd->options & NAND_BBT_PERCHIP)
+               table_size = this->chipsize >> this->bbt_erase_shift;
+       else
+               table_size = mtd->size >> this->bbt_erase_shift;
+       table_size >>= 3;
+       table_size *= bits;
+       if (bd->options & NAND_BBT_NO_OOB)
+               table_size += pattern_len;
+       BUG_ON(table_size > (1 << this->bbt_erase_shift));
+}
+
 /**
  * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s)
  * @mtd:       MTD device structure
@@ -978,6 +1178,8 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
                }
                return res;
        }
+       verify_bbt_descr(mtd, td);
+       verify_bbt_descr(mtd, md);
 
        /* Allocate a temporary buffer for one eraseblock incl. oob */
        len = (1 << this->bbt_erase_shift);
@@ -1073,34 +1275,6 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
  * while scanning a device for factory marked good / bad blocks. */
 static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
 
-static struct nand_bbt_descr smallpage_memorybased = {
-       .options = NAND_BBT_SCAN2NDPAGE,
-       .offs = 5,
-       .len = 1,
-       .pattern = scan_ff_pattern
-};
-
-static struct nand_bbt_descr largepage_memorybased = {
-       .options = 0,
-       .offs = 0,
-       .len = 2,
-       .pattern = scan_ff_pattern
-};
-
-static struct nand_bbt_descr smallpage_flashbased = {
-       .options = NAND_BBT_SCAN2NDPAGE,
-       .offs = 5,
-       .len = 1,
-       .pattern = scan_ff_pattern
-};
-
-static struct nand_bbt_descr largepage_flashbased = {
-       .options = NAND_BBT_SCAN2NDPAGE,
-       .offs = 0,
-       .len = 2,
-       .pattern = scan_ff_pattern
-};
-
 static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 };
 
 static struct nand_bbt_descr agand_flashbased = {
@@ -1135,6 +1309,59 @@ static struct nand_bbt_descr bbt_mirror_descr = {
        .pattern = mirror_pattern
 };
 
+static struct nand_bbt_descr bbt_main_no_bbt_descr = {
+       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+               | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
+               | NAND_BBT_NO_OOB,
+       .len = 4,
+       .veroffs = 4,
+       .maxblocks = 4,
+       .pattern = bbt_pattern
+};
+
+static struct nand_bbt_descr bbt_mirror_no_bbt_descr = {
+       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+               | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
+               | NAND_BBT_NO_OOB,
+       .len = 4,
+       .veroffs = 4,
+       .maxblocks = 4,
+       .pattern = mirror_pattern
+};
+
+#define BBT_SCAN_OPTIONS (NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE | \
+               NAND_BBT_SCANBYTE1AND6)
+/**
+ * nand_create_default_bbt_descr - [Internal] Creates a BBT descriptor structure
+ * @this:      NAND chip to create descriptor for
+ *
+ * This function allocates and initializes a nand_bbt_descr for BBM detection
+ * based on the properties of "this". The new descriptor is stored in
+ * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when
+ * passed to this function.
+ *
+ */
+static int nand_create_default_bbt_descr(struct nand_chip *this)
+{
+       struct nand_bbt_descr *bd;
+       if (this->badblock_pattern) {
+               printk(KERN_WARNING "BBT descr already allocated; not replacing.\n");
+               return -EINVAL;
+       }
+       bd = kzalloc(sizeof(*bd), GFP_KERNEL);
+       if (!bd) {
+               printk(KERN_ERR "nand_create_default_bbt_descr: Out of memory\n");
+               return -ENOMEM;
+       }
+       bd->options = this->options & BBT_SCAN_OPTIONS;
+       bd->offs = this->badblockpos;
+       bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1;
+       bd->pattern = scan_ff_pattern;
+       bd->options |= NAND_BBT_DYNAMICSTRUCT;
+       this->badblock_pattern = bd;
+       return 0;
+}
+
 /**
  * nand_default_bbt - [NAND Interface] Select a default bad block table for the device
  * @mtd:       MTD device structure
@@ -1168,20 +1395,22 @@ int nand_default_bbt(struct mtd_info *mtd)
        if (this->options & NAND_USE_FLASH_BBT) {
                /* Use the default pattern descriptors */
                if (!this->bbt_td) {
-                       this->bbt_td = &bbt_main_descr;
-                       this->bbt_md = &bbt_mirror_descr;
-               }
-               if (!this->badblock_pattern) {
-                       this->badblock_pattern = (mtd->writesize > 512) ? &largepage_flashbased : &smallpage_flashbased;
+                       if (this->options & NAND_USE_FLASH_BBT_NO_OOB) {
+                               this->bbt_td = &bbt_main_no_bbt_descr;
+                               this->bbt_md = &bbt_mirror_no_bbt_descr;
+                       } else {
+                               this->bbt_td = &bbt_main_descr;
+                               this->bbt_md = &bbt_mirror_descr;
+                       }
                }
        } else {
                this->bbt_td = NULL;
                this->bbt_md = NULL;
-               if (!this->badblock_pattern) {
-                       this->badblock_pattern = (mtd->writesize > 512) ?
-                           &largepage_memorybased : &smallpage_memorybased;
-               }
        }
+
+       if (!this->badblock_pattern)
+               nand_create_default_bbt_descr(this);
+
        return nand_scan_bbt(mtd, this->badblock_pattern);
 }
 
@@ -1202,8 +1431,8 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
        block = (int)(offs >> (this->bbt_erase_shift - 1));
        res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;
 
-       MTDDEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: "
-                 "(block %d) 0x%02x\n", (unsigned int)offs, res, block >> 1);
+       MTDDEBUG(MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
+             (unsigned int)offs, block >> 1, res);
 
        switch ((int)res) {
        case 0x00:
diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c
new file mode 100644 (file)
index 0000000..7835fce
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * This file provides ECC correction for more than 1 bit per block of data,
+ * using binary BCH codes. It relies on the generic BCH library lib/bch.c.
+ *
+ * Copyright Â© 2011 Ivan Djelic <ivan.djelic@parrot.com>
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 or (at your option) any
+ * later version.
+ *
+ * This file 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 file; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <common.h>
+/*#include <asm/io.h>*/
+#include <linux/types.h>
+
+#include <linux/bitops.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_bch.h>
+#include <linux/bch.h>
+#include <malloc.h>
+
+/**
+ * struct nand_bch_control - private NAND BCH control structure
+ * @bch:       BCH control structure
+ * @ecclayout: private ecc layout for this BCH configuration
+ * @errloc:    error location array
+ * @eccmask:   XOR ecc mask, allows erased pages to be decoded as valid
+ */
+struct nand_bch_control {
+       struct bch_control   *bch;
+       struct nand_ecclayout ecclayout;
+       unsigned int         *errloc;
+       unsigned char        *eccmask;
+};
+
+/**
+ * nand_bch_calculate_ecc - [NAND Interface] Calculate ECC for data block
+ * @mtd:       MTD block structure
+ * @buf:       input buffer with raw data
+ * @code:      output buffer with ECC
+ */
+int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
+                          unsigned char *code)
+{
+       const struct nand_chip *chip = mtd->priv;
+       struct nand_bch_control *nbc = chip->ecc.priv;
+       unsigned int i;
+
+       memset(code, 0, chip->ecc.bytes);
+       encode_bch(nbc->bch, buf, chip->ecc.size, code);
+
+       /* apply mask so that an erased page is a valid codeword */
+       for (i = 0; i < chip->ecc.bytes; i++)
+               code[i] ^= nbc->eccmask[i];
+
+       return 0;
+}
+
+/**
+ * nand_bch_correct_data - [NAND Interface] Detect and correct bit error(s)
+ * @mtd:       MTD block structure
+ * @buf:       raw data read from the chip
+ * @read_ecc:  ECC from the chip
+ * @calc_ecc:  the ECC calculated from raw data
+ *
+ * Detect and correct bit errors for a data byte block
+ */
+int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
+                         unsigned char *read_ecc, unsigned char *calc_ecc)
+{
+       const struct nand_chip *chip = mtd->priv;
+       struct nand_bch_control *nbc = chip->ecc.priv;
+       unsigned int *errloc = nbc->errloc;
+       int i, count;
+
+       count = decode_bch(nbc->bch, NULL, chip->ecc.size, read_ecc, calc_ecc,
+                          NULL, errloc);
+       if (count > 0) {
+               for (i = 0; i < count; i++) {
+                       if (errloc[i] < (chip->ecc.size*8))
+                               /* error is located in data, correct it */
+                               buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7));
+                       /* else error in ecc, no action needed */
+
+                       MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: corrected bitflip %u\n",
+                             __func__, errloc[i]);
+               }
+       } else if (count < 0) {
+               printk(KERN_ERR "ecc unrecoverable error\n");
+               count = -1;
+       }
+       return count;
+}
+
+/**
+ * nand_bch_init - [NAND Interface] Initialize NAND BCH error correction
+ * @mtd:       MTD block structure
+ * @eccsize:   ecc block size in bytes
+ * @eccbytes:  ecc length in bytes
+ * @ecclayout: output default layout
+ *
+ * Returns:
+ *  a pointer to a new NAND BCH control structure, or NULL upon failure
+ *
+ * Initialize NAND BCH error correction. Parameters @eccsize and @eccbytes
+ * are used to compute BCH parameters m (Galois field order) and t (error
+ * correction capability). @eccbytes should be equal to the number of bytes
+ * required to store m*t bits, where m is such that 2^m-1 > @eccsize*8.
+ *
+ * Example: to configure 4 bit correction per 512 bytes, you should pass
+ * @eccsize = 512  (thus, m=13 is the smallest integer such that 2^m-1 > 512*8)
+ * @eccbytes = 7   (7 bytes are required to store m*t = 13*4 = 52 bits)
+ */
+struct nand_bch_control *
+nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
+             struct nand_ecclayout **ecclayout)
+{
+       unsigned int m, t, eccsteps, i;
+       struct nand_ecclayout *layout;
+       struct nand_bch_control *nbc = NULL;
+       unsigned char *erased_page;
+
+       if (!eccsize || !eccbytes) {
+               printk(KERN_WARNING "ecc parameters not supplied\n");
+               goto fail;
+       }
+
+       m = fls(1+8*eccsize);
+       t = (eccbytes*8)/m;
+
+       nbc = kzalloc(sizeof(*nbc), GFP_KERNEL);
+       if (!nbc)
+               goto fail;
+
+       nbc->bch = init_bch(m, t, 0);
+       if (!nbc->bch)
+               goto fail;
+
+       /* verify that eccbytes has the expected value */
+       if (nbc->bch->ecc_bytes != eccbytes) {
+               printk(KERN_WARNING "invalid eccbytes %u, should be %u\n",
+                      eccbytes, nbc->bch->ecc_bytes);
+               goto fail;
+       }
+
+       eccsteps = mtd->writesize/eccsize;
+
+       /* if no ecc placement scheme was provided, build one */
+       if (!*ecclayout) {
+
+               /* handle large page devices only */
+               if (mtd->oobsize < 64) {
+                       printk(KERN_WARNING "must provide an oob scheme for "
+                              "oobsize %d\n", mtd->oobsize);
+                       goto fail;
+               }
+
+               layout = &nbc->ecclayout;
+               layout->eccbytes = eccsteps*eccbytes;
+
+               /* reserve 2 bytes for bad block marker */
+               if (layout->eccbytes+2 > mtd->oobsize) {
+                       printk(KERN_WARNING "no suitable oob scheme available "
+                              "for oobsize %d eccbytes %u\n", mtd->oobsize,
+                              eccbytes);
+                       goto fail;
+               }
+               /* put ecc bytes at oob tail */
+               for (i = 0; i < layout->eccbytes; i++)
+                       layout->eccpos[i] = mtd->oobsize-layout->eccbytes+i;
+
+               layout->oobfree[0].offset = 2;
+               layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes;
+
+               *ecclayout = layout;
+       }
+
+       /* sanity checks */
+       if (8*(eccsize+eccbytes) >= (1 << m)) {
+               printk(KERN_WARNING "eccsize %u is too large\n", eccsize);
+               goto fail;
+       }
+       if ((*ecclayout)->eccbytes != (eccsteps*eccbytes)) {
+               printk(KERN_WARNING "invalid ecc layout\n");
+               goto fail;
+       }
+
+       nbc->eccmask = kmalloc(eccbytes, GFP_KERNEL);
+       nbc->errloc = kmalloc(t*sizeof(*nbc->errloc), GFP_KERNEL);
+       if (!nbc->eccmask || !nbc->errloc)
+               goto fail;
+       /*
+        * compute and store the inverted ecc of an erased ecc block
+        */
+       erased_page = kmalloc(eccsize, GFP_KERNEL);
+       if (!erased_page)
+               goto fail;
+
+       memset(erased_page, 0xff, eccsize);
+       memset(nbc->eccmask, 0, eccbytes);
+       encode_bch(nbc->bch, erased_page, eccsize, nbc->eccmask);
+       kfree(erased_page);
+
+       for (i = 0; i < eccbytes; i++)
+               nbc->eccmask[i] ^= 0xff;
+
+       return nbc;
+fail:
+       nand_bch_free(nbc);
+       return NULL;
+}
+
+/**
+ * nand_bch_free - [NAND Interface] Release NAND BCH ECC resources
+ * @nbc:       NAND BCH control structure
+ */
+void nand_bch_free(struct nand_bch_control *nbc)
+{
+       if (nbc) {
+               free_bch(nbc->bch);
+               kfree(nbc->errloc);
+               kfree(nbc->eccmask);
+               kfree(nbc);
+       }
+}
index 8d7ea767dd5aa47537a8571dd7c1f59aeaa1daab..39535497f8dfede06d6ca0e7ee009178fc7b8569 100644 (file)
@@ -76,9 +76,13 @@ const struct nand_flash_dev nand_flash_ids[] = {
 
        /*512 Megabit */
        {"NAND 64MiB 1,8V 8-bit",       0xA2, 0,  64, 0, LP_OPTIONS},
+       {"NAND 64MiB 1,8V 8-bit",       0xA0, 0,  64, 0, LP_OPTIONS},
        {"NAND 64MiB 3,3V 8-bit",       0xF2, 0,  64, 0, LP_OPTIONS},
+       {"NAND 64MiB 3,3V 8-bit",       0xD0, 0,  64, 0, LP_OPTIONS},
        {"NAND 64MiB 1,8V 16-bit",      0xB2, 0,  64, 0, LP_OPTIONS16},
+       {"NAND 64MiB 1,8V 16-bit",      0xB0, 0,  64, 0, LP_OPTIONS16},
        {"NAND 64MiB 3,3V 16-bit",      0xC2, 0,  64, 0, LP_OPTIONS16},
+       {"NAND 64MiB 3,3V 16-bit",      0xC0, 0,  64, 0, LP_OPTIONS16},
 
        /* 1 Gigabit */
        {"NAND 128MiB 1,8V 8-bit",      0xA1, 0, 128, 0, LP_OPTIONS},
@@ -86,6 +90,7 @@ const struct nand_flash_dev nand_flash_ids[] = {
        {"NAND 128MiB 3,3V 8-bit",      0xD1, 0, 128, 0, LP_OPTIONS},
        {"NAND 128MiB 1,8V 16-bit",     0xB1, 0, 128, 0, LP_OPTIONS16},
        {"NAND 128MiB 3,3V 16-bit",     0xC1, 0, 128, 0, LP_OPTIONS16},
+       {"NAND 128MiB 1,8V 16-bit",     0xAD, 0, 128, 0, LP_OPTIONS16},
 
        /* 2 Gigabit */
        {"NAND 256MiB 1,8V 8-bit",      0xAA, 0, 256, 0, LP_OPTIONS},
@@ -111,6 +116,36 @@ const struct nand_flash_dev nand_flash_ids[] = {
        {"NAND 2GiB 1,8V 16-bit",       0xB5, 0, 2048, 0, LP_OPTIONS16},
        {"NAND 2GiB 3,3V 16-bit",       0xC5, 0, 2048, 0, LP_OPTIONS16},
 
+       /* 32 Gigabit */
+       {"NAND 4GiB 1,8V 8-bit",        0xA7, 0, 4096, 0, LP_OPTIONS},
+       {"NAND 4GiB 3,3V 8-bit",        0xD7, 0, 4096, 0, LP_OPTIONS},
+       {"NAND 4GiB 1,8V 16-bit",       0xB7, 0, 4096, 0, LP_OPTIONS16},
+       {"NAND 4GiB 3,3V 16-bit",       0xC7, 0, 4096, 0, LP_OPTIONS16},
+
+       /* 64 Gigabit */
+       {"NAND 8GiB 1,8V 8-bit",        0xAE, 0, 8192, 0, LP_OPTIONS},
+       {"NAND 8GiB 3,3V 8-bit",        0xDE, 0, 8192, 0, LP_OPTIONS},
+       {"NAND 8GiB 1,8V 16-bit",       0xBE, 0, 8192, 0, LP_OPTIONS16},
+       {"NAND 8GiB 3,3V 16-bit",       0xCE, 0, 8192, 0, LP_OPTIONS16},
+
+       /* 128 Gigabit */
+       {"NAND 16GiB 1,8V 8-bit",       0x1A, 0, 16384, 0, LP_OPTIONS},
+       {"NAND 16GiB 3,3V 8-bit",       0x3A, 0, 16384, 0, LP_OPTIONS},
+       {"NAND 16GiB 1,8V 16-bit",      0x2A, 0, 16384, 0, LP_OPTIONS16},
+       {"NAND 16GiB 3,3V 16-bit",      0x4A, 0, 16384, 0, LP_OPTIONS16},
+
+       /* 256 Gigabit */
+       {"NAND 32GiB 1,8V 8-bit",       0x1C, 0, 32768, 0, LP_OPTIONS},
+       {"NAND 32GiB 3,3V 8-bit",       0x3C, 0, 32768, 0, LP_OPTIONS},
+       {"NAND 32GiB 1,8V 16-bit",      0x2C, 0, 32768, 0, LP_OPTIONS16},
+       {"NAND 32GiB 3,3V 16-bit",      0x4C, 0, 32768, 0, LP_OPTIONS16},
+
+       /* 512 Gigabit */
+       {"NAND 64GiB 1,8V 8-bit",       0x1E, 0, 65536, 0, LP_OPTIONS},
+       {"NAND 64GiB 3,3V 8-bit",       0x3E, 0, 65536, 0, LP_OPTIONS},
+       {"NAND 64GiB 1,8V 16-bit",      0x2E, 0, 65536, 0, LP_OPTIONS16},
+       {"NAND 64GiB 3,3V 16-bit",      0x4E, 0, 65536, 0, LP_OPTIONS16},
+
        /*
         * Renesas AND 1 Gigabit. Those chips do not support extended id and
         * have a strange page/block layout !  The chosen minimum erasesize is
index 7eb08a3b089dfdfb9d031caba651fe62967fc540..4a4d02f4c8b5c1c4d95c8735a52862ab4c7fd4fe 100644 (file)
@@ -27,6 +27,11 @@ static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS;
 static nand_info_t mtd;
 static struct nand_chip nand_chip;
 
+#define ECCSTEPS       (CONFIG_SYS_NAND_PAGE_SIZE / \
+                                       CONFIG_SYS_NAND_ECCSIZE)
+#define ECCTOTAL       (ECCSTEPS * CONFIG_SYS_NAND_ECCBYTES)
+
+
 #if (CONFIG_SYS_NAND_PAGE_SIZE <= 512)
 /*
  * NAND command for small page NAND devices (512)
@@ -145,29 +150,21 @@ static int nand_is_bad_block(int block)
 static int nand_read_page(int block, int page, uchar *dst)
 {
        struct nand_chip *this = mtd.priv;
-       u_char *ecc_calc;
-       u_char *ecc_code;
-       u_char *oob_data;
+       u_char ecc_calc[ECCTOTAL];
+       u_char ecc_code[ECCTOTAL];
+       u_char oob_data[CONFIG_SYS_NAND_OOBSIZE];
        int i;
        int eccsize = CONFIG_SYS_NAND_ECCSIZE;
        int eccbytes = CONFIG_SYS_NAND_ECCBYTES;
-       int eccsteps = CONFIG_SYS_NAND_ECCSTEPS;
+       int eccsteps = ECCSTEPS;
        uint8_t *p = dst;
 
-       /*
-        * No malloc available for now, just use some temporary locations
-        * in SDRAM
-        */
-       ecc_calc = (u_char *)(CONFIG_SYS_SDRAM_BASE + 0x10000);
-       ecc_code = ecc_calc + 0x100;
-       oob_data = ecc_calc + 0x200;
-
        nand_command(block, page, 0, NAND_CMD_READOOB);
        this->read_buf(&mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE);
        nand_command(block, page, 0, NAND_CMD_READ0);
 
        /* Pick the ECC bytes out of the oob data */
-       for (i = 0; i < CONFIG_SYS_NAND_ECCTOTAL; i++)
+       for (i = 0; i < ECCTOTAL; i++)
                ecc_code[i] = oob_data[nand_ecc_pos[i]];
 
 
@@ -184,24 +181,17 @@ static int nand_read_page(int block, int page, uchar *dst)
 static int nand_read_page(int block, int page, void *dst)
 {
        struct nand_chip *this = mtd.priv;
-       u_char *ecc_calc;
-       u_char *ecc_code;
-       u_char *oob_data;
+       u_char ecc_calc[ECCTOTAL];
+       u_char ecc_code[ECCTOTAL];
+       u_char oob_data[CONFIG_SYS_NAND_OOBSIZE];
        int i;
        int eccsize = CONFIG_SYS_NAND_ECCSIZE;
        int eccbytes = CONFIG_SYS_NAND_ECCBYTES;
-       int eccsteps = CONFIG_SYS_NAND_ECCSTEPS;
+       int eccsteps = ECCSTEPS;
        uint8_t *p = dst;
 
        nand_command(block, page, 0, NAND_CMD_READ0);
 
-       /* No malloc available for now, just use some temporary locations
-        * in SDRAM
-        */
-       ecc_calc = (u_char *)(CONFIG_SYS_SDRAM_BASE + 0x10000);
-       ecc_code = ecc_calc + 0x100;
-       oob_data = ecc_calc + 0x200;
-
        for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
                if (this->ecc.mode != NAND_ECC_SOFT)
                        this->ecc.hwctl(&mtd, NAND_ECC_READ);
@@ -211,10 +201,10 @@ static int nand_read_page(int block, int page, void *dst)
        this->read_buf(&mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE);
 
        /* Pick the ECC bytes out of the oob data */
-       for (i = 0; i < CONFIG_SYS_NAND_ECCTOTAL; i++)
+       for (i = 0; i < ECCTOTAL; i++)
                ecc_code[i] = oob_data[nand_ecc_pos[i]];
 
-       eccsteps = CONFIG_SYS_NAND_ECCSTEPS;
+       eccsteps = ECCSTEPS;
        p = dst;
 
        for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
index 00fa74d6f7b6261ae6548fe411474d9ffb8ca0da..cee788ab1310c4f070d7f4524f34e99c9670b275 100644 (file)
@@ -273,11 +273,10 @@ extern unsigned long get_board_sys_clk(unsigned long dummy);
 #endif
 #endif
 
+#define CONFIG_CMD_NAND
 #define CONFIG_SYS_NAND_BASE_LIST      {CONFIG_SYS_NAND_BASE}
 #define CONFIG_SYS_MAX_NAND_DEVICE     1
-#define NAND_MAX_CHIPS                 1
 #define CONFIG_MTD_NAND_VERIFY_WRITE
-#define CONFIG_CMD_NAND                        1
 #define CONFIG_NAND_FSL_ELBC           1
 #define CONFIG_SYS_NAND_BLOCK_SIZE     (16 * 1024)
 
index ed47a87820f0a461b84a334547ffac95dd449f69..b82095454ca74a93c6d2da190ba34ec9c2408d24 100644 (file)
 
 #define CONFIG_SYS_NAND_ECCSIZE        256
 #define CONFIG_SYS_NAND_ECCBYTES       3
-#define CONFIG_SYS_NAND_ECCSTEPS       (CONFIG_SYS_NAND_PAGE_SIZE / CONFIG_SYS_NAND_ECCSIZE)
 #define CONFIG_SYS_NAND_OOBSIZE        16
-#define CONFIG_SYS_NAND_ECCTOTAL       (CONFIG_SYS_NAND_ECCBYTES * CONFIG_SYS_NAND_ECCSTEPS)
 #define CONFIG_SYS_NAND_ECCPOS         {0, 1, 2, 3, 6, 7}
 #endif
 
index 77be3600f27b17db6eee8ad53b0aa3398186face..09760774fb59fef15b94a52fa4437061504b5de6 100644 (file)
 #endif
 #define CONFIG_SYS_FPGA_BASE           0xFF000000
 
+#define CONFIG_CMD_NAND
 #define CONFIG_SYS_MAX_NAND_DEVICE     1
-#define NAND_MAX_CHIPS                 1
 #define CONFIG_MTD_NAND_VERIFY_WRITE
-#define CONFIG_CMD_NAND                        1
 #define CONFIG_NAND_FSL_ELBC           1
 
 #define CONFIG_SYS_NAND_BR_PRELIM      (CONFIG_SYS_NAND_BASE \
index a370c150b23f072a85d4225a68131c40d9eb6598..5cc8ece7de6672d6142697c3c400bee434b6ae34 100644 (file)
 #define CONFIG_NAND_S3C2410
 #define CONFIG_SYS_S3C2410_NAND_HWECC
 #define CONFIG_SYS_MAX_NAND_DEVICE     1
-#define NAND_MAX_CHIPS                 1
 #define CONFIG_SYS_NAND_BASE           0x4E000000
 #define CONFIG_S3C24XX_CUSTOM_NAND_TIMING
 #define CONFIG_S3C24XX_TACLS           1
index 5573dc7a32f73a9397efac5e97e927a2b9837988..8c447ca951a00ac5c47c94adcedeb311c476a88a 100644 (file)
 
 #define CONFIG_SYS_NAND_ECCSIZE        256
 #define CONFIG_SYS_NAND_ECCBYTES       3
-#define CONFIG_SYS_NAND_ECCSTEPS       (CONFIG_SYS_NAND_PAGE_SIZE / CONFIG_SYS_NAND_ECCSIZE)
 #define CONFIG_SYS_NAND_OOBSIZE        16
-#define CONFIG_SYS_NAND_ECCTOTAL       (CONFIG_SYS_NAND_ECCBYTES * CONFIG_SYS_NAND_ECCSTEPS)
 #define CONFIG_SYS_NAND_ECCPOS         {0, 1, 2, 3, 6, 7}
 
 #ifdef CONFIG_ENV_IS_IN_NAND
index 2cea1f461278c8fb5b277efacf36a510fef3987f..6683b3ec29a281e182d82722e61130fd47e0e632 100644 (file)
 #define CONFIG_SYS_NS16550_CLK         (48000000)
 #define CONFIG_SYS_NS16550_COM1                0x44e09000      /* Base EVM has UART0 */
 
+/* I2C Configuration */
+#define CONFIG_I2C
+#define CONFIG_CMD_I2C
+#define CONFIG_HARD_I2C
+#define CONFIG_SYS_I2C_SPEED           100000
+#define CONFIG_SYS_I2C_SLAVE           1
+#define CONFIG_DRIVER_OMAP24XX_I2C
+
 #define CONFIG_BAUDRATE                115200
 #define CONFIG_SYS_BAUDRATE_TABLE      { 110, 300, 600, 1200, 2400, \
 4800, 9600, 14400, 19200, 28800, 38400, 56000, 57600, 115200 }
 #define CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME       "u-boot.img"
 #define CONFIG_SPL_MMC_SUPPORT
 #define CONFIG_SPL_FAT_SUPPORT
+#define CONFIG_SPL_I2C_SUPPORT
 
 #define CONFIG_SPL_LIBCOMMON_SUPPORT
 #define CONFIG_SPL_LIBDISK_SUPPORT
index 0a0c261bf9507c1e9b5a2a200f8f1c355d2b2f44..b0dd2f0af61ff1f2ceb9ad8386909791e1b9b67a 100644 (file)
                                                10, 11, 12, 13}
 #define CONFIG_SYS_NAND_ECCSIZE                512
 #define CONFIG_SYS_NAND_ECCBYTES       3
-#define CONFIG_SYS_NAND_ECCSTEPS       (CONFIG_SYS_NAND_PAGE_SIZE / \
-                                               CONFIG_SYS_NAND_ECCSIZE)
-#define CONFIG_SYS_NAND_ECCTOTAL       (CONFIG_SYS_NAND_ECCBYTES * \
-                                               CONFIG_SYS_NAND_ECCSTEPS)
 #define CONFIG_SYS_NAND_U_BOOT_START   CONFIG_SYS_TEXT_BASE
 #define CONFIG_SYS_NAND_U_BOOT_OFFS    0x80000
 
index d44eeec5b68b98956ac946cb162c5e1919fbd8b1..f797f3ffd97f0425614404e4b78ef0a980495e18 100644 (file)
                                                10, 11, 12, 13}
 #define CONFIG_SYS_NAND_ECCSIZE                512
 #define CONFIG_SYS_NAND_ECCBYTES       3
-#define CONFIG_SYS_NAND_ECCSTEPS       (CONFIG_SYS_NAND_PAGE_SIZE / \
-                                               CONFIG_SYS_NAND_ECCSIZE)
-#define CONFIG_SYS_NAND_ECCTOTAL       (CONFIG_SYS_NAND_ECCBYTES * \
-                                               CONFIG_SYS_NAND_ECCSTEPS)
 #define CONFIG_SYS_NAND_U_BOOT_START   CONFIG_SYS_TEXT_BASE
 #define CONFIG_SYS_NAND_U_BOOT_OFFS    0x80000
 
index cf2e7d4323f2003131146fd34ad66e7449059989..c9f0076ee6a177f67f9e10ce0d5e64c7ac249ebe 100644 (file)
  */
 #define CONFIG_CMD_NAND                                        /* enable NAND support */
 #define CONFIG_JFFS2_NAND                              /* with JFFS2 on it */
-
-
 #define CONFIG_NAND_MPC5121_NFC
 #define CONFIG_SYS_NAND_BASE           0x40000000
-
 #define CONFIG_SYS_MAX_NAND_DEVICE     1
-#define NAND_MAX_CHIPS                 CONFIG_SYS_MAX_NAND_DEVICE
 
 /*
  * Configuration parameters for MPC5121 NAND driver
index 5ef6bd230770ab3055929c2679f8d0fe7bcdbdd2..6a02188108f0c4a2a3135457b3d2793e2ce01306 100644 (file)
 
 /* NAND flash */
 #ifdef CONFIG_CMD_NAND
-#define CONFIG_NAND_MAX_CHIPS                  1
 #define CONFIG_NAND_ATMEL
 #define CONFIG_SYS_MAX_NAND_DEVICE             1
 #define CONFIG_SYS_NAND_BASE                   ATMEL_BASE_CS3
index 7b66fc092a73a316539ace3e3aa6720766074c0f..506a558f14e5bf0262bb50818837072304d00799 100644 (file)
 
 #define CONFIG_SYS_NAND_ECCSIZE        256
 #define CONFIG_SYS_NAND_ECCBYTES       3
-#define CONFIG_SYS_NAND_ECCSTEPS       (CONFIG_SYS_NAND_PAGE_SIZE / CONFIG_SYS_NAND_ECCSIZE)
 #define CONFIG_SYS_NAND_OOBSIZE        16
-#define CONFIG_SYS_NAND_ECCTOTAL       (CONFIG_SYS_NAND_ECCBYTES * CONFIG_SYS_NAND_ECCSTEPS)
 #define CONFIG_SYS_NAND_ECCPOS         {0, 1, 2, 3, 6, 7}
 
 #ifdef CONFIG_ENV_IS_IN_NAND
index 1945c032ab5d78931b59088c8cd44bdc50c4ff35..003109329a2bb0dc67efb4273130ee4eba65e477 100644 (file)
@@ -70,7 +70,6 @@
 #define CONFIG_DRIVER_NAND_BFIN
 #define CONFIG_SYS_NAND_BASE           0 /* not actually used */
 #define CONFIG_SYS_MAX_NAND_DEVICE     1
-#define NAND_MAX_CHIPS         1
 #define CONFIG_CMD_NAND
 #endif
 
index 9c35f2d0b7808ba50debcbc52eef77b0897eac9a..fa05103e5aae3075c15fd3a8ff61bb4ce256b881 100644 (file)
@@ -69,7 +69,6 @@
 #define CONFIG_DRIVER_NAND_BFIN
 #define CONFIG_SYS_NAND_BASE           0 /* not actually used */
 #define CONFIG_SYS_MAX_NAND_DEVICE     1
-#define NAND_MAX_CHIPS         1
 #endif
 
 
index 1256e815d50825e4ccc065c6d04c135eca5d6eba..d80eac22db65e562050615d861c7fa3bdefb512c 100644 (file)
@@ -69,7 +69,6 @@
 #define CONFIG_DRIVER_NAND_BFIN
 #define CONFIG_SYS_NAND_BASE           0 /* not actually used */
 #define CONFIG_SYS_MAX_NAND_DEVICE     1
-#define NAND_MAX_CHIPS         1
 #endif
 
 
index 3eadcefb83e3dd28d20d1d3619796f67812fceab..89adfefee3797b8c129e8733d3ba9224cdfc35db 100644 (file)
 #define CONFIG_DRIVER_NAND_BFIN
 #define CONFIG_SYS_NAND_BASE           0 /* not actually used */
 #define CONFIG_SYS_MAX_NAND_DEVICE     1
-#define NAND_MAX_CHIPS         1
 
 
 /*
index a21d4482af498beac0280bd6fcd0c112037a4449..5d9672fbc812d1c13331f9a3250f5360aec1329d 100644 (file)
@@ -90,7 +90,6 @@
 #define CONFIG_SYS_NAND_BASE_LIST      { 0x02000000, }
 /* socket has two chipselects, nCE0 gated by address BIT(14) */
 #define CONFIG_SYS_MAX_NAND_DEVICE     1
-#define CONFIG_SYS_NAND_MAX_CHIPS      1
 
 /* SPI support */
 #define CONFIG_SPI
 #define CONFIG_SYS_NAND_ECCBYTES       10
 #define CONFIG_SYS_NAND_OOBSIZE                64
 #define CONFIG_SYS_NAND_5_ADDR_CYCLE
-#define CONFIG_SYS_NAND_ECCSTEPS       (CONFIG_SYS_NAND_PAGE_SIZE /     \
-                                        CONFIG_SYS_NAND_ECCSIZE)
-#define CONFIG_SYS_NAND_ECCTOTAL       (40)
 
 /*
  * RBL searches from Block n (n = 1..24)
index 8c03582c8ddc149249eb3e67a6827b3ad62c5f82..acb127c1d1227a166da8a01d0d45d922ec7ceabe 100644 (file)
 
 #define CONFIG_SYS_NAND_ECCSIZE        256
 #define CONFIG_SYS_NAND_ECCBYTES       3
-#define CONFIG_SYS_NAND_ECCSTEPS       (CONFIG_SYS_NAND_PAGE_SIZE / CONFIG_SYS_NAND_ECCSIZE)
 #define CONFIG_SYS_NAND_OOBSIZE        64
-#define CONFIG_SYS_NAND_ECCTOTAL       (CONFIG_SYS_NAND_ECCBYTES * CONFIG_SYS_NAND_ECCSTEPS)
 #define CONFIG_SYS_NAND_ECCPOS         {40, 41, 42, 43, 44, 45, 46, 47, \
                                 48, 49, 50, 51, 52, 53, 54, 55, \
                                 56, 57, 58, 59, 60, 61, 62, 63}
index 4f2b904d54ef6ffd0e7ea50d6f76f3254ccd7d74..b15a1eb7a2ee82333382d23a6bf3425811a10651 100644 (file)
@@ -68,7 +68,6 @@
 #define CONFIG_BFIN_NFC_CTL_VAL        0x0033
 #define CONFIG_SYS_NAND_BASE           0 /* not actually used */
 #define CONFIG_SYS_MAX_NAND_DEVICE     1
-#define NAND_MAX_CHIPS         1
 #define CONFIG_CMD_NAND
 #endif
 
index 8674a35d2238b1bf79e35df2601cbb47b4086b0c..8b6a6879892aff6a2ddae9e8b3ebfe0a35e3925c 100644 (file)
 
 /* NAND flash */
 #define CONFIG_NAND_ATMEL
-#define NAND_MAX_CHIPS                         1
 #define CONFIG_SYS_MAX_NAND_DEVICE             1
 #define CONFIG_SYS_NAND_BASE                   0x40000000
 #define CONFIG_SYS_NAND_DBW_8                  1
index 6ac25d2b9c11e7781da0f819ce73d31855b0dfdd..e8c021262ac4b747363cc6a013df7d4f89316203 100644 (file)
 #define CONFIG_SYS_CLE_MASK            0x10
 #define CONFIG_SYS_ALE_MASK            0x8
 #define CONFIG_SYS_MAX_NAND_DEVICE     1 /* Max number of NAND devices */
-#define NAND_MAX_CHIPS                 1
 #endif
 
 #ifdef CONFIG_USE_NOR
index fcbbace1cae347e28addeaff6d0c09088ce4e0fb..220890dfd9750c6633360a802a4c60798f4fd072 100644 (file)
 #define CONFIG_SYS_ALE_MASK            0x8
 #undef CONFIG_SYS_NAND_HW_ECC
 #define CONFIG_SYS_MAX_NAND_DEVICE     1 /* Max number of NAND devices */
-#define NAND_MAX_CHIPS                 1
 #endif
 
 /*
index dfa0a00475d8baa36298321044cc28cf159cc3db..dc5b408a618e542797694ba03f35993813f7dbf9 100644 (file)
@@ -69,7 +69,6 @@
 
 #define CONFIG_SYS_NAND_BASE_LIST      { 0x02000000, }
 #define CONFIG_SYS_MAX_NAND_DEVICE     1
-#define CONFIG_SYS_NAND_MAX_CHIPS      1
 
 /* U-Boot command configuration */
 #include <config_cmd_default.h>
index 758326bb9dddbd5099dfee5007b56618721cad4b..2b6a6ee091815a36162f7d601d0a71aaa28b8ff4 100644 (file)
 #define CONFIG_SYS_NAND_ECCSIZE                512
 #define CONFIG_SYS_NAND_ECCBYTES       3
 
-#define CONFIG_SYS_NAND_ECCSTEPS       (CONFIG_SYS_NAND_PAGE_SIZE / \
-                                               CONFIG_SYS_NAND_ECCSIZE)
-#define CONFIG_SYS_NAND_ECCTOTAL       (CONFIG_SYS_NAND_ECCBYTES * \
-                                               CONFIG_SYS_NAND_ECCSTEPS)
-
 #define CONFIG_SYS_NAND_U_BOOT_START   CONFIG_SYS_TEXT_BASE
 
 #define CONFIG_SYS_NAND_U_BOOT_OFFS    0x80000
index 74fec3f8b5d8e040655c39d84d4b7e8ae7f7f2b0..cc0f5b05cd63538eaebef8533b04d7f029dc15c1 100644 (file)
 #define CONFIG_SYS_NAND_4BIT_HW_ECC_OOBFIRST
 #define        CONFIG_SYS_NAND_USE_FLASH_BBT
 #define CONFIG_SYS_MAX_NAND_DEVICE     1 /* Max number of NAND devices */
-#define NAND_MAX_CHIPS                 1
 #define CONFIG_SYS_64BIT_VSPRINTF      /* needed for nand_util.c */
 #endif
 
index b08de4a72efaf376bfa4c940083420e5d031d515..9046cf0c01f712e11820992b27eec0beb5ddcf32 100644 (file)
 
 /* NAND */
 
-#define CONFIG_SYS_NAND_MAX_CHIPS      1
 #define CONFIG_SYS_MAX_NAND_DEVICE     1
 #define CONFIG_SYS_NAND_BASE           0x40000000
 #define CONFIG_SYS_NAND_DBW_8          1
index c427dc7c692be5de02e4d81c2c6f92d6686a0d6b..83aec790e6fefde9e7614f807894da8d67b3b09b 100644 (file)
 #define CONFIG_SYS_ALE_MASK            0x8
 #undef CONFIG_SYS_NAND_HW_ECC
 #define CONFIG_SYS_MAX_NAND_DEVICE     1 /* Max number of NAND devices */
-#define NAND_MAX_CHIPS                 1
 
 #define MTDIDS_DEFAULT         "nor0=physmap-flash.0,nand0=davinci_nand.1"
 #define MTDPARTS_DEFAULT                       \
index 12acb27aef7e4e68d8d8b3374bd469b99e1fb177..fa214941afbf8f52438e0fc02483b522a1d6e7ed 100644 (file)
 /* Max number of NAND devices */
 #define CONFIG_SYS_MAX_NAND_DEVICE     1
 #define CONFIG_SYS_NAND_BASE_LIST      { 0x62000000, }
-#define NAND_MAX_CHIPS                 1
 /* Block 0--not used by bootcode */
 #define CONFIG_ENV_OFFSET              0x0
 
 #define CONFIG_SYS_NAND_BAD_BLOCK_POS  0
 #define CONFIG_SYS_NAND_ECCSIZE                512
 #define CONFIG_SYS_NAND_ECCBYTES       10
-#define CONFIG_SYS_NAND_ECCSTEPS       (CONFIG_SYS_NAND_PAGE_SIZE /     \
-                                        CONFIG_SYS_NAND_ECCSIZE)
 #define CONFIG_SYS_NAND_OOBSIZE                64
-#define CONFIG_SYS_NAND_ECCTOTAL       (CONFIG_SYS_NAND_ECCBYTES *     \
-                                       CONFIG_SYS_NAND_ECCSTEPS)
+
 #endif /* CONFIG_SYS_USE_NAND */
 
 /*
index e66aadf97e0c9c41908689937c0ab64fd6837579..621dbb8fa67fe74c7e06d4db187d2bd3f0aaec17 100644 (file)
 
 #define CONFIG_SYS_NAND_ECCSIZE        256
 #define CONFIG_SYS_NAND_ECCBYTES       3
-#define CONFIG_SYS_NAND_ECCSTEPS       (CONFIG_SYS_NAND_PAGE_SIZE / CONFIG_SYS_NAND_ECCSIZE)
 #define CONFIG_SYS_NAND_OOBSIZE        16
-#define CONFIG_SYS_NAND_ECCTOTAL       (CONFIG_SYS_NAND_ECCBYTES * CONFIG_SYS_NAND_ECCSTEPS)
 #define CONFIG_SYS_NAND_ECCPOS         {0, 1, 2, 3, 6, 7}
 
 #ifdef CONFIG_ENV_IS_IN_NAND
index 700124c0c43281881210e665579d607608de0ad9..9c8d222c2fe28bbd52f144f362b52cc3410329dd 100644 (file)
  * NAND Flash configuration
  */
 #define CONFIG_SYS_MAX_NAND_DEVICE     1
-#define NAND_MAX_CHIPS                 1
 
 #define BOOTFLASH_START                0x0
 
index b891b12fef81f38ce19122606efa67dc1fac667f..4efff0992b8e1c80fb859a0b44939f3d73b5f36a 100644 (file)
 #define        CONFIG_SYS_MAX_NAND_DEVICE      1
 #define        CONFIG_SYS_NAND_BASE            0x60000000
 #define        CONFIG_SYS_NAND_5_ADDR_CYCLE
-#define        NAND_MAX_CHIPS                  8
 
 /* Environment is in NAND */
 #define        CONFIG_ENV_IS_IN_NAND
index ed9282b998a2b64796495dcfac5a20938cf6503f..f5765b0d4e18997137b6e96afb3c37ef80c84f18 100644 (file)
 #define CONFIG_CMD_NAND
 #define CONFIG_NAND_MPC5121_NFC
 #define CONFIG_SYS_NAND_BASE            0x40000000
-
 #define CONFIG_SYS_MAX_NAND_DEVICE      1
-#define NAND_MAX_CHIPS                  CONFIG_SYS_MAX_NAND_DEVICE
 
 /*
  * Configuration parameters for MPC5121 NAND driver
index c3d3afde0e0f94328dead73fa93fb7e25741d252..01df8b1273268d17e77397f7484e70e9414ad01b 100644 (file)
 #define CONFIG_SYS_NAND_BASE            0x40000000
 
 #define CONFIG_SYS_MAX_NAND_DEVICE      2
-#define NAND_MAX_CHIPS                  CONFIG_SYS_MAX_NAND_DEVICE
 #define CONFIG_SYS_NAND_SELECT_DEVICE  /* driver supports mutipl. chips */
 
 /*
index 3f5fcc69a2d2b4d460d4142ab29a4f82a85d12a2..1a6379176b3b4c3590326abe6f0aa43b16bb420b 100644 (file)
  */
 #ifdef CONFIG_CMD_NAND
 #define CONFIG_SYS_MAX_NAND_DEVICE     1
-#define NAND_MAX_CHIPS                 1
 #define CONFIG_SYS_64BIT_VSPRINTF      /* needed for nand_util.c */
 #endif
 
index 91af8a025697b0055b87d135db0034b3e6b3e117..4c7a686d390b713be73d930b51f34c93dac0581b 100644 (file)
                                                10, 11, 12, 13}
 #define CONFIG_SYS_NAND_ECCSIZE                512
 #define CONFIG_SYS_NAND_ECCBYTES       3
-#define CONFIG_SYS_NAND_ECCSTEPS       (CONFIG_SYS_NAND_PAGE_SIZE / \
-                                               CONFIG_SYS_NAND_ECCSIZE)
-#define CONFIG_SYS_NAND_ECCTOTAL       (CONFIG_SYS_NAND_ECCBYTES * \
-                                               CONFIG_SYS_NAND_ECCSTEPS)
 #define CONFIG_SYS_NAND_U_BOOT_START   CONFIG_SYS_TEXT_BASE
 #define CONFIG_SYS_NAND_U_BOOT_OFFS    0x80000
 
index 2ce3959fdaf5f8963a0edce96f90791c3702f81c..1fcb7af9fe2128969ebee408323c8411c72a44d0 100644 (file)
                                                10, 11, 12, 13}
 #define CONFIG_SYS_NAND_ECCSIZE                512
 #define CONFIG_SYS_NAND_ECCBYTES       3
-#define CONFIG_SYS_NAND_ECCSTEPS       (CONFIG_SYS_NAND_PAGE_SIZE / \
-                                               CONFIG_SYS_NAND_ECCSIZE)
-#define CONFIG_SYS_NAND_ECCTOTAL       (CONFIG_SYS_NAND_ECCBYTES * \
-                                               CONFIG_SYS_NAND_ECCSTEPS)
 #define CONFIG_SYS_NAND_U_BOOT_START   CONFIG_SYS_TEXT_BASE
 #define CONFIG_SYS_NAND_U_BOOT_OFFS    0x80000
 
index 2f879c0bf12ffd5b9799dc9aff1015ff4e11ce83..362fa1d720a06d7940f5f603e75205018d7893aa 100644 (file)
                                                10, 11, 12, 13}
 #define CONFIG_SYS_NAND_ECCSIZE                512
 #define CONFIG_SYS_NAND_ECCBYTES       3
-#define CONFIG_SYS_NAND_ECCSTEPS       (CONFIG_SYS_NAND_PAGE_SIZE / \
-                                               CONFIG_SYS_NAND_ECCSIZE)
-#define CONFIG_SYS_NAND_ECCTOTAL       (CONFIG_SYS_NAND_ECCBYTES * \
-                                               CONFIG_SYS_NAND_ECCSTEPS)
 #define CONFIG_SYS_NAND_U_BOOT_START   CONFIG_SYS_TEXT_BASE
 #define CONFIG_SYS_NAND_U_BOOT_OFFS    0x80000
 
index f0154e091e5883d8ed462f1622b03b70ffa49220..8afc3c03dbfaa9c437966832a0b70c50df4f758d 100644 (file)
 #define CONFIG_CMD_NAND                        /* enable NAND support */
 #define CONFIG_NAND_MPC5121_NFC
 #define CONFIG_SYS_NAND_BASE            0x40000000
-
 #define CONFIG_SYS_MAX_NAND_DEVICE      1
-#define NAND_MAX_CHIPS                  CONFIG_SYS_MAX_NAND_DEVICE
 #define CONFIG_SYS_NAND_SELECT_DEVICE  /* driver supports mutipl. chips */
 
 /*
index 1e803169e6a28e47a74aeb30a558b9e081d8bfde..eba5616ddf9df6446692d7aad57b424da3ff46de 100644 (file)
 
 /* NAND flash */
 #define CONFIG_NAND_ATMEL
-#define NAND_MAX_CHIPS                         1
 #define CONFIG_SYS_MAX_NAND_DEVICE             1
 #define CONFIG_SYS_NAND_BASE                   0x40000000
 #define CONFIG_SYS_NAND_DBW_8                  1
index 32c596241a48101082ba55a329b59087f6c72316..bf31c13bdcfdbcc4e71625c97d6c90e2ca02983c 100644 (file)
 /* NAND flash */
 #ifdef CONFIG_CMD_NAND
 #define CONFIG_NAND_ATMEL
-#define CONFIG_SYS_NAND_MAX_CHIPS      1
 #define CONFIG_SYS_MAX_NAND_DEVICE     1
 #define CONFIG_SYS_NAND_BASE           0x40000000
 #define CONFIG_SYS_NAND_DBW_8          1
index eec915330038e3b02f088f232a053dbdebc1875a..47798787de3f39071bf06863e920f57de67c2eb4 100644 (file)
 
 /* NAND flash */
 #ifdef CONFIG_CMD_NAND
-#define CONFIG_NAND_MAX_CHIPS          1
 #define CONFIG_NAND_ATMEL
 #define CONFIG_SYS_MAX_NAND_DEVICE     1
 #define CONFIG_SYS_NAND_BASE           0x40000000
index f989595d0e10d85713128c83d7f0cc5a849f5d51..ebd8223d6f4de77152e1e29a5436e8200172689e 100644 (file)
 #define CONFIG_SYS_NAND_ECC_POS                (6 * NANONOTE_NAND_SIZE)
 #define CONFIG_SYS_NAND_ECCSIZE                512
 #define CONFIG_SYS_NAND_ECCBYTES       9
-#define CONFIG_SYS_NAND_ECCSTEPS       \
-       (CONFIG_SYS_NAND_PAGE_SIZE / CONFIG_SYS_NAND_ECCSIZE)
-#define CONFIG_SYS_NAND_ECCTOTAL       \
-       (CONFIG_SYS_NAND_ECCBYTES * CONFIG_SYS_NAND_ECCSTEPS)
 #define CONFIG_SYS_NAND_ECCPOS         \
                {12, 13, 14, 15, 16, 17, 18, 19,\
                20, 21, 22, 23, 24, 25, 26, 27, \
 #define CONFIG_SYS_NAND_OOBSIZE                128
 #define CONFIG_SYS_NAND_BASE           0xB8000000
 #define CONFIG_SYS_ONENAND_BASE                CONFIG_SYS_NAND_BASE
-#define NAND_MAX_CHIPS                 1
 #define CONFIG_SYS_MAX_NAND_DEVICE     1
 #define CONFIG_SYS_NAND_SELECT_DEVICE  1 /* nand driver supports mutipl.*/
 #define CONFIG_NAND_SPL_TEXT_BASE      0x80000000
index a406ca032ce9153d023a3199083ce255a8cf3b0d..8e6954e3aa774d036a08d5053a20e2563b2d43fb 100644 (file)
 
 #define CONFIG_SYS_NAND_ECCSIZE        256
 #define CONFIG_SYS_NAND_ECCBYTES       3
-#define CONFIG_SYS_NAND_ECCSTEPS       (CONFIG_SYS_NAND_PAGE_SIZE / CONFIG_SYS_NAND_ECCSIZE)
 #define CONFIG_SYS_NAND_OOBSIZE        16
-#define CONFIG_SYS_NAND_ECCTOTAL       (CONFIG_SYS_NAND_ECCBYTES * CONFIG_SYS_NAND_ECCSTEPS)
 #define CONFIG_SYS_NAND_ECCPOS         {0, 1, 2, 3, 6, 7}
 
 #ifdef CONFIG_ENV_IS_IN_NAND
index 77c0a08d4cc327aea9de9ed9cbfe21ea0328eec1..73159846ef895801c34ccfe46f9c8a1e5baa539f 100644 (file)
 #define CONFIG_NAND_S3C2410
 #define CONFIG_SYS_S3C2410_NAND_HWECC
 #define CONFIG_SYS_MAX_NAND_DEVICE     1
-#define NAND_MAX_CHIPS                 1
 #define CONFIG_SYS_NAND_BASE           0x4E000000
 #endif
 
index 4d0b7b2d4d282687a692646669c880e5194e72d5..a2b9441050f4592771ad747319224590b27e9877 100644 (file)
 #define CONFIG_SYS_NAND_ECCSIZE        CONFIG_SYS_NAND_PAGE_SIZE
 /* Number of ECC bytes per OOB - S3C6400 calculates 4 bytes ECC in 1-bit mode */
 #define CONFIG_SYS_NAND_ECCBYTES       4
-/* Number of ECC-blocks per NAND page */
-#define CONFIG_SYS_NAND_ECCSTEPS       (CONFIG_SYS_NAND_PAGE_SIZE / CONFIG_SYS_NAND_ECCSIZE)
 /* Size of a single OOB region */
 #define CONFIG_SYS_NAND_OOBSIZE        64
-/* Number of ECC bytes per page */
-#define CONFIG_SYS_NAND_ECCTOTAL       (CONFIG_SYS_NAND_ECCBYTES * CONFIG_SYS_NAND_ECCSTEPS)
 /* ECC byte positions */
 #define CONFIG_SYS_NAND_ECCPOS         {40, 41, 42, 43, 44, 45, 46, 47, \
                                 48, 49, 50, 51, 52, 53, 54, 55, \
index 817d468a72c279e07d15b06892a0a09641f5776c..f4963ac07e88854a8c6ebef953a95fdf5fa7de68 100644 (file)
 #define CONFIG_SYS_NAND_ECCSIZE                256
 #define CONFIG_SYS_NAND_ECCBYTES       3
 
-#define CONFIG_SYS_NAND_ECCSTEPS       (CONFIG_SYS_NAND_PAGE_SIZE / \
-                                               CONFIG_SYS_NAND_ECCSIZE)
-#define CONFIG_SYS_NAND_ECCTOTAL       (CONFIG_SYS_NAND_ECCBYTES * \
-                                               CONFIG_SYS_NAND_ECCSTEPS)
-
 #define CONFIG_SYS_NAND_U_BOOT_START   CONFIG_SYS_TEXT_BASE
 
 #define CONFIG_SYS_NAND_U_BOOT_OFFS    0x80000
index 4bced0c9994edfebf6cbeb38eb64b924db29f2c2..7c3f33427c4ca0b47dced4297fd7c444fd80ea90 100644 (file)
@@ -90,7 +90,6 @@
 #define CONFIG_CMD_MTDPARTS
 #define CONFIG_MTD_DEVICE
 #define CONFIG_JFFS2_NAND
-#define NAND_MAX_CHIPS                 1
 #define CONFIG_ENV_OFFSET              0x180000
 
 /*
index a553712699b6b2a4b6be02c10036785e54cde359..7e293c676c238dbcc9675c5e7d1bc6d6712ca717 100644 (file)
 
 #define CONFIG_NAND_MXC
 #define CONFIG_SYS_MAX_NAND_DEVICE             1
-#define CONFIG_SYS_NAND_MAX_CHIPS              1
 
 /*
  * actually this is nothing someone wants to configure!
diff --git a/include/linux/bch.h b/include/linux/bch.h
new file mode 100644 (file)
index 0000000..295b4ef
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Generic binary BCH encoding/decoding library
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * Copyright Â© 2011 Parrot S.A.
+ *
+ * Author: Ivan Djelic <ivan.djelic@parrot.com>
+ *
+ * Description:
+ *
+ * This library provides runtime configurable encoding/decoding of binary
+ * Bose-Chaudhuri-Hocquenghem (BCH) codes.
+*/
+#ifndef _BCH_H
+#define _BCH_H
+
+#include <linux/types.h>
+
+/**
+ * struct bch_control - BCH control structure
+ * @m:          Galois field order
+ * @n:          maximum codeword size in bits (= 2^m-1)
+ * @t:          error correction capability in bits
+ * @ecc_bits:   ecc exact size in bits, i.e. generator polynomial degree (<=m*t)
+ * @ecc_bytes:  ecc max size (m*t bits) in bytes
+ * @a_pow_tab:  Galois field GF(2^m) exponentiation lookup table
+ * @a_log_tab:  Galois field GF(2^m) log lookup table
+ * @mod8_tab:   remainder generator polynomial lookup tables
+ * @ecc_buf:    ecc parity words buffer
+ * @ecc_buf2:   ecc parity words buffer
+ * @xi_tab:     GF(2^m) base for solving degree 2 polynomial roots
+ * @syn:        syndrome buffer
+ * @cache:      log-based polynomial representation buffer
+ * @elp:        error locator polynomial
+ * @poly_2t:    temporary polynomials of degree 2t
+ */
+struct bch_control {
+       unsigned int    m;
+       unsigned int    n;
+       unsigned int    t;
+       unsigned int    ecc_bits;
+       unsigned int    ecc_bytes;
+/* private: */
+       uint16_t       *a_pow_tab;
+       uint16_t       *a_log_tab;
+       uint32_t       *mod8_tab;
+       uint32_t       *ecc_buf;
+       uint32_t       *ecc_buf2;
+       unsigned int   *xi_tab;
+       unsigned int   *syn;
+       int            *cache;
+       struct gf_poly *elp;
+       struct gf_poly *poly_2t[4];
+};
+
+struct bch_control *init_bch(int m, int t, unsigned int prim_poly);
+
+void free_bch(struct bch_control *bch);
+
+void encode_bch(struct bch_control *bch, const uint8_t *data,
+               unsigned int len, uint8_t *ecc);
+
+int decode_bch(struct bch_control *bch, const uint8_t *data, unsigned int len,
+              const uint8_t *recv_ecc, const uint8_t *calc_ecc,
+              const unsigned int *syn, unsigned int *errloc);
+
+#endif /* _BCH_H */
index 7db25465df1a4a5c06b2ef0ead78d778cfbaad85..8cbcdae1143fa28ef406ce7dc795c8c0b6f8f7b8 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,14 @@ 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 bad block table does not OOB for marker */
+#define NAND_BBT_NO_OOB                0x00400000
 
 /* The maximum number of blocks to scan for a bbt */
 #define NAND_BBT_SCAN_MAXBLOCKS        4
index 1cdc7ae279352b982127566987497e9eb12bba4e..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
 #ifndef __LINUX_MTD_NAND_H
 #define __LINUX_MTD_NAND_H
 
-/* XXX U-BOOT XXX */
-#if 0
-#include <linux/wait.h>
-#include <linux/spinlock.h>
-#include <linux/mtd/mtd.h>
-#endif
-
 #include "config.h"
 
 #include "linux/mtd/compat.h"
@@ -43,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
@@ -86,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
@@ -132,6 +130,7 @@ typedef enum {
        NAND_ECC_HW,
        NAND_ECC_HW_SYNDROME,
        NAND_ECC_HW_OOB_FIRST,
+       NAND_ECC_SOFT_BCH,
 } nand_ecc_modes_t;
 
 /*
@@ -148,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 */
@@ -161,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 \
@@ -196,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
 
@@ -281,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 */
@@ -308,56 +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
  * @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                    (*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);
 };
 
 /**
@@ -377,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;
 };
 
 /*
@@ -539,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[];
@@ -552,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
@@ -573,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
@@ -596,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;
 };
 
 /**
@@ -610,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 */
diff --git a/include/linux/mtd/nand_bch.h b/include/linux/mtd/nand_bch.h
new file mode 100644 (file)
index 0000000..d8754dd
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright Â© 2011 Ivan Djelic <ivan.djelic@parrot.com>
+ *
+ * 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.
+ *
+ * This file is the header for the NAND BCH ECC implementation.
+ */
+
+#ifndef __MTD_NAND_BCH_H__
+#define __MTD_NAND_BCH_H__
+
+struct mtd_info;
+struct nand_bch_control;
+
+#if defined(CONFIG_NAND_ECC_BCH)
+
+static inline int mtd_nand_has_bch(void) { return 1; }
+
+/*
+ * Calculate BCH ecc code
+ */
+int nand_bch_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+                          u_char *ecc_code);
+
+/*
+ * Detect and correct bit errors
+ */
+int nand_bch_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc,
+                         u_char *calc_ecc);
+/*
+ * Initialize BCH encoder/decoder
+ */
+struct nand_bch_control *
+nand_bch_init(struct mtd_info *mtd, unsigned int eccsize,
+             unsigned int eccbytes, struct nand_ecclayout **ecclayout);
+/*
+ * Release BCH encoder/decoder resources
+ */
+void nand_bch_free(struct nand_bch_control *nbc);
+
+#else /* !CONFIG_NAND_ECC_BCH */
+
+static inline int mtd_nand_has_bch(void) { return 0; }
+
+static inline int
+nand_bch_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+                      u_char *ecc_code)
+{
+       return -1;
+}
+
+static inline int
+nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
+                     unsigned char *read_ecc, unsigned char *calc_ecc)
+{
+       return -1;
+}
+
+static inline struct nand_bch_control *
+nand_bch_init(struct mtd_info *mtd, unsigned int eccsize,
+             unsigned int eccbytes, struct nand_ecclayout **ecclayout)
+{
+       return NULL;
+}
+
+static inline void nand_bch_free(struct nand_bch_control *nbc) {}
+
+#endif /* CONFIG_NAND_ECC_BCH */
+
+#endif /* __MTD_NAND_BCH_H__ */
index 090da505425d77d105acb6133d63dfaaa7c95b7b..9715a53d86d4ec3716b167a646dd3732da556d13 100644 (file)
 
 struct mtd_info;
 
+#if defined(CONFIG_MTD_ECC_SOFT)
+
+static inline int mtd_nand_has_ecc_soft(void) { return 1; }
+
 /*
  * Calculate 3 byte ECC code for 256 byte block
  */
@@ -25,4 +29,25 @@ int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code
  */
 int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);
 
+#else
+
+static inline int mtd_nand_has_ecc_soft(void) { return 0; }
+
+static inline int
+nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
+{
+       return -1;
+}
+
+static inline int
+nand_correct_data(struct mtd_info *mtd,
+                       u_char *dat,
+                       u_char *read_ecc,
+                       u_char *calc_ecc)
+{
+       return -1;
+}
+
+#endif
+
 #endif /* __MTD_NAND_ECC_H__ */
index 62390399b0b1b7e160001abd437fd2020bfee808..9a8cbc24cdceeef5612dcdeca82fe788b3d33f56 100644 (file)
@@ -47,6 +47,10 @@ extern char * strchr(const char *,int);
 #ifndef __HAVE_ARCH_STRRCHR
 extern char * strrchr(const char *,int);
 #endif
+extern char * skip_spaces(const char *);
+
+extern char *strim(char *);
+
 #ifndef __HAVE_ARCH_STRSTR
 extern char * strstr(const char *,const char *);
 #endif
index d444ddcefea7c37a9dbb96aa97f10109b39cd0ce..8b3a1a77a399552b9eb8e10cc9a2746e24989711 100644 (file)
 #ifndef _NAND_H_
 #define _NAND_H_
 
+#include <config.h>
+
+/*
+ * All boards using a given driver must convert to self-init
+ * at the same time, so do it here.  When all drivers are
+ * converted, this will go away.
+ */
+#if defined(CONFIG_NAND_FSL_ELBC)
+#define CONFIG_SYS_NAND_SELF_INIT
+#endif
+
 extern void nand_init(void);
 
 #include <linux/mtd/compat.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 
+#ifdef CONFIG_SYS_NAND_SELF_INIT
+void board_nand_init(void);
+int nand_register(int devnum);
+#else
 extern int board_nand_init(struct nand_chip *nand);
+#endif
 
 typedef struct mtd_info nand_info_t;
 
index 35ba7ffe47f9852e90eb027c51d20e4267783bfb..e6e6ec63779be056942565c0bc515e35e8528285 100644 (file)
@@ -27,6 +27,7 @@ LIB   = $(obj)libgeneric.o
 
 ifndef CONFIG_SPL_BUILD
 COBJS-$(CONFIG_ADDR_MAP) += addr_map.o
+COBJS-$(CONFIG_BCH) += bch.o
 COBJS-$(CONFIG_BZIP2) += bzlib.o
 COBJS-$(CONFIG_BZIP2) += bzlib_crctable.o
 COBJS-$(CONFIG_BZIP2) += bzlib_decompress.o
diff --git a/lib/bch.c b/lib/bch.c
new file mode 100644 (file)
index 0000000..7f4ca92
--- /dev/null
+++ b/lib/bch.c
@@ -0,0 +1,1358 @@
+/*
+ * Generic binary BCH encoding/decoding library
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * Copyright Â© 2011 Parrot S.A.
+ *
+ * Author: Ivan Djelic <ivan.djelic@parrot.com>
+ *
+ * Description:
+ *
+ * This library provides runtime configurable encoding/decoding of binary
+ * Bose-Chaudhuri-Hocquenghem (BCH) codes.
+ *
+ * Call init_bch to get a pointer to a newly allocated bch_control structure for
+ * the given m (Galois field order), t (error correction capability) and
+ * (optional) primitive polynomial parameters.
+ *
+ * Call encode_bch to compute and store ecc parity bytes to a given buffer.
+ * Call decode_bch to detect and locate errors in received data.
+ *
+ * On systems supporting hw BCH features, intermediate results may be provided
+ * to decode_bch in order to skip certain steps. See decode_bch() documentation
+ * for details.
+ *
+ * Option CONFIG_BCH_CONST_PARAMS can be used to force fixed values of
+ * parameters m and t; thus allowing extra compiler optimizations and providing
+ * better (up to 2x) encoding performance. Using this option makes sense when
+ * (m,t) are fixed and known in advance, e.g. when using BCH error correction
+ * on a particular NAND flash device.
+ *
+ * Algorithmic details:
+ *
+ * Encoding is performed by processing 32 input bits in parallel, using 4
+ * remainder lookup tables.
+ *
+ * The final stage of decoding involves the following internal steps:
+ * a. Syndrome computation
+ * b. Error locator polynomial computation using Berlekamp-Massey algorithm
+ * c. Error locator root finding (by far the most expensive step)
+ *
+ * In this implementation, step c is not performed using the usual Chien search.
+ * Instead, an alternative approach described in [1] is used. It consists in
+ * factoring the error locator polynomial using the Berlekamp Trace algorithm
+ * (BTA) down to a certain degree (4), after which ad hoc low-degree polynomial
+ * solving techniques [2] are used. The resulting algorithm, called BTZ, yields
+ * much better performance than Chien search for usual (m,t) values (typically
+ * m >= 13, t < 32, see [1]).
+ *
+ * [1] B. Biswas, V. Herbert. Efficient root finding of polynomials over fields
+ * of characteristic 2, in: Western European Workshop on Research in Cryptology
+ * - WEWoRC 2009, Graz, Austria, LNCS, Springer, July 2009, to appear.
+ * [2] [Zin96] V.A. Zinoviev. On the solution of equations of degree 10 over
+ * finite fields GF(2^q). In Rapport de recherche INRIA no 2829, 1996.
+ */
+
+#include <common.h>
+#include <ubi_uboot.h>
+
+#include <linux/bitops.h>
+#include <asm/byteorder.h>
+#include <linux/bch.h>
+
+#if defined(CONFIG_BCH_CONST_PARAMS)
+#define GF_M(_p)               (CONFIG_BCH_CONST_M)
+#define GF_T(_p)               (CONFIG_BCH_CONST_T)
+#define GF_N(_p)               ((1 << (CONFIG_BCH_CONST_M))-1)
+#else
+#define GF_M(_p)               ((_p)->m)
+#define GF_T(_p)               ((_p)->t)
+#define GF_N(_p)               ((_p)->n)
+#endif
+
+#define BCH_ECC_WORDS(_p)      DIV_ROUND_UP(GF_M(_p)*GF_T(_p), 32)
+#define BCH_ECC_BYTES(_p)      DIV_ROUND_UP(GF_M(_p)*GF_T(_p), 8)
+
+#ifndef dbg
+#define dbg(_fmt, args...)     do {} while (0)
+#endif
+
+/*
+ * represent a polynomial over GF(2^m)
+ */
+struct gf_poly {
+       unsigned int deg;    /* polynomial degree */
+       unsigned int c[0];   /* polynomial terms */
+};
+
+/* given its degree, compute a polynomial size in bytes */
+#define GF_POLY_SZ(_d) (sizeof(struct gf_poly)+((_d)+1)*sizeof(unsigned int))
+
+/* polynomial of degree 1 */
+struct gf_poly_deg1 {
+       struct gf_poly poly;
+       unsigned int   c[2];
+};
+
+/*
+ * same as encode_bch(), but process input data one byte at a time
+ */
+static void encode_bch_unaligned(struct bch_control *bch,
+                                const unsigned char *data, unsigned int len,
+                                uint32_t *ecc)
+{
+       int i;
+       const uint32_t *p;
+       const int l = BCH_ECC_WORDS(bch)-1;
+
+       while (len--) {
+               p = bch->mod8_tab + (l+1)*(((ecc[0] >> 24)^(*data++)) & 0xff);
+
+               for (i = 0; i < l; i++)
+                       ecc[i] = ((ecc[i] << 8)|(ecc[i+1] >> 24))^(*p++);
+
+               ecc[l] = (ecc[l] << 8)^(*p);
+       }
+}
+
+/*
+ * convert ecc bytes to aligned, zero-padded 32-bit ecc words
+ */
+static void load_ecc8(struct bch_control *bch, uint32_t *dst,
+                     const uint8_t *src)
+{
+       uint8_t pad[4] = {0, 0, 0, 0};
+       unsigned int i, nwords = BCH_ECC_WORDS(bch)-1;
+
+       for (i = 0; i < nwords; i++, src += 4)
+               dst[i] = (src[0] << 24)|(src[1] << 16)|(src[2] << 8)|src[3];
+
+       memcpy(pad, src, BCH_ECC_BYTES(bch)-4*nwords);
+       dst[nwords] = (pad[0] << 24)|(pad[1] << 16)|(pad[2] << 8)|pad[3];
+}
+
+/*
+ * convert 32-bit ecc words to ecc bytes
+ */
+static void store_ecc8(struct bch_control *bch, uint8_t *dst,
+                      const uint32_t *src)
+{
+       uint8_t pad[4];
+       unsigned int i, nwords = BCH_ECC_WORDS(bch)-1;
+
+       for (i = 0; i < nwords; i++) {
+               *dst++ = (src[i] >> 24);
+               *dst++ = (src[i] >> 16) & 0xff;
+               *dst++ = (src[i] >>  8) & 0xff;
+               *dst++ = (src[i] >>  0) & 0xff;
+       }
+       pad[0] = (src[nwords] >> 24);
+       pad[1] = (src[nwords] >> 16) & 0xff;
+       pad[2] = (src[nwords] >>  8) & 0xff;
+       pad[3] = (src[nwords] >>  0) & 0xff;
+       memcpy(dst, pad, BCH_ECC_BYTES(bch)-4*nwords);
+}
+
+/**
+ * encode_bch - calculate BCH ecc parity of data
+ * @bch:   BCH control structure
+ * @data:  data to encode
+ * @len:   data length in bytes
+ * @ecc:   ecc parity data, must be initialized by caller
+ *
+ * The @ecc parity array is used both as input and output parameter, in order to
+ * allow incremental computations. It should be of the size indicated by member
+ * @ecc_bytes of @bch, and should be initialized to 0 before the first call.
+ *
+ * The exact number of computed ecc parity bits is given by member @ecc_bits of
+ * @bch; it may be less than m*t for large values of t.
+ */
+void encode_bch(struct bch_control *bch, const uint8_t *data,
+               unsigned int len, uint8_t *ecc)
+{
+       const unsigned int l = BCH_ECC_WORDS(bch)-1;
+       unsigned int i, mlen;
+       unsigned long m;
+       uint32_t w, r[l+1];
+       const uint32_t * const tab0 = bch->mod8_tab;
+       const uint32_t * const tab1 = tab0 + 256*(l+1);
+       const uint32_t * const tab2 = tab1 + 256*(l+1);
+       const uint32_t * const tab3 = tab2 + 256*(l+1);
+       const uint32_t *pdata, *p0, *p1, *p2, *p3;
+
+       if (ecc) {
+               /* load ecc parity bytes into internal 32-bit buffer */
+               load_ecc8(bch, bch->ecc_buf, ecc);
+       } else {
+               memset(bch->ecc_buf, 0, sizeof(r));
+       }
+
+       /* process first unaligned data bytes */
+       m = ((unsigned long)data) & 3;
+       if (m) {
+               mlen = (len < (4-m)) ? len : 4-m;
+               encode_bch_unaligned(bch, data, mlen, bch->ecc_buf);
+               data += mlen;
+               len  -= mlen;
+       }
+
+       /* process 32-bit aligned data words */
+       pdata = (uint32_t *)data;
+       mlen  = len/4;
+       data += 4*mlen;
+       len  -= 4*mlen;
+       memcpy(r, bch->ecc_buf, sizeof(r));
+
+       /*
+        * split each 32-bit word into 4 polynomials of weight 8 as follows:
+        *
+        * 31 ...24  23 ...16  15 ... 8  7 ... 0
+        * xxxxxxxx  yyyyyyyy  zzzzzzzz  tttttttt
+        *                               tttttttt  mod g = r0 (precomputed)
+        *                     zzzzzzzz  00000000  mod g = r1 (precomputed)
+        *           yyyyyyyy  00000000  00000000  mod g = r2 (precomputed)
+        * xxxxxxxx  00000000  00000000  00000000  mod g = r3 (precomputed)
+        * xxxxxxxx  yyyyyyyy  zzzzzzzz  tttttttt  mod g = r0^r1^r2^r3
+        */
+       while (mlen--) {
+               /* input data is read in big-endian format */
+               w = r[0]^cpu_to_be32(*pdata++);
+               p0 = tab0 + (l+1)*((w >>  0) & 0xff);
+               p1 = tab1 + (l+1)*((w >>  8) & 0xff);
+               p2 = tab2 + (l+1)*((w >> 16) & 0xff);
+               p3 = tab3 + (l+1)*((w >> 24) & 0xff);
+
+               for (i = 0; i < l; i++)
+                       r[i] = r[i+1]^p0[i]^p1[i]^p2[i]^p3[i];
+
+               r[l] = p0[l]^p1[l]^p2[l]^p3[l];
+       }
+       memcpy(bch->ecc_buf, r, sizeof(r));
+
+       /* process last unaligned bytes */
+       if (len)
+               encode_bch_unaligned(bch, data, len, bch->ecc_buf);
+
+       /* store ecc parity bytes into original parity buffer */
+       if (ecc)
+               store_ecc8(bch, ecc, bch->ecc_buf);
+}
+
+static inline int modulo(struct bch_control *bch, unsigned int v)
+{
+       const unsigned int n = GF_N(bch);
+       while (v >= n) {
+               v -= n;
+               v = (v & n) + (v >> GF_M(bch));
+       }
+       return v;
+}
+
+/*
+ * shorter and faster modulo function, only works when v < 2N.
+ */
+static inline int mod_s(struct bch_control *bch, unsigned int v)
+{
+       const unsigned int n = GF_N(bch);
+       return (v < n) ? v : v-n;
+}
+
+static inline int deg(unsigned int poly)
+{
+       /* polynomial degree is the most-significant bit index */
+       return fls(poly)-1;
+}
+
+static inline int parity(unsigned int x)
+{
+       /*
+        * public domain code snippet, lifted from
+        * http://www-graphics.stanford.edu/~seander/bithacks.html
+        */
+       x ^= x >> 1;
+       x ^= x >> 2;
+       x = (x & 0x11111111U) * 0x11111111U;
+       return (x >> 28) & 1;
+}
+
+/* Galois field basic operations: multiply, divide, inverse, etc. */
+
+static inline unsigned int gf_mul(struct bch_control *bch, unsigned int a,
+                                 unsigned int b)
+{
+       return (a && b) ? bch->a_pow_tab[mod_s(bch, bch->a_log_tab[a]+
+                                              bch->a_log_tab[b])] : 0;
+}
+
+static inline unsigned int gf_sqr(struct bch_control *bch, unsigned int a)
+{
+       return a ? bch->a_pow_tab[mod_s(bch, 2*bch->a_log_tab[a])] : 0;
+}
+
+static inline unsigned int gf_div(struct bch_control *bch, unsigned int a,
+                                 unsigned int b)
+{
+       return a ? bch->a_pow_tab[mod_s(bch, bch->a_log_tab[a]+
+                                       GF_N(bch)-bch->a_log_tab[b])] : 0;
+}
+
+static inline unsigned int gf_inv(struct bch_control *bch, unsigned int a)
+{
+       return bch->a_pow_tab[GF_N(bch)-bch->a_log_tab[a]];
+}
+
+static inline unsigned int a_pow(struct bch_control *bch, int i)
+{
+       return bch->a_pow_tab[modulo(bch, i)];
+}
+
+static inline int a_log(struct bch_control *bch, unsigned int x)
+{
+       return bch->a_log_tab[x];
+}
+
+static inline int a_ilog(struct bch_control *bch, unsigned int x)
+{
+       return mod_s(bch, GF_N(bch)-bch->a_log_tab[x]);
+}
+
+/*
+ * compute 2t syndromes of ecc polynomial, i.e. ecc(a^j) for j=1..2t
+ */
+static void compute_syndromes(struct bch_control *bch, uint32_t *ecc,
+                             unsigned int *syn)
+{
+       int i, j, s;
+       unsigned int m;
+       uint32_t poly;
+       const int t = GF_T(bch);
+
+       s = bch->ecc_bits;
+
+       /* make sure extra bits in last ecc word are cleared */
+       m = ((unsigned int)s) & 31;
+       if (m)
+               ecc[s/32] &= ~((1u << (32-m))-1);
+       memset(syn, 0, 2*t*sizeof(*syn));
+
+       /* compute v(a^j) for j=1 .. 2t-1 */
+       do {
+               poly = *ecc++;
+               s -= 32;
+               while (poly) {
+                       i = deg(poly);
+                       for (j = 0; j < 2*t; j += 2)
+                               syn[j] ^= a_pow(bch, (j+1)*(i+s));
+
+                       poly ^= (1 << i);
+               }
+       } while (s > 0);
+
+       /* v(a^(2j)) = v(a^j)^2 */
+       for (j = 0; j < t; j++)
+               syn[2*j+1] = gf_sqr(bch, syn[j]);
+}
+
+static void gf_poly_copy(struct gf_poly *dst, struct gf_poly *src)
+{
+       memcpy(dst, src, GF_POLY_SZ(src->deg));
+}
+
+static int compute_error_locator_polynomial(struct bch_control *bch,
+                                           const unsigned int *syn)
+{
+       const unsigned int t = GF_T(bch);
+       const unsigned int n = GF_N(bch);
+       unsigned int i, j, tmp, l, pd = 1, d = syn[0];
+       struct gf_poly *elp = bch->elp;
+       struct gf_poly *pelp = bch->poly_2t[0];
+       struct gf_poly *elp_copy = bch->poly_2t[1];
+       int k, pp = -1;
+
+       memset(pelp, 0, GF_POLY_SZ(2*t));
+       memset(elp, 0, GF_POLY_SZ(2*t));
+
+       pelp->deg = 0;
+       pelp->c[0] = 1;
+       elp->deg = 0;
+       elp->c[0] = 1;
+
+       /* use simplified binary Berlekamp-Massey algorithm */
+       for (i = 0; (i < t) && (elp->deg <= t); i++) {
+               if (d) {
+                       k = 2*i-pp;
+                       gf_poly_copy(elp_copy, elp);
+                       /* e[i+1](X) = e[i](X)+di*dp^-1*X^2(i-p)*e[p](X) */
+                       tmp = a_log(bch, d)+n-a_log(bch, pd);
+                       for (j = 0; j <= pelp->deg; j++) {
+                               if (pelp->c[j]) {
+                                       l = a_log(bch, pelp->c[j]);
+                                       elp->c[j+k] ^= a_pow(bch, tmp+l);
+                               }
+                       }
+                       /* compute l[i+1] = max(l[i]->c[l[p]+2*(i-p]) */
+                       tmp = pelp->deg+k;
+                       if (tmp > elp->deg) {
+                               elp->deg = tmp;
+                               gf_poly_copy(pelp, elp_copy);
+                               pd = d;
+                               pp = 2*i;
+                       }
+               }
+               /* di+1 = S(2i+3)+elp[i+1].1*S(2i+2)+...+elp[i+1].lS(2i+3-l) */
+               if (i < t-1) {
+                       d = syn[2*i+2];
+                       for (j = 1; j <= elp->deg; j++)
+                               d ^= gf_mul(bch, elp->c[j], syn[2*i+2-j]);
+               }
+       }
+       dbg("elp=%s\n", gf_poly_str(elp));
+       return (elp->deg > t) ? -1 : (int)elp->deg;
+}
+
+/*
+ * solve a m x m linear system in GF(2) with an expected number of solutions,
+ * and return the number of found solutions
+ */
+static int solve_linear_system(struct bch_control *bch, unsigned int *rows,
+                              unsigned int *sol, int nsol)
+{
+       const int m = GF_M(bch);
+       unsigned int tmp, mask;
+       int rem, c, r, p, k, param[m];
+
+       k = 0;
+       mask = 1 << m;
+
+       /* Gaussian elimination */
+       for (c = 0; c < m; c++) {
+               rem = 0;
+               p = c-k;
+               /* find suitable row for elimination */
+               for (r = p; r < m; r++) {
+                       if (rows[r] & mask) {
+                               if (r != p) {
+                                       tmp = rows[r];
+                                       rows[r] = rows[p];
+                                       rows[p] = tmp;
+                               }
+                               rem = r+1;
+                               break;
+                       }
+               }
+               if (rem) {
+                       /* perform elimination on remaining rows */
+                       tmp = rows[p];
+                       for (r = rem; r < m; r++) {
+                               if (rows[r] & mask)
+                                       rows[r] ^= tmp;
+                       }
+               } else {
+                       /* elimination not needed, store defective row index */
+                       param[k++] = c;
+               }
+               mask >>= 1;
+       }
+       /* rewrite system, inserting fake parameter rows */
+       if (k > 0) {
+               p = k;
+               for (r = m-1; r >= 0; r--) {
+                       if ((r > m-1-k) && rows[r])
+                               /* system has no solution */
+                               return 0;
+
+                       rows[r] = (p && (r == param[p-1])) ?
+                               p--, 1u << (m-r) : rows[r-p];
+               }
+       }
+
+       if (nsol != (1 << k))
+               /* unexpected number of solutions */
+               return 0;
+
+       for (p = 0; p < nsol; p++) {
+               /* set parameters for p-th solution */
+               for (c = 0; c < k; c++)
+                       rows[param[c]] = (rows[param[c]] & ~1)|((p >> c) & 1);
+
+               /* compute unique solution */
+               tmp = 0;
+               for (r = m-1; r >= 0; r--) {
+                       mask = rows[r] & (tmp|1);
+                       tmp |= parity(mask) << (m-r);
+               }
+               sol[p] = tmp >> 1;
+       }
+       return nsol;
+}
+
+/*
+ * this function builds and solves a linear system for finding roots of a degree
+ * 4 affine monic polynomial X^4+aX^2+bX+c over GF(2^m).
+ */
+static int find_affine4_roots(struct bch_control *bch, unsigned int a,
+                             unsigned int b, unsigned int c,
+                             unsigned int *roots)
+{
+       int i, j, k;
+       const int m = GF_M(bch);
+       unsigned int mask = 0xff, t, rows[16] = {0,};
+
+       j = a_log(bch, b);
+       k = a_log(bch, a);
+       rows[0] = c;
+
+       /* buid linear system to solve X^4+aX^2+bX+c = 0 */
+       for (i = 0; i < m; i++) {
+               rows[i+1] = bch->a_pow_tab[4*i]^
+                       (a ? bch->a_pow_tab[mod_s(bch, k)] : 0)^
+                       (b ? bch->a_pow_tab[mod_s(bch, j)] : 0);
+               j++;
+               k += 2;
+       }
+       /*
+        * transpose 16x16 matrix before passing it to linear solver
+        * warning: this code assumes m < 16
+        */
+       for (j = 8; j != 0; j >>= 1, mask ^= (mask << j)) {
+               for (k = 0; k < 16; k = (k+j+1) & ~j) {
+                       t = ((rows[k] >> j)^rows[k+j]) & mask;
+                       rows[k] ^= (t << j);
+                       rows[k+j] ^= t;
+               }
+       }
+       return solve_linear_system(bch, rows, roots, 4);
+}
+
+/*
+ * compute root r of a degree 1 polynomial over GF(2^m) (returned as log(1/r))
+ */
+static int find_poly_deg1_roots(struct bch_control *bch, struct gf_poly *poly,
+                               unsigned int *roots)
+{
+       int n = 0;
+
+       if (poly->c[0])
+               /* poly[X] = bX+c with c!=0, root=c/b */
+               roots[n++] = mod_s(bch, GF_N(bch)-bch->a_log_tab[poly->c[0]]+
+                                  bch->a_log_tab[poly->c[1]]);
+       return n;
+}
+
+/*
+ * compute roots of a degree 2 polynomial over GF(2^m)
+ */
+static int find_poly_deg2_roots(struct bch_control *bch, struct gf_poly *poly,
+                               unsigned int *roots)
+{
+       int n = 0, i, l0, l1, l2;
+       unsigned int u, v, r;
+
+       if (poly->c[0] && poly->c[1]) {
+
+               l0 = bch->a_log_tab[poly->c[0]];
+               l1 = bch->a_log_tab[poly->c[1]];
+               l2 = bch->a_log_tab[poly->c[2]];
+
+               /* using z=a/bX, transform aX^2+bX+c into z^2+z+u (u=ac/b^2) */
+               u = a_pow(bch, l0+l2+2*(GF_N(bch)-l1));
+               /*
+                * let u = sum(li.a^i) i=0..m-1; then compute r = sum(li.xi):
+                * r^2+r = sum(li.(xi^2+xi)) = sum(li.(a^i+Tr(a^i).a^k)) =
+                * u + sum(li.Tr(a^i).a^k) = u+a^k.Tr(sum(li.a^i)) = u+a^k.Tr(u)
+                * i.e. r and r+1 are roots iff Tr(u)=0
+                */
+               r = 0;
+               v = u;
+               while (v) {
+                       i = deg(v);
+                       r ^= bch->xi_tab[i];
+                       v ^= (1 << i);
+               }
+               /* verify root */
+               if ((gf_sqr(bch, r)^r) == u) {
+                       /* reverse z=a/bX transformation and compute log(1/r) */
+                       roots[n++] = modulo(bch, 2*GF_N(bch)-l1-
+                                           bch->a_log_tab[r]+l2);
+                       roots[n++] = modulo(bch, 2*GF_N(bch)-l1-
+                                           bch->a_log_tab[r^1]+l2);
+               }
+       }
+       return n;
+}
+
+/*
+ * compute roots of a degree 3 polynomial over GF(2^m)
+ */
+static int find_poly_deg3_roots(struct bch_control *bch, struct gf_poly *poly,
+                               unsigned int *roots)
+{
+       int i, n = 0;
+       unsigned int a, b, c, a2, b2, c2, e3, tmp[4];
+
+       if (poly->c[0]) {
+               /* transform polynomial into monic X^3 + a2X^2 + b2X + c2 */
+               e3 = poly->c[3];
+               c2 = gf_div(bch, poly->c[0], e3);
+               b2 = gf_div(bch, poly->c[1], e3);
+               a2 = gf_div(bch, poly->c[2], e3);
+
+               /* (X+a2)(X^3+a2X^2+b2X+c2) = X^4+aX^2+bX+c (affine) */
+               c = gf_mul(bch, a2, c2);           /* c = a2c2      */
+               b = gf_mul(bch, a2, b2)^c2;        /* b = a2b2 + c2 */
+               a = gf_sqr(bch, a2)^b2;            /* a = a2^2 + b2 */
+
+               /* find the 4 roots of this affine polynomial */
+               if (find_affine4_roots(bch, a, b, c, tmp) == 4) {
+                       /* remove a2 from final list of roots */
+                       for (i = 0; i < 4; i++) {
+                               if (tmp[i] != a2)
+                                       roots[n++] = a_ilog(bch, tmp[i]);
+                       }
+               }
+       }
+       return n;
+}
+
+/*
+ * compute roots of a degree 4 polynomial over GF(2^m)
+ */
+static int find_poly_deg4_roots(struct bch_control *bch, struct gf_poly *poly,
+                               unsigned int *roots)
+{
+       int i, l, n = 0;
+       unsigned int a, b, c, d, e = 0, f, a2, b2, c2, e4;
+
+       if (poly->c[0] == 0)
+               return 0;
+
+       /* transform polynomial into monic X^4 + aX^3 + bX^2 + cX + d */
+       e4 = poly->c[4];
+       d = gf_div(bch, poly->c[0], e4);
+       c = gf_div(bch, poly->c[1], e4);
+       b = gf_div(bch, poly->c[2], e4);
+       a = gf_div(bch, poly->c[3], e4);
+
+       /* use Y=1/X transformation to get an affine polynomial */
+       if (a) {
+               /* first, eliminate cX by using z=X+e with ae^2+c=0 */
+               if (c) {
+                       /* compute e such that e^2 = c/a */
+                       f = gf_div(bch, c, a);
+                       l = a_log(bch, f);
+                       l += (l & 1) ? GF_N(bch) : 0;
+                       e = a_pow(bch, l/2);
+                       /*
+                        * use transformation z=X+e:
+                        * z^4+e^4 + a(z^3+ez^2+e^2z+e^3) + b(z^2+e^2) +cz+ce+d
+                        * z^4 + az^3 + (ae+b)z^2 + (ae^2+c)z+e^4+be^2+ae^3+ce+d
+                        * z^4 + az^3 + (ae+b)z^2 + e^4+be^2+d
+                        * z^4 + az^3 +     b'z^2 + d'
+                        */
+                       d = a_pow(bch, 2*l)^gf_mul(bch, b, f)^d;
+                       b = gf_mul(bch, a, e)^b;
+               }
+               /* now, use Y=1/X to get Y^4 + b/dY^2 + a/dY + 1/d */
+               if (d == 0)
+                       /* assume all roots have multiplicity 1 */
+                       return 0;
+
+               c2 = gf_inv(bch, d);
+               b2 = gf_div(bch, a, d);
+               a2 = gf_div(bch, b, d);
+       } else {
+               /* polynomial is already affine */
+               c2 = d;
+               b2 = c;
+               a2 = b;
+       }
+       /* find the 4 roots of this affine polynomial */
+       if (find_affine4_roots(bch, a2, b2, c2, roots) == 4) {
+               for (i = 0; i < 4; i++) {
+                       /* post-process roots (reverse transformations) */
+                       f = a ? gf_inv(bch, roots[i]) : roots[i];
+                       roots[i] = a_ilog(bch, f^e);
+               }
+               n = 4;
+       }
+       return n;
+}
+
+/*
+ * build monic, log-based representation of a polynomial
+ */
+static void gf_poly_logrep(struct bch_control *bch,
+                          const struct gf_poly *a, int *rep)
+{
+       int i, d = a->deg, l = GF_N(bch)-a_log(bch, a->c[a->deg]);
+
+       /* represent 0 values with -1; warning, rep[d] is not set to 1 */
+       for (i = 0; i < d; i++)
+               rep[i] = a->c[i] ? mod_s(bch, a_log(bch, a->c[i])+l) : -1;
+}
+
+/*
+ * compute polynomial Euclidean division remainder in GF(2^m)[X]
+ */
+static void gf_poly_mod(struct bch_control *bch, struct gf_poly *a,
+                       const struct gf_poly *b, int *rep)
+{
+       int la, p, m;
+       unsigned int i, j, *c = a->c;
+       const unsigned int d = b->deg;
+
+       if (a->deg < d)
+               return;
+
+       /* reuse or compute log representation of denominator */
+       if (!rep) {
+               rep = bch->cache;
+               gf_poly_logrep(bch, b, rep);
+       }
+
+       for (j = a->deg; j >= d; j--) {
+               if (c[j]) {
+                       la = a_log(bch, c[j]);
+                       p = j-d;
+                       for (i = 0; i < d; i++, p++) {
+                               m = rep[i];
+                               if (m >= 0)
+                                       c[p] ^= bch->a_pow_tab[mod_s(bch,
+                                                                    m+la)];
+                       }
+               }
+       }
+       a->deg = d-1;
+       while (!c[a->deg] && a->deg)
+               a->deg--;
+}
+
+/*
+ * compute polynomial Euclidean division quotient in GF(2^m)[X]
+ */
+static void gf_poly_div(struct bch_control *bch, struct gf_poly *a,
+                       const struct gf_poly *b, struct gf_poly *q)
+{
+       if (a->deg >= b->deg) {
+               q->deg = a->deg-b->deg;
+               /* compute a mod b (modifies a) */
+               gf_poly_mod(bch, a, b, NULL);
+               /* quotient is stored in upper part of polynomial a */
+               memcpy(q->c, &a->c[b->deg], (1+q->deg)*sizeof(unsigned int));
+       } else {
+               q->deg = 0;
+               q->c[0] = 0;
+       }
+}
+
+/*
+ * compute polynomial GCD (Greatest Common Divisor) in GF(2^m)[X]
+ */
+static struct gf_poly *gf_poly_gcd(struct bch_control *bch, struct gf_poly *a,
+                                  struct gf_poly *b)
+{
+       struct gf_poly *tmp;
+
+       dbg("gcd(%s,%s)=", gf_poly_str(a), gf_poly_str(b));
+
+       if (a->deg < b->deg) {
+               tmp = b;
+               b = a;
+               a = tmp;
+       }
+
+       while (b->deg > 0) {
+               gf_poly_mod(bch, a, b, NULL);
+               tmp = b;
+               b = a;
+               a = tmp;
+       }
+
+       dbg("%s\n", gf_poly_str(a));
+
+       return a;
+}
+
+/*
+ * Given a polynomial f and an integer k, compute Tr(a^kX) mod f
+ * This is used in Berlekamp Trace algorithm for splitting polynomials
+ */
+static void compute_trace_bk_mod(struct bch_control *bch, int k,
+                                const struct gf_poly *f, struct gf_poly *z,
+                                struct gf_poly *out)
+{
+       const int m = GF_M(bch);
+       int i, j;
+
+       /* z contains z^2j mod f */
+       z->deg = 1;
+       z->c[0] = 0;
+       z->c[1] = bch->a_pow_tab[k];
+
+       out->deg = 0;
+       memset(out, 0, GF_POLY_SZ(f->deg));
+
+       /* compute f log representation only once */
+       gf_poly_logrep(bch, f, bch->cache);
+
+       for (i = 0; i < m; i++) {
+               /* add a^(k*2^i)(z^(2^i) mod f) and compute (z^(2^i) mod f)^2 */
+               for (j = z->deg; j >= 0; j--) {
+                       out->c[j] ^= z->c[j];
+                       z->c[2*j] = gf_sqr(bch, z->c[j]);
+                       z->c[2*j+1] = 0;
+               }
+               if (z->deg > out->deg)
+                       out->deg = z->deg;
+
+               if (i < m-1) {
+                       z->deg *= 2;
+                       /* z^(2(i+1)) mod f = (z^(2^i) mod f)^2 mod f */
+                       gf_poly_mod(bch, z, f, bch->cache);
+               }
+       }
+       while (!out->c[out->deg] && out->deg)
+               out->deg--;
+
+       dbg("Tr(a^%d.X) mod f = %s\n", k, gf_poly_str(out));
+}
+
+/*
+ * factor a polynomial using Berlekamp Trace algorithm (BTA)
+ */
+static void factor_polynomial(struct bch_control *bch, int k, struct gf_poly *f,
+                             struct gf_poly **g, struct gf_poly **h)
+{
+       struct gf_poly *f2 = bch->poly_2t[0];
+       struct gf_poly *q  = bch->poly_2t[1];
+       struct gf_poly *tk = bch->poly_2t[2];
+       struct gf_poly *z  = bch->poly_2t[3];
+       struct gf_poly *gcd;
+
+       dbg("factoring %s...\n", gf_poly_str(f));
+
+       *g = f;
+       *h = NULL;
+
+       /* tk = Tr(a^k.X) mod f */
+       compute_trace_bk_mod(bch, k, f, z, tk);
+
+       if (tk->deg > 0) {
+               /* compute g = gcd(f, tk) (destructive operation) */
+               gf_poly_copy(f2, f);
+               gcd = gf_poly_gcd(bch, f2, tk);
+               if (gcd->deg < f->deg) {
+                       /* compute h=f/gcd(f,tk); this will modify f and q */
+                       gf_poly_div(bch, f, gcd, q);
+                       /* store g and h in-place (clobbering f) */
+                       *h = &((struct gf_poly_deg1 *)f)[gcd->deg].poly;
+                       gf_poly_copy(*g, gcd);
+                       gf_poly_copy(*h, q);
+               }
+       }
+}
+
+/*
+ * find roots of a polynomial, using BTZ algorithm; see the beginning of this
+ * file for details
+ */
+static int find_poly_roots(struct bch_control *bch, unsigned int k,
+                          struct gf_poly *poly, unsigned int *roots)
+{
+       int cnt;
+       struct gf_poly *f1, *f2;
+
+       switch (poly->deg) {
+               /* handle low degree polynomials with ad hoc techniques */
+       case 1:
+               cnt = find_poly_deg1_roots(bch, poly, roots);
+               break;
+       case 2:
+               cnt = find_poly_deg2_roots(bch, poly, roots);
+               break;
+       case 3:
+               cnt = find_poly_deg3_roots(bch, poly, roots);
+               break;
+       case 4:
+               cnt = find_poly_deg4_roots(bch, poly, roots);
+               break;
+       default:
+               /* factor polynomial using Berlekamp Trace Algorithm (BTA) */
+               cnt = 0;
+               if (poly->deg && (k <= GF_M(bch))) {
+                       factor_polynomial(bch, k, poly, &f1, &f2);
+                       if (f1)
+                               cnt += find_poly_roots(bch, k+1, f1, roots);
+                       if (f2)
+                               cnt += find_poly_roots(bch, k+1, f2, roots+cnt);
+               }
+               break;
+       }
+       return cnt;
+}
+
+#if defined(USE_CHIEN_SEARCH)
+/*
+ * exhaustive root search (Chien) implementation - not used, included only for
+ * reference/comparison tests
+ */
+static int chien_search(struct bch_control *bch, unsigned int len,
+                       struct gf_poly *p, unsigned int *roots)
+{
+       int m;
+       unsigned int i, j, syn, syn0, count = 0;
+       const unsigned int k = 8*len+bch->ecc_bits;
+
+       /* use a log-based representation of polynomial */
+       gf_poly_logrep(bch, p, bch->cache);
+       bch->cache[p->deg] = 0;
+       syn0 = gf_div(bch, p->c[0], p->c[p->deg]);
+
+       for (i = GF_N(bch)-k+1; i <= GF_N(bch); i++) {
+               /* compute elp(a^i) */
+               for (j = 1, syn = syn0; j <= p->deg; j++) {
+                       m = bch->cache[j];
+                       if (m >= 0)
+                               syn ^= a_pow(bch, m+j*i);
+               }
+               if (syn == 0) {
+                       roots[count++] = GF_N(bch)-i;
+                       if (count == p->deg)
+                               break;
+               }
+       }
+       return (count == p->deg) ? count : 0;
+}
+#define find_poly_roots(_p, _k, _elp, _loc) chien_search(_p, len, _elp, _loc)
+#endif /* USE_CHIEN_SEARCH */
+
+/**
+ * decode_bch - decode received codeword and find bit error locations
+ * @bch:      BCH control structure
+ * @data:     received data, ignored if @calc_ecc is provided
+ * @len:      data length in bytes, must always be provided
+ * @recv_ecc: received ecc, if NULL then assume it was XORed in @calc_ecc
+ * @calc_ecc: calculated ecc, if NULL then calc_ecc is computed from @data
+ * @syn:      hw computed syndrome data (if NULL, syndrome is calculated)
+ * @errloc:   output array of error locations
+ *
+ * Returns:
+ *  The number of errors found, or -EBADMSG if decoding failed, or -EINVAL if
+ *  invalid parameters were provided
+ *
+ * Depending on the available hw BCH support and the need to compute @calc_ecc
+ * separately (using encode_bch()), this function should be called with one of
+ * the following parameter configurations -
+ *
+ * by providing @data and @recv_ecc only:
+ *   decode_bch(@bch, @data, @len, @recv_ecc, NULL, NULL, @errloc)
+ *
+ * by providing @recv_ecc and @calc_ecc:
+ *   decode_bch(@bch, NULL, @len, @recv_ecc, @calc_ecc, NULL, @errloc)
+ *
+ * by providing ecc = recv_ecc XOR calc_ecc:
+ *   decode_bch(@bch, NULL, @len, NULL, ecc, NULL, @errloc)
+ *
+ * by providing syndrome results @syn:
+ *   decode_bch(@bch, NULL, @len, NULL, NULL, @syn, @errloc)
+ *
+ * Once decode_bch() has successfully returned with a positive value, error
+ * locations returned in array @errloc should be interpreted as follows -
+ *
+ * if (errloc[n] >= 8*len), then n-th error is located in ecc (no need for
+ * data correction)
+ *
+ * if (errloc[n] < 8*len), then n-th error is located in data and can be
+ * corrected with statement data[errloc[n]/8] ^= 1 << (errloc[n] % 8);
+ *
+ * Note that this function does not perform any data correction by itself, it
+ * merely indicates error locations.
+ */
+int decode_bch(struct bch_control *bch, const uint8_t *data, unsigned int len,
+              const uint8_t *recv_ecc, const uint8_t *calc_ecc,
+              const unsigned int *syn, unsigned int *errloc)
+{
+       const unsigned int ecc_words = BCH_ECC_WORDS(bch);
+       unsigned int nbits;
+       int i, err, nroots;
+       uint32_t sum;
+
+       /* sanity check: make sure data length can be handled */
+       if (8*len > (bch->n-bch->ecc_bits))
+               return -EINVAL;
+
+       /* if caller does not provide syndromes, compute them */
+       if (!syn) {
+               if (!calc_ecc) {
+                       /* compute received data ecc into an internal buffer */
+                       if (!data || !recv_ecc)
+                               return -EINVAL;
+                       encode_bch(bch, data, len, NULL);
+               } else {
+                       /* load provided calculated ecc */
+                       load_ecc8(bch, bch->ecc_buf, calc_ecc);
+               }
+               /* load received ecc or assume it was XORed in calc_ecc */
+               if (recv_ecc) {
+                       load_ecc8(bch, bch->ecc_buf2, recv_ecc);
+                       /* XOR received and calculated ecc */
+                       for (i = 0, sum = 0; i < (int)ecc_words; i++) {
+                               bch->ecc_buf[i] ^= bch->ecc_buf2[i];
+                               sum |= bch->ecc_buf[i];
+                       }
+                       if (!sum)
+                               /* no error found */
+                               return 0;
+               }
+               compute_syndromes(bch, bch->ecc_buf, bch->syn);
+               syn = bch->syn;
+       }
+
+       err = compute_error_locator_polynomial(bch, syn);
+       if (err > 0) {
+               nroots = find_poly_roots(bch, 1, bch->elp, errloc);
+               if (err != nroots)
+                       err = -1;
+       }
+       if (err > 0) {
+               /* post-process raw error locations for easier correction */
+               nbits = (len*8)+bch->ecc_bits;
+               for (i = 0; i < err; i++) {
+                       if (errloc[i] >= nbits) {
+                               err = -1;
+                               break;
+                       }
+                       errloc[i] = nbits-1-errloc[i];
+                       errloc[i] = (errloc[i] & ~7)|(7-(errloc[i] & 7));
+               }
+       }
+       return (err >= 0) ? err : -EBADMSG;
+}
+
+/*
+ * generate Galois field lookup tables
+ */
+static int build_gf_tables(struct bch_control *bch, unsigned int poly)
+{
+       unsigned int i, x = 1;
+       const unsigned int k = 1 << deg(poly);
+
+       /* primitive polynomial must be of degree m */
+       if (k != (1u << GF_M(bch)))
+               return -1;
+
+       for (i = 0; i < GF_N(bch); i++) {
+               bch->a_pow_tab[i] = x;
+               bch->a_log_tab[x] = i;
+               if (i && (x == 1))
+                       /* polynomial is not primitive (a^i=1 with 0<i<2^m-1) */
+                       return -1;
+               x <<= 1;
+               if (x & k)
+                       x ^= poly;
+       }
+       bch->a_pow_tab[GF_N(bch)] = 1;
+       bch->a_log_tab[0] = 0;
+
+       return 0;
+}
+
+/*
+ * compute generator polynomial remainder tables for fast encoding
+ */
+static void build_mod8_tables(struct bch_control *bch, const uint32_t *g)
+{
+       int i, j, b, d;
+       uint32_t data, hi, lo, *tab;
+       const int l = BCH_ECC_WORDS(bch);
+       const int plen = DIV_ROUND_UP(bch->ecc_bits+1, 32);
+       const int ecclen = DIV_ROUND_UP(bch->ecc_bits, 32);
+
+       memset(bch->mod8_tab, 0, 4*256*l*sizeof(*bch->mod8_tab));
+
+       for (i = 0; i < 256; i++) {
+               /* p(X)=i is a small polynomial of weight <= 8 */
+               for (b = 0; b < 4; b++) {
+                       /* we want to compute (p(X).X^(8*b+deg(g))) mod g(X) */
+                       tab = bch->mod8_tab + (b*256+i)*l;
+                       data = i << (8*b);
+                       while (data) {
+                               d = deg(data);
+                               /* subtract X^d.g(X) from p(X).X^(8*b+deg(g)) */
+                               data ^= g[0] >> (31-d);
+                               for (j = 0; j < ecclen; j++) {
+                                       hi = (d < 31) ? g[j] << (d+1) : 0;
+                                       lo = (j+1 < plen) ?
+                                               g[j+1] >> (31-d) : 0;
+                                       tab[j] ^= hi|lo;
+                               }
+                       }
+               }
+       }
+}
+
+/*
+ * build a base for factoring degree 2 polynomials
+ */
+static int build_deg2_base(struct bch_control *bch)
+{
+       const int m = GF_M(bch);
+       int i, j, r;
+       unsigned int sum, x, y, remaining, ak = 0, xi[m];
+
+       /* find k s.t. Tr(a^k) = 1 and 0 <= k < m */
+       for (i = 0; i < m; i++) {
+               for (j = 0, sum = 0; j < m; j++)
+                       sum ^= a_pow(bch, i*(1 << j));
+
+               if (sum) {
+                       ak = bch->a_pow_tab[i];
+                       break;
+               }
+       }
+       /* find xi, i=0..m-1 such that xi^2+xi = a^i+Tr(a^i).a^k */
+       remaining = m;
+       memset(xi, 0, sizeof(xi));
+
+       for (x = 0; (x <= GF_N(bch)) && remaining; x++) {
+               y = gf_sqr(bch, x)^x;
+               for (i = 0; i < 2; i++) {
+                       r = a_log(bch, y);
+                       if (y && (r < m) && !xi[r]) {
+                               bch->xi_tab[r] = x;
+                               xi[r] = 1;
+                               remaining--;
+                               dbg("x%d = %x\n", r, x);
+                               break;
+                       }
+                       y ^= ak;
+               }
+       }
+       /* should not happen but check anyway */
+       return remaining ? -1 : 0;
+}
+
+static void *bch_alloc(size_t size, int *err)
+{
+       void *ptr;
+
+       ptr = kmalloc(size, GFP_KERNEL);
+       if (ptr == NULL)
+               *err = 1;
+       return ptr;
+}
+
+/*
+ * compute generator polynomial for given (m,t) parameters.
+ */
+static uint32_t *compute_generator_polynomial(struct bch_control *bch)
+{
+       const unsigned int m = GF_M(bch);
+       const unsigned int t = GF_T(bch);
+       int n, err = 0;
+       unsigned int i, j, nbits, r, word, *roots;
+       struct gf_poly *g;
+       uint32_t *genpoly;
+
+       g = bch_alloc(GF_POLY_SZ(m*t), &err);
+       roots = bch_alloc((bch->n+1)*sizeof(*roots), &err);
+       genpoly = bch_alloc(DIV_ROUND_UP(m*t+1, 32)*sizeof(*genpoly), &err);
+
+       if (err) {
+               kfree(genpoly);
+               genpoly = NULL;
+               goto finish;
+       }
+
+       /* enumerate all roots of g(X) */
+       memset(roots , 0, (bch->n+1)*sizeof(*roots));
+       for (i = 0; i < t; i++) {
+               for (j = 0, r = 2*i+1; j < m; j++) {
+                       roots[r] = 1;
+                       r = mod_s(bch, 2*r);
+               }
+       }
+       /* build generator polynomial g(X) */
+       g->deg = 0;
+       g->c[0] = 1;
+       for (i = 0; i < GF_N(bch); i++) {
+               if (roots[i]) {
+                       /* multiply g(X) by (X+root) */
+                       r = bch->a_pow_tab[i];
+                       g->c[g->deg+1] = 1;
+                       for (j = g->deg; j > 0; j--)
+                               g->c[j] = gf_mul(bch, g->c[j], r)^g->c[j-1];
+
+                       g->c[0] = gf_mul(bch, g->c[0], r);
+                       g->deg++;
+               }
+       }
+       /* store left-justified binary representation of g(X) */
+       n = g->deg+1;
+       i = 0;
+
+       while (n > 0) {
+               nbits = (n > 32) ? 32 : n;
+               for (j = 0, word = 0; j < nbits; j++) {
+                       if (g->c[n-1-j])
+                               word |= 1u << (31-j);
+               }
+               genpoly[i++] = word;
+               n -= nbits;
+       }
+       bch->ecc_bits = g->deg;
+
+finish:
+       kfree(g);
+       kfree(roots);
+
+       return genpoly;
+}
+
+/**
+ * init_bch - initialize a BCH encoder/decoder
+ * @m:          Galois field order, should be in the range 5-15
+ * @t:          maximum error correction capability, in bits
+ * @prim_poly:  user-provided primitive polynomial (or 0 to use default)
+ *
+ * Returns:
+ *  a newly allocated BCH control structure if successful, NULL otherwise
+ *
+ * This initialization can take some time, as lookup tables are built for fast
+ * encoding/decoding; make sure not to call this function from a time critical
+ * path. Usually, init_bch() should be called on module/driver init and
+ * free_bch() should be called to release memory on exit.
+ *
+ * You may provide your own primitive polynomial of degree @m in argument
+ * @prim_poly, or let init_bch() use its default polynomial.
+ *
+ * Once init_bch() has successfully returned a pointer to a newly allocated
+ * BCH control structure, ecc length in bytes is given by member @ecc_bytes of
+ * the structure.
+ */
+struct bch_control *init_bch(int m, int t, unsigned int prim_poly)
+{
+       int err = 0;
+       unsigned int i, words;
+       uint32_t *genpoly;
+       struct bch_control *bch = NULL;
+
+       const int min_m = 5;
+       const int max_m = 15;
+
+       /* default primitive polynomials */
+       static const unsigned int prim_poly_tab[] = {
+               0x25, 0x43, 0x83, 0x11d, 0x211, 0x409, 0x805, 0x1053, 0x201b,
+               0x402b, 0x8003,
+       };
+
+#if defined(CONFIG_BCH_CONST_PARAMS)
+       if ((m != (CONFIG_BCH_CONST_M)) || (t != (CONFIG_BCH_CONST_T))) {
+               printk(KERN_ERR "bch encoder/decoder was configured to support "
+                      "parameters m=%d, t=%d only!\n",
+                      CONFIG_BCH_CONST_M, CONFIG_BCH_CONST_T);
+               goto fail;
+       }
+#endif
+       if ((m < min_m) || (m > max_m))
+               /*
+                * values of m greater than 15 are not currently supported;
+                * supporting m > 15 would require changing table base type
+                * (uint16_t) and a small patch in matrix transposition
+                */
+               goto fail;
+
+       /* sanity checks */
+       if ((t < 1) || (m*t >= ((1 << m)-1)))
+               /* invalid t value */
+               goto fail;
+
+       /* select a primitive polynomial for generating GF(2^m) */
+       if (prim_poly == 0)
+               prim_poly = prim_poly_tab[m-min_m];
+
+       bch = kzalloc(sizeof(*bch), GFP_KERNEL);
+       if (bch == NULL)
+               goto fail;
+
+       bch->m = m;
+       bch->t = t;
+       bch->n = (1 << m)-1;
+       words  = DIV_ROUND_UP(m*t, 32);
+       bch->ecc_bytes = DIV_ROUND_UP(m*t, 8);
+       bch->a_pow_tab = bch_alloc((1+bch->n)*sizeof(*bch->a_pow_tab), &err);
+       bch->a_log_tab = bch_alloc((1+bch->n)*sizeof(*bch->a_log_tab), &err);
+       bch->mod8_tab  = bch_alloc(words*1024*sizeof(*bch->mod8_tab), &err);
+       bch->ecc_buf   = bch_alloc(words*sizeof(*bch->ecc_buf), &err);
+       bch->ecc_buf2  = bch_alloc(words*sizeof(*bch->ecc_buf2), &err);
+       bch->xi_tab    = bch_alloc(m*sizeof(*bch->xi_tab), &err);
+       bch->syn       = bch_alloc(2*t*sizeof(*bch->syn), &err);
+       bch->cache     = bch_alloc(2*t*sizeof(*bch->cache), &err);
+       bch->elp       = bch_alloc((t+1)*sizeof(struct gf_poly_deg1), &err);
+
+       for (i = 0; i < ARRAY_SIZE(bch->poly_2t); i++)
+               bch->poly_2t[i] = bch_alloc(GF_POLY_SZ(2*t), &err);
+
+       if (err)
+               goto fail;
+
+       err = build_gf_tables(bch, prim_poly);
+       if (err)
+               goto fail;
+
+       /* use generator polynomial for computing encoding tables */
+       genpoly = compute_generator_polynomial(bch);
+       if (genpoly == NULL)
+               goto fail;
+
+       build_mod8_tables(bch, genpoly);
+       kfree(genpoly);
+
+       err = build_deg2_base(bch);
+       if (err)
+               goto fail;
+
+       return bch;
+
+fail:
+       free_bch(bch);
+       return NULL;
+}
+
+/**
+ *  free_bch - free the BCH control structure
+ *  @bch:    BCH control structure to release
+ */
+void free_bch(struct bch_control *bch)
+{
+       unsigned int i;
+
+       if (bch) {
+               kfree(bch->a_pow_tab);
+               kfree(bch->a_log_tab);
+               kfree(bch->mod8_tab);
+               kfree(bch->ecc_buf);
+               kfree(bch->ecc_buf2);
+               kfree(bch->xi_tab);
+               kfree(bch->syn);
+               kfree(bch->cache);
+               kfree(bch->elp);
+
+               for (i = 0; i < ARRAY_SIZE(bch->poly_2t); i++)
+                       kfree(bch->poly_2t[i]);
+
+               kfree(bch);
+       }
+}
index 2c4f0ec9a11f8e7219b9c5d40659616bf4bc6aaf..c3ad055e2caeca752ba4238f65578edb0abfb814 100644 (file)
@@ -214,6 +214,45 @@ char * strrchr(const char * s, int c)
 }
 #endif
 
+
+/**
+ * skip_spaces - Removes leading whitespace from @str.
+ * @str: The string to be stripped.
+ *
+ * Returns a pointer to the first non-whitespace character in @str.
+ */
+char *skip_spaces(const char *str)
+{
+       while (isspace(*str))
+               ++str;
+       return (char *)str;
+}
+
+/**
+ * strim - Removes leading and trailing whitespace from @s.
+ * @s: The string to be stripped.
+ *
+ * Note that the first trailing whitespace is replaced with a %NUL-terminator
+ * in the given string @s. Returns a pointer to the first non-whitespace
+ * character in @s.
+ */
+char *strim(char *s)
+{
+       size_t size;
+       char *end;
+
+       s = skip_spaces(s);
+       size = strlen(s);
+       if (!size)
+               return s;
+
+       end = s + size - 1;
+       while (end >= s && isspace(*end))
+               end--;
+       *(end + 1) = '\0';
+
+       return s;
+}
 #ifndef __HAVE_ARCH_STRLEN
 /**
  * strlen - Find the length of a string
index 2326962b20fca42c8f432a683ae01a7b2ed3772e..bfaabd3199c68321b05994c32feacbc0c6f6ee1c 100644 (file)
 
 static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS;
 
+#define ECCSTEPS       (CONFIG_SYS_NAND_PAGE_SIZE / \
+                                       CONFIG_SYS_NAND_ECCSIZE)
+#define ECCTOTAL       (ECCSTEPS * CONFIG_SYS_NAND_ECCBYTES)
+
+
 #if (CONFIG_SYS_NAND_PAGE_SIZE <= 512)
 /*
  * NAND command for small page NAND devices (512)
@@ -139,29 +144,21 @@ static int nand_is_bad_block(struct mtd_info *mtd, int block)
 static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst)
 {
        struct nand_chip *this = mtd->priv;
-       u_char *ecc_calc;
-       u_char *ecc_code;
-       u_char *oob_data;
+       u_char ecc_calc[ECCTOTAL];
+       u_char ecc_code[ECCTOTAL];
+       u_char oob_data[CONFIG_SYS_NAND_OOBSIZE];
        int i;
        int eccsize = CONFIG_SYS_NAND_ECCSIZE;
        int eccbytes = CONFIG_SYS_NAND_ECCBYTES;
-       int eccsteps = CONFIG_SYS_NAND_ECCSTEPS;
+       int eccsteps = ECCSTEPS;
        uint8_t *p = dst;
 
-       /*
-        * No malloc available for now, just use some temporary locations
-        * in SDRAM
-        */
-       ecc_calc = (u_char *)(CONFIG_SYS_SDRAM_BASE + 0x10000);
-       ecc_code = ecc_calc + 0x100;
-       oob_data = ecc_calc + 0x200;
-
        nand_command(mtd, block, page, 0, NAND_CMD_READOOB);
        this->read_buf(mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE);
        nand_command(mtd, block, page, 0, NAND_CMD_READ0);
 
        /* Pick the ECC bytes out of the oob data */
-       for (i = 0; i < CONFIG_SYS_NAND_ECCTOTAL; i++)
+       for (i = 0; i < ECCTOTAL; i++)
                ecc_code[i] = oob_data[nand_ecc_pos[i]];
 
 
@@ -178,24 +175,17 @@ static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst)
 static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst)
 {
        struct nand_chip *this = mtd->priv;
-       u_char *ecc_calc;
-       u_char *ecc_code;
-       u_char *oob_data;
+       u_char ecc_calc[ECCTOTAL];
+       u_char ecc_code[ECCTOTAL];
+       u_char oob_data[CONFIG_SYS_NAND_OOBSIZE];
        int i;
        int eccsize = CONFIG_SYS_NAND_ECCSIZE;
        int eccbytes = CONFIG_SYS_NAND_ECCBYTES;
-       int eccsteps = CONFIG_SYS_NAND_ECCSTEPS;
+       int eccsteps = ECCSTEPS;
        uint8_t *p = dst;
 
        nand_command(mtd, block, page, 0, NAND_CMD_READ0);
 
-       /* No malloc available for now, just use some temporary locations
-        * in SDRAM
-        */
-       ecc_calc = (u_char *)(CONFIG_SYS_SDRAM_BASE + 0x10000);
-       ecc_code = ecc_calc + 0x100;
-       oob_data = ecc_calc + 0x200;
-
        for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
                this->ecc.hwctl(mtd, NAND_ECC_READ);
                this->read_buf(mtd, p, eccsize);
@@ -204,10 +194,10 @@ static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst)
        this->read_buf(mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE);
 
        /* Pick the ECC bytes out of the oob data */
-       for (i = 0; i < CONFIG_SYS_NAND_ECCTOTAL; i++)
+       for (i = 0; i < ECCTOTAL; i++)
                ecc_code[i] = oob_data[nand_ecc_pos[i]];
 
-       eccsteps = CONFIG_SYS_NAND_ECCSTEPS;
+       eccsteps = ECCSTEPS;
        p = dst;
 
        for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {