iARM:LPC32XX: Updated NAND driver with inverted ECC linux-2.6.34-lpc32x0_v1.06a
authorKevin Wells <wellsk40@gmail.com>
Wed, 22 Dec 2010 20:56:06 +0000 (12:56 -0800)
committerKevin Wells <wellsk40@gmail.com>
Wed, 22 Dec 2010 20:56:06 +0000 (12:56 -0800)
drivers/mtd/nand/lpc32xx_nand.c

index 52f0f61..033bc03 100644 (file)
 
 #define NAND_ERASED_BLOCK_ECC_VALUE    0xFFFFFFFF
 
+/*
+ * NAND ECC Layout for Small page flashes
+ * NOTE: For large page devices, default layout is used
+ */
 static struct nand_ecclayout lpc32xx_nand_oob_16 = {
-        .eccbytes = 8,
-        .eccpos = {8, 9, 10, 11, 12, 13, 14, 15},
-        .oobfree = {
-                {.offset = 0,
-                 . length = 5},
-                {.offset = 6,
-                 . length = 2}}
-};
-
-static struct nand_ecclayout lpc32xx_nand_oob_64 = {
-        .eccbytes = 32,
-        .eccpos = { 8, 9, 10, 11, 12, 13, 14, 15,
-                   24, 25, 26, 27, 28, 29, 30, 31,
-                   40, 41, 42, 43, 44, 45, 46, 47,
-                   56, 57, 58, 59, 60, 61, 62, 63},
-        .oobfree = {
-                {.offset = 2,
-                 . length = 6},
-                {.offset = 16,
-                 . length = 8},
-                {.offset = 32,
-                 . length = 8},
-                {.offset = 48,
-                 . length = 8}}
+       .eccbytes = 6,
+       .eccpos = {10, 11, 12, 13, 14, 15},
+       .oobfree = {
+               {.offset = 0,
+                . length = 4},
+               {.offset = 6,
+                . length = 4}}
 };
 
 struct lpc32xx_nand_host {
@@ -100,7 +87,7 @@ struct lpc32xx_nand_host {
         * Virtual addresses of ECC buffer,DMA data buffers,OOB data buffer
         */
        uint8_t *oob_buf;
-       uint8_t *ecc_calc_buf;
+       uint32_t *ecc_calc_buf;
        uint8_t * dma_buf;
        /* Physical address of DMA base address */
        dma_addr_t io_base_phy;
@@ -111,20 +98,6 @@ struct lpc32xx_nand_host {
 const char *part_probes[] = { "cmdlinepart", NULL };
 #endif
 
-static uint8_t nand_slc_bit_cnt16(uint16_t ch)
-{
-        ch = (ch & 0x5555) + ((ch & ~0x5555) >> 1);
-        ch = (ch & 0x3333) + ((ch & ~0x3333) >> 2);
-        ch = (ch & 0x0F0F) + ((ch & ~0x0F0F) >> 4);
-        return (ch + (ch >> 8)) & 0xFF;
-}
-
-static uint8_t bit_cnt32(uint32_t val)
-{
-        return nand_slc_bit_cnt16(val & 0xFFFF) +
-                nand_slc_bit_cnt16(val >> 16);
-}
-
 static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
 {
        u32 clkrate, tmp;
@@ -215,6 +188,9 @@ static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host)
                host->ncfg->enable_write_prot(0);
 }
 
+/*
+ * Read a single byte from NAND device
+ */
 static uint8_t lpc32xx_read_byte(struct mtd_info *mtd)
 {
        struct nand_chip *nand_chip = mtd->priv;
@@ -223,16 +199,9 @@ static uint8_t lpc32xx_read_byte(struct mtd_info *mtd)
        return (uint8_t) __raw_readl(SLC_DATA(host->io_base));
 }
 
-static void lpc32xx_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-       struct nand_chip *nand_chip = mtd->priv;
-       struct lpc32xx_nand_host *host = nand_chip->priv;
-       int i;
-
-       for (i = 0; i < len; i++)
-               buf[i] = (uint8_t) __raw_readl(SLC_DATA(host->io_base));
-}
-
+/*
+ * Verify written data for vaildity
+ */
 static int lpc32xx_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
        struct nand_chip *nand_chip = mtd->priv;
@@ -247,16 +216,6 @@ static int lpc32xx_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
        return 0;
 }
 
