diff options
Diffstat (limited to 'drivers/mtd/nand/rtc_from4.c')
-rw-r--r-- | drivers/mtd/nand/rtc_from4.c | 140 |
1 files changed, 132 insertions, 8 deletions
diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index 02305a2adca7..031051cbde76 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * Derived from drivers/mtd/nand/spia.c | 6 | * Derived from drivers/mtd/nand/spia.c |
7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) | 7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) |
8 | * | 8 | * |
9 | * $Id: rtc_from4.c,v 1.7 2004/11/04 12:53:10 gleixner Exp $ | 9 | * $Id: rtc_from4.c,v 1.9 2005/01/24 20:40:11 dmarlin Exp $ |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
@@ -83,13 +83,18 @@ static struct mtd_info *rtc_from4_mtd = NULL; | |||
83 | #define RTC_FROM4_RS_ECC_CHK (RTC_FROM4_NAND_ADDR_FPGA | 0x00000070) | 83 | #define RTC_FROM4_RS_ECC_CHK (RTC_FROM4_NAND_ADDR_FPGA | 0x00000070) |
84 | #define RTC_FROM4_RS_ECC_CHK_ERROR (1 << 7) | 84 | #define RTC_FROM4_RS_ECC_CHK_ERROR (1 << 7) |
85 | 85 | ||
86 | #define ERR_STAT_ECC_AVAILABLE 0x20 | ||
87 | |||
86 | /* Undefine for software ECC */ | 88 | /* Undefine for software ECC */ |
87 | #define RTC_FROM4_HWECC 1 | 89 | #define RTC_FROM4_HWECC 1 |
88 | 90 | ||
91 | /* Define as 1 for no virtual erase blocks (in JFFS2) */ | ||
92 | #define RTC_FROM4_NO_VIRTBLOCKS 0 | ||
93 | |||
89 | /* | 94 | /* |
90 | * Module stuff | 95 | * Module stuff |
91 | */ | 96 | */ |
92 | static void __iomem *rtc_from4_fio_base = P2SEGADDR(RTC_FROM4_FIO_BASE); | 97 | static void __iomem *rtc_from4_fio_base = (void *)P2SEGADDR(RTC_FROM4_FIO_BASE); |
93 | 98 | ||
94 | const static struct mtd_partition partition_info[] = { | 99 | const static struct mtd_partition partition_info[] = { |
95 | { | 100 | { |
@@ -267,7 +272,6 @@ static void rtc_from4_nand_select_chip(struct mtd_info *mtd, int chip) | |||
267 | } | 272 | } |
268 | 273 | ||
269 | 274 | ||
270 | |||
271 | /* | 275 | /* |
272 | * rtc_from4_nand_device_ready - hardware specific ready/busy check | 276 | * rtc_from4_nand_device_ready - hardware specific ready/busy check |
273 | * @mtd: MTD device structure | 277 | * @mtd: MTD device structure |
@@ -286,6 +290,40 @@ static int rtc_from4_nand_device_ready(struct mtd_info *mtd) | |||
286 | 290 | ||
287 | } | 291 | } |
288 | 292 | ||
293 | |||
294 | /* | ||
295 | * deplete - code to perform device recovery in case there was a power loss | ||
296 | * @mtd: MTD device structure | ||
297 | * @chip: Chip to select (0 == slot 3, 1 == slot 4) | ||
298 | * | ||
299 | * If there was a sudden loss of power during an erase operation, a | ||
300 | * "device recovery" operation must be performed when power is restored | ||
301 | * to ensure correct operation. This routine performs the required steps | ||
302 | * for the requested chip. | ||
303 | * | ||
304 | * See page 86 of the data sheet for details. | ||
305 | * | ||
306 | */ | ||
307 | static void deplete(struct mtd_info *mtd, int chip) | ||
308 | { | ||
309 | struct nand_chip *this = mtd->priv; | ||
310 | |||
311 | /* wait until device is ready */ | ||
312 | while (!this->dev_ready(mtd)); | ||
313 | |||
314 | this->select_chip(mtd, chip); | ||
315 | |||
316 | /* Send the commands for device recovery, phase 1 */ | ||
317 | this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0000); | ||
318 | this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1); | ||
319 | |||
320 | /* Send the commands for device recovery, phase 2 */ | ||
321 | this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0004); | ||
322 | this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1); | ||
323 | |||
324 | } | ||
325 | |||
326 | |||
289 | #ifdef RTC_FROM4_HWECC | 327 | #ifdef RTC_FROM4_HWECC |
290 | /* | 328 | /* |
291 | * rtc_from4_enable_hwecc - hardware specific hardware ECC enable function | 329 | * rtc_from4_enable_hwecc - hardware specific hardware ECC enable function |
@@ -329,6 +367,7 @@ static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode) | |||
329 | 367 | ||
330 | } | 368 | } |
331 | 369 | ||
370 | |||
332 | /* | 371 | /* |
333 | * rtc_from4_calculate_ecc - hardware specific code to read ECC code | 372 | * rtc_from4_calculate_ecc - hardware specific code to read ECC code |
334 | * @mtd: MTD device structure | 373 | * @mtd: MTD device structure |
@@ -356,6 +395,7 @@ static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_c | |||
356 | ecc_code[7] |= 0x0f; /* set the last four bits (not used) */ | 395 | ecc_code[7] |= 0x0f; /* set the last four bits (not used) */ |
357 | } | 396 | } |
358 | 397 | ||
398 | |||
359 | /* | 399 | /* |
360 | * rtc_from4_correct_data - hardware specific code to correct data using ECC code | 400 | * rtc_from4_correct_data - hardware specific code to correct data using ECC code |
361 | * @mtd: MTD device structure | 401 | * @mtd: MTD device structure |
@@ -365,16 +405,14 @@ static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_c | |||
365 | * | 405 | * |
366 | * The FPGA tells us fast, if there's an error or not. If no, we go back happy | 406 | * The FPGA tells us fast, if there's an error or not. If no, we go back happy |
367 | * else we read the ecc results from the fpga and call the rs library to decode | 407 | * else we read the ecc results from the fpga and call the rs library to decode |
368 | * and hopefully correct the error | 408 | * and hopefully correct the error. |
369 | * | 409 | * |
370 | * For now I use the code, which we read from the FLASH to use the RS lib, | ||
371 | * as the syndrom conversion has a unresolved issue. | ||
372 | */ | 410 | */ |
373 | static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_char *ecc1, u_char *ecc2) | 411 | static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_char *ecc1, u_char *ecc2) |
374 | { | 412 | { |
375 | int i, j, res; | 413 | int i, j, res; |
376 | unsigned short status; | 414 | unsigned short status; |
377 | uint16_t par[6], syn[6], tmp; | 415 | uint16_t par[6], syn[6]; |
378 | uint8_t ecc[8]; | 416 | uint8_t ecc[8]; |
379 | volatile unsigned short *rs_ecc; | 417 | volatile unsigned short *rs_ecc; |
380 | 418 | ||
@@ -416,15 +454,86 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha | |||
416 | } | 454 | } |
417 | 455 | ||
418 | /* Let the library code do its magic.*/ | 456 | /* Let the library code do its magic.*/ |
419 | res = decode_rs8(rs_decoder, buf, par, 512, syn, 0, NULL, 0xff, NULL); | 457 | res = decode_rs8(rs_decoder, (uint8_t *)buf, par, 512, syn, 0, NULL, 0xff, NULL); |
420 | if (res > 0) { | 458 | if (res > 0) { |
421 | DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: " | 459 | DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: " |
422 | "ECC corrected %d errors on read\n", res); | 460 | "ECC corrected %d errors on read\n", res); |
423 | } | 461 | } |
424 | return res; | 462 | return res; |
425 | } | 463 | } |
464 | |||
465 | |||
466 | /** | ||
467 | * rtc_from4_errstat - perform additional error status checks | ||
468 | * @mtd: MTD device structure | ||
469 | * @this: NAND chip structure | ||
470 | * @state: state or the operation | ||
471 | * @status: status code returned from read status | ||
472 | * @page: startpage inside the chip, must be called with (page & this->pagemask) | ||
473 | * | ||
474 | * Perform additional error status checks on erase and write failures | ||
475 | * to determine if errors are correctable. For this device, correctable | ||
476 | * 1-bit errors on erase and write are considered acceptable. | ||
477 | * | ||
478 | * note: see pages 34..37 of data sheet for details. | ||
479 | * | ||
480 | */ | ||
481 | static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page) | ||
482 | { | ||
483 | int er_stat=0; | ||
484 | int rtn, retlen; | ||
485 | size_t len; | ||
486 | uint8_t *buf; | ||
487 | int i; | ||
488 | |||
489 | this->cmdfunc (mtd, NAND_CMD_STATUS_CLEAR, -1, -1); | ||
490 | |||
491 | if (state == FL_ERASING) { | ||
492 | for (i=0; i<4; i++) { | ||
493 | if (status & 1<<(i+1)) { | ||
494 | this->cmdfunc (mtd, (NAND_CMD_STATUS_ERROR + i + 1), -1, -1); | ||
495 | rtn = this->read_byte(mtd); | ||
496 | this->cmdfunc (mtd, NAND_CMD_STATUS_RESET, -1, -1); | ||
497 | if (!(rtn & ERR_STAT_ECC_AVAILABLE)) { | ||
498 | er_stat |= 1<<(i+1); /* err_ecc_not_avail */ | ||
499 | } | ||
500 | } | ||
501 | } | ||
502 | } else if (state == FL_WRITING) { | ||
503 | /* single bank write logic */ | ||
504 | this->cmdfunc (mtd, NAND_CMD_STATUS_ERROR, -1, -1); | ||
505 | rtn = this->read_byte(mtd); | ||
506 | this->cmdfunc (mtd, NAND_CMD_STATUS_RESET, -1, -1); | ||
507 | if (!(rtn & ERR_STAT_ECC_AVAILABLE)) { | ||
508 | er_stat |= 1<<1; /* err_ecc_not_avail */ | ||
509 | } else { | ||
510 | len = mtd->oobblock; | ||
511 | buf = kmalloc (len, GFP_KERNEL); | ||
512 | if (!buf) { | ||
513 | printk (KERN_ERR "rtc_from4_errstat: Out of memory!\n"); | ||
514 | er_stat = 1; /* if we can't check, assume failed */ | ||
515 | } else { | ||
516 | /* recovery read */ | ||
517 | /* page read */ | ||
518 | rtn = nand_do_read_ecc (mtd, page, len, &retlen, buf, NULL, this->autooob, 1); | ||
519 | if (rtn) { /* if read failed or > 1-bit error corrected */ | ||
520 | er_stat |= 1<<1; /* ECC read failed */ | ||
521 | } | ||
522 | kfree(buf); | ||
523 | } | ||
524 | } | ||
525 | } | ||
526 | |||
527 | rtn = status; | ||
528 | if (er_stat == 0) { /* if ECC is available */ | ||
529 | rtn = (status & ~NAND_STATUS_FAIL); /* clear the error bit */ | ||
530 | } | ||
531 | |||
532 | return rtn; | ||
533 | } | ||
426 | #endif | 534 | #endif |
427 | 535 | ||
536 | |||
428 | /* | 537 | /* |
429 | * Main initialization routine | 538 | * Main initialization routine |
430 | */ | 539 | */ |
@@ -432,6 +541,7 @@ int __init rtc_from4_init (void) | |||
432 | { | 541 | { |
433 | struct nand_chip *this; | 542 | struct nand_chip *this; |
434 | unsigned short bcr1, bcr2, wcr2; | 543 | unsigned short bcr1, bcr2, wcr2; |
544 | int i; | ||
435 | 545 | ||
436 | /* Allocate memory for MTD device structure and private data */ | 546 | /* Allocate memory for MTD device structure and private data */ |
437 | rtc_from4_mtd = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip), | 547 | rtc_from4_mtd = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip), |
@@ -483,6 +593,8 @@ int __init rtc_from4_init (void) | |||
483 | 593 | ||
484 | this->eccmode = NAND_ECC_HW8_512; | 594 | this->eccmode = NAND_ECC_HW8_512; |
485 | this->options |= NAND_HWECC_SYNDROME; | 595 | this->options |= NAND_HWECC_SYNDROME; |
596 | /* return the status of extra status and ECC checks */ | ||
597 | this->errstat = rtc_from4_errstat; | ||
486 | /* set the nand_oobinfo to support FPGA H/W error detection */ | 598 | /* set the nand_oobinfo to support FPGA H/W error detection */ |
487 | this->autooob = &rtc_from4_nand_oobinfo; | 599 | this->autooob = &rtc_from4_nand_oobinfo; |
488 | this->enable_hwecc = rtc_from4_enable_hwecc; | 600 | this->enable_hwecc = rtc_from4_enable_hwecc; |
@@ -504,6 +616,18 @@ int __init rtc_from4_init (void) | |||
504 | return -ENXIO; | 616 | return -ENXIO; |
505 | } | 617 | } |
506 | 618 | ||
619 | /* Perform 'device recovery' for each chip in case there was a power loss. */ | ||
620 | for (i=0; i < this->numchips; i++) { | ||
621 | deplete(rtc_from4_mtd, i); | ||
622 | } | ||
623 | |||
624 | #if RTC_FROM4_NO_VIRTBLOCKS | ||
625 | /* use a smaller erase block to minimize wasted space when a block is bad */ | ||
626 | /* note: this uses eight times as much RAM as using the default and makes */ | ||
627 | /* mounts take four times as long. */ | ||
628 | rtc_from4_mtd->flags |= MTD_NO_VIRTBLOCKS; | ||
629 | #endif | ||
630 | |||
507 | /* Register the partitions */ | 631 | /* Register the partitions */ |
508 | add_mtd_partitions(rtc_from4_mtd, partition_info, NUM_PARTITIONS); | 632 | add_mtd_partitions(rtc_from4_mtd, partition_info, NUM_PARTITIONS); |
509 | 633 | ||