Commit eae39cb4 authored by Pekon Gupta's avatar Pekon Gupta Committed by Brian Norris

mtd: nand: omap: fix ecclayout to be in sync with u-boot NAND driver

Fixes: commit a919e511
       mtd: nand: omap2: clean-up BCHx_HW and BCHx_SW ECC configurations in device_probe

Fixes ecclayout mismatch introduced in above commit for following ecc-schemes:
 - OMAP_ECC_BCH4_CODE_HW_DETECTION_SW
 - OMAP_ECC_BCH8_CODE_HW_DETECTION_SW
 However, this patch also touches other ecc-schemes as the fix required
 refactoring common code, into ecc-scheme specific code.

This patch aligns ecc-layout for below ecc-schemes as per reference [1],[2],[3]

 +---+------------+-------------++-------------+-------------+
 |OOB|BCH8_CODE_HW|BCH8_CODE_HW_||HAM1_CODE_HW |HAM1_CODE_HW |
 |pos|            | DETECTION_SW||(x8 device)  |(x16 device) |
 +---+------------+-------------++-------------+-------------+
 | 0 |BADBLK_MARK | BADBLK_MARK || BADBLK_MARK | BADBLK_MARK |
 | 1 |BADBLK_MARK | BADBLK_MARK || eccpos[0]   | BADBLK_MARK |
 | 2 | eccpos[0]  | eccpos[0]   || eccpos[1]   | eccpos[0]   |
 | 3 | eccpos[1]  | eccpos[1]   || eccpos[2]   | eccpos[1]   |
 | 4 | eccpos[2]  | eccpos[2]   || eccpos[3]   | eccpos[2]   |
 | 5 | eccpos[3]  | eccpos[3]   || eccpos[4]   | eccpos[3]   |
 | 6 | eccpos[4]  | eccpos[4]   || eccpos[5]   | eccpos[4]   |
 | 7 | eccpos[5]  | eccpos[5]   || eccpos[6]   | eccpos[5]   |
 | 8 | eccpos[6]  | eccpos[6]   || eccpos[7]   | eccpos[6]   |
 | 9 | eccpos[7]  | eccpos[7]   || eccpos[8]   | eccpos[7]   |
 |10 | eccpos[8]  | eccpos[8]   || eccpos[9]   | eccpos[8]   |
 |11 | eccpos[9]  | eccpos[9]   || eccpos[10]  | eccpos[9]   |
 |12 | eccpos[10] | eccpos[10]  || eccpos[11]  | eccpos[10]  |
 |13 | eccpos[11] | eccpos[11]  || oobfree[0]  | eccpos[11]  |
 |14 | eccpos[12] | eccpos[12]  || oobfree[1]  | oobfree[0]  |
 |15 | eccpos[13] | <reserved>  || oobfree[2]  | oobfree[1]  |
 +---+------------+-------------++-------------+-------------+
 |16 | eccpos[14] | eccpos[13]  || oobfree[3]  | oobfree[2]  |
 |...| [...]      | [...]       || [...]       | [...]       |
 |56 | eccpos[54] | eccpos[51]  || oobfree[43] | oobfree[42] |
 |57 | eccpos[55] | <reserved>  || oobfree[44] | oobfree[43] |
 +===+============+=============+==============+=============+
 |58 | oobfree[0] | oobfree[0]  || oobfree[45] | oobfree[44] |
 |59 | oobfree[1] | oobfree[1]  || oobfree[46] | oobfree[45] |
 |60 | oobfree[2] | oobfree[2]  || oobfree[47] | oobfree[46] |
 |61 | oobfree[3] | oobfree[3]  || oobfree[48] | oobfree[47] |
 |62 | oobfree[4] | oobfree[4]  || oobfree[49] | oobfree[48] |
 |63 | oobfree[5] | oobfree[5]  || oobfree[50] | oobfree[49] |
 +---+------------+-------------+--------------+-------------+

[1] ecc-layout expected by ROM code, as specified in SoC TRM under:
      Chapter="Initialization"
        Section="Device Initialization by ROM code"
            Sub-Section="Memory Booting"
                Heading="NAND"
                Figure="ECC Locations in NAND Spare Areas"

[2] ecc-layout updates in u-boot
    http://lists.denx.de/pipermail/u-boot/2013-November/167551.html

[3] u-boot configurations to match above ecc-layout are documented at
    https://processors.wiki.ti.com/index.php/Linux_Core_NAND_User%27s_Guide

