diff options
-rw-r--r-- | drivers/mtd/nand/omap2.c | 573 | ||||
-rw-r--r-- | include/linux/platform_data/elm.h | 3 |
2 files changed, 536 insertions, 40 deletions
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index ec20f67e8949..1a88bd062ac1 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c | |||
@@ -22,9 +22,12 @@ | |||
22 | #include <linux/omap-dma.h> | 22 | #include <linux/omap-dma.h> |
23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/of.h> | ||
26 | #include <linux/of_device.h> | ||
25 | 27 | ||
26 | #ifdef CONFIG_MTD_NAND_OMAP_BCH | 28 | #ifdef CONFIG_MTD_NAND_OMAP_BCH |
27 | #include <linux/bch.h> | 29 | #include <linux/bch.h> |
30 | #include <linux/platform_data/elm.h> | ||
28 | #endif | 31 | #endif |
29 | 32 | ||
30 | #include <linux/platform_data/mtd-nand-omap2.h> | 33 | #include <linux/platform_data/mtd-nand-omap2.h> |
@@ -120,6 +123,30 @@ | |||
120 | #define BCH8_MAX_ERROR 8 /* upto 8 bit correctable */ | 123 | #define BCH8_MAX_ERROR 8 /* upto 8 bit correctable */ |
121 | #define BCH4_MAX_ERROR 4 /* upto 4 bit correctable */ | 124 | #define BCH4_MAX_ERROR 4 /* upto 4 bit correctable */ |
122 | 125 | ||
126 | #define SECTOR_BYTES 512 | ||
127 | /* 4 bit padding to make byte aligned, 56 = 52 + 4 */ | ||
128 | #define BCH4_BIT_PAD 4 | ||
129 | #define BCH8_ECC_MAX ((SECTOR_BYTES + BCH8_ECC_OOB_BYTES) * 8) | ||
130 | #define BCH4_ECC_MAX ((SECTOR_BYTES + BCH4_ECC_OOB_BYTES) * 8) | ||
131 | |||
132 | /* GPMC ecc engine settings for read */ | ||
133 | #define BCH_WRAPMODE_1 1 /* BCH wrap mode 1 */ | ||
134 | #define BCH8R_ECC_SIZE0 0x1a /* ecc_size0 = 26 */ | ||
135 | #define BCH8R_ECC_SIZE1 0x2 /* ecc_size1 = 2 */ | ||
136 | #define BCH4R_ECC_SIZE0 0xd /* ecc_size0 = 13 */ | ||
137 | #define BCH4R_ECC_SIZE1 0x3 /* ecc_size1 = 3 */ | ||
138 | |||
139 | /* GPMC ecc engine settings for write */ | ||
140 | #define BCH_WRAPMODE_6 6 /* BCH wrap mode 6 */ | ||
141 | #define BCH_ECC_SIZE0 0x0 /* ecc_size0 = 0, no oob protection */ | ||
142 | #define BCH_ECC_SIZE1 0x20 /* ecc_size1 = 32 */ | ||
143 | |||
144 | #ifdef CONFIG_MTD_NAND_OMAP_BCH | ||
145 | static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc, | ||
146 | 0xac, 0x6b, 0xff, 0x99, 0x7b}; | ||
147 | static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10}; | ||
148 | #endif | ||
149 | |||
123 | /* oob info generated runtime depending on ecc algorithm and layout selected */ | 150 | /* oob info generated runtime depending on ecc algorithm and layout selected */ |
124 | static struct nand_ecclayout omap_oobinfo; | 151 | static struct nand_ecclayout omap_oobinfo; |
125 | /* Define some generic bad / good block scan pattern which are used | 152 | /* Define some generic bad / good block scan pattern which are used |
@@ -159,6 +186,9 @@ struct omap_nand_info { | |||
159 | #ifdef CONFIG_MTD_NAND_OMAP_BCH | 186 | #ifdef CONFIG_MTD_NAND_OMAP_BCH |
160 | struct bch_control *bch; | 187 | struct bch_control *bch; |
161 | struct nand_ecclayout ecclayout; | 188 | struct nand_ecclayout ecclayout; |
189 | bool is_elm_used; | ||
190 | struct device *elm_dev; | ||
191 | struct device_node *of_node; | ||
162 | #endif | 192 | #endif |
163 | }; | 193 | }; |
164 | 194 | ||
@@ -1034,6 +1064,13 @@ static int omap_dev_ready(struct mtd_info *mtd) | |||
1034 | * omap3_enable_hwecc_bch - Program OMAP3 GPMC to perform BCH ECC correction | 1064 | * omap3_enable_hwecc_bch - Program OMAP3 GPMC to perform BCH ECC correction |
1035 | * @mtd: MTD device structure | 1065 | * @mtd: MTD device structure |
1036 | * @mode: Read/Write mode | 1066 | * @mode: Read/Write mode |
1067 | * | ||
1068 | * When using BCH, sector size is hardcoded to 512 bytes. | ||
1069 | * Using wrapping mode 6 both for reading and writing if ELM module not uses | ||
1070 | * for error correction. | ||
1071 | * On writing, | ||
1072 | * eccsize0 = 0 (no additional protected byte in spare area) | ||
1073 | * eccsize1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area) | ||
1037 | */ | 1074 | */ |
1038 | static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode) | 1075 | static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode) |
1039 | { | 1076 | { |
@@ -1042,32 +1079,57 @@ static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode) | |||
1042 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | 1079 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, |
1043 | mtd); | 1080 | mtd); |
1044 | struct nand_chip *chip = mtd->priv; | 1081 | struct nand_chip *chip = mtd->priv; |
1045 | u32 val; | 1082 | u32 val, wr_mode; |
1083 | unsigned int ecc_size1, ecc_size0; | ||
1084 | |||
1085 | /* Using wrapping mode 6 for writing */ | ||
1086 | wr_mode = BCH_WRAPMODE_6; | ||
1046 | 1087 | ||
1047 | nerrors = info->nand.ecc.strength; | ||
1048 | dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0; | ||
1049 | nsectors = 1; | ||
1050 | /* | 1088 | /* |
1051 | * Program GPMC to perform correction on one 512-byte sector at a time. | 1089 | * ECC engine enabled for valid ecc_size0 nibbles |
1052 | * Using 4 sectors at a time (i.e. ecc.size = 2048) is also possible and | 1090 | * and disabled for ecc_size1 nibbles. |
1053 | * gives a slight (5%) performance gain (but requires additional code). | ||
1054 | */ | 1091 | */ |
1092 | ecc_size0 = BCH_ECC_SIZE0; | ||
1093 | ecc_size1 = BCH_ECC_SIZE1; | ||
1094 | |||
1095 | /* Perform ecc calculation on 512-byte sector */ | ||
1096 | nsectors = 1; | ||
1097 | |||
1098 | /* Update number of error correction */ | ||
1099 | nerrors = info->nand.ecc.strength; | ||
1100 | |||
1101 | /* Multi sector reading/writing for NAND flash with page size < 4096 */ | ||
1102 | if (info->is_elm_used && (mtd->writesize <= 4096)) { | ||
1103 | if (mode == NAND_ECC_READ) { | ||
1104 | /* Using wrapping mode 1 for reading */ | ||
1105 | wr_mode = BCH_WRAPMODE_1; | ||
1106 | |||
1107 | /* | ||
1108 | * ECC engine enabled for ecc_size0 nibbles | ||
1109 | * and disabled for ecc_size1 nibbles. | ||
1110 | */ | ||
1111 | ecc_size0 = (nerrors == 8) ? | ||
1112 | BCH8R_ECC_SIZE0 : BCH4R_ECC_SIZE0; | ||
1113 | ecc_size1 = (nerrors == 8) ? | ||
1114 | BCH8R_ECC_SIZE1 : BCH4R_ECC_SIZE1; | ||
1115 | } | ||
1116 | |||
1117 | /* Perform ecc calculation for one page (< 4096) */ | ||
1118 | nsectors = info->nand.ecc.steps; | ||
1119 | } | ||
1055 | 1120 | ||
1056 | writel(ECC1, info->reg.gpmc_ecc_control); | 1121 | writel(ECC1, info->reg.gpmc_ecc_control); |
1057 | 1122 | ||
1058 | /* | 1123 | /* Configure ecc size for BCH */ |
1059 | * When using BCH, sector size is hardcoded to 512 bytes. | 1124 | val = (ecc_size1 << ECCSIZE1_SHIFT) | (ecc_size0 << ECCSIZE0_SHIFT); |
1060 | * Here we are using wrapping mode 6 both for reading and writing, with: | ||
1061 | * size0 = 0 (no additional protected byte in spare area) | ||
1062 | * size1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area) | ||
1063 | */ | ||
1064 | val = (32 << ECCSIZE1_SHIFT) | (0 << ECCSIZE0_SHIFT); | ||
1065 | writel(val, info->reg.gpmc_ecc_size_config); | 1125 | writel(val, info->reg.gpmc_ecc_size_config); |
1066 | 1126 | ||
1127 | dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0; | ||
1128 | |||
1067 | /* BCH configuration */ | 1129 | /* BCH configuration */ |
1068 | val = ((1 << 16) | /* enable BCH */ | 1130 | val = ((1 << 16) | /* enable BCH */ |
1069 | (((nerrors == 8) ? 1 : 0) << 12) | /* 8 or 4 bits */ | 1131 | (((nerrors == 8) ? 1 : 0) << 12) | /* 8 or 4 bits */ |
1070 | (0x06 << 8) | /* wrap mode = 6 */ | 1132 | (wr_mode << 8) | /* wrap mode */ |
1071 | (dev_width << 7) | /* bus width */ | 1133 | (dev_width << 7) | /* bus width */ |
1072 | (((nsectors-1) & 0x7) << 4) | /* number of sectors */ | 1134 | (((nsectors-1) & 0x7) << 4) | /* number of sectors */ |
1073 | (info->gpmc_cs << 1) | /* ECC CS */ | 1135 | (info->gpmc_cs << 1) | /* ECC CS */ |
@@ -1075,7 +1137,7 @@ static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode) | |||
1075 | 1137 | ||
1076 | writel(val, info->reg.gpmc_ecc_config); | 1138 | writel(val, info->reg.gpmc_ecc_config); |
1077 | 1139 | ||
1078 | /* clear ecc and enable bits */ | 1140 | /* Clear ecc and enable bits */ |
1079 | writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control); | 1141 | writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control); |
1080 | } | 1142 | } |
1081 | 1143 | ||
@@ -1165,6 +1227,298 @@ static int omap3_calculate_ecc_bch8(struct mtd_info *mtd, const u_char *dat, | |||
1165 | } | 1227 | } |
1166 | 1228 | ||
1167 | /** | 1229 | /** |
1230 | * omap3_calculate_ecc_bch - Generate bytes of ECC bytes | ||
1231 | * @mtd: MTD device structure | ||
1232 | * @dat: The pointer to data on which ecc is computed | ||
1233 | * @ecc_code: The ecc_code buffer | ||
1234 | * | ||
1235 | * Support calculating of BCH4/8 ecc vectors for the page | ||
1236 | */ | ||
1237 | static int omap3_calculate_ecc_bch(struct mtd_info *mtd, const u_char *dat, | ||
1238 | u_char *ecc_code) | ||
1239 | { | ||
1240 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | ||
1241 | mtd); | ||
1242 | unsigned long nsectors, bch_val1, bch_val2, bch_val3, bch_val4; | ||
1243 | int i, eccbchtsel; | ||
1244 | |||
1245 | nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1; | ||
1246 | /* | ||
1247 | * find BCH scheme used | ||
1248 | * 0 -> BCH4 | ||
1249 | * 1 -> BCH8 | ||
1250 | */ | ||
1251 | eccbchtsel = ((readl(info->reg.gpmc_ecc_config) >> 12) & 0x3); | ||
1252 | |||
1253 | for (i = 0; i < nsectors; i++) { | ||
1254 | |||
1255 | /* Read hw-computed remainder */ | ||
1256 | bch_val1 = readl(info->reg.gpmc_bch_result0[i]); | ||
1257 | bch_val2 = readl(info->reg.gpmc_bch_result1[i]); | ||
1258 | if (eccbchtsel) { | ||
1259 | bch_val3 = readl(info->reg.gpmc_bch_result2[i]); | ||
1260 | bch_val4 = readl(info->reg.gpmc_bch_result3[i]); | ||
1261 | } | ||
1262 | |||
1263 | if (eccbchtsel) { | ||
1264 | /* BCH8 ecc scheme */ | ||
1265 | *ecc_code++ = (bch_val4 & 0xFF); | ||
1266 | *ecc_code++ = ((bch_val3 >> 24) & 0xFF); | ||
1267 | *ecc_code++ = ((bch_val3 >> 16) & 0xFF); | ||
1268 | *ecc_code++ = ((bch_val3 >> 8) & 0xFF); | ||
1269 | *ecc_code++ = (bch_val3 & 0xFF); | ||
1270 | *ecc_code++ = ((bch_val2 >> 24) & 0xFF); | ||
1271 | *ecc_code++ = ((bch_val2 >> 16) & 0xFF); | ||
1272 | *ecc_code++ = ((bch_val2 >> 8) & 0xFF); | ||
1273 | *ecc_code++ = (bch_val2 & 0xFF); | ||
1274 | *ecc_code++ = ((bch_val1 >> 24) & 0xFF); | ||
1275 | *ecc_code++ = ((bch_val1 >> 16) & 0xFF); | ||
1276 | *ecc_code++ = ((bch_val1 >> 8) & 0xFF); | ||
1277 | *ecc_code++ = (bch_val1 & 0xFF); | ||
1278 | /* | ||
1279 | * Setting 14th byte to zero to handle | ||
1280 | * erased page & maintain compatibility | ||
1281 | * with RBL | ||
1282 | */ | ||
1283 | *ecc_code++ = 0x0; | ||
1284 | } else { | ||
1285 | /* BCH4 ecc scheme */ | ||
1286 | *ecc_code++ = ((bch_val2 >> 12) & 0xFF); | ||
1287 | *ecc_code++ = ((bch_val2 >> 4) & 0xFF); | ||
1288 | *ecc_code++ = ((bch_val2 & 0xF) << 4) | | ||
1289 | ((bch_val1 >> 28) & 0xF); | ||
1290 | *ecc_code++ = ((bch_val1 >> 20) & 0xFF); | ||
1291 | *ecc_code++ = ((bch_val1 >> 12) & 0xFF); | ||
1292 | *ecc_code++ = ((bch_val1 >> 4) & 0xFF); | ||
1293 | *ecc_code++ = ((bch_val1 & 0xF) << 4); | ||
1294 | /* | ||
1295 | * Setting 8th byte to zero to handle | ||
1296 | * erased page | ||
1297 | */ | ||
1298 | *ecc_code++ = 0x0; | ||
1299 | } | ||
1300 | } | ||
1301 | |||
1302 | return 0; | ||
1303 | } | ||
1304 | |||
1305 | /** | ||
1306 | * erased_sector_bitflips - count bit flips | ||
1307 | * @data: data sector buffer | ||
1308 | * @oob: oob buffer | ||
1309 | * @info: omap_nand_info | ||
1310 | * | ||
1311 | * Check the bit flips in erased page falls below correctable level. | ||
1312 | * If falls below, report the page as erased with correctable bit | ||
1313 | * flip, else report as uncorrectable page. | ||
1314 | */ | ||
1315 | static int erased_sector_bitflips(u_char *data, u_char *oob, | ||
1316 | struct omap_nand_info *info) | ||
1317 | { | ||
1318 | int flip_bits = 0, i; | ||
1319 | |||
1320 | for (i = 0; i < info->nand.ecc.size; i++) { | ||
1321 | flip_bits += hweight8(~data[i]); | ||
1322 | if (flip_bits > info->nand.ecc.strength) | ||
1323 | return 0; | ||
1324 | } | ||
1325 | |||
1326 | for (i = 0; i < info->nand.ecc.bytes - 1; i++) { | ||
1327 | flip_bits += hweight8(~oob[i]); | ||
1328 | if (flip_bits > info->nand.ecc.strength) | ||
1329 | return 0; | ||
1330 | } | ||
1331 | |||
1332 | /* | ||
1333 | * Bit flips falls in correctable level. | ||
1334 | * Fill data area with 0xFF | ||
1335 | */ | ||
1336 | if (flip_bits) { | ||
1337 | memset(data, 0xFF, info->nand.ecc.size); | ||
1338 | memset(oob, 0xFF, info->nand.ecc.bytes); | ||
1339 | } | ||
1340 | |||
1341 | return flip_bits; | ||
1342 | } | ||
1343 | |||
1344 | /** | ||
1345 | * omap_elm_correct_data - corrects page data area in case error reported | ||
1346 | * @mtd: MTD device structure | ||
1347 | * @data: page data | ||
1348 | * @read_ecc: ecc read from nand flash | ||
1349 | * @calc_ecc: ecc read from HW ECC registers | ||
1350 | * | ||
1351 | * Calculated ecc vector reported as zero in case of non-error pages. | ||
1352 | * In case of error/erased pages non-zero error vector is reported. | ||
1353 | * In case of non-zero ecc vector, check read_ecc at fixed offset | ||
1354 | * (x = 13/7 in case of BCH8/4 == 0) to find page programmed or not. | ||
1355 | * To handle bit flips in this data, count the number of 0's in | ||
1356 | * read_ecc[x] and check if it greater than 4. If it is less, it is | ||
1357 | * programmed page, else erased page. | ||
1358 | * | ||
1359 | * 1. If page is erased, check with standard ecc vector (ecc vector | ||
1360 | * for erased page to find any bit flip). If check fails, bit flip | ||
1361 | * is present in erased page. Count the bit flips in erased page and | ||
1362 | * if it falls under correctable level, report page with 0xFF and | ||
1363 | * update the correctable bit information. | ||
1364 | * 2. If error is reported on programmed page, update elm error | ||
1365 | * vector and correct the page with ELM error correction routine. | ||
1366 | * | ||
1367 | */ | ||
1368 | static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, | ||
1369 | u_char *read_ecc, u_char *calc_ecc) | ||
1370 | { | ||
1371 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | ||
1372 | mtd); | ||
1373 | int eccsteps = info->nand.ecc.steps; | ||
1374 | int i , j, stat = 0; | ||
1375 | int eccsize, eccflag, ecc_vector_size; | ||
1376 | struct elm_errorvec err_vec[ERROR_VECTOR_MAX]; | ||
1377 | u_char *ecc_vec = calc_ecc; | ||
1378 | u_char *spare_ecc = read_ecc; | ||
1379 | u_char *erased_ecc_vec; | ||
1380 | enum bch_ecc type; | ||
1381 | bool is_error_reported = false; | ||
1382 | |||
1383 | /* Initialize elm error vector to zero */ | ||
1384 | memset(err_vec, 0, sizeof(err_vec)); | ||
1385 | |||
1386 | if (info->nand.ecc.strength == BCH8_MAX_ERROR) { | ||
1387 | type = BCH8_ECC; | ||
1388 | erased_ecc_vec = bch8_vector; | ||
1389 | } else { | ||
1390 | type = BCH4_ECC; | ||
1391 | erased_ecc_vec = bch4_vector; | ||
1392 | } | ||
1393 | |||
1394 | ecc_vector_size = info->nand.ecc.bytes; | ||
1395 | |||
1396 | /* | ||
1397 | * Remove extra byte padding for BCH8 RBL | ||
1398 | * compatibility and erased page handling | ||
1399 | */ | ||
1400 | eccsize = ecc_vector_size - 1; | ||
1401 | |||
1402 | for (i = 0; i < eccsteps ; i++) { | ||
1403 | eccflag = 0; /* initialize eccflag */ | ||
1404 | |||
1405 | /* | ||
1406 | * Check any error reported, | ||
1407 | * In case of error, non zero ecc reported. | ||
1408 | */ | ||
1409 | |||
1410 | for (j = 0; (j < eccsize); j++) { | ||
1411 | if (calc_ecc[j] != 0) { | ||
1412 | eccflag = 1; /* non zero ecc, error present */ | ||
1413 | break; | ||
1414 | } | ||
1415 | } | ||
1416 | |||
1417 | if (eccflag == 1) { | ||
1418 | /* | ||
1419 | * Set threshold to minimum of 4, half of ecc.strength/2 | ||
1420 | * to allow max bit flip in byte to 4 | ||
1421 | */ | ||
1422 | unsigned int threshold = min_t(unsigned int, 4, | ||
1423 | info->nand.ecc.strength / 2); | ||
1424 | |||
1425 | /* | ||
1426 | * Check data area is programmed by counting | ||
1427 | * number of 0's at fixed offset in spare area. | ||
1428 | * Checking count of 0's against threshold. | ||
1429 | * In case programmed page expects at least threshold | ||
1430 | * zeros in byte. | ||
1431 | * If zeros are less than threshold for programmed page/ | ||
1432 | * zeros are more than threshold erased page, either | ||
1433 | * case page reported as uncorrectable. | ||
1434 | */ | ||
1435 | if (hweight8(~read_ecc[eccsize]) >= threshold) { | ||
1436 | /* | ||
1437 | * Update elm error vector as | ||
1438 | * data area is programmed | ||
1439 | */ | ||
1440 | err_vec[i].error_reported = true; | ||
1441 | is_error_reported = true; | ||
1442 | } else { | ||
1443 | /* Error reported in erased page */ | ||
1444 | int bitflip_count; | ||
1445 | u_char *buf = &data[info->nand.ecc.size * i]; | ||
1446 | |||
1447 | if (memcmp(calc_ecc, erased_ecc_vec, eccsize)) { | ||
1448 | bitflip_count = erased_sector_bitflips( | ||
1449 | buf, read_ecc, info); | ||
1450 | |||
1451 | if (bitflip_count) | ||
1452 | stat += bitflip_count; | ||
1453 | else | ||
1454 | return -EINVAL; | ||
1455 | } | ||
1456 | } | ||
1457 | } | ||
1458 | |||
1459 | /* Update the ecc vector */ | ||
1460 | calc_ecc += ecc_vector_size; | ||
1461 | read_ecc += ecc_vector_size; | ||
1462 | } | ||
1463 | |||
1464 | /* Check if any error reported */ | ||
1465 | if (!is_error_reported) | ||
1466 | return 0; | ||
1467 | |||
1468 | /* Decode BCH error using ELM module */ | ||
1469 | elm_decode_bch_error_page(info->elm_dev, ecc_vec, err_vec); | ||
1470 | |||
1471 | for (i = 0; i < eccsteps; i++) { | ||
1472 | if (err_vec[i].error_reported) { | ||
1473 | for (j = 0; j < err_vec[i].error_count; j++) { | ||
1474 | u32 bit_pos, byte_pos, error_max, pos; | ||
1475 | |||
1476 | if (type == BCH8_ECC) | ||
1477 | error_max = BCH8_ECC_MAX; | ||
1478 | else | ||
1479 | error_max = BCH4_ECC_MAX; | ||
1480 | |||
1481 | if (info->nand.ecc.strength == BCH8_MAX_ERROR) | ||
1482 | pos = err_vec[i].error_loc[j]; | ||
1483 | else | ||
1484 | /* Add 4 to take care 4 bit padding */ | ||
1485 | pos = err_vec[i].error_loc[j] + | ||
1486 | BCH4_BIT_PAD; | ||
1487 | |||
1488 | /* Calculate bit position of error */ | ||
1489 | bit_pos = pos % 8; | ||
1490 | |||
1491 | /* Calculate byte position of error */ | ||
1492 | byte_pos = (error_max - pos - 1) / 8; | ||
1493 | |||
1494 | if (pos < error_max) { | ||
1495 | if (byte_pos < 512) | ||
1496 | data[byte_pos] ^= 1 << bit_pos; | ||
1497 | else | ||
1498 | spare_ecc[byte_pos - 512] ^= | ||
1499 | 1 << bit_pos; | ||
1500 | } | ||
1501 | /* else, not interested to correct ecc */ | ||
1502 | } | ||
1503 | } | ||
1504 | |||
1505 | /* Update number of correctable errors */ | ||
1506 | stat += err_vec[i].error_count; | ||
1507 | |||
1508 | /* Update page data with sector size */ | ||
1509 | data += info->nand.ecc.size; | ||
1510 | spare_ecc += ecc_vector_size; | ||
1511 | } | ||
1512 | |||
1513 | for (i = 0; i < eccsteps; i++) | ||
1514 | /* Return error if uncorrectable error present */ | ||
1515 | if (err_vec[i].error_uncorrectable) | ||
1516 | return -EINVAL; | ||
1517 | |||
1518 | return stat; | ||
1519 | } | ||
1520 | |||
1521 | /** | ||
1168 | * omap3_correct_data_bch - Decode received data and correct errors | 1522 | * omap3_correct_data_bch - Decode received data and correct errors |
1169 | * @mtd: MTD device structure | 1523 | * @mtd: MTD device structure |
1170 | * @data: page data | 1524 | * @data: page data |
@@ -1197,6 +1551,92 @@ static int omap3_correct_data_bch(struct mtd_info *mtd, u_char *data, | |||
1197 | } | 1551 | } |
1198 | 1552 | ||
1199 | /** | 1553 | /** |
1554 | * omap_write_page_bch - BCH ecc based write page function for entire page | ||
1555 | * @mtd: mtd info structure | ||
1556 | * @chip: nand chip info structure | ||
1557 | * @buf: data buffer | ||
1558 | * @oob_required: must write chip->oob_poi to OOB | ||
1559 | * | ||
1560 | * Custom write page method evolved to support multi sector writing in one shot | ||
1561 | */ | ||
1562 | static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip, | ||
1563 | const uint8_t *buf, int oob_required) | ||
1564 | { | ||
1565 | int i; | ||
1566 | uint8_t *ecc_calc = chip->buffers->ecccalc; | ||
1567 | uint32_t *eccpos = chip->ecc.layout->eccpos; | ||
1568 | |||
1569 | /* Enable GPMC ecc engine */ | ||
1570 | chip->ecc.hwctl(mtd, NAND_ECC_WRITE); | ||
1571 | |||
1572 | /* Write data */ | ||
1573 | chip->write_buf(mtd, buf, mtd->writesize); | ||
1574 | |||
1575 | /* Update ecc vector from GPMC result registers */ | ||
1576 | chip->ecc.calculate(mtd, buf, &ecc_calc[0]); | ||
1577 | |||
1578 | for (i = 0; i < chip->ecc.total; i++) | ||
1579 | chip->oob_poi[eccpos[i]] = ecc_calc[i]; | ||
1580 | |||
1581 | /* Write ecc vector to OOB area */ | ||
1582 | chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
1583 | return 0; | ||
1584 | } | ||
1585 | |||
1586 | /** | ||
1587 | * omap_read_page_bch - BCH ecc based page read function for entire page | ||
1588 | * @mtd: mtd info structure | ||
1589 | * @chip: nand chip info structure | ||
1590 | * @buf: buffer to store read data | ||
1591 | * @oob_required: caller requires OOB data read to chip->oob_poi | ||
1592 | * @page: page number to read | ||
1593 | * | ||
1594 | * For BCH ecc scheme, GPMC used for syndrome calculation and ELM module | ||
1595 | * used for error correction. | ||
1596 | * Custom method evolved to support ELM error correction & multi sector | ||
1597 | * reading. On reading page data area is read along with OOB data with | ||
1598 | * ecc engine enabled. ecc vector updated after read of OOB data. | ||
1599 | * For non error pages ecc vector reported as zero. | ||
1600 | */ | ||
1601 | static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, | ||
1602 | uint8_t *buf, int oob_required, int page) | ||
1603 | { | ||
1604 | uint8_t *ecc_calc = chip->buffers->ecccalc; | ||
1605 | uint8_t *ecc_code = chip->buffers->ecccode; | ||
1606 | uint32_t *eccpos = chip->ecc.layout->eccpos; | ||
1607 | uint8_t *oob = &chip->oob_poi[eccpos[0]]; | ||
1608 | uint32_t oob_pos = mtd->writesize + chip->ecc.layout->eccpos[0]; | ||
1609 | int stat; | ||
1610 | unsigned int max_bitflips = 0; | ||
1611 | |||
1612 | /* Enable GPMC ecc engine */ | ||
1613 | chip->ecc.hwctl(mtd, NAND_ECC_READ); | ||
1614 | |||
1615 | /* Read data */ | ||
1616 | chip->read_buf(mtd, buf, mtd->writesize); | ||
1617 | |||
1618 | /* Read oob bytes */ | ||
1619 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, -1); | ||
1620 | chip->read_buf(mtd, oob, chip->ecc.total); | ||
1621 | |||
1622 | /* Calculate ecc bytes */ | ||
1623 | chip->ecc.calculate(mtd, buf, ecc_calc); | ||
1624 | |||
1625 | memcpy(ecc_code, &chip->oob_poi[eccpos[0]], chip->ecc.total); | ||
1626 | |||
1627 | stat = chip->ecc.correct(mtd, buf, ecc_code, ecc_calc); | ||
1628 | |||
1629 | if (stat < 0) { | ||
1630 | mtd->ecc_stats.failed++; | ||
1631 | } else { | ||
1632 | mtd->ecc_stats.corrected += stat; | ||
1633 | max_bitflips = max_t(unsigned int, max_bitflips, stat); | ||
1634 | } | ||
1635 | |||
1636 | return max_bitflips; | ||
1637 | } | ||
1638 | |||
1639 | /** | ||
1200 | * omap3_free_bch - Release BCH ecc resources | 1640 | * omap3_free_bch - Release BCH ecc resources |
1201 | * @mtd: MTD device structure | 1641 | * @mtd: MTD device structure |
1202 | */ | 1642 | */ |
@@ -1225,6 +1665,11 @@ static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt) | |||
1225 | #else | 1665 | #else |
1226 | const int hw_errors = BCH4_MAX_ERROR; | 1666 | const int hw_errors = BCH4_MAX_ERROR; |
1227 | #endif | 1667 | #endif |
1668 | enum bch_ecc bch_type; | ||
1669 | const __be32 *parp; | ||
1670 | int lenp; | ||
1671 | struct device_node *elm_node; | ||
1672 | |||
1228 | info->bch = NULL; | 1673 | info->bch = NULL; |
1229 | 1674 | ||
1230 | max_errors = (ecc_opt == OMAP_ECC_BCH8_CODE_HW) ? | 1675 | max_errors = (ecc_opt == OMAP_ECC_BCH8_CODE_HW) ? |
@@ -1235,30 +1680,67 @@ static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt) | |||
1235 | goto fail; | 1680 | goto fail; |
1236 | } | 1681 | } |
1237 | 1682 | ||
1238 | /* software bch library is only used to detect and locate errors */ | 1683 | info->nand.ecc.size = 512; |
1239 | info->bch = init_bch(13, max_errors, 0x201b /* hw polynomial */); | 1684 | info->nand.ecc.hwctl = omap3_enable_hwecc_bch; |
1240 | if (!info->bch) | 1685 | info->nand.ecc.mode = NAND_ECC_HW; |
1241 | goto fail; | 1686 | info->nand.ecc.strength = max_errors; |
1242 | 1687 | ||
1243 | info->nand.ecc.size = 512; | 1688 | if (hw_errors == BCH8_MAX_ERROR) |
1244 | info->nand.ecc.hwctl = omap3_enable_hwecc_bch; | 1689 | bch_type = BCH8_ECC; |
1245 | info->nand.ecc.correct = omap3_correct_data_bch; | 1690 | else |
1246 | info->nand.ecc.mode = NAND_ECC_HW; | 1691 | bch_type = BCH4_ECC; |
1247 | 1692 | ||
1248 | /* | 1693 | /* Detect availability of ELM module */ |
1249 | * The number of corrected errors in an ecc block that will trigger | 1694 | parp = of_get_property(info->of_node, "elm_id", &lenp); |
1250 | * block scrubbing defaults to the ecc strength (4 or 8). | 1695 | if ((parp == NULL) && (lenp != (sizeof(void *) * 2))) { |
1251 | * Set mtd->bitflip_threshold here to define a custom threshold. | 1696 | pr_err("Missing elm_id property, fall back to Software BCH\n"); |
1252 | */ | 1697 | info->is_elm_used = false; |
1698 | } else { | ||
1699 | struct platform_device *pdev; | ||
1253 | 1700 | ||
1254 | if (max_errors == 8) { | 1701 | elm_node = of_find_node_by_phandle(be32_to_cpup(parp)); |
1255 | info->nand.ecc.strength = 8; | 1702 | pdev = of_find_device_by_node(elm_node); |
1256 | info->nand.ecc.bytes = 13; | 1703 | info->elm_dev = &pdev->dev; |
1257 | info->nand.ecc.calculate = omap3_calculate_ecc_bch8; | 1704 | elm_config(info->elm_dev, bch_type); |
1705 | info->is_elm_used = true; | ||
1706 | } | ||
1707 | |||
1708 | if (info->is_elm_used && (mtd->writesize <= 4096)) { | ||
1709 | |||
1710 | if (hw_errors == BCH8_MAX_ERROR) | ||
1711 | info->nand.ecc.bytes = BCH8_SIZE; | ||
1712 | else | ||
1713 | info->nand.ecc.bytes = BCH4_SIZE; | ||
1714 | |||
1715 | info->nand.ecc.correct = omap_elm_correct_data; | ||
1716 | info->nand.ecc.calculate = omap3_calculate_ecc_bch; | ||
1717 | info->nand.ecc.read_page = omap_read_page_bch; | ||
1718 | info->nand.ecc.write_page = omap_write_page_bch; | ||
1258 | } else { | 1719 | } else { |
1259 | info->nand.ecc.strength = 4; | 1720 | /* |
1260 | info->nand.ecc.bytes = 7; | 1721 | * software bch library is only used to detect and |
1261 | info->nand.ecc.calculate = omap3_calculate_ecc_bch4; | 1722 | * locate errors |
1723 | */ | ||
1724 | info->bch = init_bch(13, max_errors, | ||
1725 | 0x201b /* hw polynomial */); | ||
1726 | if (!info->bch) | ||
1727 | goto fail; | ||
1728 | |||
1729 | info->nand.ecc.correct = omap3_correct_data_bch; | ||
1730 | |||
1731 | /* | ||
1732 | * The number of corrected errors in an ecc block that will | ||
1733 | * trigger block scrubbing defaults to the ecc strength (4 or 8) | ||
1734 | * Set mtd->bitflip_threshold here to define a custom threshold. | ||
1735 | */ | ||
1736 | |||
1737 | if (max_errors == 8) { | ||
1738 | info->nand.ecc.bytes = 13; | ||
1739 | info->nand.ecc.calculate = omap3_calculate_ecc_bch8; | ||
1740 | } else { | ||
1741 | info->nand.ecc.bytes = 7; | ||
1742 | info->nand.ecc.calculate = omap3_calculate_ecc_bch4; | ||
1743 | } | ||
1262 | } | 1744 | } |
1263 | 1745 | ||
1264 | pr_info("enabling NAND BCH ecc with %d-bit correction\n", max_errors); | 1746 | pr_info("enabling NAND BCH ecc with %d-bit correction\n", max_errors); |
@@ -1274,7 +1756,7 @@ fail: | |||
1274 | */ | 1756 | */ |
1275 | static int omap3_init_bch_tail(struct mtd_info *mtd) | 1757 | static int omap3_init_bch_tail(struct mtd_info *mtd) |
1276 | { | 1758 | { |
1277 | int i, steps; | 1759 | int i, steps, offset; |
1278 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | 1760 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, |
1279 | mtd); | 1761 | mtd); |
1280 | struct nand_ecclayout *layout = &info->ecclayout; | 1762 | struct nand_ecclayout *layout = &info->ecclayout; |
@@ -1296,11 +1778,21 @@ static int omap3_init_bch_tail(struct mtd_info *mtd) | |||
1296 | goto fail; | 1778 | goto fail; |
1297 | } | 1779 | } |
1298 | 1780 | ||
1781 | /* ECC layout compatible with RBL for BCH8 */ | ||
1782 | if (info->is_elm_used && (info->nand.ecc.bytes == BCH8_SIZE)) | ||
1783 | offset = 2; | ||
1784 | else | ||
1785 | offset = mtd->oobsize - layout->eccbytes; | ||
1786 | |||
1299 | /* put ecc bytes at oob tail */ | 1787 | /* put ecc bytes at oob tail */ |
1300 | for (i = 0; i < layout->eccbytes; i++) | 1788 | for (i = 0; i < layout->eccbytes; i++) |
1301 | layout->eccpos[i] = mtd->oobsize-layout->eccbytes+i; | 1789 | layout->eccpos[i] = offset + i; |
1790 | |||
1791 | if (info->is_elm_used && (info->nand.ecc.bytes == BCH8_SIZE)) | ||
1792 | layout->oobfree[0].offset = 2 + layout->eccbytes * steps; | ||
1793 | else | ||
1794 | layout->oobfree[0].offset = 2; | ||
1302 | 1795 | ||
1303 | layout->oobfree[0].offset = 2; | ||
1304 | layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes; | 1796 | layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes; |
1305 | info->nand.ecc.layout = layout; | 1797 | info->nand.ecc.layout = layout; |
1306 | 1798 | ||
@@ -1363,6 +1855,9 @@ static int omap_nand_probe(struct platform_device *pdev) | |||
1363 | 1855 | ||
1364 | info->nand.options = pdata->devsize; | 1856 | info->nand.options = pdata->devsize; |
1365 | info->nand.options |= NAND_SKIP_BBTSCAN; | 1857 | info->nand.options |= NAND_SKIP_BBTSCAN; |
1858 | #ifdef CONFIG_MTD_NAND_OMAP_BCH | ||
1859 | info->of_node = pdata->of_node; | ||
1860 | #endif | ||
1366 | 1861 | ||
1367 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1862 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1368 | if (res == NULL) { | 1863 | if (res == NULL) { |
diff --git a/include/linux/platform_data/elm.h b/include/linux/platform_data/elm.h index 11ab6aaf2431..1bd5244d1dcd 100644 --- a/include/linux/platform_data/elm.h +++ b/include/linux/platform_data/elm.h | |||
@@ -30,7 +30,8 @@ enum bch_ecc { | |||
30 | #define BCH4_ECC_OOB_BYTES 7 | 30 | #define BCH4_ECC_OOB_BYTES 7 |
31 | /* RBL requires 14 byte even though BCH8 uses only 13 byte */ | 31 | /* RBL requires 14 byte even though BCH8 uses only 13 byte */ |
32 | #define BCH8_SIZE (BCH8_ECC_OOB_BYTES + 1) | 32 | #define BCH8_SIZE (BCH8_ECC_OOB_BYTES + 1) |
33 | #define BCH4_SIZE (BCH4_ECC_OOB_BYTES) | 33 | /* Uses 1 extra byte to handle erased pages */ |
34 | #define BCH4_SIZE (BCH4_ECC_OOB_BYTES + 1) | ||
34 | 35 | ||
35 | /** | 36 | /** |
36 | * struct elm_errorvec - error vector for elm | 37 | * struct elm_errorvec - error vector for elm |