diff options
Diffstat (limited to 'drivers/mtd/nand/omap2.c')
-rw-r--r-- | drivers/mtd/nand/omap2.c | 512 |
1 files changed, 218 insertions, 294 deletions
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index bf642ceef681..1ff49b80bdaf 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c | |||
@@ -118,14 +118,9 @@ | |||
118 | 118 | ||
119 | #define OMAP24XX_DMA_GPMC 4 | 119 | #define OMAP24XX_DMA_GPMC 4 |
120 | 120 | ||
121 | #define BCH8_MAX_ERROR 8 /* upto 8 bit correctable */ | ||
122 | #define BCH4_MAX_ERROR 4 /* upto 4 bit correctable */ | ||
123 | |||
124 | #define SECTOR_BYTES 512 | 121 | #define SECTOR_BYTES 512 |
125 | /* 4 bit padding to make byte aligned, 56 = 52 + 4 */ | 122 | /* 4 bit padding to make byte aligned, 56 = 52 + 4 */ |
126 | #define BCH4_BIT_PAD 4 | 123 | #define BCH4_BIT_PAD 4 |
127 | #define BCH8_ECC_MAX ((SECTOR_BYTES + BCH8_ECC_OOB_BYTES) * 8) | ||
128 | #define BCH4_ECC_MAX ((SECTOR_BYTES + BCH4_ECC_OOB_BYTES) * 8) | ||
129 | 124 | ||
130 | /* GPMC ecc engine settings for read */ | 125 | /* GPMC ecc engine settings for read */ |
131 | #define BCH_WRAPMODE_1 1 /* BCH wrap mode 1 */ | 126 | #define BCH_WRAPMODE_1 1 /* BCH wrap mode 1 */ |
@@ -159,7 +154,7 @@ struct omap_nand_info { | |||
159 | 154 | ||
160 | int gpmc_cs; | 155 | int gpmc_cs; |
161 | unsigned long phys_base; | 156 | unsigned long phys_base; |
162 | unsigned long mem_size; | 157 | enum omap_ecc ecc_opt; |
163 | struct completion comp; | 158 | struct completion comp; |
164 | struct dma_chan *dma; | 159 | struct dma_chan *dma; |
165 | int gpmc_irq_fifo; | 160 | int gpmc_irq_fifo; |
@@ -172,7 +167,6 @@ struct omap_nand_info { | |||
172 | int buf_len; | 167 | int buf_len; |
173 | struct gpmc_nand_regs reg; | 168 | struct gpmc_nand_regs reg; |
174 | /* fields specific for BCHx_HW ECC scheme */ | 169 | /* fields specific for BCHx_HW ECC scheme */ |
175 | bool is_elm_used; | ||
176 | struct device *elm_dev; | 170 | struct device *elm_dev; |
177 | struct device_node *of_node; | 171 | struct device_node *of_node; |
178 | }; | 172 | }; |
@@ -1043,9 +1037,8 @@ static int omap_dev_ready(struct mtd_info *mtd) | |||
1043 | } | 1037 | } |
1044 | } | 1038 | } |
1045 | 1039 | ||
1046 | #if defined(CONFIG_MTD_NAND_ECC_BCH) || defined(CONFIG_MTD_NAND_OMAP_BCH) | ||
1047 | /** | 1040 | /** |
1048 | * omap3_enable_hwecc_bch - Program OMAP3 GPMC to perform BCH ECC correction | 1041 | * omap_enable_hwecc_bch - Program GPMC to perform BCH ECC calculation |
1049 | * @mtd: MTD device structure | 1042 | * @mtd: MTD device structure |
1050 | * @mode: Read/Write mode | 1043 | * @mode: Read/Write mode |
1051 | * | 1044 | * |
@@ -1056,50 +1049,73 @@ static int omap_dev_ready(struct mtd_info *mtd) | |||
1056 | * eccsize0 = 0 (no additional protected byte in spare area) | 1049 | * eccsize0 = 0 (no additional protected byte in spare area) |
1057 | * eccsize1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area) | 1050 | * eccsize1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area) |
1058 | */ | 1051 | */ |
1059 | static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode) | 1052 | static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd, int mode) |
1060 | { | 1053 | { |
1061 | int nerrors; | 1054 | unsigned int bch_type; |
1062 | unsigned int dev_width, nsectors; | 1055 | unsigned int dev_width, nsectors; |
1063 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | 1056 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, |
1064 | mtd); | 1057 | mtd); |
1058 | enum omap_ecc ecc_opt = info->ecc_opt; | ||
1065 | struct nand_chip *chip = mtd->priv; | 1059 | struct nand_chip *chip = mtd->priv; |
1066 | u32 val, wr_mode; | 1060 | u32 val, wr_mode; |
1067 | unsigned int ecc_size1, ecc_size0; | 1061 | unsigned int ecc_size1, ecc_size0; |
1068 | 1062 | ||
1069 | /* Using wrapping mode 6 for writing */ | 1063 | /* GPMC configurations for calculating ECC */ |
1070 | wr_mode = BCH_WRAPMODE_6; | 1064 | switch (ecc_opt) { |
1071 | 1065 | case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: | |
1072 | /* | 1066 | bch_type = 0; |
1073 | * ECC engine enabled for valid ecc_size0 nibbles | 1067 | nsectors = 1; |
1074 | * and disabled for ecc_size1 nibbles. | 1068 | if (mode == NAND_ECC_READ) { |
1075 | */ | 1069 | wr_mode = BCH_WRAPMODE_6; |
1076 | ecc_size0 = BCH_ECC_SIZE0; | 1070 | ecc_size0 = BCH_ECC_SIZE0; |
1077 | ecc_size1 = BCH_ECC_SIZE1; | 1071 | ecc_size1 = BCH_ECC_SIZE1; |
1078 | 1072 | } else { | |
1079 | /* Perform ecc calculation on 512-byte sector */ | 1073 | wr_mode = BCH_WRAPMODE_6; |
1080 | nsectors = 1; | 1074 | ecc_size0 = BCH_ECC_SIZE0; |
1081 | 1075 | ecc_size1 = BCH_ECC_SIZE1; | |
1082 | /* Update number of error correction */ | 1076 | } |
1083 | nerrors = info->nand.ecc.strength; | 1077 | break; |
1084 | 1078 | case OMAP_ECC_BCH4_CODE_HW: | |
1085 | /* Multi sector reading/writing for NAND flash with page size < 4096 */ | 1079 | bch_type = 0; |
1086 | if (info->is_elm_used && (mtd->writesize <= 4096)) { | 1080 | nsectors = chip->ecc.steps; |
1087 | if (mode == NAND_ECC_READ) { | 1081 | if (mode == NAND_ECC_READ) { |
1088 | /* Using wrapping mode 1 for reading */ | 1082 | wr_mode = BCH_WRAPMODE_1; |
1089 | wr_mode = BCH_WRAPMODE_1; | 1083 | ecc_size0 = BCH4R_ECC_SIZE0; |
1090 | 1084 | ecc_size1 = BCH4R_ECC_SIZE1; | |
1091 | /* | 1085 | } else { |
1092 | * ECC engine enabled for ecc_size0 nibbles | 1086 | wr_mode = BCH_WRAPMODE_6; |
1093 | * and disabled for ecc_size1 nibbles. | 1087 | ecc_size0 = BCH_ECC_SIZE0; |
1094 | */ | 1088 | ecc_size1 = BCH_ECC_SIZE1; |
1095 | ecc_size0 = (nerrors == 8) ? | ||
1096 | BCH8R_ECC_SIZE0 : BCH4R_ECC_SIZE0; | ||
1097 | ecc_size1 = (nerrors == 8) ? | ||
1098 | BCH8R_ECC_SIZE1 : BCH4R_ECC_SIZE1; | ||
1099 | } | 1089 | } |
1100 | 1090 | break; | |
1101 | /* Perform ecc calculation for one page (< 4096) */ | 1091 | case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: |
1102 | nsectors = info->nand.ecc.steps; | 1092 | bch_type = 1; |
1093 | nsectors = 1; | ||
1094 | if (mode == NAND_ECC_READ) { | ||
1095 | wr_mode = BCH_WRAPMODE_6; | ||
1096 | ecc_size0 = BCH_ECC_SIZE0; | ||
1097 | ecc_size1 = BCH_ECC_SIZE1; | ||
1098 | } else { | ||
1099 | wr_mode = BCH_WRAPMODE_6; | ||
1100 | ecc_size0 = BCH_ECC_SIZE0; | ||
1101 | ecc_size1 = BCH_ECC_SIZE1; | ||
1102 | } | ||
1103 | break; | ||
1104 | case OMAP_ECC_BCH8_CODE_HW: | ||
1105 | bch_type = 1; | ||
1106 | nsectors = chip->ecc.steps; | ||
1107 | if (mode == NAND_ECC_READ) { | ||
1108 | wr_mode = BCH_WRAPMODE_1; | ||
1109 | ecc_size0 = BCH8R_ECC_SIZE0; | ||
1110 | ecc_size1 = BCH8R_ECC_SIZE1; | ||
1111 | } else { | ||
1112 | wr_mode = BCH_WRAPMODE_6; | ||
1113 | ecc_size0 = BCH_ECC_SIZE0; | ||
1114 | ecc_size1 = BCH_ECC_SIZE1; | ||
1115 | } | ||
1116 | break; | ||
1117 | default: | ||
1118 | return; | ||
1103 | } | 1119 | } |
1104 | 1120 | ||
1105 | writel(ECC1, info->reg.gpmc_ecc_control); | 1121 | writel(ECC1, info->reg.gpmc_ecc_control); |
@@ -1112,7 +1128,7 @@ static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode) | |||
1112 | 1128 | ||
1113 | /* BCH configuration */ | 1129 | /* BCH configuration */ |
1114 | val = ((1 << 16) | /* enable BCH */ | 1130 | val = ((1 << 16) | /* enable BCH */ |
1115 | (((nerrors == 8) ? 1 : 0) << 12) | /* 8 or 4 bits */ | 1131 | (bch_type << 12) | /* BCH4/BCH8/BCH16 */ |
1116 | (wr_mode << 8) | /* wrap mode */ | 1132 | (wr_mode << 8) | /* wrap mode */ |
1117 | (dev_width << 7) | /* bus width */ | 1133 | (dev_width << 7) | /* bus width */ |
1118 | (((nsectors-1) & 0x7) << 4) | /* number of sectors */ | 1134 | (((nsectors-1) & 0x7) << 4) | /* number of sectors */ |
@@ -1124,132 +1140,40 @@ static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode) | |||
1124 | /* Clear ecc and enable bits */ | 1140 | /* Clear ecc and enable bits */ |
1125 | writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control); | 1141 | writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control); |
1126 | } | 1142 | } |
1127 | #endif | ||
1128 | |||
1129 | #ifdef CONFIG_MTD_NAND_ECC_BCH | ||
1130 | /** | ||
1131 | * omap3_calculate_ecc_bch4 - Generate 7 bytes of ECC bytes | ||
1132 | * @mtd: MTD device structure | ||
1133 | * @dat: The pointer to data on which ecc is computed | ||
1134 | * @ecc_code: The ecc_code buffer | ||
1135 | */ | ||
1136 | static int omap3_calculate_ecc_bch4(struct mtd_info *mtd, const u_char *dat, | ||
1137 | u_char *ecc_code) | ||
1138 | { | ||
1139 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | ||
1140 | mtd); | ||
1141 | unsigned long nsectors, val1, val2; | ||
1142 | int i; | ||
1143 | |||
1144 | nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1; | ||
1145 | |||
1146 | for (i = 0; i < nsectors; i++) { | ||
1147 | 1143 | ||
1148 | /* Read hw-computed remainder */ | 1144 | static u8 bch4_polynomial[] = {0x28, 0x13, 0xcc, 0x39, 0x96, 0xac, 0x7f}; |
1149 | val1 = readl(info->reg.gpmc_bch_result0[i]); | 1145 | static u8 bch8_polynomial[] = {0xef, 0x51, 0x2e, 0x09, 0xed, 0x93, 0x9a, 0xc2, |
1150 | val2 = readl(info->reg.gpmc_bch_result1[i]); | 1146 | 0x97, 0x79, 0xe5, 0x24, 0xb5}; |
1151 | |||
1152 | /* | ||
1153 | * Add constant polynomial to remainder, in order to get an ecc | ||
1154 | * sequence of 0xFFs for a buffer filled with 0xFFs; and | ||
1155 | * left-justify the resulting polynomial. | ||
1156 | */ | ||
1157 | *ecc_code++ = 0x28 ^ ((val2 >> 12) & 0xFF); | ||
1158 | *ecc_code++ = 0x13 ^ ((val2 >> 4) & 0xFF); | ||
1159 | *ecc_code++ = 0xcc ^ (((val2 & 0xF) << 4)|((val1 >> 28) & 0xF)); | ||
1160 | *ecc_code++ = 0x39 ^ ((val1 >> 20) & 0xFF); | ||
1161 | *ecc_code++ = 0x96 ^ ((val1 >> 12) & 0xFF); | ||
1162 | *ecc_code++ = 0xac ^ ((val1 >> 4) & 0xFF); | ||
1163 | *ecc_code++ = 0x7f ^ ((val1 & 0xF) << 4); | ||
1164 | } | ||
1165 | |||
1166 | return 0; | ||
1167 | } | ||
1168 | 1147 | ||
1169 | /** | 1148 | /** |
1170 | * omap3_calculate_ecc_bch8 - Generate 13 bytes of ECC bytes | 1149 | * omap_calculate_ecc_bch - Generate bytes of ECC bytes |
1171 | * @mtd: MTD device structure | ||
1172 | * @dat: The pointer to data on which ecc is computed | ||
1173 | * @ecc_code: The ecc_code buffer | ||
1174 | */ | ||
1175 | static int omap3_calculate_ecc_bch8(struct mtd_info *mtd, const u_char *dat, | ||
1176 | u_char *ecc_code) | ||
1177 | { | ||
1178 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | ||
1179 | mtd); | ||
1180 | unsigned long nsectors, val1, val2, val3, val4; | ||
1181 | int i; | ||
1182 | |||
1183 | nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1; | ||
1184 | |||
1185 | for (i = 0; i < nsectors; i++) { | ||
1186 | |||
1187 | /* Read hw-computed remainder */ | ||
1188 | val1 = readl(info->reg.gpmc_bch_result0[i]); | ||
1189 | val2 = readl(info->reg.gpmc_bch_result1[i]); | ||
1190 | val3 = readl(info->reg.gpmc_bch_result2[i]); | ||
1191 | val4 = readl(info->reg.gpmc_bch_result3[i]); | ||
1192 | |||
1193 | /* | ||
1194 | * Add constant polynomial to remainder, in order to get an ecc | ||
1195 | * sequence of 0xFFs for a buffer filled with 0xFFs. | ||
1196 | */ | ||
1197 | *ecc_code++ = 0xef ^ (val4 & 0xFF); | ||
1198 | *ecc_code++ = 0x51 ^ ((val3 >> 24) & 0xFF); | ||
1199 | *ecc_code++ = 0x2e ^ ((val3 >> 16) & 0xFF); | ||
1200 | *ecc_code++ = 0x09 ^ ((val3 >> 8) & 0xFF); | ||
1201 | *ecc_code++ = 0xed ^ (val3 & 0xFF); | ||
1202 | *ecc_code++ = 0x93 ^ ((val2 >> 24) & 0xFF); | ||
1203 | *ecc_code++ = 0x9a ^ ((val2 >> 16) & 0xFF); | ||
1204 | *ecc_code++ = 0xc2 ^ ((val2 >> 8) & 0xFF); | ||
1205 | *ecc_code++ = 0x97 ^ (val2 & 0xFF); | ||
1206 | *ecc_code++ = 0x79 ^ ((val1 >> 24) & 0xFF); | ||
1207 | *ecc_code++ = 0xe5 ^ ((val1 >> 16) & 0xFF); | ||
1208 | *ecc_code++ = 0x24 ^ ((val1 >> 8) & 0xFF); | ||
1209 | *ecc_code++ = 0xb5 ^ (val1 & 0xFF); | ||
1210 | } | ||
1211 | |||
1212 | return 0; | ||
1213 | } | ||
1214 | #endif /* CONFIG_MTD_NAND_ECC_BCH */ | ||
1215 | |||
1216 | #ifdef CONFIG_MTD_NAND_OMAP_BCH | ||
1217 | /** | ||
1218 | * omap3_calculate_ecc_bch - Generate bytes of ECC bytes | ||
1219 | * @mtd: MTD device structure | 1150 | * @mtd: MTD device structure |
1220 | * @dat: The pointer to data on which ecc is computed | 1151 | * @dat: The pointer to data on which ecc is computed |
1221 | * @ecc_code: The ecc_code buffer | 1152 | * @ecc_code: The ecc_code buffer |
1222 | * | 1153 | * |
1223 | * Support calculating of BCH4/8 ecc vectors for the page | 1154 | * Support calculating of BCH4/8 ecc vectors for the page |
1224 | */ | 1155 | */ |
1225 | static int omap3_calculate_ecc_bch(struct mtd_info *mtd, const u_char *dat, | 1156 | static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd, |
1226 | u_char *ecc_code) | 1157 | const u_char *dat, u_char *ecc_calc) |
1227 | { | 1158 | { |
1228 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | 1159 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, |
1229 | mtd); | 1160 | mtd); |
1161 | int eccbytes = info->nand.ecc.bytes; | ||
1162 | struct gpmc_nand_regs *gpmc_regs = &info->reg; | ||
1163 | u8 *ecc_code; | ||
1230 | unsigned long nsectors, bch_val1, bch_val2, bch_val3, bch_val4; | 1164 | unsigned long nsectors, bch_val1, bch_val2, bch_val3, bch_val4; |
1231 | int i, eccbchtsel; | 1165 | int i; |
1232 | 1166 | ||
1233 | nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1; | 1167 | nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1; |
1234 | /* | ||
1235 | * find BCH scheme used | ||
1236 | * 0 -> BCH4 | ||
1237 | * 1 -> BCH8 | ||
1238 | */ | ||
1239 | eccbchtsel = ((readl(info->reg.gpmc_ecc_config) >> 12) & 0x3); | ||
1240 | |||
1241 | for (i = 0; i < nsectors; i++) { | 1168 | for (i = 0; i < nsectors; i++) { |
1242 | 1169 | ecc_code = ecc_calc; | |
1243 | /* Read hw-computed remainder */ | 1170 | switch (info->ecc_opt) { |
1244 | bch_val1 = readl(info->reg.gpmc_bch_result0[i]); | 1171 | case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: |
1245 | bch_val2 = readl(info->reg.gpmc_bch_result1[i]); | 1172 | case OMAP_ECC_BCH8_CODE_HW: |
1246 | if (eccbchtsel) { | 1173 | bch_val1 = readl(gpmc_regs->gpmc_bch_result0[i]); |
1247 | bch_val3 = readl(info->reg.gpmc_bch_result2[i]); | 1174 | bch_val2 = readl(gpmc_regs->gpmc_bch_result1[i]); |
1248 | bch_val4 = readl(info->reg.gpmc_bch_result3[i]); | 1175 | bch_val3 = readl(gpmc_regs->gpmc_bch_result2[i]); |
1249 | } | 1176 | bch_val4 = readl(gpmc_regs->gpmc_bch_result3[i]); |
1250 | |||
1251 | if (eccbchtsel) { | ||
1252 | /* BCH8 ecc scheme */ | ||
1253 | *ecc_code++ = (bch_val4 & 0xFF); | 1177 | *ecc_code++ = (bch_val4 & 0xFF); |
1254 | *ecc_code++ = ((bch_val3 >> 24) & 0xFF); | 1178 | *ecc_code++ = ((bch_val3 >> 24) & 0xFF); |
1255 | *ecc_code++ = ((bch_val3 >> 16) & 0xFF); | 1179 | *ecc_code++ = ((bch_val3 >> 16) & 0xFF); |
@@ -1263,14 +1187,11 @@ static int omap3_calculate_ecc_bch(struct mtd_info *mtd, const u_char *dat, | |||
1263 | *ecc_code++ = ((bch_val1 >> 16) & 0xFF); | 1187 | *ecc_code++ = ((bch_val1 >> 16) & 0xFF); |
1264 | *ecc_code++ = ((bch_val1 >> 8) & 0xFF); | 1188 | *ecc_code++ = ((bch_val1 >> 8) & 0xFF); |
1265 | *ecc_code++ = (bch_val1 & 0xFF); | 1189 | *ecc_code++ = (bch_val1 & 0xFF); |
1266 | /* | 1190 | break; |
1267 | * Setting 14th byte to zero to handle | 1191 | case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: |
1268 | * erased page & maintain compatibility | 1192 | case OMAP_ECC_BCH4_CODE_HW: |
1269 | * with RBL | 1193 | bch_val1 = readl(gpmc_regs->gpmc_bch_result0[i]); |
1270 | */ | 1194 | bch_val2 = readl(gpmc_regs->gpmc_bch_result1[i]); |
1271 | *ecc_code++ = 0x0; | ||
1272 | } else { | ||
1273 | /* BCH4 ecc scheme */ | ||
1274 | *ecc_code++ = ((bch_val2 >> 12) & 0xFF); | 1195 | *ecc_code++ = ((bch_val2 >> 12) & 0xFF); |
1275 | *ecc_code++ = ((bch_val2 >> 4) & 0xFF); | 1196 | *ecc_code++ = ((bch_val2 >> 4) & 0xFF); |
1276 | *ecc_code++ = ((bch_val2 & 0xF) << 4) | | 1197 | *ecc_code++ = ((bch_val2 & 0xF) << 4) | |
@@ -1279,12 +1200,38 @@ static int omap3_calculate_ecc_bch(struct mtd_info *mtd, const u_char *dat, | |||
1279 | *ecc_code++ = ((bch_val1 >> 12) & 0xFF); | 1200 | *ecc_code++ = ((bch_val1 >> 12) & 0xFF); |
1280 | *ecc_code++ = ((bch_val1 >> 4) & 0xFF); | 1201 | *ecc_code++ = ((bch_val1 >> 4) & 0xFF); |
1281 | *ecc_code++ = ((bch_val1 & 0xF) << 4); | 1202 | *ecc_code++ = ((bch_val1 & 0xF) << 4); |
1282 | /* | 1203 | break; |
1283 | * Setting 8th byte to zero to handle | 1204 | default: |
1284 | * erased page | 1205 | return -EINVAL; |
1285 | */ | ||
1286 | *ecc_code++ = 0x0; | ||
1287 | } | 1206 | } |
1207 | |||
1208 | /* ECC scheme specific syndrome customizations */ | ||
1209 | switch (info->ecc_opt) { | ||
1210 | case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: | ||
1211 | /* Add constant polynomial to remainder, so that | ||
1212 | * ECC of blank pages results in 0x0 on reading back */ | ||
1213 | for (i = 0; i < eccbytes; i++) | ||
1214 | ecc_calc[i] ^= bch4_polynomial[i]; | ||
1215 | break; | ||
1216 | case OMAP_ECC_BCH4_CODE_HW: | ||
1217 | /* Set 8th ECC byte as 0x0 for ROM compatibility */ | ||
1218 | ecc_calc[eccbytes - 1] = 0x0; | ||
1219 | break; | ||
1220 | case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: | ||
1221 | /* Add constant polynomial to remainder, so that | ||
1222 | * ECC of blank pages results in 0x0 on reading back */ | ||
1223 | for (i = 0; i < eccbytes; i++) | ||
1224 | ecc_calc[i] ^= bch8_polynomial[i]; | ||
1225 | break; | ||
1226 | case OMAP_ECC_BCH8_CODE_HW: | ||
1227 | /* Set 14th ECC byte as 0x0 for ROM compatibility */ | ||
1228 | ecc_calc[eccbytes - 1] = 0x0; | ||
1229 | break; | ||
1230 | default: | ||
1231 | return -EINVAL; | ||
1232 | } | ||
1233 | |||
1234 | ecc_calc += eccbytes; | ||
1288 | } | 1235 | } |
1289 | 1236 | ||
1290 | return 0; | 1237 | return 0; |
@@ -1329,6 +1276,7 @@ static int erased_sector_bitflips(u_char *data, u_char *oob, | |||
1329 | return flip_bits; | 1276 | return flip_bits; |
1330 | } | 1277 | } |
1331 | 1278 | ||
1279 | #ifdef CONFIG_MTD_NAND_OMAP_BCH | ||
1332 | /** | 1280 | /** |
1333 | * omap_elm_correct_data - corrects page data area in case error reported | 1281 | * omap_elm_correct_data - corrects page data area in case error reported |
1334 | * @mtd: MTD device structure | 1282 | * @mtd: MTD device structure |
@@ -1337,55 +1285,46 @@ static int erased_sector_bitflips(u_char *data, u_char *oob, | |||
1337 | * @calc_ecc: ecc read from HW ECC registers | 1285 | * @calc_ecc: ecc read from HW ECC registers |
1338 | * | 1286 | * |
1339 | * Calculated ecc vector reported as zero in case of non-error pages. | 1287 | * Calculated ecc vector reported as zero in case of non-error pages. |
1340 | * In case of error/erased pages non-zero error vector is reported. | 1288 | * In case of non-zero ecc vector, first filter out erased-pages, and |
1341 | * In case of non-zero ecc vector, check read_ecc at fixed offset | 1289 | * then process data via ELM to detect bit-flips. |
1342 | * (x = 13/7 in case of BCH8/4 == 0) to find page programmed or not. | ||
1343 | * To handle bit flips in this data, count the number of 0's in | ||
1344 | * read_ecc[x] and check if it greater than 4. If it is less, it is | ||
1345 | * programmed page, else erased page. | ||
1346 | * | ||
1347 | * 1. If page is erased, check with standard ecc vector (ecc vector | ||
1348 | * for erased page to find any bit flip). If check fails, bit flip | ||
1349 | * is present in erased page. Count the bit flips in erased page and | ||
1350 | * if it falls under correctable level, report page with 0xFF and | ||
1351 | * update the correctable bit information. | ||
1352 | * 2. If error is reported on programmed page, update elm error | ||
1353 | * vector and correct the page with ELM error correction routine. | ||
1354 | * | ||
1355 | */ | 1290 | */ |
1356 | static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, | 1291 | static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, |
1357 | u_char *read_ecc, u_char *calc_ecc) | 1292 | u_char *read_ecc, u_char *calc_ecc) |
1358 | { | 1293 | { |
1359 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | 1294 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, |
1360 | mtd); | 1295 | mtd); |
1296 | struct nand_ecc_ctrl *ecc = &info->nand.ecc; | ||
1361 | int eccsteps = info->nand.ecc.steps; | 1297 | int eccsteps = info->nand.ecc.steps; |
1362 | int i , j, stat = 0; | 1298 | int i , j, stat = 0; |
1363 | int eccsize, eccflag, ecc_vector_size; | 1299 | int eccflag, actual_eccbytes; |
1364 | struct elm_errorvec err_vec[ERROR_VECTOR_MAX]; | 1300 | struct elm_errorvec err_vec[ERROR_VECTOR_MAX]; |
1365 | u_char *ecc_vec = calc_ecc; | 1301 | u_char *ecc_vec = calc_ecc; |
1366 | u_char *spare_ecc = read_ecc; | 1302 | u_char *spare_ecc = read_ecc; |
1367 | u_char *erased_ecc_vec; | 1303 | u_char *erased_ecc_vec; |
1368 | enum bch_ecc type; | 1304 | u_char *buf; |
1305 | int bitflip_count; | ||
1369 | bool is_error_reported = false; | 1306 | bool is_error_reported = false; |
1307 | u32 bit_pos, byte_pos, error_max, pos; | ||
1308 | int err; | ||
1370 | 1309 | ||
1371 | /* Initialize elm error vector to zero */ | 1310 | switch (info->ecc_opt) { |
1372 | memset(err_vec, 0, sizeof(err_vec)); | 1311 | case OMAP_ECC_BCH4_CODE_HW: |
1373 | 1312 | /* omit 7th ECC byte reserved for ROM code compatibility */ | |
1374 | if (info->nand.ecc.strength == BCH8_MAX_ERROR) { | 1313 | actual_eccbytes = ecc->bytes - 1; |
1375 | type = BCH8_ECC; | ||
1376 | erased_ecc_vec = bch8_vector; | ||
1377 | } else { | ||
1378 | type = BCH4_ECC; | ||
1379 | erased_ecc_vec = bch4_vector; | 1314 | erased_ecc_vec = bch4_vector; |
1315 | break; | ||
1316 | case OMAP_ECC_BCH8_CODE_HW: | ||
1317 | /* omit 14th ECC byte reserved for ROM code compatibility */ | ||
1318 | actual_eccbytes = ecc->bytes - 1; | ||
1319 | erased_ecc_vec = bch8_vector; | ||
1320 | break; | ||
1321 | default: | ||
1322 | pr_err("invalid driver configuration\n"); | ||
1323 | return -EINVAL; | ||
1380 | } | 1324 | } |
1381 | 1325 | ||
1382 | ecc_vector_size = info->nand.ecc.bytes; | 1326 | /* Initialize elm error vector to zero */ |
1383 | 1327 | memset(err_vec, 0, sizeof(err_vec)); | |
1384 | /* | ||
1385 | * Remove extra byte padding for BCH8 RBL | ||
1386 | * compatibility and erased page handling | ||
1387 | */ | ||
1388 | eccsize = ecc_vector_size - 1; | ||
1389 | 1328 | ||
1390 | for (i = 0; i < eccsteps ; i++) { | 1329 | for (i = 0; i < eccsteps ; i++) { |
1391 | eccflag = 0; /* initialize eccflag */ | 1330 | eccflag = 0; /* initialize eccflag */ |
@@ -1394,8 +1333,7 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, | |||
1394 | * Check any error reported, | 1333 | * Check any error reported, |
1395 | * In case of error, non zero ecc reported. | 1334 | * In case of error, non zero ecc reported. |
1396 | */ | 1335 | */ |
1397 | 1336 | for (j = 0; j < actual_eccbytes; j++) { | |
1398 | for (j = 0; (j < eccsize); j++) { | ||
1399 | if (calc_ecc[j] != 0) { | 1337 | if (calc_ecc[j] != 0) { |
1400 | eccflag = 1; /* non zero ecc, error present */ | 1338 | eccflag = 1; /* non zero ecc, error present */ |
1401 | break; | 1339 | break; |
@@ -1403,50 +1341,43 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, | |||
1403 | } | 1341 | } |
1404 | 1342 | ||
1405 | if (eccflag == 1) { | 1343 | if (eccflag == 1) { |
1406 | /* | 1344 | if (memcmp(calc_ecc, erased_ecc_vec, |
1407 | * Set threshold to minimum of 4, half of ecc.strength/2 | 1345 | actual_eccbytes) == 0) { |
1408 | * to allow max bit flip in byte to 4 | ||
1409 | */ | ||
1410 | unsigned int threshold = min_t(unsigned int, 4, | ||
1411 | info->nand.ecc.strength / 2); | ||
1412 | |||
1413 | /* | ||
1414 | * Check data area is programmed by counting | ||
1415 | * number of 0's at fixed offset in spare area. | ||
1416 | * Checking count of 0's against threshold. | ||
1417 | * In case programmed page expects at least threshold | ||
1418 | * zeros in byte. | ||
1419 | * If zeros are less than threshold for programmed page/ | ||
1420 | * zeros are more than threshold erased page, either | ||
1421 | * case page reported as uncorrectable. | ||
1422 | */ | ||
1423 | if (hweight8(~read_ecc[eccsize]) >= threshold) { | ||
1424 | /* | 1346 | /* |
1425 | * Update elm error vector as | 1347 | * calc_ecc[] matches pattern for ECC(all 0xff) |
1426 | * data area is programmed | 1348 | * so this is definitely an erased-page |
1427 | */ | 1349 | */ |
1428 | err_vec[i].error_reported = true; | ||
1429 | is_error_reported = true; | ||
1430 | } else { | 1350 | } else { |
1431 | /* Error reported in erased page */ | 1351 | buf = &data[info->nand.ecc.size * i]; |
1432 | int bitflip_count; | 1352 | /* |
1433 | u_char *buf = &data[info->nand.ecc.size * i]; | 1353 | * count number of 0-bits in read_buf. |
1434 | 1354 | * This check can be removed once a similar | |
1435 | if (memcmp(calc_ecc, erased_ecc_vec, eccsize)) { | 1355 | * check is introduced in generic NAND driver |
1436 | bitflip_count = erased_sector_bitflips( | 1356 | */ |
1437 | buf, read_ecc, info); | 1357 | bitflip_count = erased_sector_bitflips( |
1438 | 1358 | buf, read_ecc, info); | |
1439 | if (bitflip_count) | 1359 | if (bitflip_count) { |
1440 | stat += bitflip_count; | 1360 | /* |
1441 | else | 1361 | * number of 0-bits within ECC limits |
1442 | return -EINVAL; | 1362 | * So this may be an erased-page |
1363 | */ | ||
1364 | stat += bitflip_count; | ||
1365 | } else { | ||
1366 | /* | ||
1367 | * Too many 0-bits. It may be a | ||
1368 | * - programmed-page, OR | ||
1369 | * - erased-page with many bit-flips | ||
1370 | * So this page requires check by ELM | ||
1371 | */ | ||
1372 | err_vec[i].error_reported = true; | ||
1373 | is_error_reported = true; | ||
1443 | } | 1374 | } |
1444 | } | 1375 | } |
1445 | } | 1376 | } |
1446 | 1377 | ||
1447 | /* Update the ecc vector */ | 1378 | /* Update the ecc vector */ |
1448 | calc_ecc += ecc_vector_size; | 1379 | calc_ecc += ecc->bytes; |
1449 | read_ecc += ecc_vector_size; | 1380 | read_ecc += ecc->bytes; |
1450 | } | 1381 | } |
1451 | 1382 | ||
1452 | /* Check if any error reported */ | 1383 | /* Check if any error reported */ |
@@ -1456,23 +1387,26 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, | |||
1456 | /* Decode BCH error using ELM module */ | 1387 | /* Decode BCH error using ELM module */ |
1457 | elm_decode_bch_error_page(info->elm_dev, ecc_vec, err_vec); | 1388 | elm_decode_bch_error_page(info->elm_dev, ecc_vec, err_vec); |
1458 | 1389 | ||
1390 | err = 0; | ||
1459 | for (i = 0; i < eccsteps; i++) { | 1391 | for (i = 0; i < eccsteps; i++) { |
1460 | if (err_vec[i].error_reported) { | 1392 | if (err_vec[i].error_uncorrectable) { |
1393 | pr_err("nand: uncorrectable bit-flips found\n"); | ||
1394 | err = -EBADMSG; | ||
1395 | } else if (err_vec[i].error_reported) { | ||
1461 | for (j = 0; j < err_vec[i].error_count; j++) { | 1396 | for (j = 0; j < err_vec[i].error_count; j++) { |
1462 | u32 bit_pos, byte_pos, error_max, pos; | 1397 | switch (info->ecc_opt) { |
1463 | 1398 | case OMAP_ECC_BCH4_CODE_HW: | |
1464 | if (type == BCH8_ECC) | 1399 | /* Add 4 bits to take care of padding */ |
1465 | error_max = BCH8_ECC_MAX; | ||
1466 | else | ||
1467 | error_max = BCH4_ECC_MAX; | ||
1468 | |||
1469 | if (info->nand.ecc.strength == BCH8_MAX_ERROR) | ||
1470 | pos = err_vec[i].error_loc[j]; | ||
1471 | else | ||
1472 | /* Add 4 to take care 4 bit padding */ | ||
1473 | pos = err_vec[i].error_loc[j] + | 1400 | pos = err_vec[i].error_loc[j] + |
1474 | BCH4_BIT_PAD; | 1401 | BCH4_BIT_PAD; |
1475 | 1402 | break; | |
1403 | case OMAP_ECC_BCH8_CODE_HW: | ||
1404 | pos = err_vec[i].error_loc[j]; | ||
1405 | break; | ||
1406 | default: | ||
1407 | return -EINVAL; | ||
1408 | } | ||
1409 | error_max = (ecc->size + actual_eccbytes) * 8; | ||
1476 | /* Calculate bit position of error */ | 1410 | /* Calculate bit position of error */ |
1477 | bit_pos = pos % 8; | 1411 | bit_pos = pos % 8; |
1478 | 1412 | ||
@@ -1480,13 +1414,22 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, | |||
1480 | byte_pos = (error_max - pos - 1) / 8; | 1414 | byte_pos = (error_max - pos - 1) / 8; |
1481 | 1415 | ||
1482 | if (pos < error_max) { | 1416 | if (pos < error_max) { |
1483 | if (byte_pos < 512) | 1417 | if (byte_pos < 512) { |
1418 | pr_debug("bitflip@dat[%d]=%x\n", | ||
1419 | byte_pos, data[byte_pos]); | ||
1484 | data[byte_pos] ^= 1 << bit_pos; | 1420 | data[byte_pos] ^= 1 << bit_pos; |
1485 | else | 1421 | } else { |
1422 | pr_debug("bitflip@oob[%d]=%x\n", | ||
1423 | (byte_pos - 512), | ||
1424 | spare_ecc[byte_pos - 512]); | ||
1486 | spare_ecc[byte_pos - 512] ^= | 1425 | spare_ecc[byte_pos - 512] ^= |
1487 | 1 << bit_pos; | 1426 | 1 << bit_pos; |
1427 | } | ||
1428 | } else { | ||
1429 | pr_err("invalid bit-flip @ %d:%d\n", | ||
1430 | byte_pos, bit_pos); | ||
1431 | err = -EBADMSG; | ||
1488 | } | 1432 | } |
1489 | /* else, not interested to correct ecc */ | ||
1490 | } | 1433 | } |
1491 | } | 1434 | } |
1492 | 1435 | ||
@@ -1494,16 +1437,11 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, | |||
1494 | stat += err_vec[i].error_count; | 1437 | stat += err_vec[i].error_count; |
1495 | 1438 | ||
1496 | /* Update page data with sector size */ | 1439 | /* Update page data with sector size */ |
1497 | data += info->nand.ecc.size; | 1440 | data += ecc->size; |
1498 | spare_ecc += ecc_vector_size; | 1441 | spare_ecc += ecc->bytes; |
1499 | } | 1442 | } |
1500 | 1443 | ||
1501 | for (i = 0; i < eccsteps; i++) | 1444 | return (err) ? err : stat; |
1502 | /* Return error if uncorrectable error present */ | ||
1503 | if (err_vec[i].error_uncorrectable) | ||
1504 | return -EINVAL; | ||
1505 | |||
1506 | return stat; | ||
1507 | } | 1445 | } |
1508 | 1446 | ||
1509 | /** | 1447 | /** |
@@ -1601,7 +1539,8 @@ static int is_elm_present(struct omap_nand_info *info, | |||
1601 | struct device_node *elm_node, enum bch_ecc bch_type) | 1539 | struct device_node *elm_node, enum bch_ecc bch_type) |
1602 | { | 1540 | { |
1603 | struct platform_device *pdev; | 1541 | struct platform_device *pdev; |
1604 | info->is_elm_used = false; | 1542 | struct nand_ecc_ctrl *ecc = &info->nand.ecc; |
1543 | int err; | ||
1605 | /* check whether elm-id is passed via DT */ | 1544 | /* check whether elm-id is passed via DT */ |
1606 | if (!elm_node) { | 1545 | if (!elm_node) { |
1607 | pr_err("nand: error: ELM DT node not found\n"); | 1546 | pr_err("nand: error: ELM DT node not found\n"); |
@@ -1615,10 +1554,10 @@ static int is_elm_present(struct omap_nand_info *info, | |||
1615 | } | 1554 | } |
1616 | /* ELM module available, now configure it */ | 1555 | /* ELM module available, now configure it */ |
1617 | info->elm_dev = &pdev->dev; | 1556 | info->elm_dev = &pdev->dev; |
1618 | if (elm_config(info->elm_dev, bch_type)) | 1557 | err = elm_config(info->elm_dev, bch_type, |
1619 | return -ENODEV; | 1558 | (info->mtd.writesize / ecc->size), ecc->size, ecc->bytes); |
1620 | info->is_elm_used = true; | 1559 | |
1621 | return 0; | 1560 | return err; |
1622 | } | 1561 | } |
1623 | #endif /* CONFIG_MTD_NAND_ECC_BCH */ | 1562 | #endif /* CONFIG_MTD_NAND_ECC_BCH */ |
1624 | 1563 | ||
@@ -1657,6 +1596,7 @@ static int omap_nand_probe(struct platform_device *pdev) | |||
1657 | info->gpmc_cs = pdata->cs; | 1596 | info->gpmc_cs = pdata->cs; |
1658 | info->reg = pdata->reg; | 1597 | info->reg = pdata->reg; |
1659 | info->of_node = pdata->of_node; | 1598 | info->of_node = pdata->of_node; |
1599 | info->ecc_opt = pdata->ecc_opt; | ||
1660 | mtd = &info->mtd; | 1600 | mtd = &info->mtd; |
1661 | mtd->priv = &info->nand; | 1601 | mtd->priv = &info->nand; |
1662 | mtd->name = dev_name(&pdev->dev); | 1602 | mtd->name = dev_name(&pdev->dev); |
@@ -1666,27 +1606,11 @@ static int omap_nand_probe(struct platform_device *pdev) | |||
1666 | nand_chip->options |= NAND_SKIP_BBTSCAN; | 1606 | nand_chip->options |= NAND_SKIP_BBTSCAN; |
1667 | 1607 | ||
1668 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1608 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1669 | if (res == NULL) { | 1609 | nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res); |
1670 | err = -EINVAL; | 1610 | if (IS_ERR(nand_chip->IO_ADDR_R)) |
1671 | dev_err(&pdev->dev, "error getting memory resource\n"); | 1611 | return PTR_ERR(nand_chip->IO_ADDR_R); |
1672 | goto return_error; | ||
1673 | } | ||
1674 | 1612 | ||
1675 | info->phys_base = res->start; | 1613 | info->phys_base = res->start; |
1676 | info->mem_size = resource_size(res); | ||
1677 | |||
1678 | if (!devm_request_mem_region(&pdev->dev, info->phys_base, | ||
1679 | info->mem_size, pdev->dev.driver->name)) { | ||
1680 | err = -EBUSY; | ||
1681 | goto return_error; | ||
1682 | } | ||
1683 | |||
1684 | nand_chip->IO_ADDR_R = devm_ioremap(&pdev->dev, info->phys_base, | ||
1685 | info->mem_size); | ||
1686 | if (!nand_chip->IO_ADDR_R) { | ||
1687 | err = -ENOMEM; | ||
1688 | goto return_error; | ||
1689 | } | ||
1690 | 1614 | ||
1691 | nand_chip->controller = &info->controller; | 1615 | nand_chip->controller = &info->controller; |
1692 | 1616 | ||
@@ -1812,7 +1736,7 @@ static int omap_nand_probe(struct platform_device *pdev) | |||
1812 | /* populate MTD interface based on ECC scheme */ | 1736 | /* populate MTD interface based on ECC scheme */ |
1813 | nand_chip->ecc.layout = &omap_oobinfo; | 1737 | nand_chip->ecc.layout = &omap_oobinfo; |
1814 | ecclayout = &omap_oobinfo; | 1738 | ecclayout = &omap_oobinfo; |
1815 | switch (pdata->ecc_opt) { | 1739 | switch (info->ecc_opt) { |
1816 | case OMAP_ECC_HAM1_CODE_HW: | 1740 | case OMAP_ECC_HAM1_CODE_HW: |
1817 | pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n"); | 1741 | pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n"); |
1818 | nand_chip->ecc.mode = NAND_ECC_HW; | 1742 | nand_chip->ecc.mode = NAND_ECC_HW; |
@@ -1844,9 +1768,9 @@ static int omap_nand_probe(struct platform_device *pdev) | |||
1844 | nand_chip->ecc.size = 512; | 1768 | nand_chip->ecc.size = 512; |
1845 | nand_chip->ecc.bytes = 7; | 1769 | nand_chip->ecc.bytes = 7; |
1846 | nand_chip->ecc.strength = 4; | 1770 | nand_chip->ecc.strength = 4; |
1847 | nand_chip->ecc.hwctl = omap3_enable_hwecc_bch; | 1771 | nand_chip->ecc.hwctl = omap_enable_hwecc_bch; |
1848 | nand_chip->ecc.correct = nand_bch_correct_data; | 1772 | nand_chip->ecc.correct = nand_bch_correct_data; |
1849 | nand_chip->ecc.calculate = omap3_calculate_ecc_bch4; | 1773 | nand_chip->ecc.calculate = omap_calculate_ecc_bch; |
1850 | /* define ECC layout */ | 1774 | /* define ECC layout */ |
1851 | ecclayout->eccbytes = nand_chip->ecc.bytes * | 1775 | ecclayout->eccbytes = nand_chip->ecc.bytes * |
1852 | (mtd->writesize / | 1776 | (mtd->writesize / |
@@ -1884,9 +1808,9 @@ static int omap_nand_probe(struct platform_device *pdev) | |||
1884 | /* 14th bit is kept reserved for ROM-code compatibility */ | 1808 | /* 14th bit is kept reserved for ROM-code compatibility */ |
1885 | nand_chip->ecc.bytes = 7 + 1; | 1809 | nand_chip->ecc.bytes = 7 + 1; |
1886 | nand_chip->ecc.strength = 4; | 1810 | nand_chip->ecc.strength = 4; |
1887 | nand_chip->ecc.hwctl = omap3_enable_hwecc_bch; | 1811 | nand_chip->ecc.hwctl = omap_enable_hwecc_bch; |
1888 | nand_chip->ecc.correct = omap_elm_correct_data; | 1812 | nand_chip->ecc.correct = omap_elm_correct_data; |
1889 | nand_chip->ecc.calculate = omap3_calculate_ecc_bch; | 1813 | nand_chip->ecc.calculate = omap_calculate_ecc_bch; |
1890 | nand_chip->ecc.read_page = omap_read_page_bch; | 1814 | nand_chip->ecc.read_page = omap_read_page_bch; |
1891 | nand_chip->ecc.write_page = omap_write_page_bch; | 1815 | nand_chip->ecc.write_page = omap_write_page_bch; |
1892 | /* define ECC layout */ | 1816 | /* define ECC layout */ |
@@ -1919,9 +1843,9 @@ static int omap_nand_probe(struct platform_device *pdev) | |||
1919 | nand_chip->ecc.size = 512; | 1843 | nand_chip->ecc.size = 512; |
1920 | nand_chip->ecc.bytes = 13; | 1844 | nand_chip->ecc.bytes = 13; |
1921 | nand_chip->ecc.strength = 8; | 1845 | nand_chip->ecc.strength = 8; |
1922 | nand_chip->ecc.hwctl = omap3_enable_hwecc_bch; | 1846 | nand_chip->ecc.hwctl = omap_enable_hwecc_bch; |
1923 | nand_chip->ecc.correct = nand_bch_correct_data; | 1847 | nand_chip->ecc.correct = nand_bch_correct_data; |
1924 | nand_chip->ecc.calculate = omap3_calculate_ecc_bch8; | 1848 | nand_chip->ecc.calculate = omap_calculate_ecc_bch; |
1925 | /* define ECC layout */ | 1849 | /* define ECC layout */ |
1926 | ecclayout->eccbytes = nand_chip->ecc.bytes * | 1850 | ecclayout->eccbytes = nand_chip->ecc.bytes * |
1927 | (mtd->writesize / | 1851 | (mtd->writesize / |
@@ -1960,9 +1884,9 @@ static int omap_nand_probe(struct platform_device *pdev) | |||
1960 | /* 14th bit is kept reserved for ROM-code compatibility */ | 1884 | /* 14th bit is kept reserved for ROM-code compatibility */ |
1961 | nand_chip->ecc.bytes = 13 + 1; | 1885 | nand_chip->ecc.bytes = 13 + 1; |
1962 | nand_chip->ecc.strength = 8; | 1886 | nand_chip->ecc.strength = 8; |
1963 | nand_chip->ecc.hwctl = omap3_enable_hwecc_bch; | 1887 | nand_chip->ecc.hwctl = omap_enable_hwecc_bch; |
1964 | nand_chip->ecc.correct = omap_elm_correct_data; | 1888 | nand_chip->ecc.correct = omap_elm_correct_data; |
1965 | nand_chip->ecc.calculate = omap3_calculate_ecc_bch; | 1889 | nand_chip->ecc.calculate = omap_calculate_ecc_bch; |
1966 | nand_chip->ecc.read_page = omap_read_page_bch; | 1890 | nand_chip->ecc.read_page = omap_read_page_bch; |
1967 | nand_chip->ecc.write_page = omap_write_page_bch; | 1891 | nand_chip->ecc.write_page = omap_write_page_bch; |
1968 | /* This ECC scheme requires ELM H/W block */ | 1892 | /* This ECC scheme requires ELM H/W block */ |