diff options
author | Boris Brezillon <boris.brezillon@free-electrons.com> | 2016-02-03 14:11:14 -0500 |
---|---|---|
committer | Boris Brezillon <boris.brezillon@free-electrons.com> | 2016-04-19 16:05:49 -0400 |
commit | 78d28e8ec4fbd4d1e0c375d7a28f4f23e9e7b15e (patch) | |
tree | e2dee2e1186735d8be0fa8bd3366d0a1ae68d2a6 | |
parent | 846031d3e1837b71e350bd8098f00995069859a8 (diff) |
mtd: nand: atmel: use mtd_ooblayout_xxx() helpers where appropriate
The mtd_ooblayout_xxx() helper functions have been added to avoid direct
accesses to the ecclayout field, and thus ease for future reworks.
Use these helpers in all places where the oobfree[] and eccpos[] arrays
where directly accessed.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Reviewed-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-rw-r--r-- | drivers/mtd/nand/atmel_nand.c | 50 |
1 files changed, 31 insertions, 19 deletions
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 5e716f2a8739..b132c8fd3701 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c | |||
@@ -833,13 +833,16 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc, | |||
833 | dev_dbg(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", | 833 | dev_dbg(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", |
834 | pos, bit_pos, err_byte, *(buf + byte_pos)); | 834 | pos, bit_pos, err_byte, *(buf + byte_pos)); |
835 | } else { | 835 | } else { |
836 | struct mtd_oob_region oobregion; | ||
837 | |||
836 | /* Bit flip in OOB area */ | 838 | /* Bit flip in OOB area */ |
837 | tmp = sector_num * nand_chip->ecc.bytes | 839 | tmp = sector_num * nand_chip->ecc.bytes |
838 | + (byte_pos - sector_size); | 840 | + (byte_pos - sector_size); |
839 | err_byte = ecc[tmp]; | 841 | err_byte = ecc[tmp]; |
840 | ecc[tmp] ^= (1 << bit_pos); | 842 | ecc[tmp] ^= (1 << bit_pos); |
841 | 843 | ||
842 | pos = tmp + nand_chip->ecc.layout->eccpos[0]; | 844 | mtd_ooblayout_ecc(mtd, 0, &oobregion); |
845 | pos = tmp + oobregion.offset; | ||
843 | dev_dbg(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", | 846 | dev_dbg(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", |
844 | pos, bit_pos, err_byte, ecc[tmp]); | 847 | pos, bit_pos, err_byte, ecc[tmp]); |
845 | } | 848 | } |
@@ -931,7 +934,6 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, | |||
931 | struct atmel_nand_host *host = nand_get_controller_data(chip); | 934 | struct atmel_nand_host *host = nand_get_controller_data(chip); |
932 | int eccsize = chip->ecc.size * chip->ecc.steps; | 935 | int eccsize = chip->ecc.size * chip->ecc.steps; |
933 | uint8_t *oob = chip->oob_poi; | 936 | uint8_t *oob = chip->oob_poi; |
934 | uint32_t *eccpos = chip->ecc.layout->eccpos; | ||
935 | uint32_t stat; | 937 | uint32_t stat; |
936 | unsigned long end_time; | 938 | unsigned long end_time; |
937 | int bitflips = 0; | 939 | int bitflips = 0; |
@@ -953,7 +955,11 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, | |||
953 | 955 | ||
954 | stat = pmecc_readl_relaxed(host->ecc, ISR); | 956 | stat = pmecc_readl_relaxed(host->ecc, ISR); |
955 | if (stat != 0) { | 957 | if (stat != 0) { |
956 | bitflips = pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]); | 958 | struct mtd_oob_region oobregion; |
959 | |||
960 | mtd_ooblayout_ecc(mtd, 0, &oobregion); | ||
961 | bitflips = pmecc_correction(mtd, stat, buf, | ||
962 | &oob[oobregion.offset]); | ||
957 | if (bitflips < 0) | 963 | if (bitflips < 0) |
958 | /* uncorrectable errors */ | 964 | /* uncorrectable errors */ |
959 | return 0; | 965 | return 0; |
@@ -967,8 +973,8 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, | |||
967 | int page) | 973 | int page) |
968 | { | 974 | { |
969 | struct atmel_nand_host *host = nand_get_controller_data(chip); | 975 | struct atmel_nand_host *host = nand_get_controller_data(chip); |
970 | uint32_t *eccpos = chip->ecc.layout->eccpos; | 976 | struct mtd_oob_region oobregion = { }; |
971 | int i, j; | 977 | int i, j, section = 0; |
972 | unsigned long end_time; | 978 | unsigned long end_time; |
973 | 979 | ||
974 | if (!host->nfc || !host->nfc->write_by_sram) { | 980 | if (!host->nfc || !host->nfc->write_by_sram) { |
@@ -987,11 +993,14 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, | |||
987 | 993 | ||
988 | for (i = 0; i < chip->ecc.steps; i++) { | 994 | for (i = 0; i < chip->ecc.steps; i++) { |
989 | for (j = 0; j < chip->ecc.bytes; j++) { | 995 | for (j = 0; j < chip->ecc.bytes; j++) { |
990 | int pos; | 996 | if (!oobregion.length) |
997 | mtd_ooblayout_ecc(mtd, section, &oobregion); | ||
991 | 998 | ||
992 | pos = i * chip->ecc.bytes + j; | 999 | chip->oob_poi[oobregion.offset] = |
993 | chip->oob_poi[eccpos[pos]] = | ||
994 | pmecc_readb_ecc_relaxed(host->ecc, i, j); | 1000 | pmecc_readb_ecc_relaxed(host->ecc, i, j); |
1001 | oobregion.length--; | ||
1002 | oobregion.offset++; | ||
1003 | section++; | ||
995 | } | 1004 | } |
996 | } | 1005 | } |
997 | chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); | 1006 | chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); |
@@ -1005,6 +1014,7 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd) | |||
1005 | struct atmel_nand_host *host = nand_get_controller_data(nand_chip); | 1014 | struct atmel_nand_host *host = nand_get_controller_data(nand_chip); |
1006 | uint32_t val = 0; | 1015 | uint32_t val = 0; |
1007 | struct nand_ecclayout *ecc_layout; | 1016 | struct nand_ecclayout *ecc_layout; |
1017 | struct mtd_oob_region oobregion; | ||
1008 | 1018 | ||
1009 | pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST); | 1019 | pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST); |
1010 | pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); | 1020 | pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); |
@@ -1056,9 +1066,10 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd) | |||
1056 | 1066 | ||
1057 | ecc_layout = nand_chip->ecc.layout; | 1067 | ecc_layout = nand_chip->ecc.layout; |
1058 | pmecc_writel(host->ecc, SAREA, mtd->oobsize - 1); | 1068 | pmecc_writel(host->ecc, SAREA, mtd->oobsize - 1); |
1059 | pmecc_writel(host->ecc, SADDR, ecc_layout->eccpos[0]); | 1069 | mtd_ooblayout_ecc(mtd, 0, &oobregion); |
1070 | pmecc_writel(host->ecc, SADDR, oobregion.offset); | ||
1060 | pmecc_writel(host->ecc, EADDR, | 1071 | pmecc_writel(host->ecc, EADDR, |
1061 | ecc_layout->eccpos[ecc_layout->eccbytes - 1]); | 1072 | oobregion.offset + ecc_layout->eccbytes - 1); |
1062 | /* See datasheet about PMECC Clock Control Register */ | 1073 | /* See datasheet about PMECC Clock Control Register */ |
1063 | pmecc_writel(host->ecc, CLK, 2); | 1074 | pmecc_writel(host->ecc, CLK, 2); |
1064 | pmecc_writel(host->ecc, IDR, 0xff); | 1075 | pmecc_writel(host->ecc, IDR, 0xff); |
@@ -1359,12 +1370,12 @@ static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, | |||
1359 | { | 1370 | { |
1360 | int eccsize = chip->ecc.size; | 1371 | int eccsize = chip->ecc.size; |
1361 | int eccbytes = chip->ecc.bytes; | 1372 | int eccbytes = chip->ecc.bytes; |
1362 | uint32_t *eccpos = chip->ecc.layout->eccpos; | ||
1363 | uint8_t *p = buf; | 1373 | uint8_t *p = buf; |
1364 | uint8_t *oob = chip->oob_poi; | 1374 | uint8_t *oob = chip->oob_poi; |
1365 | uint8_t *ecc_pos; | 1375 | uint8_t *ecc_pos; |
1366 | int stat; | 1376 | int stat; |
1367 | unsigned int max_bitflips = 0; | 1377 | unsigned int max_bitflips = 0; |
1378 | struct mtd_oob_region oobregion = {}; | ||
1368 | 1379 | ||
1369 | /* | 1380 | /* |
1370 | * Errata: ALE is incorrectly wired up to the ECC controller | 1381 | * Errata: ALE is incorrectly wired up to the ECC controller |
@@ -1382,19 +1393,20 @@ static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, | |||
1382 | chip->read_buf(mtd, p, eccsize); | 1393 | chip->read_buf(mtd, p, eccsize); |
1383 | 1394 | ||
1384 | /* move to ECC position if needed */ | 1395 | /* move to ECC position if needed */ |
1385 | if (eccpos[0] != 0) { | 1396 | mtd_ooblayout_ecc(mtd, 0, &oobregion); |
1386 | /* This only works on large pages | 1397 | if (oobregion.offset != 0) { |
1387 | * because the ECC controller waits for | 1398 | /* |
1388 | * NAND_CMD_RNDOUTSTART after the | 1399 | * This only works on large pages because the ECC controller |
1389 | * NAND_CMD_RNDOUT. | 1400 | * waits for NAND_CMD_RNDOUTSTART after the NAND_CMD_RNDOUT. |
1390 | * anyway, for small pages, the eccpos[0] == 0 | 1401 | * Anyway, for small pages, the first ECC byte is at offset |
1402 | * 0 in the OOB area. | ||
1391 | */ | 1403 | */ |
1392 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, | 1404 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, |
1393 | mtd->writesize + eccpos[0], -1); | 1405 | mtd->writesize + oobregion.offset, -1); |
1394 | } | 1406 | } |
1395 | 1407 | ||
1396 | /* the ECC controller needs to read the ECC just after the data */ | 1408 | /* the ECC controller needs to read the ECC just after the data */ |
1397 | ecc_pos = oob + eccpos[0]; | 1409 | ecc_pos = oob + oobregion.offset; |
1398 | chip->read_buf(mtd, ecc_pos, eccbytes); | 1410 | chip->read_buf(mtd, ecc_pos, eccbytes); |
1399 | 1411 | ||
1400 | /* check if there's an error */ | 1412 | /* check if there's an error */ |