aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/gpmi-nand/gpmi-nand.c')
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.c63
1 files changed, 39 insertions, 24 deletions
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index e9b1c47e3cf9..717881a3d1b8 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -94,6 +94,25 @@ static inline int get_ecc_strength(struct gpmi_nand_data *this)
94 return round_down(ecc_strength, 2); 94 return round_down(ecc_strength, 2);
95} 95}
96 96
97static inline bool gpmi_check_ecc(struct gpmi_nand_data *this)
98{
99 struct bch_geometry *geo = &this->bch_geometry;
100
101 /* Do the sanity check. */
102 if (GPMI_IS_MX23(this) || GPMI_IS_MX28(this)) {
103 /* The mx23/mx28 only support the GF13. */
104 if (geo->gf_len == 14)
105 return false;
106
107 if (geo->ecc_strength > MXS_ECC_STRENGTH_MAX)
108 return false;
109 } else if (GPMI_IS_MX6Q(this)) {
110 if (geo->ecc_strength > MX6_ECC_STRENGTH_MAX)
111 return false;
112 }
113 return true;
114}
115
97int common_nfc_set_geometry(struct gpmi_nand_data *this) 116int common_nfc_set_geometry(struct gpmi_nand_data *this)
98{ 117{
99 struct bch_geometry *geo = &this->bch_geometry; 118 struct bch_geometry *geo = &this->bch_geometry;
@@ -112,17 +131,24 @@ int common_nfc_set_geometry(struct gpmi_nand_data *this)
112 /* The default for the length of Galois Field. */ 131 /* The default for the length of Galois Field. */
113 geo->gf_len = 13; 132 geo->gf_len = 13;
114 133
115 /* The default for chunk size. There is no oobsize greater then 512. */ 134 /* The default for chunk size. */
116 geo->ecc_chunk_size = 512; 135 geo->ecc_chunk_size = 512;
117 while (geo->ecc_chunk_size < mtd->oobsize) 136 while (geo->ecc_chunk_size < mtd->oobsize) {
118 geo->ecc_chunk_size *= 2; /* keep C >= O */ 137 geo->ecc_chunk_size *= 2; /* keep C >= O */
138 geo->gf_len = 14;
139 }
119 140
120 geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size; 141 geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size;
121 142
122 /* We use the same ECC strength for all chunks. */ 143 /* We use the same ECC strength for all chunks. */
123 geo->ecc_strength = get_ecc_strength(this); 144 geo->ecc_strength = get_ecc_strength(this);
124 if (!geo->ecc_strength) { 145 if (!gpmi_check_ecc(this)) {
125 pr_err("wrong ECC strength.\n"); 146 dev_err(this->dev,
147 "We can not support this nand chip."
148 " Its required ecc strength(%d) is beyond our"
149 " capability(%d).\n", geo->ecc_strength,
150 (GPMI_IS_MX6Q(this) ? MX6_ECC_STRENGTH_MAX
151 : MXS_ECC_STRENGTH_MAX));
126 return -EINVAL; 152 return -EINVAL;
127 } 153 }
128 154
@@ -920,8 +946,7 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
920 dma_addr_t auxiliary_phys; 946 dma_addr_t auxiliary_phys;
921 unsigned int i; 947 unsigned int i;
922 unsigned char *status; 948 unsigned char *status;
923 unsigned int failed; 949 unsigned int max_bitflips = 0;
924 unsigned int corrected;
925 int ret; 950 int ret;
926 951
927 pr_debug("page number is : %d\n", page); 952 pr_debug("page number is : %d\n", page);
@@ -945,35 +970,25 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
945 payload_virt, payload_phys); 970 payload_virt, payload_phys);
946 if (ret) { 971 if (ret) {
947 pr_err("Error in ECC-based read: %d\n", ret); 972 pr_err("Error in ECC-based read: %d\n", ret);
948 goto exit_nfc; 973 return ret;
949 } 974 }
950 975
951 /* handle the block mark swapping */ 976 /* handle the block mark swapping */
952 block_mark_swapping(this, payload_virt, auxiliary_virt); 977 block_mark_swapping(this, payload_virt, auxiliary_virt);
953 978
954 /* Loop over status bytes, accumulating ECC status. */ 979 /* Loop over status bytes, accumulating ECC status. */
955 failed = 0; 980 status = auxiliary_virt + nfc_geo->auxiliary_status_offset;
956 corrected = 0;
957 status = auxiliary_virt + nfc_geo->auxiliary_status_offset;
958 981
959 for (i = 0; i < nfc_geo->ecc_chunk_count; i++, status++) { 982 for (i = 0; i < nfc_geo->ecc_chunk_count; i++, status++) {
960 if ((*status == STATUS_GOOD) || (*status == STATUS_ERASED)) 983 if ((*status == STATUS_GOOD) || (*status == STATUS_ERASED))
961 continue; 984 continue;
962 985
963 if (*status == STATUS_UNCORRECTABLE) { 986 if (*status == STATUS_UNCORRECTABLE) {
964 failed++; 987 mtd->ecc_stats.failed++;
965 continue; 988 continue;
966 } 989 }
967 corrected += *status; 990 mtd->ecc_stats.corrected += *status;
968 } 991 max_bitflips = max_t(unsigned int, max_bitflips, *status);
969
970 /*
971 * Propagate ECC status to the owning MTD only when failed or
972 * corrected times nearly reaches our ECC correction threshold.
973 */
974 if (failed || corrected >= (nfc_geo->ecc_strength - 1)) {
975 mtd->ecc_stats.failed += failed;
976 mtd->ecc_stats.corrected += corrected;
977 } 992 }
978 993
979 if (oob_required) { 994 if (oob_required) {
@@ -995,8 +1010,8 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
995 this->payload_virt, this->payload_phys, 1010 this->payload_virt, this->payload_phys,
996 nfc_geo->payload_size, 1011 nfc_geo->payload_size,
997 payload_virt, payload_phys); 1012 payload_virt, payload_phys);
998exit_nfc: 1013
999 return ret; 1014 return max_bitflips;
1000} 1015}
1001 1016
1002static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, 1017static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
@@ -1668,8 +1683,8 @@ exit_nfc_init:
1668 release_resources(this); 1683 release_resources(this);
1669exit_acquire_resources: 1684exit_acquire_resources:
1670 platform_set_drvdata(pdev, NULL); 1685 platform_set_drvdata(pdev, NULL);
1671 kfree(this);
1672 dev_err(this->dev, "driver registration failed: %d\n", ret); 1686 dev_err(this->dev, "driver registration failed: %d\n", ret);
1687 kfree(this);
1673 1688
1674 return ret; 1689 return ret;
1675} 1690}