-static void lpc32xx_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
-       struct nand_chip *nand_chip = mtd->priv;
-       struct lpc32xx_nand_host *host = nand_chip->priv;
-       int i;
-
-       for (i = 0; i < len; i++)
-               __raw_writel((u32) buf[i], SLC_DATA(host->io_base));
-}
-
 /*
  * DMA ISR - occurs when DMA transfer complete.
  */
@@ -280,11 +239,11 @@ static int lpc32xx_nand_dma_setup(struct lpc32xx_nand_host *host, int num_entrie
 
        host->dmach = DMA_CH_SLCNAND;
        host->dmacfg.ch = DMA_CH_SLCNAND;
-       
+
        /*
         * All the DMA configuration parameters will
         * be overwritten in lpc32xx_nand_dma_configure().
-        */     
+        */
        host->dmacfg.tc_inten = 1;
        host->dmacfg.err_inten = 1;
        host->dmacfg.src_size = 4;
@@ -305,7 +264,7 @@ static int lpc32xx_nand_dma_setup(struct lpc32xx_nand_host *host, int num_entrie
                goto dma_ch_err;
        }
 
-       /* 
+       /*
         * Allocate Linked list of total DMA Descriptors.
         * For Large Block: 17 descriptors = ((16 Data and ECC Read) + 1 Spare Area)
         * For Small Block: 5 descriptors = ((4 Data and ECC Read) + 1 Spare Area)
@@ -337,9 +296,8 @@ static void lpc32xx_nand_dma_configure(struct mtd_info *mtd,
        uint32_t page_divider = (size == NAND_LARGE_BLOCK_PAGE_SIZE) ? 8: 2;
        uint32_t dmasrc, dmadst, ctrl, ecc_ctrl, oob_ctrl;
        int i;
-       uint32_t *eccpos = chip->ecc.layout->eccpos;
 
-       /* 
+       /*
         * CTRL descriptor entry for reading ECC
         * Copy Multiple times to sync DMA with Flash Controller
         */
@@ -360,21 +318,21 @@ static void lpc32xx_nand_dma_configure(struct mtd_info *mtd,
 
        /* CTRL descriptor entry for reading/writing Spare Area */
        oob_ctrl =  ((mtd->oobsize / 4) |
-                        DMAC_CHAN_SRC_BURST_4 |
-                        DMAC_CHAN_DEST_BURST_4 |
-                        DMAC_CHAN_SRC_WIDTH_32 |
-                        DMAC_CHAN_DEST_WIDTH_32 |
-                        DMAC_CHAN_DEST_AHB1);
-
-        if (read) {
-                dmasrc = (uint32_t) SLC_DMA_DATA(host->io_base_phy);
-                dmadst = (uint32_t) (buffer);
-                ctrl |= DMAC_CHAN_DEST_AUTOINC;
-        } else {
-                dmadst = (uint32_t) SLC_DMA_DATA(host->io_base_phy);
-                dmasrc = (uint32_t) (buffer);
-                ctrl |= DMAC_CHAN_SRC_AUTOINC;
-        }
+                       DMAC_CHAN_SRC_BURST_4 |
+                       DMAC_CHAN_DEST_BURST_4 |
+                       DMAC_CHAN_SRC_WIDTH_32 |
+                       DMAC_CHAN_DEST_WIDTH_32 |
+                       DMAC_CHAN_DEST_AHB1);
+
+       if (read) {
+               dmasrc = (uint32_t) SLC_DMA_DATA(host->io_base_phy);
+               dmadst = (uint32_t) (buffer);
+               ctrl |= DMAC_CHAN_DEST_AUTOINC;
+       } else {
+               dmadst = (uint32_t) SLC_DMA_DATA(host->io_base_phy);
+               dmasrc = (uint32_t) (buffer);
+               ctrl |= DMAC_CHAN_SRC_AUTOINC;
+       }
 
        /*
         * Write Operation Sequence for Small Block NAND
@@ -403,37 +361,60 @@ static void lpc32xx_nand_dma_configure(struct mtd_info *mtd,
         * Read Operation Sequence for Large Block NAND
         * ----------------------------------------------------------
         * 1. Steps(1-4) of Read Operations repeate for four times
-        * which generates 16 DMA descriptors to X'fer 2048 byets of 
+        * which generates 16 DMA descriptors to X'fer 2048 byets of
         * data & 32 bytes of ECC data.
         * 2. X'fer 64 bytes of Spare area from Flash to Memory.
         */
-        for (i = 0; i < size/256; i++) {
+       for (i = 0; i < size/256; i++) {
                lpc32xx_dma_queue_llist(host->dmach,
-                               (void *)(read ?(dmasrc) :(dmasrc + (i*256))), 
+                               (void *)(read ?(dmasrc) :(dmasrc + (i*256))),
                                (void *)(read ?(dmadst + (i*256)) :dmadst),
                                -1, ctrl);
                lpc32xx_dma_queue_llist(host->dmach,
                                (void *)SLC_ECC(host->io_base_phy),
-                               (void *)(read ?((uint32_t) host->ecc_calc_buf_phy + (i*4)):
-                                ((uint32_t) host->oob_buf_phy + eccpos[i*4])),
-                               -1, ecc_ctrl);
-        }
-
-        if (read) {
-                dmasrc = (uint32_t) (uint32_t) SLC_DMA_DATA(host->io_base_phy);
-                dmadst = (uint32_t) (host->oob_buf_phy);
-                oob_ctrl |= DMAC_CHAN_DEST_AUTOINC;
-        } else {
-                dmadst = (uint32_t) (uint32_t) SLC_DMA_DATA(host->io_base_phy);
-                dmasrc = (uint32_t) (host->oob_buf_phy);
-                oob_ctrl |= DMAC_CHAN_SRC_AUTOINC;
-        }
-
-        /* Read/ Write Spare Area Data To/From Flash */
+                               (void *)((uint32_t) host->ecc_calc_buf_phy + (i*4)),
+                               -1, ecc_ctrl | (i+1 == size/256 ? DMAC_CHAN_INT_TC_EN : 0));
+       }
+
+       if (i) {
+               /* Data only transfer */
+               return ;
+       }
+
+       /* OOB only transfer */
+       if (read) {
+               dmasrc = (uint32_t) SLC_DMA_DATA(host->io_base_phy);
+               dmadst = (uint32_t) (buffer);
+               oob_ctrl |= DMAC_CHAN_DEST_AUTOINC;
+       } else {
+               dmadst = (uint32_t) SLC_DMA_DATA(host->io_base_phy);
+               dmasrc = (uint32_t) (buffer);
+               oob_ctrl |= DMAC_CHAN_SRC_AUTOINC;
+       }
+
+       /* Read/ Write Spare Area Data To/From Flash */
        lpc32xx_dma_queue_llist(host->dmach, (void *)dmasrc, (void *)dmadst, -1,
                        oob_ctrl | DMAC_CHAN_INT_TC_EN);
 }
 
