diff options
Diffstat (limited to 'drivers/mtd/nand/bf5xx_nand.c')
-rw-r--r-- | drivers/mtd/nand/bf5xx_nand.c | 93 |
1 files changed, 71 insertions, 22 deletions
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index e87a57297328..9af2a2cc1153 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c | |||
@@ -91,6 +91,41 @@ static const unsigned short bfin_nfc_pin_req[] = | |||
91 | P_NAND_ALE, | 91 | P_NAND_ALE, |
92 | 0}; | 92 | 0}; |
93 | 93 | ||
94 | #ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC | ||
95 | static uint8_t bbt_pattern[] = { 0xff }; | ||
96 | |||
97 | static struct nand_bbt_descr bootrom_bbt = { | ||
98 | .options = 0, | ||
99 | .offs = 63, | ||
100 | .len = 1, | ||
101 | .pattern = bbt_pattern, | ||
102 | }; | ||
103 | |||
104 | static struct nand_ecclayout bootrom_ecclayout = { | ||
105 | .eccbytes = 24, | ||
106 | .eccpos = { | ||
107 | 0x8 * 0, 0x8 * 0 + 1, 0x8 * 0 + 2, | ||
108 | 0x8 * 1, 0x8 * 1 + 1, 0x8 * 1 + 2, | ||
109 | 0x8 * 2, 0x8 * 2 + 1, 0x8 * 2 + 2, | ||
110 | 0x8 * 3, 0x8 * 3 + 1, 0x8 * 3 + 2, | ||
111 | 0x8 * 4, 0x8 * 4 + 1, 0x8 * 4 + 2, | ||
112 | 0x8 * 5, 0x8 * 5 + 1, 0x8 * 5 + 2, | ||
113 | 0x8 * 6, 0x8 * 6 + 1, 0x8 * 6 + 2, | ||
114 | 0x8 * 7, 0x8 * 7 + 1, 0x8 * 7 + 2 | ||
115 | }, | ||
116 | .oobfree = { | ||
117 | { 0x8 * 0 + 3, 5 }, | ||
118 | { 0x8 * 1 + 3, 5 }, | ||
119 | { 0x8 * 2 + 3, 5 }, | ||
120 | { 0x8 * 3 + 3, 5 }, | ||
121 | { 0x8 * 4 + 3, 5 }, | ||
122 | { 0x8 * 5 + 3, 5 }, | ||
123 | { 0x8 * 6 + 3, 5 }, | ||
124 | { 0x8 * 7 + 3, 5 }, | ||
125 | } | ||
126 | }; | ||
127 | #endif | ||
128 | |||
94 | /* | 129 | /* |
95 | * Data structures for bf5xx nand flash controller driver | 130 | * Data structures for bf5xx nand flash controller driver |
96 | */ | 131 | */ |
@@ -273,7 +308,7 @@ static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat, | |||
273 | dat += 256; | 308 | dat += 256; |
274 | read_ecc += 8; | 309 | read_ecc += 8; |
275 | calc_ecc += 8; | 310 | calc_ecc += 8; |
276 | ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc); | 311 | ret |= bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc); |
277 | } | 312 | } |
278 | 313 | ||
279 | return ret; | 314 | return ret; |
@@ -298,7 +333,7 @@ static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd, | |||
298 | ecc0 = bfin_read_NFC_ECC0(); | 333 | ecc0 = bfin_read_NFC_ECC0(); |
299 | ecc1 = bfin_read_NFC_ECC1(); | 334 | ecc1 = bfin_read_NFC_ECC1(); |
300 | 335 | ||
301 | code[0] = (ecc0 & 0x3FF) | ((ecc1 & 0x3FF) << 11); | 336 | code[0] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11); |
302 | 337 | ||
303 | dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]); | 338 | dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]); |
304 | 339 | ||
@@ -310,7 +345,7 @@ static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd, | |||
310 | if (page_size == 512) { | 345 | if (page_size == 512) { |
311 | ecc0 = bfin_read_NFC_ECC2(); | 346 | ecc0 = bfin_read_NFC_ECC2(); |
312 | ecc1 = bfin_read_NFC_ECC3(); | 347 | ecc1 = bfin_read_NFC_ECC3(); |
313 | code[1] = (ecc0 & 0x3FF) | ((ecc1 & 0x3FF) << 11); | 348 | code[1] = (ecc0 & 0x7ff) | ((ecc1 & 0x7ff) << 11); |
314 | 349 | ||
315 | /* second 3 bytes in ecc_code for second 256 | 350 | /* second 3 bytes in ecc_code for second 256 |
316 | * bytes of 512 page size | 351 | * bytes of 512 page size |
@@ -514,7 +549,6 @@ static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd, | |||
514 | /* | 549 | /* |
515 | * System initialization functions | 550 | * System initialization functions |
516 | */ | 551 | */ |
517 | |||
518 | static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info) | 552 | static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info) |
519 | { | 553 | { |
520 | int ret; | 554 | int ret; |
@@ -547,6 +581,13 @@ static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info) | |||
547 | return 0; | 581 | return 0; |
548 | } | 582 | } |
549 | 583 | ||
584 | static void bf5xx_nand_dma_remove(struct bf5xx_nand_info *info) | ||
585 | { | ||
586 | /* Free NFC DMA channel */ | ||
587 | if (hardware_ecc) | ||
588 | free_dma(CH_NFC); | ||
589 | } | ||
590 | |||
550 | /* | 591 | /* |
551 | * BF5XX NFC hardware initialization | 592 | * BF5XX NFC hardware initialization |
552 | * - pin mux setup | 593 | * - pin mux setup |
@@ -605,7 +646,7 @@ static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info) | |||
605 | #endif | 646 | #endif |
606 | } | 647 | } |
607 | 648 | ||
608 | static int bf5xx_nand_remove(struct platform_device *pdev) | 649 | static int __devexit bf5xx_nand_remove(struct platform_device *pdev) |
609 | { | 650 | { |
610 | struct bf5xx_nand_info *info = to_nand_info(pdev); | 651 | struct bf5xx_nand_info *info = to_nand_info(pdev); |
611 | struct mtd_info *mtd = NULL; | 652 | struct mtd_info *mtd = NULL; |
@@ -623,6 +664,7 @@ static int bf5xx_nand_remove(struct platform_device *pdev) | |||
623 | } | 664 | } |
624 | 665 | ||
625 | peripheral_free_list(bfin_nfc_pin_req); | 666 | peripheral_free_list(bfin_nfc_pin_req); |
667 | bf5xx_nand_dma_remove(info); | ||
626 | 668 | ||
627 | /* free the common resources */ | 669 | /* free the common resources */ |
628 | kfree(info); | 670 | kfree(info); |
@@ -638,7 +680,7 @@ static int bf5xx_nand_remove(struct platform_device *pdev) | |||
638 | * it can allocate all necessary resources then calls the | 680 | * it can allocate all necessary resources then calls the |
639 | * nand layer to look for devices | 681 | * nand layer to look for devices |
640 | */ | 682 | */ |
641 | static int bf5xx_nand_probe(struct platform_device *pdev) | 683 | static int __devinit bf5xx_nand_probe(struct platform_device *pdev) |
642 | { | 684 | { |
643 | struct bf5xx_nand_platform *plat = to_nand_plat(pdev); | 685 | struct bf5xx_nand_platform *plat = to_nand_plat(pdev); |
644 | struct bf5xx_nand_info *info = NULL; | 686 | struct bf5xx_nand_info *info = NULL; |
@@ -648,22 +690,21 @@ static int bf5xx_nand_probe(struct platform_device *pdev) | |||
648 | 690 | ||
649 | dev_dbg(&pdev->dev, "(%p)\n", pdev); | 691 | dev_dbg(&pdev->dev, "(%p)\n", pdev); |
650 | 692 | ||
651 | if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) { | ||
652 | printk(KERN_ERR DRV_NAME | ||
653 | ": Requesting Peripherals failed\n"); | ||
654 | return -EFAULT; | ||
655 | } | ||
656 | |||
657 | if (!plat) { | 693 | if (!plat) { |
658 | dev_err(&pdev->dev, "no platform specific information\n"); | 694 | dev_err(&pdev->dev, "no platform specific information\n"); |
659 | goto exit_error; | 695 | return -EINVAL; |
696 | } | ||
697 | |||
698 | if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) { | ||
699 | dev_err(&pdev->dev, "requesting Peripherals failed\n"); | ||
700 | return -EFAULT; | ||
660 | } | 701 | } |
661 | 702 | ||
662 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 703 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
663 | if (info == NULL) { | 704 | if (info == NULL) { |
664 | dev_err(&pdev->dev, "no memory for flash info\n"); | 705 | dev_err(&pdev->dev, "no memory for flash info\n"); |
665 | err = -ENOMEM; | 706 | err = -ENOMEM; |
666 | goto exit_error; | 707 | goto out_err_kzalloc; |
667 | } | 708 | } |
668 | 709 | ||
669 | platform_set_drvdata(pdev, info); | 710 | platform_set_drvdata(pdev, info); |
@@ -707,11 +748,16 @@ static int bf5xx_nand_probe(struct platform_device *pdev) | |||
707 | 748 | ||
708 | /* initialise the hardware */ | 749 | /* initialise the hardware */ |
709 | err = bf5xx_nand_hw_init(info); | 750 | err = bf5xx_nand_hw_init(info); |
710 | if (err != 0) | 751 | if (err) |
711 | goto exit_error; | 752 | goto out_err_hw_init; |
712 | 753 | ||
713 | /* setup hardware ECC data struct */ | 754 | /* setup hardware ECC data struct */ |
714 | if (hardware_ecc) { | 755 | if (hardware_ecc) { |
756 | #ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC | ||
757 | chip->badblock_pattern = &bootrom_bbt; | ||
758 | chip->ecc.layout = &bootrom_ecclayout; | ||
759 | #endif | ||
760 | |||
715 | if (plat->page_size == NFC_PG_SIZE_256) { | 761 | if (plat->page_size == NFC_PG_SIZE_256) { |
716 | chip->ecc.bytes = 3; | 762 | chip->ecc.bytes = 3; |
717 | chip->ecc.size = 256; | 763 | chip->ecc.size = 256; |
@@ -733,7 +779,7 @@ static int bf5xx_nand_probe(struct platform_device *pdev) | |||
733 | /* scan hardware nand chip and setup mtd info data struct */ | 779 | /* scan hardware nand chip and setup mtd info data struct */ |
734 | if (nand_scan(mtd, 1)) { | 780 | if (nand_scan(mtd, 1)) { |
735 | err = -ENXIO; | 781 | err = -ENXIO; |
736 | goto exit_error; | 782 | goto out_err_nand_scan; |
737 | } | 783 | } |
738 | 784 | ||
739 | /* add NAND partition */ | 785 | /* add NAND partition */ |
@@ -742,11 +788,14 @@ static int bf5xx_nand_probe(struct platform_device *pdev) | |||
742 | dev_dbg(&pdev->dev, "initialised ok\n"); | 788 | dev_dbg(&pdev->dev, "initialised ok\n"); |
743 | return 0; | 789 | return 0; |
744 | 790 | ||
745 | exit_error: | 791 | out_err_nand_scan: |
746 | bf5xx_nand_remove(pdev); | 792 | bf5xx_nand_dma_remove(info); |
793 | out_err_hw_init: | ||
794 | platform_set_drvdata(pdev, NULL); | ||
795 | kfree(info); | ||
796 | out_err_kzalloc: | ||
797 | peripheral_free_list(bfin_nfc_pin_req); | ||
747 | 798 | ||
748 | if (err == 0) | ||
749 | err = -EINVAL; | ||
750 | return err; | 799 | return err; |
751 | } | 800 | } |
752 | 801 | ||
@@ -775,7 +824,7 @@ static int bf5xx_nand_resume(struct platform_device *dev) | |||
775 | /* driver device registration */ | 824 | /* driver device registration */ |
776 | static struct platform_driver bf5xx_nand_driver = { | 825 | static struct platform_driver bf5xx_nand_driver = { |
777 | .probe = bf5xx_nand_probe, | 826 | .probe = bf5xx_nand_probe, |
778 | .remove = bf5xx_nand_remove, | 827 | .remove = __devexit_p(bf5xx_nand_remove), |
779 | .suspend = bf5xx_nand_suspend, | 828 | .suspend = bf5xx_nand_suspend, |
780 | .resume = bf5xx_nand_resume, | 829 | .resume = bf5xx_nand_resume, |
781 | .driver = { | 830 | .driver = { |