aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorBarry Song <barry.song@analog.com>2010-08-05 11:07:43 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2010-08-05 11:14:38 -0400
commit44299179c0e87cc6d8b753c1ca8c97b1cf9340e1 (patch)
tree32937511cd59cb954164422376d4fd364f7b02b6 /drivers/mtd
parent752b957a37ee1cc09fccb39a8bc5843edf32119b (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')
-rw-r--r--drivers/mtd/nand/bf5xx_nand.c86
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,
314static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat, 314static 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
708static 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 }