diff options
-rw-r--r-- | arch/blackfin/include/asm/nand.h | 3 | ||||
-rw-r--r-- | drivers/mtd/nand/bf5xx_nand.c | 86 |
2 files changed, 48 insertions, 41 deletions
diff --git a/arch/blackfin/include/asm/nand.h b/arch/blackfin/include/asm/nand.h index 3a1e79dfc8d9..256c50d8d465 100644 --- a/arch/blackfin/include/asm/nand.h +++ b/arch/blackfin/include/asm/nand.h | |||
@@ -15,8 +15,6 @@ | |||
15 | * partitions = mtd partition list | 15 | * partitions = mtd partition list |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #define NFC_PG_SIZE_256 0 | ||
19 | #define NFC_PG_SIZE_512 1 | ||
20 | #define NFC_PG_SIZE_OFFSET 9 | 18 | #define NFC_PG_SIZE_OFFSET 9 |
21 | 19 | ||
22 | #define NFC_NWIDTH_8 0 | 20 | #define NFC_NWIDTH_8 0 |
@@ -30,7 +28,6 @@ | |||
30 | 28 | ||
31 | struct bf5xx_nand_platform { | 29 | struct bf5xx_nand_platform { |
32 | /* NAND chip information */ | 30 | /* NAND chip information */ |
33 | unsigned short page_size; | ||
34 | unsigned short data_width; | 31 | unsigned short data_width; |
35 | 32 | ||
36 | /* RD/WR strobe delay timing information, all times in SCLK cycles */ | 33 | /* RD/WR strobe delay timing information, all times in SCLK cycles */ |
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index 8070ff359a41..3784f4137994 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c | |||
@@ -314,18 +314,16 @@ static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat, | |||
314 | 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, |
315 | u_char *read_ecc, u_char *calc_ecc) | 315 | u_char *read_ecc, u_char *calc_ecc) |
316 | { | 316 | { |
317 | struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); | 317 | struct nand_chip *chip = mtd->priv; |
318 | struct bf5xx_nand_platform *plat = info->platform; | ||
319 | unsigned short page_size = (plat->page_size ? 512 : 256); | ||
320 | int ret; | 318 | int ret; |
321 | 319 | ||
322 | 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); |
323 | 321 | ||
324 | /* If page size is 512, correct second 256 bytes */ | 322 | /* If ecc size is 512, correct second 256 bytes */ |
325 | if (page_size == 512) { | 323 | if (chip->ecc.size == 512) { |
326 | dat += 256; | 324 | dat += 256; |
327 | read_ecc += 8; | 325 | read_ecc += 3; |
328 | calc_ecc += 8; | 326 | calc_ecc += 3; |
329 | 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); |
330 | } | 328 | } |
331 | 329 | ||
@@ -341,13 +339,12 @@ static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd, | |||
341 | const u_char *dat, u_char *ecc_code) | 339 | const u_char *dat, u_char *ecc_code) |
342 | { | 340 | { |
343 | struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); | 341 | struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); |
344 | struct bf5xx_nand_platform *plat = info->platform; | 342 | struct nand_chip *chip = mtd->priv; |
345 | u16 page_size = (plat->page_size ? 512 : 256); | ||
346 | u16 ecc0, ecc1; | 343 | u16 ecc0, ecc1; |
347 | u32 code[2]; | 344 | u32 code[2]; |
348 | u8 *p; | 345 | u8 *p; |
349 | 346 | ||
350 | /* first 4 bytes ECC code for 256 page size */ | 347 | /* first 3 bytes ECC code for 256 page size */ |
351 | ecc0 = bfin_read_NFC_ECC0(); | 348 | ecc0 = bfin_read_NFC_ECC0(); |
352 | ecc1 = bfin_read_NFC_ECC1(); | 349 | ecc1 = bfin_read_NFC_ECC1(); |
353 | 350 | ||
@@ -355,12 +352,11 @@ static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd, | |||
355 | 352 | ||
356 | dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]); | 353 | dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]); |
357 | 354 | ||
358 | /* first 3 bytes in ecc_code for 256 page size */ | ||
359 | p = (u8 *) code; | 355 | p = (u8 *) code; |
360 | memcpy(ecc_code, p, 3); | 356 | memcpy(ecc_code, p, 3); |
361 | 357 | ||
362 | /* second 4 bytes ECC code for 512 page size */ | 358 | /* second 3 bytes ECC code for 512 ecc size */ |
363 | if (page_size == 512) { | 359 | if (chip->ecc.size == 512) { |
364 | ecc0 = bfin_read_NFC_ECC2(); | 360 | ecc0 = bfin_read_NFC_ECC2(); |
365 | ecc1 = bfin_read_NFC_ECC3(); | 361 | ecc1 = bfin_read_NFC_ECC3(); |
366 | code[1] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11); | 362 | code[1] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11); |
@@ -480,8 +476,7 @@ static void bf5xx_nand_dma_rw(struct mtd_info *mtd, | |||
480 | uint8_t *buf, int is_read) | 476 | uint8_t *buf, int is_read) |
481 | { | 477 | { |
482 | struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); | 478 | struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); |
483 | struct bf5xx_nand_platform *plat = info->platform; | 479 | struct nand_chip *chip = mtd->priv; |
484 | unsigned short page_size = (plat->page_size ? 512 : 256); | ||
485 | unsigned short val; | 480 | unsigned short val; |
486 | 481 | ||
487 | 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", |
@@ -495,10 +490,10 @@ static void bf5xx_nand_dma_rw(struct mtd_info *mtd, | |||
495 | */ | 490 | */ |
496 | if (is_read) | 491 | if (is_read) |
497 | invalidate_dcache_range((unsigned int)buf, | 492 | invalidate_dcache_range((unsigned int)buf, |
498 | (unsigned int)(buf + page_size)); | 493 | (unsigned int)(buf + chip->ecc.size)); |
499 | else | 494 | else |
500 | flush_dcache_range((unsigned int)buf, | 495 | flush_dcache_range((unsigned int)buf, |
501 | (unsigned int)(buf + page_size)); | 496 | (unsigned int)(buf + chip->ecc.size)); |
502 | 497 | ||
503 | /* | 498 | /* |
504 | * This register must be written before each page is | 499 | * This register must be written before each page is |
@@ -519,13 +514,13 @@ static void bf5xx_nand_dma_rw(struct mtd_info *mtd, | |||
519 | 514 | ||
520 | /* The DMAs have different size on BF52x and BF54x */ | 515 | /* The DMAs have different size on BF52x and BF54x */ |
521 | #ifdef CONFIG_BF52x | 516 | #ifdef CONFIG_BF52x |
522 | set_dma_x_count(CH_NFC, (page_size >> 1)); | 517 | set_dma_x_count(CH_NFC, (chip->ecc.size >> 1)); |
523 | set_dma_x_modify(CH_NFC, 2); | 518 | set_dma_x_modify(CH_NFC, 2); |
524 | val = DI_EN | WDSIZE_16; | 519 | val = DI_EN | WDSIZE_16; |
525 | #endif | 520 | #endif |
526 | 521 | ||
527 | #ifdef CONFIG_BF54x | 522 | #ifdef CONFIG_BF54x |
528 | set_dma_x_count(CH_NFC, (page_size >> 2)); | 523 | set_dma_x_count(CH_NFC, (chip->ecc.size >> 2)); |
529 | set_dma_x_modify(CH_NFC, 4); | 524 | set_dma_x_modify(CH_NFC, 4); |
530 | val = DI_EN | WDSIZE_32; | 525 | val = DI_EN | WDSIZE_32; |
531 | #endif | 526 | #endif |
@@ -547,12 +542,11 @@ static void bf5xx_nand_dma_read_buf(struct mtd_info *mtd, | |||
547 | uint8_t *buf, int len) | 542 | uint8_t *buf, int len) |
548 | { | 543 | { |
549 | struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); | 544 | struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); |
550 | struct bf5xx_nand_platform *plat = info->platform; | 545 | struct nand_chip *chip = mtd->priv; |
551 | unsigned short page_size = (plat->page_size ? 512 : 256); | ||
552 | 546 | ||
553 | 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); |
554 | 548 | ||
555 | if (len == page_size) | 549 | if (len == chip->ecc.size) |
556 | bf5xx_nand_dma_rw(mtd, buf, 1); | 550 | bf5xx_nand_dma_rw(mtd, buf, 1); |
557 | else | 551 | else |
558 | bf5xx_nand_read_buf(mtd, buf, len); | 552 | bf5xx_nand_read_buf(mtd, buf, len); |
@@ -562,12 +556,11 @@ static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd, | |||
562 | const uint8_t *buf, int len) | 556 | const uint8_t *buf, int len) |
563 | { | 557 | { |
564 | struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); | 558 | struct bf5xx_nand_info *info = mtd_to_nand_info(mtd); |
565 | struct bf5xx_nand_platform *plat = info->platform; | 559 | struct nand_chip *chip = mtd->priv; |
566 | unsigned short page_size = (plat->page_size ? 512 : 256); | ||
567 | 560 | ||
568 | 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); |
569 | 562 | ||
570 | if (len == page_size) | 563 | if (len == chip->ecc.size) |
571 | bf5xx_nand_dma_rw(mtd, (uint8_t *)buf, 0); | 564 | bf5xx_nand_dma_rw(mtd, (uint8_t *)buf, 0); |
572 | else | 565 | else |
573 | bf5xx_nand_write_buf(mtd, buf, len); | 566 | bf5xx_nand_write_buf(mtd, buf, len); |
@@ -642,12 +635,11 @@ static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info) | |||
642 | 635 | ||
643 | /* setup NFC_CTL register */ | 636 | /* setup NFC_CTL register */ |
644 | dev_info(info->device, | 637 | dev_info(info->device, |
645 | "page_size=%d, data_width=%d, wr_dly=%d, rd_dly=%d\n", | 638 | "data_width=%d, wr_dly=%d, rd_dly=%d\n", |
646 | (plat->page_size ? 512 : 256), | ||
647 | (plat->data_width ? 16 : 8), | 639 | (plat->data_width ? 16 : 8), |
648 | plat->wr_dly, plat->rd_dly); | 640 | plat->wr_dly, plat->rd_dly); |
649 | 641 | ||
650 | val = (plat->page_size << NFC_PG_SIZE_OFFSET) | | 642 | val = (1 << NFC_PG_SIZE_OFFSET) | |
651 | (plat->data_width << NFC_NWIDTH_OFFSET) | | 643 | (plat->data_width << NFC_NWIDTH_OFFSET) | |
652 | (plat->rd_dly << NFC_RDDLY_OFFSET) | | 644 | (plat->rd_dly << NFC_RDDLY_OFFSET) | |
653 | (plat->wr_dly << NFC_WRDLY_OFFSET); | 645 | (plat->wr_dly << NFC_WRDLY_OFFSET); |
@@ -713,6 +705,33 @@ static int __devexit bf5xx_nand_remove(struct platform_device *pdev) | |||
713 | return 0; | 705 | return 0; |
714 | } | 706 | } |
715 | 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 | |||
716 | /* | 735 | /* |
717 | * bf5xx_nand_probe | 736 | * bf5xx_nand_probe |
718 | * | 737 | * |
@@ -798,15 +817,6 @@ static int __devinit bf5xx_nand_probe(struct platform_device *pdev) | |||
798 | chip->badblock_pattern = &bootrom_bbt; | 817 | chip->badblock_pattern = &bootrom_bbt; |
799 | chip->ecc.layout = &bootrom_ecclayout; | 818 | chip->ecc.layout = &bootrom_ecclayout; |
800 | #endif | 819 | #endif |
801 | |||
802 | if (plat->page_size == NFC_PG_SIZE_256) { | ||
803 | chip->ecc.bytes = 3; | ||
804 | chip->ecc.size = 256; | ||
805 | } else if (plat->page_size == NFC_PG_SIZE_512) { | ||
806 | chip->ecc.bytes = 6; | ||
807 | chip->ecc.size = 512; | ||
808 | } | ||
809 | |||
810 | chip->read_buf = bf5xx_nand_dma_read_buf; | 820 | chip->read_buf = bf5xx_nand_dma_read_buf; |
811 | chip->write_buf = bf5xx_nand_dma_write_buf; | 821 | chip->write_buf = bf5xx_nand_dma_write_buf; |
812 | chip->ecc.calculate = bf5xx_nand_calculate_ecc; | 822 | chip->ecc.calculate = bf5xx_nand_calculate_ecc; |
@@ -820,7 +830,7 @@ static int __devinit bf5xx_nand_probe(struct platform_device *pdev) | |||
820 | } | 830 | } |
821 | 831 | ||
822 | /* scan hardware nand chip and setup mtd info data struct */ | 832 | /* scan hardware nand chip and setup mtd info data struct */ |
823 | if (nand_scan(mtd, 1)) { | 833 | if (bf5xx_nand_scan(mtd)) { |
824 | err = -ENXIO; | 834 | err = -ENXIO; |
825 | goto out_err_nand_scan; | 835 | goto out_err_nand_scan; |
826 | } | 836 | } |