Large page support with the 4-bit ECC hardware.

 - OOB layout
     * construct layout descriptors to match NAND core's algorithm
       (the defaults are wrong, but are still used blindly)

 - Bad Block handling
     * prevent scanning, since the manufacturer's markings get clobbered
     * require a flash BBT (to compensate) ...
     * ... created by someone *else* since we can't scan

NOTE:  presumes an MTD core bugfix to do "raw" (non-ECC) page I/O the
same way it does non-raw (ECC-enabled) page I/O.  I suspect some other
glitchiness is caused by similar bugs elsewhere in the NAND core.

---
 drivers/mtd/nand/davinci_nand.c |  104 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 100 insertions(+), 4 deletions(-)

--- a/drivers/mtd/nand/davinci_nand.c
+++ b/drivers/mtd/nand/davinci_nand.c
@@ -515,6 +515,46 @@ static struct nand_ecclayout hwecc_small
        },
 };
 
+/* With large page flash and ECC_HW_SYNDROME, prevent scanning according
+ * to the factory bad block marking rules ... the subpage-type chunking
+ * of OOB data means those markers get overwritten by (non-0xff) data.
+ */
+static const struct nand_bbt_descr hwecc_large_bbt = {
+       .len = 0,
+};
+
+/* These are the same BBT descriptors the NAND core uses for
+ * large block chips, except:
+ *   (a) pattern offsets are changed to sit *OUTSIDE* the ECC data
+ *   (b) cleared NAND_BBT_CREATE ... create BBTs before running Linux
+ *
+ * Used with ECC_HW_SYNDROME, and compatible with the original
+ * Linux distro on the DM355 EVM.
+ */
+static const uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
+static const uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
+
+static const struct nand_bbt_descr bbt_main_descr = {
+       .options        = NAND_BBT_LASTBLOCK | NAND_BBT_WRITE
+                       | NAND_BBT_2BIT | NAND_BBT_VERSION
+                       | NAND_BBT_PERCHIP,
+       .offs           = 2,
+       .len            = 4,
+       .veroffs        = 16,
+       .maxblocks      = 4,
+       .pattern        = (void *) bbt_pattern,
+};
+
+static const struct nand_bbt_descr bbt_mirror_descr = {
+       .options        = NAND_BBT_LASTBLOCK | NAND_BBT_WRITE
+                       | NAND_BBT_2BIT | NAND_BBT_VERSION
+                       | NAND_BBT_PERCHIP,
+       .offs           = 2,
+       .len            = 4,
+       .veroffs        = 16,
+       .maxblocks      = 4,
+       .pattern        = (void *) mirror_pattern,
+};
 
 static int __init nand_davinci_probe(struct platform_device *pdev)
 {
@@ -716,10 +756,66 @@ static int __init nand_davinci_probe(str
                        goto syndrome_done;
                }
 
-               dev_warn(&pdev->dev, "no 4-bit ECC support yet "
-                               "for large page NAND\n");
-               ret = -EIO;
-               goto err_scan;
+               /* Build ECC layout on the fly, so we're not limited to
+                * a single page size (like 2KiB).
+                *
+                * REVISIT the NAND core could do this, or at least
+                * verify that it's done right.  The layout is fully
+                * constrained by ecc.{prepad,bytes,postpad} values,
+                * mtd.oobsize, and ecclayout itself.
+                */
+               info->ecclayout.eccbytes = chunks * 10;
+               for (i = 0, oobindex = 0; i < chunks; i++) {
+                       int j;
+
+                       /* ecc.prepad == ECC_PREPAD */
+                       if (i < ARRAY_SIZE(info->ecclayout.oobfree)
+                                       && ECC_PREPAD) {
+                               info->ecclayout.oobfree[i].offset = oobindex;
+                               info->ecclayout.oobfree[i].length = ECC_PREPAD;
+                       }
+                       oobindex += ECC_PREPAD;
+
+                       /* ecc.bytes == 10 */
+                       for (j = 0; j < 10; j++, oobindex++) {
+                               /* EEC gets read/written regardless of
+                                * whether eccpos is too small.
+                                */
+                               if (oobindex > sizeof info->ecclayout.eccpos)
+                                       continue;
+                               info->ecclayout.eccpos[i * 10 + j]
+                                       = oobindex;
+                       }
+
+                       /* ecc.postpad == 0 */
+               }
+               info->ecclayout.oobfree[i].offset = oobindex;
+               info->ecclayout.oobfree[i].length = info->mtd.oobsize - i;
+
+               /* The manufacturer's bad block markings (first byte of the
+                * spare area, e.g. address 2048 of a 2K page) will only be
+                * usable only _before_ this chip is initialized, since the
+                * ECC_HW_SYNDROME OOB layout overwrites it with data.  So
+                * we can't use that scheme:
+                *
+                *   - Prevent standard badblock scanning
+                *   - Require a BBT in flash
+                *   - Disallow BBT creation (since we won't scan...)
+                *   - Use sane BBT markers (living OUTSIDE the ECC data)
+                *
+                * The only part of thise which couldn't be generated by
+                * the NAND core is a BBT pattern offset that's compatible
+                * with DM355 DVSDK software (contrast:  what's used above
+                * for small page chips).
+                */
+               info->chip.badblock_pattern = (void *) &hwecc_large_bbt;
+               if (!(info->chip.options & NAND_USE_FLASH_BBT)) {
+                       dev_dbg(&pdev->dev, "not using FLASH_BBT?\n");
+                       ret = -EOPNOTSUPP;
+                       goto err_scan;
+               }
+               info->chip.bbt_td = (void *) &bbt_main_descr;
+               info->chip.bbt_md = (void *) &bbt_mirror_descr;
 
 syndrome_done:
                info->chip.ecc.layout = &info->ecclayout;

_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

Reply via email to