+/*
+ * Returns true if a transfer is pending
+ */
+static int is_xfer_pending(struct mtd_info *mtd)
+{
+       struct nand_chip *this = mtd->priv;
+       struct lpc32xx_nand_host *host = this->priv;
+       return (__raw_readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO) |
+               __raw_readl(SLC_TC(host->io_base));
+}
+
+/*
+ * Routine that will perform the actual data transfers
+ * from/to the NAND device
+ * When @read is 0 it is a write transfer (data transfered from
+ * mem to NAND), if not 0 then the transfer is a read transfer
+ * (data transfered from NAND device to memory)
+ */
 static void lpc32xx_nand_dma_xfer(struct mtd_info *mtd, u_char *buf, int len, int read)
 {
        struct nand_chip *this = mtd->priv;
@@ -470,14 +451,31 @@ static void lpc32xx_nand_dma_xfer(struct mtd_info *mtd, u_char *buf, int len, in
        /* Prepare descriptors for read transfer */
        lpc32xx_nand_dma_configure(mtd, buf_phy, len, read);
 
-       /* This should start the DMA transfers */
-       lpc32xx_dma_start_xfer(host->dmach, config);
+       /* Setup SLC controller and start transfer */
+       if (read)
+               __raw_writel(__raw_readl(SLC_CFG(host->io_base)) | SLCCFG_DMA_DIR,
+                       SLC_CFG(host->io_base));
+       else  /* NAND_ECC_WRITE */
+               __raw_writel(__raw_readl(SLC_CFG(host->io_base)) & ~SLCCFG_DMA_DIR,
+                       SLC_CFG(host->io_base));
+       __raw_writel(__raw_readl(SLC_CFG(host->io_base)) | SLCCFG_DMA_BURST,
+               SLC_CFG(host->io_base));
+
+       /* Write length for new transfers */
+       if (!is_xfer_pending(mtd))
+               __raw_writel(len +
+                       (len != mtd->oobsize ? mtd->oobsize : 0),
+                       SLC_TC(host->io_base));
+
        __raw_writel(__raw_readl(SLC_CTRL(host->io_base)) | SLCCTRL_DMA_START,
                        SLC_CTRL(host->io_base));
 
+       /* This should start the DMA transfers */
+       lpc32xx_dma_start_xfer(host->dmach, config);
+
        /* Wait for NAND to be ready */
        nand_wait_ready(mtd);
-       
+
        /* Wait till DMA transfer is DONE! */
        wait_for_completion(&host->comp);
        if (unlikely(host->dma_xfer_status != 0)) {
@@ -489,7 +487,7 @@ static void lpc32xx_nand_dma_xfer(struct mtd_info *mtd, u_char *buf, int len, in
                dma_unmap_single(mtd->dev.parent, buf_phy, len,
                                read ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 
-        /* Stop DMA & HW ECC */
+       /* Stop DMA & HW ECC */
        __raw_writel(__raw_readl(SLC_CTRL(host->io_base)) & ~SLCCTRL_DMA_START,
                        SLC_CTRL(host->io_base));
        __raw_writel( __raw_readl(SLC_CFG(host->io_base)) &
@@ -498,152 +496,59 @@ static void lpc32xx_nand_dma_xfer(struct mtd_info *mtd, u_char *buf, int len, in
                        SLC_CFG(host->io_base));
 }
 
-static int lpc32xx_nand_correct_data(struct mtd_info *mtd, u_char *dat,
-                u_char *read_ecc, u_char *calc_ecc)
-{
-        int ret = 0;
-        uint32_t tmp, err;
-        uint32_t *ecc_stored = (uint32_t*)read_ecc;
-        uint32_t *ecc_gen = (uint32_t*)calc_ecc;
-
-
-        err = *ecc_stored ^ *ecc_gen;
-        /* Only perform ECC processing if an error is detected */
-        if (err) {
-                /* ECC Failure in i-th block */
-                tmp = bit_cnt32(err);
-                if (tmp == 11) {
-                        uint32_t byte = err >> 6;
-                        uint32_t bit = 0;
-                        bit = ((err & _BIT(1)) >> 1)|((err & _BIT(3)) >> 2)|
-                                ((err & _BIT(5)) >> 3);
-
-                        /* Calculate Byte offset */
-                        byte = ((byte & _BIT(1)) >> 1)|((byte & _BIT(3)) >> 2)|
-                                ((byte & _BIT(5)) >> 3)|((byte & _BIT(7)) >> 4)|
-                                ((byte & _BIT(9)) >> 5)|((byte & _BIT(11)) >> 6)|
-                                ((byte & _BIT(13)) >> 7)|((byte & _BIT(15)) >> 8);
-
-                        /* Do the correction */
-                        dat[byte] ^= _BIT(bit);
-                        ret = 1;
-                }else {
-                        /* Non-corrrectable */
-                        ret = -1;
-                }
-        }
-        return ret;
-}
-
 /* Prepares SLC for transfers with H/W ECC enabled */
 static void lpc32xx_ecc_enable(struct mtd_info *mtd, int mode)
 {
        struct nand_chip *this = mtd->priv;
        struct lpc32xx_nand_host *host = this->priv;
 
-       /* Clear ECC, start DMA */
+       /* Clear ECC */
        __raw_writel(SLCCTRL_ECC_CLEAR, SLC_CTRL(host->io_base));
 
-       if (mode == NAND_ECC_READ) {
-               __raw_writel( __raw_readl(SLC_CFG(host->io_base)) |
-                       SLCCFG_DMA_DIR, SLC_CFG(host->io_base));
-       }
-       else  { /* NAND_ECC_WRITE */
-               __raw_writel( __raw_readl(SLC_CFG(host->io_base)) &
-                       ~SLCCFG_DMA_DIR, SLC_CFG(host->io_base));
-       }
-
-       __raw_writel( __raw_readl(SLC_CFG(host->io_base)) |
-                       SLCCFG_DMA_BURST | SLCCFG_ECC_EN | SLCCFG_DMA_ECC,
-                       SLC_CFG(host->io_base));
-
-       /* Set transfer count */
-       __raw_writel(this->ecc.size + mtd->oobsize, SLC_TC(host->io_base));
+       /* Setup SLC controller for H/W ECC operations */
+       __raw_writel((SLCCFG_ECC_EN | SLCCFG_DMA_ECC) |
+               __raw_readl(SLC_CFG(host->io_base)),
+               SLC_CFG(host->io_base));
 }
 
-/* Function to calculate inverted ECC from the ECC got from H/W */
-static int lpc32xx_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,
-                                uint8_t *ecc_code)
+/*
+ * Copies the ECC generated by h/w to kernel buffer
+ */
+static uint32_t slc_ecc_copy_to_buffer(uint8_t * spare,
+               const uint32_t * ecc, int count)
 {
+       int i;
+       for (i = 0; i < (count * 3); i += 3) {
+               uint32_t ce = ecc[i/3];
+               ce = ~(ce << 2) & 0xFFFFFF;
+               spare[i+2] = (uint8_t)(ce & 0xFF); ce >>= 8;
+               spare[i+1] = (uint8_t)(ce & 0xFF); ce >>= 8;
+               spare[i]   = (uint8_t)(ce & 0xFF);
+       }
        return 0;
 }
 
-static void lpc32xx_nand_write_page_hwecc(struct mtd_info *mtd,
-                               struct nand_chip *chip, const uint8_t *buf)
+/* Function to calculate inverted ECC from the ECC got from H/W */
+static int lpc32xx_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,
+                                uint8_t *ecc_code)
 {
        struct nand_chip *this = mtd->priv;
        struct lpc32xx_nand_host *host = this->priv;
-        int eccsize = chip->ecc.size;
-
-       /* 
-        * Skip writting page which has all 0xFF data as this will
-        * generate 0x0 value.
-        */
-        if(memcmp(buf, host->erase_buf_data, mtd->writesize) == 0)
-                return;
+       return slc_ecc_copy_to_buffer(ecc_code, host->ecc_calc_buf,
+               mtd->writesize == NAND_LARGE_BLOCK_PAGE_SIZE ? 8 : 2);
+}
 
-        /* Enable H/W ECC & DMA */
-        chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
-       
-       /* Copy OOB data from kernel buffer to DMA memory */
-       memcpy(host->oob_buf, chip->oob_poi,mtd->oobsize);
 
-        /* Configure DMA Desriptor for NAND Write Operation */
-        lpc32xx_nand_dma_xfer(mtd, (uint8_t *)buf, eccsize, 0);
+/* Wrapper function for write operation */
+static void lpc32xx_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+       lpc32xx_nand_dma_xfer(mtd, (u_char *)buf, len, 0);
 }
 
-static int lpc32xx_nand_read_page_hwecc(struct mtd_info *mtd,
-                                 struct nand_chip *chip, uint8_t *buf, int page)
+/* Wrapper function for read operation */
+static void lpc32xx_read_buf (struct mtd_info *mtd, uint8_t *buf, int len)
 {
-       struct nand_chip *this = mtd->priv;
-       struct lpc32xx_nand_host *host = this->priv;
-        int i, eccsize = chip->ecc.size;
-        int eccsteps = (mtd->writesize/NAND_ECC_SUBPAGE_LEN);
-        uint8_t *p = buf;
-        uint8_t *ecc_calc = chip->buffers->ecccalc;
-        uint8_t *ecc_code = chip->buffers->ecccode;
-        uint32_t *eccpos = chip->ecc.layout->eccpos;
-
-       memset(host->ecc_calc_buf, 0x0, this->ecc.bytes);
-
-        /* Enable HW ECC & DMA */
-        chip->ecc.hwctl(mtd, NAND_ECC_READ);
-
-        /* Configure DMA Desriptor for NAND Read Operation */
-        lpc32xx_nand_dma_xfer(mtd, buf, eccsize, 1);
-
-       /* Copy OOB data from DMA memory to kernel buffer */
-       memcpy(chip->oob_poi, host->oob_buf, mtd->oobsize);
-       
-        /* Copy only ECC data which are stored into Flash */
-        for (i = 0; i < chip->ecc.total; i++) {
-                ecc_code[i] = chip->oob_poi[eccpos[i]];
-                ecc_calc[i] = host->ecc_calc_buf[i];
-       }
-
-        /*
-        * LPC3250 has 4 bytes of ECC data per 256 bytes of data block
-        * As eccsteps are calucated based on subpage size.
-        */
-        for (i = 0; eccsteps; eccsteps--, i += NAND_ECC_LEN_PER_SUBPAGE,
-                         p += NAND_ECC_SUBPAGE_LEN) {
-                int stat;
-
-               /*
-                * Once block is erased, all the data including OOB data are 0xFF.
-                * ECC generator always generate zero value ECC for such page while,
-                * stored value is 0xFFFFFFFF.
-                */ 
-               if(*((uint32_t *)&ecc_code[i]) == NAND_ERASED_BLOCK_ECC_VALUE)
-                       continue;
-               
-               stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
-                if (stat == -1)
-                        mtd->ecc_stats.failed++;
-                else
-                        mtd->ecc_stats.corrected += stat;
-        }
-        return 0;
+       lpc32xx_nand_dma_xfer(mtd, buf, len, 1);
 }
 
 /*
@@ -668,7 +573,7 @@ static int __init lpc32xx_nand_probe(struct platform_device *pdev)
                 dev_err(&pdev->dev,"lpc32xx_nand: failed to allocate device structure.\n");
                return -ENOMEM;
        }
-       
+
        rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (rc == NULL) {
                dev_err(&pdev->dev,"No memory resource found for device!\r\n");
@@ -707,10 +612,6 @@ static int __init lpc32xx_nand_probe(struct platform_device *pdev)
        nand_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl;
        nand_chip->dev_ready = lpc32xx_nand_device_ready;
        nand_chip->chip_delay = 20;             /* 20us command delay time */
-       nand_chip->read_byte = lpc32xx_read_byte;
-       nand_chip->read_buf = lpc32xx_read_buf;
-       nand_chip->verify_buf = lpc32xx_verify_buf;
-       nand_chip->write_buf = lpc32xx_write_buf;
 
        /* Init NAND controller */
        lpc32xx_nand_setup(host);
@@ -718,6 +619,15 @@ static int __init lpc32xx_nand_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, host);
 
+       /* Initialize function pointers */
+       nand_chip->read_byte = lpc32xx_read_byte;
+       nand_chip->verify_buf = lpc32xx_verify_buf;
+       nand_chip->read_buf = lpc32xx_read_buf;
+       nand_chip->write_buf = lpc32xx_write_buf;
+       nand_chip->ecc.hwctl = lpc32xx_ecc_enable;
+       nand_chip->ecc.correct = nand_correct_data;
+       nand_chip->ecc.calculate = lpc32xx_ecc_calculate;
+
        /*
         * Scan to find existance of the device and
         * Get the type of NAND device SMALL block or LARGE block
@@ -729,53 +639,27 @@ static int __init lpc32xx_nand_probe(struct platform_device *pdev)
 
        nand_chip->ecc.mode = NAND_ECC_HW;
        nand_chip->ecc.size = mtd->writesize;
-       nand_chip->ecc.bytes = (mtd->writesize / 256) * 4;
-        nand_chip->ecc.read_page_raw = lpc32xx_nand_read_page_hwecc;
-        nand_chip->ecc.read_page = lpc32xx_nand_read_page_hwecc;
-        nand_chip->ecc.write_page = lpc32xx_nand_write_page_hwecc;
-
-       switch (mtd->oobsize) {
-               case 16:
-                       nand_chip->ecc.layout = &lpc32xx_nand_oob_16;
-                       break;
-               case 64:
-                       nand_chip->ecc.layout = &lpc32xx_nand_oob_64;
-                       break;
-               default:
-                        dev_err(&pdev->dev, "No oob scheme defined for "
-                                       "oobsize %d\n", mtd->oobsize);
-                       BUG();
-       }
+       nand_chip->ecc.bytes = (mtd->writesize / 256) * 3;
 
-       /* H/W ECC specific functions */
-       nand_chip->ecc.hwctl = lpc32xx_ecc_enable;
-       nand_chip->ecc.correct = lpc32xx_nand_correct_data;
-       nand_chip->ecc.calculate = lpc32xx_ecc_calculate;
+       if (mtd->oobsize == 16)
+               nand_chip->ecc.layout = &lpc32xx_nand_oob_16;
 
-       /*
-        * Fills out all the uninitialized function pointers with the defaults
-        * And scans for a bad block table if appropriate.
-        */
-       if (nand_scan_tail(mtd)) {
-               res = -ENXIO;
-               goto err_exit3;
-       }
 
        /* Get free DMA channel and alloc DMA descriptor link list */
        res = lpc32xx_nand_dma_setup(host,((mtd->writesize/128) + 1));
        if(res) {
-               res = -EIO;     
+               res = -EIO;
                goto err_exit3;
        }
 
        /* allocate DMA buffer */
-       host->dma_buf_len = 
+       host->dma_buf_len =
                (/* OOB size area for storing OOB data including ECC */
-                mtd->oobsize + 
+                mtd->oobsize +
                 /* Page Size area for storing Page RAW data */
                 mtd->writesize +
                 /* ECC bytes area for storing Calculated ECC at the time reading page */
-                nand_chip->ecc.bytes);
+                ((mtd->oobsize/16) * 2 * sizeof(uint32_t)));
 
        host->oob_buf = dmam_alloc_coherent(&pdev->dev, host->dma_buf_len,
                        &host->oob_buf_phy, GFP_KERNEL);
