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 | } |
