aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/nand_base.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@cruncher.tec.linutronix.de>2006-05-23 06:00:46 -0400
committerThomas Gleixner <tglx@cruncher.tec.linutronix.de>2006-05-23 06:00:46 -0400
commit6dfc6d250d0b7ebaa6423c44dcd09fcfe68deabd (patch)
tree2be25b1e302eca5984a8ad5ed3e5bde77bafaabb /drivers/mtd/nand/nand_base.c
parent7aa65bfd6793a56cc3bbce8436abbfea3a7bdd1f (diff)
[MTD] NAND modularize ECC
First step of modularizing ECC support. - Move ECC related functionality into a seperate embedded data structure - Get rid of the hardware dependend constants to simplify new ECC models Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers/mtd/nand/nand_base.c')
-rw-r--r--drivers/mtd/nand/nand_base.c146
1 files changed, 48 insertions, 98 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 37db98a58c34..98792ec4c2dc 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -879,9 +879,9 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int pag
879{ 879{
880 int i, status; 880 int i, status;
881 uint8_t ecc_code[32]; 881 uint8_t ecc_code[32];
882 int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; 882 int eccmode = oobsel->useecc ? this->ecc.mode : NAND_ECC_NONE;
883 int *oob_config = oobsel->eccpos; 883 int *oob_config = oobsel->eccpos;
884 int datidx = 0, eccidx = 0, eccsteps = this->eccsteps; 884 int datidx = 0, eccidx = 0, eccsteps = this->ecc.steps;
885 int eccbytes = 0; 885 int eccbytes = 0;
886 886
887 /* FIXME: Enable cached programming */ 887 /* FIXME: Enable cached programming */
@@ -901,20 +901,20 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int pag
901 /* Software ecc 3/256, write all */ 901 /* Software ecc 3/256, write all */
902 case NAND_ECC_SOFT: 902 case NAND_ECC_SOFT:
903 for (; eccsteps; eccsteps--) { 903 for (; eccsteps; eccsteps--) {
904 this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code); 904 this->ecc.calculate(mtd, &this->data_poi[datidx], ecc_code);
905 for (i = 0; i < 3; i++, eccidx++) 905 for (i = 0; i < 3; i++, eccidx++)
906 oob_buf[oob_config[eccidx]] = ecc_code[i]; 906 oob_buf[oob_config[eccidx]] = ecc_code[i];
907 datidx += this->eccsize; 907 datidx += this->ecc.size;
908 } 908 }
909 this->write_buf(mtd, this->data_poi, mtd->oobblock); 909 this->write_buf(mtd, this->data_poi, mtd->oobblock);
910 break; 910 break;
911 default: 911 default:
912 eccbytes = this->eccbytes; 912 eccbytes = this->ecc.bytes;
913 for (; eccsteps; eccsteps--) { 913 for (; eccsteps; eccsteps--) {
914 /* enable hardware ecc logic for write */ 914 /* enable hardware ecc logic for write */
915 this->enable_hwecc(mtd, NAND_ECC_WRITE); 915 this->ecc.hwctl(mtd, NAND_ECC_WRITE);
916 this->write_buf(mtd, &this->data_poi[datidx], this->eccsize); 916 this->write_buf(mtd, &this->data_poi[datidx], this->ecc.size);
917 this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code); 917 this->ecc.calculate(mtd, &this->data_poi[datidx], ecc_code);
918 for (i = 0; i < eccbytes; i++, eccidx++) 918 for (i = 0; i < eccbytes; i++, eccidx++)
919 oob_buf[oob_config[eccidx]] = ecc_code[i]; 919 oob_buf[oob_config[eccidx]] = ecc_code[i];
920 /* If the hardware ecc provides syndromes then 920 /* If the hardware ecc provides syndromes then
@@ -922,7 +922,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int pag
922 * the data bytes (words) */ 922 * the data bytes (words) */
923 if (this->options & NAND_HWECC_SYNDROME) 923 if (this->options & NAND_HWECC_SYNDROME)
924 this->write_buf(mtd, ecc_code, eccbytes); 924 this->write_buf(mtd, ecc_code, eccbytes);
925 datidx += this->eccsize; 925 datidx += this->ecc.size;
926 } 926 }
927 break; 927 break;
928 } 928 }
@@ -1155,7 +1155,7 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
1155 if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) 1155 if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)
1156 oobsel = this->autooob; 1156 oobsel = this->autooob;
1157 1157
1158 eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; 1158 eccmode = oobsel->useecc ? this->ecc.mode : NAND_ECC_NONE;
1159 oob_config = oobsel->eccpos; 1159 oob_config = oobsel->eccpos;
1160 1160
1161 /* Select the NAND device */ 1161 /* Select the NAND device */
@@ -1170,8 +1170,8 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
1170 col = from & (mtd->oobblock - 1); 1170 col = from & (mtd->oobblock - 1);
1171 1171
1172 end = mtd->oobblock; 1172 end = mtd->oobblock;
1173 ecc = this->eccsize; 1173 ecc = this->ecc.size;
1174 eccbytes = this->eccbytes; 1174 eccbytes = this->ecc.bytes;
1175 1175
1176 if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME)) 1176 if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME))
1177 compareecc = 0; 1177 compareecc = 0;
@@ -1216,7 +1216,7 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
1216 oobsel->useecc == MTD_NANDECC_AUTOPL_USR) 1216 oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
1217 oob_data = &this->data_buf[end]; 1217 oob_data = &this->data_buf[end];
1218 1218
1219 eccsteps = this->eccsteps; 1219 eccsteps = this->ecc.steps;
1220 1220
1221 switch (eccmode) { 1221 switch (eccmode) {
1222 case NAND_ECC_NONE:{ 1222 case NAND_ECC_NONE:{
@@ -1234,12 +1234,12 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
1234 case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */ 1234 case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */
1235 this->read_buf(mtd, data_poi, end); 1235 this->read_buf(mtd, data_poi, end);
1236 for (i = 0, datidx = 0; eccsteps; eccsteps--, i += 3, datidx += ecc) 1236 for (i = 0, datidx = 0; eccsteps; eccsteps--, i += 3, datidx += ecc)
1237 this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); 1237 this->ecc.calculate(mtd, &data_poi[datidx], &ecc_calc[i]);
1238 break; 1238 break;
1239 1239
1240 default: 1240 default:
1241 for (i = 0, datidx = 0; eccsteps; eccsteps--, i += eccbytes, datidx += ecc) { 1241 for (i = 0, datidx = 0; eccsteps; eccsteps--, i += eccbytes, datidx += ecc) {
1242 this->enable_hwecc(mtd, NAND_ECC_READ); 1242 this->ecc.hwctl(mtd, NAND_ECC_READ);
1243 this->read_buf(mtd, &data_poi[datidx], ecc); 1243 this->read_buf(mtd, &data_poi[datidx], ecc);
1244 1244
1245 /* HW ecc with syndrome calculation must read the 1245 /* HW ecc with syndrome calculation must read the
@@ -1247,19 +1247,19 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
1247 if (!compareecc) { 1247 if (!compareecc) {
1248 /* Some hw ecc generators need to know when the 1248 /* Some hw ecc generators need to know when the
1249 * syndrome is read from flash */ 1249 * syndrome is read from flash */
1250 this->enable_hwecc(mtd, NAND_ECC_READSYN); 1250 this->ecc.hwctl(mtd, NAND_ECC_READSYN);
1251 this->read_buf(mtd, &oob_data[i], eccbytes); 1251 this->read_buf(mtd, &oob_data[i], eccbytes);
1252 /* We calc error correction directly, it checks the hw 1252 /* We calc error correction directly, it checks the hw
1253 * generator for an error, reads back the syndrome and 1253 * generator for an error, reads back the syndrome and
1254 * does the error correction on the fly */ 1254 * does the error correction on the fly */
1255 ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]); 1255 ecc_status = this->ecc.correct(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
1256 if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { 1256 if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
1257 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: " 1257 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: "
1258 "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); 1258 "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
1259 ecc_failed++; 1259 ecc_failed++;
1260 } 1260 }
1261 } else { 1261 } else {
1262 this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); 1262 this->ecc.calculate(mtd, &data_poi[datidx], &ecc_calc[i]);
1263 } 1263 }
1264 } 1264 }
1265 break; 1265 break;
@@ -1277,8 +1277,8 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
1277 ecc_code[j] = oob_data[oob_config[j]]; 1277 ecc_code[j] = oob_data[oob_config[j]];
1278 1278
1279 /* correct data, if necessary */ 1279 /* correct data, if necessary */
1280 for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) { 1280 for (i = 0, j = 0, datidx = 0; i < this->ecc.steps; i++, datidx += ecc) {
1281 ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]); 1281 ecc_status = this->ecc.correct(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]);
1282 1282
1283 /* Get next chunk of ecc bytes */ 1283 /* Get next chunk of ecc bytes */
1284 j += eccbytes; 1284 j += eccbytes;
@@ -1315,7 +1315,7 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
1315 break; 1315 break;
1316 case MTD_NANDECC_PLACE: 1316 case MTD_NANDECC_PLACE:
1317 /* YAFFS1 legacy mode */ 1317 /* YAFFS1 legacy mode */
1318 oob_data += this->eccsteps * sizeof(int); 1318 oob_data += this->ecc.steps * sizeof(int);
1319 default: 1319 default:
1320 oob_data += mtd->oobsize; 1320 oob_data += mtd->oobsize;
1321 } 1321 }
@@ -2648,99 +2648,49 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
2648 * check ECC mode, default to software if 3byte/512byte hardware ECC is 2648 * check ECC mode, default to software if 3byte/512byte hardware ECC is
2649 * selected and we have 256 byte pagesize fallback to software ECC 2649 * selected and we have 256 byte pagesize fallback to software ECC
2650 */ 2650 */
2651 this->eccsize = 256; 2651 switch (this->ecc.mode) {
2652 this->eccbytes = 3; 2652 case NAND_ECC_HW:
2653 2653 case NAND_ECC_HW_SYNDROME:
2654 switch (this->eccmode) { 2654 if (!this->ecc.calculate || !this->ecc.correct ||
2655 case NAND_ECC_HW12_2048: 2655 !this->ecc.hwctl) {
2656 if (mtd->oobblock < 2048) { 2656 printk(KERN_WARNING "No ECC functions supplied, "
2657 printk(KERN_WARNING "2048 byte HW ECC not possible on " 2657 "Hardware ECC not possible\n");
2658 "%d byte page size, fallback to SW ECC\n", 2658 BUG();
2659 mtd->oobblock); 2659 }
2660 this->eccmode = NAND_ECC_SOFT; 2660 if (mtd->oobblock >= this->ecc.size)
2661 this->calculate_ecc = nand_calculate_ecc; 2661 break;
2662 this->correct_data = nand_correct_data; 2662 printk(KERN_WARNING "%d byte HW ECC not possible on "
2663 } else 2663 "%d byte page size, fallback to SW ECC\n",
2664 this->eccsize = 2048; 2664 this->ecc.size, mtd->oobblock);
2665 break; 2665 this->ecc.mode = NAND_ECC_SOFT;
2666
2667 case NAND_ECC_HW3_512:
2668 case NAND_ECC_HW6_512:
2669 case NAND_ECC_HW8_512:
2670 if (mtd->oobblock == 256) {
2671 printk(KERN_WARNING "512 byte HW ECC not possible on "
2672 "256 Byte pagesize, fallback to SW ECC \n");
2673 this->eccmode = NAND_ECC_SOFT;
2674 this->calculate_ecc = nand_calculate_ecc;
2675 this->correct_data = nand_correct_data;
2676 } else
2677 this->eccsize = 512; /* set eccsize to 512 */
2678 break;
2679 2666
2680 case NAND_ECC_HW3_256: 2667 case NAND_ECC_SOFT:
2668 this->ecc.calculate = nand_calculate_ecc;
2669 this->ecc.correct = nand_correct_data;
2670 this->ecc.size = 256;
2671 this->ecc.bytes = 3;
2681 break; 2672 break;
2682 2673
2683 case NAND_ECC_NONE: 2674 case NAND_ECC_NONE:
2684 printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. " 2675 printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
2685 "This is not recommended !!\n"); 2676 "This is not recommended !!\n");
2686 this->eccmode = NAND_ECC_NONE; 2677 this->ecc.size = mtd->oobblock;
2678 this->ecc.bytes = 0;
2687 break; 2679 break;
2688
2689 case NAND_ECC_SOFT:
2690 this->calculate_ecc = nand_calculate_ecc;
2691 this->correct_data = nand_correct_data;
2692 break;
2693
2694 default: 2680 default:
2695 printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n", 2681 printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",
2696 this->eccmode); 2682 this->ecc.mode);
2697 BUG();
2698 }
2699
2700 /*
2701 * Check hardware ecc function availability and adjust number of ecc
2702 * bytes per calculation step
2703 */
2704 switch (this->eccmode) {
2705 case NAND_ECC_HW12_2048:
2706 this->eccbytes += 4;
2707 case NAND_ECC_HW8_512:
2708 this->eccbytes += 2;
2709 case NAND_ECC_HW6_512:
2710 this->eccbytes += 3;
2711 case NAND_ECC_HW3_512:
2712 case NAND_ECC_HW3_256:
2713 if (this->calculate_ecc && this->correct_data &&
2714 this->enable_hwecc)
2715 break;
2716 printk(KERN_WARNING "No ECC functions supplied, "
2717 "Hardware ECC not possible\n");
2718 BUG(); 2683 BUG();
2719 } 2684 }
2720 2685
2721 mtd->eccsize = this->eccsize;
2722
2723 /* 2686 /*
2724 * Set the number of read / write steps for one page depending on ECC 2687 * Set the number of read / write steps for one page depending on ECC
2725 * mode 2688 * mode
2726 */ 2689 */
2727 switch (this->eccmode) { 2690 this->ecc.steps = mtd->oobblock / this->ecc.size;
2728 case NAND_ECC_HW12_2048: 2691 if(this->ecc.steps * this->ecc.size != mtd->oobblock) {
2729 this->eccsteps = mtd->oobblock / 2048; 2692 printk(KERN_WARNING "Invalid ecc parameters\n");
2730 break; 2693 BUG();
2731 case NAND_ECC_HW3_512:
2732 case NAND_ECC_HW6_512:
2733 case NAND_ECC_HW8_512:
2734 this->eccsteps = mtd->oobblock / 512;
2735 break;
2736 case NAND_ECC_HW3_256:
2737 case NAND_ECC_SOFT:
2738 this->eccsteps = mtd->oobblock / 256;
2739 break;
2740
2741 case NAND_ECC_NONE:
2742 this->eccsteps = 1;
2743 break;
2744 } 2694 }
2745 2695
2746 /* Initialize state, waitqueue and spinlock */ 2696 /* Initialize state, waitqueue and spinlock */