diff options
Diffstat (limited to 'drivers/mtd/nand/bf5xx_nand.c')
-rw-r--r-- | drivers/mtd/nand/bf5xx_nand.c | 117 |
1 files changed, 72 insertions, 45 deletions
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index 2974995e194d..a382e3dd0a5d 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c | |||
@@ -20,9 +20,6 @@ | |||
20 | * - DMA supported in ECC_HW | 20 | * - DMA supported in ECC_HW |
21 | * - YAFFS tested as rootfs in both ECC_HW and ECC_SW | 21 | * - YAFFS tested as rootfs in both ECC_HW and ECC_SW |
22 | * | 22 | * |
23 | * TODO: | ||
24 | * Enable JFFS2 over NAND as rootfs | ||
25 | * | ||
26 | * This program is free software; you can redistribute it and/or modify | 23 | * This program is free software; you can redistribute it and/or modify |
27 | * it under the terms of the GNU General Public License as published by | 24 | * it under the terms of the GNU General Public License as published by |
28 | * the Free Software Foundation; either version 2 of the License, or | 25 | * the Free Software Foundation; either version 2 of the License, or |
@@ -206,7 +203,7 @@ static void bf5xx_nand_hwcontrol(struct mtd_info *mtd, int cmd, | |||
206 | 203 | ||
207 | if (ctrl & NAND_CLE) | 204 | if (ctrl & NAND_CLE) |
208 | bfin_write_NFC_CMD(cmd); | 205 | bfin_write_NFC_CMD(cmd); |
209 | else | 206 | else if (ctrl & NAND_ALE) |
210 | bfin_write_NFC_ADDR(cmd); | 207 | bfin_write_NFC_ADDR(cmd); |
211 | SSYNC(); | 208 | SSYNC(); |
212 | } | 209 | } |
@@ -218,9 +215,9 @@ static void bf5xx_nand_hwcontrol(struct mtd_info *mtd, int cmd, | |||
218 | */ | 215 | */ |
219 | static int bf5xx_nand_devready(struct mtd_info *mtd) | 216 | static int bf5xx_nand_devready(struct mtd_info *mtd) |
220 | { | 217 | { |
221 | unsigned short val = bfin_read_NFC_IRQSTAT(); | 218 | unsigned short val = bfin_read_NFC_STAT(); |
222 | 219 | ||
223 | if ((val & NBUSYIRQ) == NBUSYIRQ) | 220 | if ((val & NBUSY) == NBUSY) |
224 | return 1; | 221 | return 1; |
225 | else | 222 | else |
226 | return 0; | 223 | return 0; |
@@ -317,18 +314,16 @@ static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat, | |||
317 | static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat, | 314 | static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat, |
318 | u_char *read_ecc, u_char *calc_ecc) | 315 | u_char *read_ecc, u_char *calc_ecc) |
319 | { | 316 | { |
320 | struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); | 317 | struct nand_chip *chip = mtd->priv; |
321 | struct bf5xx_nand_platform *plat = info->platform; | ||
322 | unsigned short page_size = (plat->page_size ? 512 : 256); | ||
323 | int ret; | 318 | int ret; |
324 | 319 | ||
325 | ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc); | 320 | ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc); |
326 | 321 | ||
327 | /* If page size is 512, correct second 256 bytes */ | 322 | /* If ecc size is 512, correct second 256 bytes */ |
328 | if (page_size == 512) { | 323 | if (chip->ecc.size == 512) { |
329 | dat += 256; | 324 | dat += 256; |
330 | read_ecc += 8; | 325 | read_ecc += 3; |
331 | calc_ecc += 8; | 326 | calc_ecc += 3; |
332 | ret |= bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc); | 327 | ret |= bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc); |
333 | } | 328 | } |
334 | 329 | ||
@@ -344,13 +339,12 @@ static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd, | |||
344 | const u_char *dat, u_char *ecc_code) | 339 | const u_char *dat, u_char *ecc_code) |
345 | { | 340 | { |
346 | struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); | 341 | struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); |
347 | struct bf5xx_nand_platform *plat = info->platform; | 342 | struct nand_chip *chip = mtd->priv; |
348 | u16 page_size = (plat->page_size ? 512 : 256); | ||
349 | u16 ecc0, ecc1; | 343 | u16 ecc0, ecc1; |
350 | u32 code[2]; | 344 | u32 code[2]; |
351 | u8 *p; | 345 | u8 *p; |
352 | 346 | ||
353 | /* first 4 bytes ECC code for 256 page size */ | 347 | /* first 3 bytes ECC code for 256 page size */ |
354 | ecc0 = bfin_read_NFC_ECC0(); | 348 | ecc0 = bfin_read_NFC_ECC0(); |
355 | ecc1 = bfin_read_NFC_ECC1(); | 349 | ecc1 = bfin_read_NFC_ECC1(); |
356 | 350 | ||
@@ -358,12 +352,11 @@ static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd, | |||
358 | 352 | ||
359 | dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]); | 353 | dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]); |
360 | 354 | ||
361 | /* first 3 bytes in ecc_code for 256 page size */ | ||
362 | p = (u8 *) code; | 355 | p = (u8 *) code; |
363 | memcpy(ecc_code, p, 3); | 356 | memcpy(ecc_code, p, 3); |
364 | 357 | ||
365 | /* second 4 bytes ECC code for 512 page size */ | 358 | /* second 3 bytes ECC code for 512 ecc size */ |
366 | if (page_size == 512) { | 359 | if (chip->ecc.size == 512) { |
367 | ecc0 = bfin_read_NFC_ECC2(); | 360 | ecc0 = bfin_read_NFC_ECC2(); |
368 | ecc1 = bfin_read_NFC_ECC3(); | 361 | ecc1 = bfin_read_NFC_ECC3(); |
369 | code[1] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11); | 362 | code[1] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11); |
@@ -483,8 +476,7 @@ static void bf5xx_nand_dma_rw(struct mtd_info *mtd, | |||
483 | uint8_t *buf, int is_read) | 476 | uint8_t *buf, int is_read) |
484 | { | 477 | { |
485 | struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); | 478 | struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); |
486 | struct bf5xx_nand_platform *plat = info->platform; | 479 | struct nand_chip *chip = mtd->priv; |
487 | unsigned short page_size = (plat->page_size ? 512 : 256); | ||
488 | unsigned short val; | 480 | unsigned short val; |
489 | 481 | ||
490 | dev_dbg(info->device, " mtd->%p, buf->%p, is_read %d\n", | 482 | dev_dbg(info->device, " mtd->%p, buf->%p, is_read %d\n", |
@@ -498,10 +490,10 @@ static void bf5xx_nand_dma_rw(struct mtd_info *mtd, | |||
498 | */ | 490 | */ |
499 | if (is_read) | 491 | if (is_read) |
500 | invalidate_dcache_range((unsigned int)buf, | 492 | invalidate_dcache_range((unsigned int)buf, |
501 | (unsigned int)(buf + page_size)); | 493 | (unsigned int)(buf + chip->ecc.size)); |
502 | else | 494 | else |
503 | flush_dcache_range((unsigned int)buf, | 495 | flush_dcache_range((unsigned int)buf, |
504 | (unsigned int)(buf + page_size)); | 496 | (unsigned int)(buf + chip->ecc.size)); |
505 | 497 | ||
506 | /* | 498 | /* |
507 | * This register must be written before each page is | 499 | * This register must be written before each page is |
@@ -510,6 +502,8 @@ static void bf5xx_nand_dma_rw(struct mtd_info *mtd, | |||
510 | */ | 502 | */ |
511 | bfin_write_NFC_RST(ECC_RST); | 503 | bfin_write_NFC_RST(ECC_RST); |
512 | SSYNC(); | 504 | SSYNC(); |
505 | while (bfin_read_NFC_RST() & ECC_RST) | ||
506 | cpu_relax(); | ||
513 | 507 | ||
514 | disable_dma(CH_NFC); | 508 | disable_dma(CH_NFC); |
515 | clear_dma_irqstat(CH_NFC); | 509 | clear_dma_irqstat(CH_NFC); |
@@ -520,13 +514,13 @@ static void bf5xx_nand_dma_rw(struct mtd_info *mtd, | |||
520 | 514 | ||
521 | /* The DMAs have different size on BF52x and BF54x */ | 515 | /* The DMAs have different size on BF52x and BF54x */ |
522 | #ifdef CONFIG_BF52x | 516 | #ifdef CONFIG_BF52x |
523 | set_dma_x_count(CH_NFC, (page_size >> 1)); | 517 | set_dma_x_count(CH_NFC, (chip->ecc.size >> 1)); |
524 | set_dma_x_modify(CH_NFC, 2); | 518 | set_dma_x_modify(CH_NFC, 2); |
525 | val = DI_EN | WDSIZE_16; | 519 | val = DI_EN | WDSIZE_16; |
526 | #endif | 520 | #endif |
527 | 521 | ||
528 | #ifdef CONFIG_BF54x | 522 | #ifdef CONFIG_BF54x |
529 | set_dma_x_count(CH_NFC, (page_size >> 2)); | 523 | set_dma_x_count(CH_NFC, (chip->ecc.size >> 2)); |
530 | set_dma_x_modify(CH_NFC, 4); | 524 | set_dma_x_modify(CH_NFC, 4); |
531 | val = DI_EN | WDSIZE_32; | 525 | val = DI_EN | WDSIZE_32; |
532 | #endif | 526 | #endif |
@@ -548,12 +542,11 @@ static void bf5xx_nand_dma_read_buf(struct mtd_info *mtd, | |||
548 | uint8_t *buf, int len) | 542 | uint8_t *buf, int len) |
549 | { | 543 | { |
550 | struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); | 544 | struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); |
551 | struct bf5xx_nand_platform *plat = info->platform; | 545 | struct nand_chip *chip = mtd->priv; |
552 | unsigned short page_size = (plat->page_size ? 512 : 256); | ||
553 | 546 | ||
554 | dev_dbg(info->device, "mtd->%p, buf->%p, int %d\n", mtd, buf, len); | 547 | dev_dbg(info->device, "mtd->%p, buf->%p, int %d\n", mtd, buf, len); |
555 | 548 | ||
556 | if (len == page_size) | 549 | if (len == chip->ecc.size) |
557 | bf5xx_nand_dma_rw(mtd, buf, 1); | 550 | bf5xx_nand_dma_rw(mtd, buf, 1); |
558 | else | 551 | else |
559 | bf5xx_nand_read_buf(mtd, buf, len); | 552 | bf5xx_nand_read_buf(mtd, buf, len); |
@@ -563,17 +556,32 @@ static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd, | |||
563 | const uint8_t *buf, int len) | 556 | const uint8_t *buf, int len) |
564 | { | 557 | { |
565 | struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); | 558 | struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); |
566 | struct bf5xx_nand_platform *plat = info->platform; | 559 | struct nand_chip *chip = mtd->priv; |
567 | unsigned short page_size = (plat->page_size ? 512 : 256); | ||
568 | 560 | ||
569 | dev_dbg(info->device, "mtd->%p, buf->%p, len %d\n", mtd, buf, len); | 561 | dev_dbg(info->device, "mtd->%p, buf->%p, len %d\n", mtd, buf, len); |
570 | 562 | ||
571 | if (len == page_size) | 563 | if (len == chip->ecc.size) |
572 | bf5xx_nand_dma_rw(mtd, (uint8_t *)buf, 0); | 564 | bf5xx_nand_dma_rw(mtd, (uint8_t *)buf, 0); |
573 | else | 565 | else |
574 | bf5xx_nand_write_buf(mtd, buf, len); | 566 | bf5xx_nand_write_buf(mtd, buf, len); |
575 | } | 567 | } |
576 | 568 | ||
569 | static int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, | ||
570 | uint8_t *buf, int page) | ||
571 | { | ||
572 | bf5xx_nand_read_buf(mtd, buf, mtd->writesize); | ||
573 | bf5xx_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
574 | |||
575 | return 0; | ||
576 | } | ||
577 | |||
578 | static void bf5xx_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, | ||
579 | const uint8_t *buf) | ||
580 | { | ||
581 | bf5xx_nand_write_buf(mtd, buf, mtd->writesize); | ||
582 | bf5xx_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
583 | } | ||
584 | |||
577 | /* | 585 | /* |
578 | * System initialization functions | 586 | * System initialization functions |
579 | */ | 587 | */ |
@@ -627,15 +635,14 @@ static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info) | |||
627 | 635 | ||
628 | /* setup NFC_CTL register */ | 636 | /* setup NFC_CTL register */ |
629 | dev_info(info->device, | 637 | dev_info(info->device, |
630 | "page_size=%d, data_width=%d, wr_dly=%d, rd_dly=%d\n", | 638 | "data_width=%d, wr_dly=%d, rd_dly=%d\n", |
631 | (plat->page_size ? 512 : 256), | ||
632 | (plat->data_width ? 16 : 8), | 639 | (plat->data_width ? 16 : 8), |
633 | plat->wr_dly, plat->rd_dly); | 640 | plat->wr_dly, plat->rd_dly); |
634 | 641 | ||
635 | val = (plat->page_size << NFC_PG_SIZE_OFFSET) | | 642 | val = (1 << NFC_PG_SIZE_OFFSET) | |
636 | (plat->data_width << NFC_NWIDTH_OFFSET) | | 643 | (plat->data_width << NFC_NWIDTH_OFFSET) | |
637 | (plat->rd_dly << NFC_RDDLY_OFFSET) | | 644 | (plat->rd_dly << NFC_RDDLY_OFFSET) | |
638 | (plat->rd_dly << NFC_WRDLY_OFFSET); | 645 | (plat->wr_dly << NFC_WRDLY_OFFSET); |
639 | dev_dbg(info->device, "NFC_CTL is 0x%04x\n", val); | 646 | dev_dbg(info->device, "NFC_CTL is 0x%04x\n", val); |
640 | 647 | ||
641 | bfin_write_NFC_CTL(val); | 648 | bfin_write_NFC_CTL(val); |
@@ -698,6 +705,33 @@ static int __devexit bf5xx_nand_remove(struct platform_device *pdev) | |||
698 | return 0; | 705 | return 0; |
699 | } | 706 | } |
700 | 707 | ||
708 | static int bf5xx_nand_scan(struct mtd_info *mtd) | ||
709 | { | ||
710 | struct nand_chip *chip = mtd->priv; | ||
711 | int ret; | ||
712 | |||
713 | ret = nand_scan_ident(mtd, 1); | ||
714 | if (ret) | ||
715 | return ret; | ||
716 | |||
717 | if (hardware_ecc) { | ||
718 | /* | ||
719 | * for nand with page size > 512B, think it as several sections with 512B | ||
720 | */ | ||
721 | if (likely(mtd->writesize >= 512)) { | ||
722 | chip->ecc.size = 512; | ||
723 | chip->ecc.bytes = 6; | ||
724 | } else { | ||
725 | chip->ecc.size = 256; | ||
726 | chip->ecc.bytes = 3; | ||
727 | bfin_write_NFC_CTL(bfin_read_NFC_CTL() & ~(1 << NFC_PG_SIZE_OFFSET)); | ||
728 | SSYNC(); | ||
729 | } | ||
730 | } | ||
731 | |||
732 | return nand_scan_tail(mtd); | ||
733 | } | ||
734 | |||
701 | /* | 735 | /* |
702 | * bf5xx_nand_probe | 736 | * bf5xx_nand_probe |
703 | * | 737 | * |
@@ -783,27 +817,20 @@ static int __devinit bf5xx_nand_probe(struct platform_device *pdev) | |||
783 | chip->badblock_pattern = &bootrom_bbt; | 817 | chip->badblock_pattern = &bootrom_bbt; |
784 | chip->ecc.layout = &bootrom_ecclayout; | 818 | chip->ecc.layout = &bootrom_ecclayout; |
785 | #endif | 819 | #endif |
786 | |||
787 | if (plat->page_size == NFC_PG_SIZE_256) { | ||
788 | chip->ecc.bytes = 3; | ||
789 | chip->ecc.size = 256; | ||
790 | } else if (plat->page_size == NFC_PG_SIZE_512) { | ||
791 | chip->ecc.bytes = 6; | ||
792 | chip->ecc.size = 512; | ||
793 | } | ||
794 | |||
795 | chip->read_buf = bf5xx_nand_dma_read_buf; | 820 | chip->read_buf = bf5xx_nand_dma_read_buf; |
796 | chip->write_buf = bf5xx_nand_dma_write_buf; | 821 | chip->write_buf = bf5xx_nand_dma_write_buf; |
797 | chip->ecc.calculate = bf5xx_nand_calculate_ecc; | 822 | chip->ecc.calculate = bf5xx_nand_calculate_ecc; |
798 | chip->ecc.correct = bf5xx_nand_correct_data; | 823 | chip->ecc.correct = bf5xx_nand_correct_data; |
799 | chip->ecc.mode = NAND_ECC_HW; | 824 | chip->ecc.mode = NAND_ECC_HW; |
800 | chip->ecc.hwctl = bf5xx_nand_enable_hwecc; | 825 | chip->ecc.hwctl = bf5xx_nand_enable_hwecc; |
826 | chip->ecc.read_page_raw = bf5xx_nand_read_page_raw; | ||
827 | chip->ecc.write_page_raw = bf5xx_nand_write_page_raw; | ||
801 | } else { | 828 | } else { |
802 | chip->ecc.mode = NAND_ECC_SOFT; | 829 | chip->ecc.mode = NAND_ECC_SOFT; |
803 | } | 830 | } |
804 | 831 | ||
805 | /* scan hardware nand chip and setup mtd info data struct */ | 832 | /* scan hardware nand chip and setup mtd info data struct */ |
806 | if (nand_scan(mtd, 1)) { | 833 | if (bf5xx_nand_scan(mtd)) { |
807 | err = -ENXIO; | 834 | err = -ENXIO; |
808 | goto out_err_nand_scan; | 835 | goto out_err_nand_scan; |
809 | } | 836 | } |