diff options
Diffstat (limited to 'drivers/mtd/devices/doc2000.c')
| -rw-r--r-- | drivers/mtd/devices/doc2000.c | 179 |
1 files changed, 73 insertions, 106 deletions
diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c index c54e40464d82..603a7951ac9b 100644 --- a/drivers/mtd/devices/doc2000.c +++ b/drivers/mtd/devices/doc2000.c | |||
| @@ -55,10 +55,6 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
| 55 | size_t *retlen, u_char *buf); | 55 | size_t *retlen, u_char *buf); |
| 56 | static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, | 56 | static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, |
| 57 | size_t *retlen, const u_char *buf); | 57 | size_t *retlen, const u_char *buf); |
| 58 | static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | ||
| 59 | size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); | ||
| 60 | static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | ||
| 61 | size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); | ||
| 62 | static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, | 58 | static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, |
| 63 | struct mtd_oob_ops *ops); | 59 | struct mtd_oob_ops *ops); |
| 64 | static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, | 60 | static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, |
| @@ -615,17 +611,10 @@ EXPORT_SYMBOL_GPL(DoC2k_init); | |||
| 615 | static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, | 611 | static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, |
| 616 | size_t * retlen, u_char * buf) | 612 | size_t * retlen, u_char * buf) |
| 617 | { | 613 | { |
| 618 | /* Just a special case of doc_read_ecc */ | ||
| 619 | return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL); | ||
| 620 | } | ||
| 621 | |||
| 622 | static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | ||
| 623 | size_t * retlen, u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel) | ||
| 624 | { | ||
| 625 | struct DiskOnChip *this = mtd->priv; | 614 | struct DiskOnChip *this = mtd->priv; |
| 626 | void __iomem *docptr = this->virtadr; | 615 | void __iomem *docptr = this->virtadr; |
| 627 | struct Nand *mychip; | 616 | struct Nand *mychip; |
| 628 | unsigned char syndrome[6]; | 617 | unsigned char syndrome[6], eccbuf[6]; |
| 629 | volatile char dummy; | 618 | volatile char dummy; |
| 630 | int i, len256 = 0, ret=0; | 619 | int i, len256 = 0, ret=0; |
| 631 | size_t left = len; | 620 | size_t left = len; |
| @@ -673,15 +662,9 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | |||
| 673 | DoC_Address(this, ADDR_COLUMN_PAGE, from, CDSN_CTRL_WP, | 662 | DoC_Address(this, ADDR_COLUMN_PAGE, from, CDSN_CTRL_WP, |
| 674 | CDSN_CTRL_ECC_IO); | 663 | CDSN_CTRL_ECC_IO); |
| 675 | 664 | ||
| 676 | if (eccbuf) { | 665 | /* Prime the ECC engine */ |
| 677 | /* Prime the ECC engine */ | 666 | WriteDOC(DOC_ECC_RESET, docptr, ECCConf); |
| 678 | WriteDOC(DOC_ECC_RESET, docptr, ECCConf); | 667 | WriteDOC(DOC_ECC_EN, docptr, ECCConf); |
| 679 | WriteDOC(DOC_ECC_EN, docptr, ECCConf); | ||
| 680 | } else { | ||
| 681 | /* disable the ECC engine */ | ||
| 682 | WriteDOC(DOC_ECC_RESET, docptr, ECCConf); | ||
| 683 | WriteDOC(DOC_ECC_DIS, docptr, ECCConf); | ||
| 684 | } | ||
| 685 | 668 | ||
| 686 | /* treat crossing 256-byte sector for 2M x 8bits devices */ | 669 | /* treat crossing 256-byte sector for 2M x 8bits devices */ |
| 687 | if (this->page256 && from + len > (from | 0xff) + 1) { | 670 | if (this->page256 && from + len > (from | 0xff) + 1) { |
| @@ -698,58 +681,59 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | |||
| 698 | /* Let the caller know we completed it */ | 681 | /* Let the caller know we completed it */ |
| 699 | *retlen += len; | 682 | *retlen += len; |
| 700 | 683 | ||
| 701 | if (eccbuf) { | 684 | /* Read the ECC data through the DiskOnChip ECC logic */ |
| 702 | /* Read the ECC data through the DiskOnChip ECC logic */ | 685 | /* Note: this will work even with 2M x 8bit devices as */ |
| 703 | /* Note: this will work even with 2M x 8bit devices as */ | 686 | /* they have 8 bytes of OOB per 256 page. mf. */ |
| 704 | /* they have 8 bytes of OOB per 256 page. mf. */ | 687 | DoC_ReadBuf(this, eccbuf, 6); |
| 705 | DoC_ReadBuf(this, eccbuf, 6); | ||
| 706 | |||
| 707 | /* Flush the pipeline */ | ||
| 708 | if (DoC_is_Millennium(this)) { | ||
| 709 | dummy = ReadDOC(docptr, ECCConf); | ||
| 710 | dummy = ReadDOC(docptr, ECCConf); | ||
| 711 | i = ReadDOC(docptr, ECCConf); | ||
| 712 | } else { | ||
| 713 | dummy = ReadDOC(docptr, 2k_ECCStatus); | ||
| 714 | dummy = ReadDOC(docptr, 2k_ECCStatus); | ||
| 715 | i = ReadDOC(docptr, 2k_ECCStatus); | ||
| 716 | } | ||
| 717 | 688 | ||
| 718 | /* Check the ECC Status */ | 689 | /* Flush the pipeline */ |
| 719 | if (i & 0x80) { | 690 | if (DoC_is_Millennium(this)) { |
| 720 | int nb_errors; | 691 | dummy = ReadDOC(docptr, ECCConf); |
| 721 | /* There was an ECC error */ | 692 | dummy = ReadDOC(docptr, ECCConf); |
| 693 | i = ReadDOC(docptr, ECCConf); | ||
| 694 | } else { | ||
| 695 | dummy = ReadDOC(docptr, 2k_ECCStatus); | ||
| 696 | dummy = ReadDOC(docptr, 2k_ECCStatus); | ||
| 697 | i = ReadDOC(docptr, 2k_ECCStatus); | ||
| 698 | } | ||
| 699 | |||
| 700 | /* Check the ECC Status */ | ||
| 701 | if (i & 0x80) { | ||
| 702 | int nb_errors; | ||
| 703 | /* There was an ECC error */ | ||
| 722 | #ifdef ECC_DEBUG | 704 | #ifdef ECC_DEBUG |
| 723 | printk(KERN_ERR "DiskOnChip ECC Error: Read at %lx\n", (long)from); | 705 | printk(KERN_ERR "DiskOnChip ECC Error: Read at %lx\n", (long)from); |
| 724 | #endif | 706 | #endif |
| 725 | /* Read the ECC syndrom through the DiskOnChip ECC logic. | 707 | /* Read the ECC syndrom through the DiskOnChip ECC |
| 726 | These syndrome will be all ZERO when there is no error */ | 708 | logic. These syndrome will be all ZERO when there |
| 727 | for (i = 0; i < 6; i++) { | 709 | is no error */ |
| 728 | syndrome[i] = | 710 | for (i = 0; i < 6; i++) { |
| 729 | ReadDOC(docptr, ECCSyndrome0 + i); | 711 | syndrome[i] = |
| 730 | } | 712 | ReadDOC(docptr, ECCSyndrome0 + i); |
| 731 | nb_errors = doc_decode_ecc(buf, syndrome); | 713 | } |
| 714 | nb_errors = doc_decode_ecc(buf, syndrome); | ||
| 732 | 715 | ||
| 733 | #ifdef ECC_DEBUG | 716 | #ifdef ECC_DEBUG |
| 734 | printk(KERN_ERR "Errors corrected: %x\n", nb_errors); | 717 | printk(KERN_ERR "Errors corrected: %x\n", nb_errors); |
| 735 | #endif | 718 | #endif |
| 736 | if (nb_errors < 0) { | 719 | if (nb_errors < 0) { |
| 737 | /* We return error, but have actually done the read. Not that | 720 | /* We return error, but have actually done the |
| 738 | this can be told to user-space, via sys_read(), but at least | 721 | read. Not that this can be told to |
| 739 | MTD-aware stuff can know about it by checking *retlen */ | 722 | user-space, via sys_read(), but at least |
| 740 | ret = -EIO; | 723 | MTD-aware stuff can know about it by |
| 741 | } | 724 | checking *retlen */ |
| 725 | ret = -EIO; | ||
| 742 | } | 726 | } |
| 727 | } | ||
| 743 | 728 | ||
| 744 | #ifdef PSYCHO_DEBUG | 729 | #ifdef PSYCHO_DEBUG |
| 745 | printk(KERN_DEBUG "ECC DATA at %lxB: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", | 730 | printk(KERN_DEBUG "ECC DATA at %lxB: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", |
| 746 | (long)from, eccbuf[0], eccbuf[1], eccbuf[2], | 731 | (long)from, eccbuf[0], eccbuf[1], eccbuf[2], |
| 747 | eccbuf[3], eccbuf[4], eccbuf[5]); | 732 | eccbuf[3], eccbuf[4], eccbuf[5]); |
| 748 | #endif | 733 | #endif |
| 749 | 734 | ||
| 750 | /* disable the ECC engine */ | 735 | /* disable the ECC engine */ |
| 751 | WriteDOC(DOC_ECC_DIS, docptr , ECCConf); | 736 | WriteDOC(DOC_ECC_DIS, docptr , ECCConf); |
| 752 | } | ||
| 753 | 737 | ||
| 754 | /* according to 11.4.1, we need to wait for the busy line | 738 | /* according to 11.4.1, we need to wait for the busy line |
| 755 | * drop if we read to the end of the page. */ | 739 | * drop if we read to the end of the page. */ |
| @@ -771,17 +755,10 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | |||
| 771 | static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, | 755 | static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, |
| 772 | size_t * retlen, const u_char * buf) | 756 | size_t * retlen, const u_char * buf) |
| 773 | { | 757 | { |
| 774 | char eccbuf[6]; | ||
| 775 | return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL); | ||
| 776 | } | ||
| 777 | |||
| 778 | static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | ||
| 779 | size_t * retlen, const u_char * buf, | ||
| 780 | u_char * eccbuf, struct nand_oobinfo *oobsel) | ||
| 781 | { | ||
| 782 | struct DiskOnChip *this = mtd->priv; | 758 | struct DiskOnChip *this = mtd->priv; |
| 783 | int di; /* Yes, DI is a hangover from when I was disassembling the binary driver */ | 759 | int di; /* Yes, DI is a hangover from when I was disassembling the binary driver */ |
| 784 | void __iomem *docptr = this->virtadr; | 760 | void __iomem *docptr = this->virtadr; |
| 761 | unsigned char eccbuf[6]; | ||
| 785 | volatile char dummy; | 762 | volatile char dummy; |
| 786 | int len256 = 0; | 763 | int len256 = 0; |
| 787 | struct Nand *mychip; | 764 | struct Nand *mychip; |
| @@ -835,15 +812,9 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | |||
| 835 | DoC_Command(this, NAND_CMD_SEQIN, 0); | 812 | DoC_Command(this, NAND_CMD_SEQIN, 0); |
| 836 | DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO); | 813 | DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO); |
| 837 | 814 | ||
| 838 | if (eccbuf) { | 815 | /* Prime the ECC engine */ |
| 839 | /* Prime the ECC engine */ | 816 | WriteDOC(DOC_ECC_RESET, docptr, ECCConf); |
| 840 | WriteDOC(DOC_ECC_RESET, docptr, ECCConf); | 817 | WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf); |
| 841 | WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf); | ||
| 842 | } else { | ||
| 843 | /* disable the ECC engine */ | ||
| 844 | WriteDOC(DOC_ECC_RESET, docptr, ECCConf); | ||
| 845 | WriteDOC(DOC_ECC_DIS, docptr, ECCConf); | ||
| 846 | } | ||
| 847 | 818 | ||
| 848 | /* treat crossing 256-byte sector for 2M x 8bits devices */ | 819 | /* treat crossing 256-byte sector for 2M x 8bits devices */ |
| 849 | if (this->page256 && to + len > (to | 0xff) + 1) { | 820 | if (this->page256 && to + len > (to | 0xff) + 1) { |
| @@ -873,39 +844,35 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | |||
| 873 | 844 | ||
| 874 | DoC_WriteBuf(this, &buf[len256], len - len256); | 845 | DoC_WriteBuf(this, &buf[len256], len - len256); |
| 875 | 846 | ||
| 876 | if (eccbuf) { | 847 | WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr, CDSNControl); |
| 877 | WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr, | ||
| 878 | CDSNControl); | ||
| 879 | |||
| 880 | if (DoC_is_Millennium(this)) { | ||
| 881 | WriteDOC(0, docptr, NOP); | ||
| 882 | WriteDOC(0, docptr, NOP); | ||
| 883 | WriteDOC(0, docptr, NOP); | ||
| 884 | } else { | ||
| 885 | WriteDOC_(0, docptr, this->ioreg); | ||
| 886 | WriteDOC_(0, docptr, this->ioreg); | ||
| 887 | WriteDOC_(0, docptr, this->ioreg); | ||
| 888 | } | ||
| 889 | 848 | ||
| 890 | WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_FLASH_IO | CDSN_CTRL_CE, docptr, | 849 | if (DoC_is_Millennium(this)) { |
| 891 | CDSNControl); | 850 | WriteDOC(0, docptr, NOP); |
| 851 | WriteDOC(0, docptr, NOP); | ||
| 852 | WriteDOC(0, docptr, NOP); | ||
| 853 | } else { | ||
| 854 | WriteDOC_(0, docptr, this->ioreg); | ||
| 855 | WriteDOC_(0, docptr, this->ioreg); | ||
| 856 | WriteDOC_(0, docptr, this->ioreg); | ||
| 857 | } | ||
| 892 | 858 | ||
| 893 | /* Read the ECC data through the DiskOnChip ECC logic */ | 859 | WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_FLASH_IO | CDSN_CTRL_CE, docptr, |
| 894 | for (di = 0; di < 6; di++) { | 860 | CDSNControl); |
| 895 | eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di); | ||
| 896 | } | ||
| 897 | 861 | ||
| 898 | /* Reset the ECC engine */ | 862 | /* Read the ECC data through the DiskOnChip ECC logic */ |
| 899 | WriteDOC(DOC_ECC_DIS, docptr, ECCConf); | 863 | for (di = 0; di < 6; di++) { |
| 864 | eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di); | ||
| 865 | } | ||
| 866 | |||
| 867 | /* Reset the ECC engine */ | ||
| 868 | WriteDOC(DOC_ECC_DIS, docptr, ECCConf); | ||
| 900 | 869 | ||
| 901 | #ifdef PSYCHO_DEBUG | 870 | #ifdef PSYCHO_DEBUG |
| 902 | printk | 871 | printk |
| 903 | ("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", | 872 | ("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", |
| 904 | (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], | 873 | (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], |
| 905 | eccbuf[4], eccbuf[5]); | 874 | eccbuf[4], eccbuf[5]); |
| 906 | #endif | 875 | #endif |
| 907 | } | ||
| 908 | |||
| 909 | DoC_Command(this, NAND_CMD_PAGEPROG, 0); | 876 | DoC_Command(this, NAND_CMD_PAGEPROG, 0); |
| 910 | 877 | ||
| 911 | DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP); | 878 | DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP); |