@@ -786,26 +670,35 @@ static int __init lpc32xx_nand_probe(struct platform_device *pdev)
        }
 
        host->dma_buf = (uint8_t *)host->oob_buf + mtd->oobsize;
-       host->ecc_calc_buf = (uint8_t *)host->dma_buf + mtd->writesize;
+       host->ecc_calc_buf = (uint32_t *)((uint8_t *)host->dma_buf + mtd->writesize);
+
        host->dma_buf_phy = host->oob_buf_phy + mtd->oobsize;
        host->ecc_calc_buf_phy = host->dma_buf_phy + mtd->writesize;
 
        host->io_base_phy = platform_get_resource(pdev, IORESOURCE_MEM, 0)->start;
 
-       /* 
+       /*
         * Allocate a page size buffer to check all 0xFF data
         * at the time page writting.
         */
        host->erase_buf_data = kmalloc(mtd->writesize, GFP_KERNEL);
        if (!host->erase_buf_data) {
-                dev_err(&pdev->dev,"lpc32xx_nand: failed to allocate device structure.\n");
+               dev_err(&pdev->dev,"lpc32xx_nand: failed to allocate device structure.\n");
                return -ENOMEM;
                goto err_exit5;
        }
-        memset(host->erase_buf_data, 0xFF, mtd->writesize);
+       memset(host->erase_buf_data, 0xFF, mtd->writesize);
        init_completion(&host->comp);
 
