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