include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / drivers / mtd / nand / davinci_nand.c
index cb5a05e..76e2dc8 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/io.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
+#include <linux/slab.h>
 
 #include <mach/nand.h>
 
@@ -348,6 +349,12 @@ compare:
        if (!(syndrome[0] | syndrome[1] | syndrome[2] | syndrome[3]))
                return 0;
 
+       /*
+        * Clear any previous address calculation by doing a dummy read of an
+        * error address register.
+        */
+       davinci_nand_readl(info, NAND_ERR_ADD1_OFFSET);
+
        /* Start address calculation, and wait for it to complete.
         * We _could_ start reading more data while this is working,
         * to speed up the overall page read.
@@ -359,8 +366,10 @@ compare:
 
                switch ((fsr >> 8) & 0x0f) {
                case 0:         /* no error, should not happen */
+                       davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET);
                        return 0;
                case 1:         /* five or more errors detected */
+                       davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET);
                        return -EIO;
                case 2:         /* error addresses computed */
                case 3:
@@ -500,6 +509,26 @@ static struct nand_ecclayout hwecc4_small __initconst = {
        },
 };
 
+/* An ECC layout for using 4-bit ECC with large-page (2048bytes) flash,
+ * storing ten ECC bytes plus the manufacturer's bad block marker byte,
+ * and not overlapping the default BBT markers.
+ */
+static struct nand_ecclayout hwecc4_2048 __initconst = {
+       .eccbytes = 40,
+       .eccpos = {
+               /* at the end of spare sector */
+               24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+               34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+               44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+               54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+               },
+       .oobfree = {
+               /* 2 bytes at offset 0 hold manufacturer badblock markers */
+               {.offset = 2, .length = 22, },
+               /* 5 bytes at offset 8 hold BBT markers */
+               /* 8 bytes at offset 16 hold JFFS2 clean markers */
+       },
+};
 
 static int __init nand_davinci_probe(struct platform_device *pdev)
 {
@@ -563,6 +592,8 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
 
        /* options such as NAND_USE_FLASH_BBT or 16-bit widths */
        info->chip.options      = pdata->options;
+       info->chip.bbt_td       = pdata->bbt_td;
+       info->chip.bbt_md       = pdata->bbt_md;
 
        info->ioaddr            = (uint32_t __force) vaddr;
 
@@ -571,7 +602,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
        info->mask_chipsel      = pdata->mask_chipsel;
 
        /* use nandboot-capable ALE/CLE masks by default */
-       info->mask_ale          = pdata->mask_cle ? : MASK_ALE;
+       info->mask_ale          = pdata->mask_ale ? : MASK_ALE;
        info->mask_cle          = pdata->mask_cle ? : MASK_CLE;
 
        /* Set address of hardware control function */
@@ -626,16 +657,17 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
        }
        info->chip.ecc.mode = ecc_mode;
 
-       info->clk = clk_get(&pdev->dev, "AEMIFCLK");
+       info->clk = clk_get(&pdev->dev, "aemif");
        if (IS_ERR(info->clk)) {
                ret = PTR_ERR(info->clk);
-               dev_dbg(&pdev->dev, "unable to get AEMIFCLK, err %d\n", ret);
+               dev_dbg(&pdev->dev, "unable to get AEMIF clock, err %d\n", ret);
                goto err_clk;
        }
 
        ret = clk_enable(info->clk);
        if (ret < 0) {
-               dev_dbg(&pdev->dev, "unable to enable AEMIFCLK, err %d\n", ret);
+               dev_dbg(&pdev->dev, "unable to enable AEMIF clock, err %d\n",
+                       ret);
                goto err_clk_enable;
        }
 
@@ -689,15 +721,20 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
                                info->mtd.oobsize - 16;
                        goto syndrome_done;
                }
+               if (chunks == 4) {
+                       info->ecclayout = hwecc4_2048;
+                       info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST;
+                       goto syndrome_done;
+               }
 
-               /* For large page chips we'll be wanting to use a
-                * not-yet-implemented mode that reads OOB data
-                * before reading the body of the page, to avoid
-                * the "infix OOB" model of NAND_ECC_HW_SYNDROME
-                * (and preserve manufacturer badblock markings).
+               /* 4KiB page chips are not yet supported. The eccpos from
+                * nand_ecclayout cannot hold 80 bytes and change to eccpos[]
+                * breaks userspace ioctl interface with mtd-utils. Once we
+                * resolve this issue, NAND_ECC_HW_OOB_FIRST mode can be used
+                * for the 4KiB page chips.
                 */
                dev_warn(&pdev->dev, "no 4-bit ECC support yet "
-                               "for large page NAND\n");
+                               "for 4KiB-page NAND\n");
                ret = -EIO;
                goto err_scan;
 
@@ -717,19 +754,8 @@ syndrome_done:
                        static const char *probes[] __initconst =
                                { "cmdlinepart", NULL };
 
-                       const char              *master_name;
-
-                       /* Set info->mtd.name = 0 temporarily */
-                       master_name             = info->mtd.name;
-                       info->mtd.name          = (char *)0;
-
-                       /* info->mtd.name == 0, means: don't bother checking
-                          <mtd-id> */
                        mtd_parts_nb = parse_mtd_partitions(&info->mtd, probes,
                                                            &mtd_parts, 0);
-
-                       /* Restore info->mtd.name */
-                       info->mtd.name = master_name;
                }
 
                if (mtd_parts_nb <= 0) {