+       /*
+        * Fills out all the uninitialized function pointers with the defaults
+        * And scans for a bad block table if appropriate.
+        */
+       if (nand_scan_tail(mtd)) {
+               res = -ENXIO;
+               goto err_exit5;
+       }
+
 #ifdef CONFIG_MTD_PARTITIONS
 #ifdef CONFIG_MTD_CMDLINE_PARTS
        mtd->name = "lpc32xx_nand";
@@ -818,7 +711,7 @@ static int __init lpc32xx_nand_probe(struct platform_device *pdev)
        }
 
        if ((!partitions) || (num_partitions == 0)) {
-                dev_err(&pdev->dev,"lpc32xx_nand: No parititions defined, or unsupported device.\n");
+               dev_err(&pdev->dev,"lpc32xx_nand: No parititions defined, or unsupported device.\n");
                res = ENXIO;
                goto err_exit6;
        }
@@ -835,7 +728,7 @@ err_exit6:
        kfree(host->erase_buf_data);
 err_exit5:
        dma_free_coherent(&pdev->dev, host->dma_buf_len,
-                                host->oob_buf, host->oob_buf_phy);
+                               host->oob_buf, host->oob_buf_phy);
 err_exit4:
        /* Free the DMA channel used by us */
        lpc32xx_dma_ch_disable(host->dmach);
@@ -871,7 +764,7 @@ static int __devexit lpc32xx_nand_remove(struct platform_device *pdev)
        host->dmach = -1;
 
        dma_free_coherent(&pdev->dev, host->dma_buf_len,
-                                host->oob_buf, host->oob_buf_phy);
+               host->oob_buf, host->oob_buf_phy);
        nand_release(mtd);
 
        /* Force CE high */
@@ -884,7 +777,7 @@ static int __devexit lpc32xx_nand_remove(struct platform_device *pdev)
        clk_put(host->clk);
 
        iounmap(host->io_base);
-       
+
        kfree(host->erase_buf_data);
        kfree(host);