diff options
Diffstat (limited to 'drivers/mtd/devices/doc2001plus.c')
-rw-r--r-- | drivers/mtd/devices/doc2001plus.c | 164 |
1 files changed, 63 insertions, 101 deletions
diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c index 66cb1e50469a..92dbb47f2ac3 100644 --- a/drivers/mtd/devices/doc2001plus.c +++ b/drivers/mtd/devices/doc2001plus.c | |||
@@ -41,12 +41,6 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
41 | size_t *retlen, u_char *buf); | 41 | size_t *retlen, u_char *buf); |
42 | static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, | 42 | static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, |
43 | size_t *retlen, const u_char *buf); | 43 | size_t *retlen, const u_char *buf); |
44 | static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | ||
45 | size_t *retlen, u_char *buf, u_char *eccbuf, | ||
46 | struct nand_oobinfo *oobsel); | ||
47 | static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | ||
48 | size_t *retlen, const u_char *buf, u_char *eccbuf, | ||
49 | struct nand_oobinfo *oobsel); | ||
50 | static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, | 44 | static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, |
51 | struct mtd_oob_ops *ops); | 45 | struct mtd_oob_ops *ops); |
52 | static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, | 46 | static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, |
@@ -595,18 +589,10 @@ static int doc_dumpblk(struct mtd_info *mtd, loff_t from) | |||
595 | static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, | 589 | static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, |
596 | size_t *retlen, u_char *buf) | 590 | size_t *retlen, u_char *buf) |
597 | { | 591 | { |
598 | /* Just a special case of doc_read_ecc */ | ||
599 | return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL); | ||
600 | } | ||
601 | |||
602 | static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | ||
603 | size_t *retlen, u_char *buf, u_char *eccbuf, | ||
604 | struct nand_oobinfo *oobsel) | ||
605 | { | ||
606 | int ret, i; | 592 | int ret, i; |
607 | volatile char dummy; | 593 | volatile char dummy; |
608 | loff_t fofs; | 594 | loff_t fofs; |
609 | unsigned char syndrome[6]; | 595 | unsigned char syndrome[6], eccbuf[6]; |
610 | struct DiskOnChip *this = mtd->priv; | 596 | struct DiskOnChip *this = mtd->priv; |
611 | void __iomem * docptr = this->virtadr; | 597 | void __iomem * docptr = this->virtadr; |
612 | struct Nand *mychip = &this->chips[from >> (this->chipshift)]; | 598 | struct Nand *mychip = &this->chips[from >> (this->chipshift)]; |
@@ -644,56 +630,51 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | |||
644 | WriteDOC(0, docptr, Mplus_FlashControl); | 630 | WriteDOC(0, docptr, Mplus_FlashControl); |
645 | DoC_WaitReady(docptr); | 631 | DoC_WaitReady(docptr); |
646 | 632 | ||
647 | if (eccbuf) { | 633 | /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/ |
648 | /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/ | 634 | WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); |
649 | WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); | 635 | WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf); |
650 | WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf); | ||
651 | } else { | ||
652 | /* disable the ECC engine */ | ||
653 | WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); | ||
654 | } | ||
655 | 636 | ||
656 | /* Let the caller know we completed it */ | 637 | /* Let the caller know we completed it */ |
657 | *retlen = len; | 638 | *retlen = len; |
658 | ret = 0; | 639 | ret = 0; |
659 | 640 | ||
660 | ReadDOC(docptr, Mplus_ReadPipeInit); | 641 | ReadDOC(docptr, Mplus_ReadPipeInit); |
661 | ReadDOC(docptr, Mplus_ReadPipeInit); | 642 | ReadDOC(docptr, Mplus_ReadPipeInit); |
662 | 643 | ||
663 | if (eccbuf) { | 644 | /* Read the data via the internal pipeline through CDSN IO |
664 | /* Read the data via the internal pipeline through CDSN IO | 645 | register, see Pipelined Read Operations 11.3 */ |
665 | register, see Pipelined Read Operations 11.3 */ | 646 | MemReadDOC(docptr, buf, len); |
666 | MemReadDOC(docptr, buf, len); | ||
667 | 647 | ||
668 | /* Read the ECC data following raw data */ | 648 | /* Read the ECC data following raw data */ |
669 | MemReadDOC(docptr, eccbuf, 4); | 649 | MemReadDOC(docptr, eccbuf, 4); |
670 | eccbuf[4] = ReadDOC(docptr, Mplus_LastDataRead); | 650 | eccbuf[4] = ReadDOC(docptr, Mplus_LastDataRead); |
671 | eccbuf[5] = ReadDOC(docptr, Mplus_LastDataRead); | 651 | eccbuf[5] = ReadDOC(docptr, Mplus_LastDataRead); |
672 | 652 | ||
673 | /* Flush the pipeline */ | 653 | /* Flush the pipeline */ |
674 | dummy = ReadDOC(docptr, Mplus_ECCConf); | 654 | dummy = ReadDOC(docptr, Mplus_ECCConf); |
675 | dummy = ReadDOC(docptr, Mplus_ECCConf); | 655 | dummy = ReadDOC(docptr, Mplus_ECCConf); |
676 | 656 | ||
677 | /* Check the ECC Status */ | 657 | /* Check the ECC Status */ |
678 | if (ReadDOC(docptr, Mplus_ECCConf) & 0x80) { | 658 | if (ReadDOC(docptr, Mplus_ECCConf) & 0x80) { |
679 | int nb_errors; | 659 | int nb_errors; |
680 | /* There was an ECC error */ | 660 | /* There was an ECC error */ |
681 | #ifdef ECC_DEBUG | 661 | #ifdef ECC_DEBUG |
682 | printk("DiskOnChip ECC Error: Read at %lx\n", (long)from); | 662 | printk("DiskOnChip ECC Error: Read at %lx\n", (long)from); |
683 | #endif | 663 | #endif |
684 | /* Read the ECC syndrom through the DiskOnChip ECC logic. | 664 | /* Read the ECC syndrom through the DiskOnChip ECC logic. |
685 | These syndrome will be all ZERO when there is no error */ | 665 | These syndrome will be all ZERO when there is no error */ |
686 | for (i = 0; i < 6; i++) | 666 | for (i = 0; i < 6; i++) |
687 | syndrome[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i); | 667 | syndrome[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i); |
688 | 668 | ||
689 | nb_errors = doc_decode_ecc(buf, syndrome); | 669 | nb_errors = doc_decode_ecc(buf, syndrome); |
690 | #ifdef ECC_DEBUG | 670 | #ifdef ECC_DEBUG |
691 | printk("ECC Errors corrected: %x\n", nb_errors); | 671 | printk("ECC Errors corrected: %x\n", nb_errors); |
692 | #endif | 672 | #endif |
693 | if (nb_errors < 0) { | 673 | if (nb_errors < 0) { |
694 | /* We return error, but have actually done the read. Not that | 674 | /* We return error, but have actually done the |
695 | this can be told to user-space, via sys_read(), but at least | 675 | read. Not that this can be told to user-space, via |
696 | MTD-aware stuff can know about it by checking *retlen */ | 676 | sys_read(), but at least MTD-aware stuff can know |
677 | about it by checking *retlen */ | ||
697 | #ifdef ECC_DEBUG | 678 | #ifdef ECC_DEBUG |
698 | printk("%s(%d): Millennium Plus ECC error (from=0x%x:\n", | 679 | printk("%s(%d): Millennium Plus ECC error (from=0x%x:\n", |
699 | __FILE__, __LINE__, (int)from); | 680 | __FILE__, __LINE__, (int)from); |
@@ -707,24 +688,16 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | |||
707 | eccbuf[3], eccbuf[4], eccbuf[5]); | 688 | eccbuf[3], eccbuf[4], eccbuf[5]); |
708 | #endif | 689 | #endif |
709 | ret = -EIO; | 690 | ret = -EIO; |
710 | } | ||
711 | } | 691 | } |
692 | } | ||
712 | 693 | ||
713 | #ifdef PSYCHO_DEBUG | 694 | #ifdef PSYCHO_DEBUG |
714 | printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", | 695 | printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", |
715 | (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], | 696 | (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], |
716 | eccbuf[4], eccbuf[5]); | 697 | eccbuf[4], eccbuf[5]); |
717 | #endif | 698 | #endif |
718 | 699 | /* disable the ECC engine */ | |
719 | /* disable the ECC engine */ | 700 | WriteDOC(DOC_ECC_DIS, docptr , Mplus_ECCConf); |
720 | WriteDOC(DOC_ECC_DIS, docptr , Mplus_ECCConf); | ||
721 | } else { | ||
722 | /* Read the data via the internal pipeline through CDSN IO | ||
723 | register, see Pipelined Read Operations 11.3 */ | ||
724 | MemReadDOC(docptr, buf, len-2); | ||
725 | buf[len-2] = ReadDOC(docptr, Mplus_LastDataRead); | ||
726 | buf[len-1] = ReadDOC(docptr, Mplus_LastDataRead); | ||
727 | } | ||
728 | 701 | ||
729 | /* Disable flash internally */ | 702 | /* Disable flash internally */ |
730 | WriteDOC(0, docptr, Mplus_FlashSelect); | 703 | WriteDOC(0, docptr, Mplus_FlashSelect); |
@@ -735,17 +708,10 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | |||
735 | static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, | 708 | static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, |
736 | size_t *retlen, const u_char *buf) | 709 | size_t *retlen, const u_char *buf) |
737 | { | 710 | { |
738 | char eccbuf[6]; | ||
739 | return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL); | ||
740 | } | ||
741 | |||
742 | static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | ||
743 | size_t *retlen, const u_char *buf, u_char *eccbuf, | ||
744 | struct nand_oobinfo *oobsel) | ||
745 | { | ||
746 | int i, before, ret = 0; | 711 | int i, before, ret = 0; |
747 | loff_t fto; | 712 | loff_t fto; |
748 | volatile char dummy; | 713 | volatile char dummy; |
714 | char eccbuf[6]; | ||
749 | struct DiskOnChip *this = mtd->priv; | 715 | struct DiskOnChip *this = mtd->priv; |
750 | void __iomem * docptr = this->virtadr; | 716 | void __iomem * docptr = this->virtadr; |
751 | struct Nand *mychip = &this->chips[to >> (this->chipshift)]; | 717 | struct Nand *mychip = &this->chips[to >> (this->chipshift)]; |
@@ -795,46 +761,42 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | |||
795 | /* Disable the ECC engine */ | 761 | /* Disable the ECC engine */ |
796 | WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); | 762 | WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); |
797 | 763 | ||
798 | if (eccbuf) { | 764 | if (before) { |
799 | if (before) { | 765 | /* Write the block status BLOCK_USED (0x5555) */ |
800 | /* Write the block status BLOCK_USED (0x5555) */ | 766 | WriteDOC(0x55, docptr, Mil_CDSN_IO); |
801 | WriteDOC(0x55, docptr, Mil_CDSN_IO); | 767 | WriteDOC(0x55, docptr, Mil_CDSN_IO); |
802 | WriteDOC(0x55, docptr, Mil_CDSN_IO); | ||
803 | } | ||
804 | |||
805 | /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/ | ||
806 | WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf); | ||
807 | } | 768 | } |
808 | 769 | ||
770 | /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/ | ||
771 | WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf); | ||
772 | |||
809 | MemWriteDOC(docptr, (unsigned char *) buf, len); | 773 | MemWriteDOC(docptr, (unsigned char *) buf, len); |
810 | 774 | ||
811 | if (eccbuf) { | 775 | /* Write ECC data to flash, the ECC info is generated by |
812 | /* Write ECC data to flash, the ECC info is generated by | 776 | the DiskOnChip ECC logic see Reed-Solomon EDC/ECC 11.1 */ |
813 | the DiskOnChip ECC logic see Reed-Solomon EDC/ECC 11.1 */ | 777 | DoC_Delay(docptr, 3); |
814 | DoC_Delay(docptr, 3); | ||
815 | 778 | ||
816 | /* Read the ECC data through the DiskOnChip ECC logic */ | 779 | /* Read the ECC data through the DiskOnChip ECC logic */ |
817 | for (i = 0; i < 6; i++) | 780 | for (i = 0; i < 6; i++) |
818 | eccbuf[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i); | 781 | eccbuf[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i); |
819 | 782 | ||
820 | /* disable the ECC engine */ | 783 | /* disable the ECC engine */ |
821 | WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf); | 784 | WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf); |
822 | 785 | ||
823 | /* Write the ECC data to flash */ | 786 | /* Write the ECC data to flash */ |
824 | MemWriteDOC(docptr, eccbuf, 6); | 787 | MemWriteDOC(docptr, eccbuf, 6); |
825 | 788 | ||
826 | if (!before) { | 789 | if (!before) { |
827 | /* Write the block status BLOCK_USED (0x5555) */ | 790 | /* Write the block status BLOCK_USED (0x5555) */ |
828 | WriteDOC(0x55, docptr, Mil_CDSN_IO+6); | 791 | WriteDOC(0x55, docptr, Mil_CDSN_IO+6); |
829 | WriteDOC(0x55, docptr, Mil_CDSN_IO+7); | 792 | WriteDOC(0x55, docptr, Mil_CDSN_IO+7); |
830 | } | 793 | } |
831 | 794 | ||
832 | #ifdef PSYCHO_DEBUG | 795 | #ifdef PSYCHO_DEBUG |
833 | printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", | 796 | printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", |
834 | (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], | 797 | (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], |
835 | eccbuf[4], eccbuf[5]); | 798 | eccbuf[4], eccbuf[5]); |
836 | #endif | 799 | #endif |
837 | } | ||
838 | 800 | ||
839 | WriteDOC(0x00, docptr, Mplus_WritePipeTerm); | 801 | WriteDOC(0x00, docptr, Mplus_WritePipeTerm); |
840 | WriteDOC(0x00, docptr, Mplus_WritePipeTerm); | 802 | WriteDOC(0x00, docptr, Mplus_WritePipeTerm); |