aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSneha Narnakaje <nsnehaprabha@ti.com>2009-09-18 15:51:47 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2009-09-19 14:14:54 -0400
commit6e0cb135b3f3713b95ea41a11155e83a8c70f5f8 (patch)
tree06e685a6d4863139a8bf68a0791c107aa7969765
parent46a8cf2df2232c0051f29716ff8a166ebeb08daf (diff)
mtd: nand: add new ECC mode - ECC_HW_OOB_FIRST
This patch adds the new mode NAND_ECC_HW_OOB_FIRST in the nand code to support 4-bit ECC on TI DaVinci devices with large page (up to 2KiB) NAND chips. This ECC mode is similar to NAND_ECC_HW, with the exception of read_page API that first reads the OOB area, reads the data in chunks, feeds the ECC from OOB area to the ECC hw engine and perform any correction on the data as per the ECC status reported by the engine. "ECC_HW_OOB_FIRST" name suggested by Thomas Gleixner Reviewed-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Sneha Narnakaje <nsnehaprabha@ti.com> Signed-off-by: Sandeep Paulraj <s-paulraj@ti.com> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
-rw-r--r--drivers/mtd/nand/nand_base.c61
-rw-r--r--include/linux/mtd/nand.h1
2 files changed, 61 insertions, 1 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 17bbd5062027..22113865438b 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -979,6 +979,54 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
979} 979}
980 980
981/** 981/**
982 * nand_read_page_hwecc_oob_first - [REPLACABLE] hw ecc, read oob first
983 * @mtd: mtd info structure
984 * @chip: nand chip info structure
985 * @buf: buffer to store read data
986 *
987 * Hardware ECC for large page chips, require OOB to be read first.
988 * For this ECC mode, the write_page method is re-used from ECC_HW.
989 * These methods read/write ECC from the OOB area, unlike the
990 * ECC_HW_SYNDROME support with multiple ECC steps, follows the
991 * "infix ECC" scheme and reads/writes ECC from the data area, by
992 * overwriting the NAND manufacturer bad block markings.
993 */
994static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
995 struct nand_chip *chip, uint8_t *buf, int page)
996{
997 int i, eccsize = chip->ecc.size;
998 int eccbytes = chip->ecc.bytes;
999 int eccsteps = chip->ecc.steps;
1000 uint8_t *p = buf;
1001 uint8_t *ecc_code = chip->buffers->ecccode;
1002 uint32_t *eccpos = chip->ecc.layout->eccpos;
1003 uint8_t *ecc_calc = chip->buffers->ecccalc;
1004
1005 /* Read the OOB area first */
1006 chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
1007 chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
1008 chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
1009
1010 for (i = 0; i < chip->ecc.total; i++)
1011 ecc_code[i] = chip->oob_poi[eccpos[i]];
1012
1013 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
1014 int stat;
1015
1016 chip->ecc.hwctl(mtd, NAND_ECC_READ);
1017 chip->read_buf(mtd, p, eccsize);
1018 chip->ecc.calculate(mtd, p, &ecc_calc[i]);
1019
1020 stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
1021 if (stat < 0)
1022 mtd->ecc_stats.failed++;
1023 else
1024 mtd->ecc_stats.corrected += stat;
1025 }
1026 return 0;
1027}
1028
1029/**
982 * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read 1030 * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read
983 * @mtd: mtd info structure 1031 * @mtd: mtd info structure
984 * @chip: nand chip info structure 1032 * @chip: nand chip info structure
@@ -2673,6 +2721,17 @@ int nand_scan_tail(struct mtd_info *mtd)
2673 */ 2721 */
2674 2722
2675 switch (chip->ecc.mode) { 2723 switch (chip->ecc.mode) {
2724 case NAND_ECC_HW_OOB_FIRST:
2725 /* Similar to NAND_ECC_HW, but a separate read_page handle */
2726 if (!chip->ecc.calculate || !chip->ecc.correct ||
2727 !chip->ecc.hwctl) {
2728 printk(KERN_WARNING "No ECC functions supplied; "
2729 "Hardware ECC not possible\n");
2730 BUG();
2731 }
2732 if (!chip->ecc.read_page)
2733 chip->ecc.read_page = nand_read_page_hwecc_oob_first;
2734
2676 case NAND_ECC_HW: 2735 case NAND_ECC_HW:
2677 /* Use standard hwecc read page function ? */ 2736 /* Use standard hwecc read page function ? */
2678 if (!chip->ecc.read_page) 2737 if (!chip->ecc.read_page)
@@ -2695,7 +2754,7 @@ int nand_scan_tail(struct mtd_info *mtd)
2695 chip->ecc.read_page == nand_read_page_hwecc || 2754 chip->ecc.read_page == nand_read_page_hwecc ||
2696 !chip->ecc.write_page || 2755 !chip->ecc.write_page ||
2697 chip->ecc.write_page == nand_write_page_hwecc)) { 2756 chip->ecc.write_page == nand_write_page_hwecc)) {
2698 printk(KERN_WARNING "No ECC functions supplied, " 2757 printk(KERN_WARNING "No ECC functions supplied; "
2699 "Hardware ECC not possible\n"); 2758 "Hardware ECC not possible\n");
2700 BUG(); 2759 BUG();
2701 } 2760 }
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 686f3701f2f4..7a232a9bdd62 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -121,6 +121,7 @@ typedef enum {
121 NAND_ECC_SOFT, 121 NAND_ECC_SOFT,
122 NAND_ECC_HW, 122 NAND_ECC_HW,
123 NAND_ECC_HW_SYNDROME, 123 NAND_ECC_HW_SYNDROME,
124 NAND_ECC_HW_OOB_FIRST,
124} nand_ecc_modes_t; 125} nand_ecc_modes_t;
125 126
126/* 127/*