mtd: MXC NAND support for 2KiB page size flashes
authorVladimir Barinov <vova.barinov@gmail.com>
Mon, 25 May 2009 09:06:17 +0000 (13:06 +0400)
committerDavid Woodhouse <David.Woodhouse@intel.com>
Fri, 5 Jun 2009 17:15:41 +0000 (18:15 +0100)
- Add support for 2KiB page size flashes
- Fix page address access for large pages
- Detect oob layout at runtime
- handle pagesize_2k variable
- Fix oob16 layout: reserve location 5 of oob area since it's used for bbt

Signed-off-by: Vladimir Barinov <vova.barinov@gmail.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
drivers/mtd/nand/mxc_nand.c

index d5aea69..d03bd4e 100644 (file)
@@ -138,7 +138,14 @@ static struct nand_ecclayout nand_hw_eccoob_8 = {
 static struct nand_ecclayout nand_hw_eccoob_16 = {
        .eccbytes = 5,
        .eccpos = {6, 7, 8, 9, 10},
-       .oobfree = {{0, 6}, {12, 4}, }
+       .oobfree = {{0, 5}, {11, 5}, }
+};
+
+static struct nand_ecclayout nand_hw_eccoob_64 = {
+       .eccbytes = 20,
+       .eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26,
+                  38, 39, 40, 41, 42, 54, 55, 56, 57, 58},
+       .oobfree = {{2, 4}, {11, 10}, {27, 10}, {43, 10}, {59, 5}, }
 };
 
 #ifdef CONFIG_MTD_PARTITIONS
@@ -795,9 +802,13 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
                send_addr(host, (page_addr & 0xff), false);
 
                if (host->pagesize_2k) {
-                       send_addr(host, (page_addr >> 8) & 0xFF, false);
-                       if (mtd->size >= 0x40000000)
+                       if (mtd->size >= 0x10000000) {
+                               /* paddr_8 - paddr_15 */
+                               send_addr(host, (page_addr >> 8) & 0xff, false);
                                send_addr(host, (page_addr >> 16) & 0xff, true);
+                       } else
+                               /* paddr_8 - paddr_15 */
+                               send_addr(host, (page_addr >> 8) & 0xff, true);
                } else {
                        /* One more address cycle for higher density devices */
                        if (mtd->size >= 0x4000000) {
@@ -919,7 +930,6 @@ static int __init mxcnd_probe(struct platform_device *pdev)
                this->ecc.mode = NAND_ECC_HW;
                this->ecc.size = 512;
                this->ecc.bytes = 3;
-               this->ecc.layout = &nand_hw_eccoob_8;
                tmp = readw(host->regs + NFC_CONFIG1);
                tmp |= NFC_ECC_EN;
                writew(tmp, host->regs + NFC_CONFIG1);
@@ -953,12 +963,44 @@ static int __init mxcnd_probe(struct platform_device *pdev)
                this->ecc.layout = &nand_hw_eccoob_16;
        }
 
-       host->pagesize_2k = 0;
+       /* first scan to find the device and get the page size */
+       if (nand_scan_ident(mtd, 1)) {
+               err = -ENXIO;
+               goto escan;
+       }
 
-       /* Scan to find existence of the device */
-       if (nand_scan(mtd, 1)) {
-               DEBUG(MTD_DEBUG_LEVEL0,
-                     "MXC_ND: Unable to find any NAND device.\n");
+       host->pagesize_2k = (mtd->writesize == 2048) ? 1 : 0;
+
+       if (this->ecc.mode == NAND_ECC_HW) {
+               switch (mtd->oobsize) {
+               case 8:
+                       this->ecc.layout = &nand_hw_eccoob_8;
+                       break;
+               case 16:
+                       this->ecc.layout = &nand_hw_eccoob_16;
+                       break;
+               case 64:
+                       this->ecc.layout = &nand_hw_eccoob_64;
+                       break;
+               default:
+                       /* page size not handled by HW ECC */
+                       /* switching back to soft ECC */
+                       this->ecc.size = 512;
+                       this->ecc.bytes = 3;
+                       this->ecc.layout = &nand_hw_eccoob_8;
+                       this->ecc.mode = NAND_ECC_SOFT;
+                       this->ecc.calculate = NULL;
+                       this->ecc.correct = NULL;
+                       this->ecc.hwctl = NULL;
+                       tmp = readw(host->regs + NFC_CONFIG1);
+                       tmp &= ~NFC_ECC_EN;
+                       writew(tmp, host->regs + NFC_CONFIG1);
+                       break;
+               }
+       }
+
+       /* second phase scan */
+       if (nand_scan_tail(mtd)) {
                err = -ENXIO;
                goto escan;
        }