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); |
