diff options
author | Barry Song <barry.song@analog.com> | 2010-08-05 11:07:43 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2010-08-05 11:14:38 -0400 |
commit | 44299179c0e87cc6d8b753c1ca8c97b1cf9340e1 (patch) | |
tree | 32937511cd59cb954164422376d4fd364f7b02b6 /drivers/mtd/nand/bf5xx_nand.c | |
parent | 752b957a37ee1cc09fccb39a8bc5843edf32119b (diff) |
mtd: Blackfin NFC: fix handling of page sizes
Rather than forcing the platform resources to declare the desired page
size, simply use the existing information passed down to us by the higher
layers. This way we work out of the box with all flash chips that the
kernel knows about.
Signed-off-by: Barry Song <barry.song@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/nand/bf5xx_nand.c')
-rw-r--r-- | drivers/mtd/nand/bf5xx_nand.c | 86 |
1 files changed, 48 insertions, 38 deletions
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 | } |