CC: <stable@vger.kernel.org> # 3.13.x+
Reported-by: default avatarEnric Balletbo Serra <eballetbo@iseebcn.com>
Tested-by: default avatarEnric Balletbo i Serra <eballetbo@gmail.com>
Tested-by: default avatarStefan Roese <sr@denx.de>
Signed-off-by: default avatarPekon Gupta <pekon@ti.com>
Signed-off-by: default avatarBrian Norris <computersforpeace@gmail.com>
parent 28fa65e6
...@@ -1633,6 +1633,7 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -1633,6 +1633,7 @@ static int omap_nand_probe(struct platform_device *pdev)
int i; int i;
dma_cap_mask_t mask; dma_cap_mask_t mask;
unsigned sig; unsigned sig;
unsigned oob_index;
struct resource *res; struct resource *res;
struct mtd_part_parser_data ppdata = {}; struct mtd_part_parser_data ppdata = {};
...@@ -1826,9 +1827,11 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -1826,9 +1827,11 @@ static int omap_nand_probe(struct platform_device *pdev)
(mtd->writesize / (mtd->writesize /
nand_chip->ecc.size); nand_chip->ecc.size);
if (nand_chip->options & NAND_BUSWIDTH_16) if (nand_chip->options & NAND_BUSWIDTH_16)
ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; oob_index = BADBLOCK_MARKER_LENGTH;
else else
ecclayout->eccpos[0] = 1; oob_index = 1;
for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
ecclayout->eccpos[i] = oob_index;
ecclayout->oobfree->offset = ecclayout->eccpos[0] + ecclayout->oobfree->offset = ecclayout->eccpos[0] +
ecclayout->eccbytes; ecclayout->eccbytes;
break; break;
...@@ -1847,7 +1850,12 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -1847,7 +1850,12 @@ static int omap_nand_probe(struct platform_device *pdev)
ecclayout->eccbytes = nand_chip->ecc.bytes * ecclayout->eccbytes = nand_chip->ecc.bytes *
(mtd->writesize / (mtd->writesize /
nand_chip->ecc.size); nand_chip->ecc.size);
ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; oob_index = BADBLOCK_MARKER_LENGTH;
for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) {
ecclayout->eccpos[i] = oob_index;
if (((i + 1) % nand_chip->ecc.bytes) == 0)
oob_index++;
}
ecclayout->oobfree->offset = ecclayout->eccpos[0] + ecclayout->oobfree->offset = ecclayout->eccpos[0] +
ecclayout->eccbytes; ecclayout->eccbytes;
/* software bch library is used for locating errors */ /* software bch library is used for locating errors */
...@@ -1883,7 +1891,9 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -1883,7 +1891,9 @@ static int omap_nand_probe(struct platform_device *pdev)
ecclayout->eccbytes = nand_chip->ecc.bytes * ecclayout->eccbytes = nand_chip->ecc.bytes *
(mtd->writesize / (mtd->writesize /
nand_chip->ecc.size); nand_chip->ecc.size);
ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; oob_index = BADBLOCK_MARKER_LENGTH;
for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
ecclayout->eccpos[i] = oob_index;
ecclayout->oobfree->offset = ecclayout->eccpos[0] + ecclayout->oobfree->offset = ecclayout->eccpos[0] +
ecclayout->eccbytes; ecclayout->eccbytes;
/* This ECC scheme requires ELM H/W block */ /* This ECC scheme requires ELM H/W block */
...@@ -1913,7 +1923,12 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -1913,7 +1923,12 @@ static int omap_nand_probe(struct platform_device *pdev)
ecclayout->eccbytes = nand_chip->ecc.bytes * ecclayout->eccbytes = nand_chip->ecc.bytes *
(mtd->writesize / (mtd->writesize /
nand_chip->ecc.size); nand_chip->ecc.size);
ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; oob_index = BADBLOCK_MARKER_LENGTH;
for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) {
ecclayout->eccpos[i] = oob_index;
if (((i + 1) % nand_chip->ecc.bytes) == 0)
oob_index++;
}
ecclayout->oobfree->offset = ecclayout->eccpos[0] + ecclayout->oobfree->offset = ecclayout->eccpos[0] +
ecclayout->eccbytes; ecclayout->eccbytes;
/* software bch library is used for locating errors */ /* software bch library is used for locating errors */
...@@ -1956,7 +1971,9 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -1956,7 +1971,9 @@ static int omap_nand_probe(struct platform_device *pdev)
ecclayout->eccbytes = nand_chip->ecc.bytes * ecclayout->eccbytes = nand_chip->ecc.bytes *
(mtd->writesize / (mtd->writesize /
nand_chip->ecc.size); nand_chip->ecc.size);
ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; oob_index = BADBLOCK_MARKER_LENGTH;
for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
ecclayout->eccpos[i] = oob_index;
ecclayout->oobfree->offset = ecclayout->eccpos[0] + ecclayout->oobfree->offset = ecclayout->eccpos[0] +
ecclayout->eccbytes; ecclayout->eccbytes;
break; break;
...@@ -1975,8 +1992,6 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -1975,8 +1992,6 @@ static int omap_nand_probe(struct platform_device *pdev)
/* populate remaining ECC layout data */ /* populate remaining ECC layout data */
ecclayout->oobfree->length = mtd->oobsize - (BADBLOCK_MARKER_LENGTH + ecclayout->oobfree->length = mtd->oobsize - (BADBLOCK_MARKER_LENGTH +
ecclayout->eccbytes); ecclayout->eccbytes);
for (i = 1; i < ecclayout->eccbytes; i++)
ecclayout->eccpos[i] = ecclayout->eccpos[0] + i;
/* check if NAND device's OOB is enough to store ECC signatures */ /* check if NAND device's OOB is enough to store ECC signatures */
if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) { if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) {
pr_err("not enough OOB bytes required = %d, available=%d\n", pr_err("not enough OOB bytes required = %d, available=%d\n",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment