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 */ |
