Here we automatically select the strongest ECC scheme compatible with
the size of the OOB.

Signed-off-by: Lee Jones <[email protected]>
---
 drivers/mtd/nand/stm_nand_bch.c | 43 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/drivers/mtd/nand/stm_nand_bch.c b/drivers/mtd/nand/stm_nand_bch.c
index 8302273..31864e5 100644
--- a/drivers/mtd/nand/stm_nand_bch.c
+++ b/drivers/mtd/nand/stm_nand_bch.c
@@ -32,6 +32,13 @@
 /* NANDi BCH Controller properties */
 #define NANDI_BCH_SECTOR_SIZE                  1024
 
+/* BCH ECC sizes */
+static int bch_ecc_sizes[] = {
+       [BCH_18BIT_ECC] = 32,
+       [BCH_30BIT_ECC] = 54,
+       [BCH_NO_ECC] = 0,
+};
+
 /* Bad Block Table (BBT) */
 struct nandi_bbt_info {
        uint32_t        bbt_size;               /* Size of bad-block table */
@@ -302,6 +309,25 @@ static void nandi_disable_interrupts(struct 
nandi_controller *nandi,
        writel(val, nandi->base + NANDBCH_INT_EN);
 }
 
+/* Select strongest ECC scheme compatible with OOB size */
+static int bch_set_ecc_auto(struct nandi_controller *nandi,
+                           struct mtd_info *mtd)
+{
+       int oob_bytes_per_sector = mtd->oobsize / nandi->sectors_per_page;
+       int try_ecc_modes[] = { BCH_30BIT_ECC, BCH_18BIT_ECC, -1 };
+       int m, ecc_mode;
+
+       for (m = 0; try_ecc_modes[m] >= 0; m++) {
+               ecc_mode = try_ecc_modes[m];
+               if (oob_bytes_per_sector >= bch_ecc_sizes[ecc_mode]) {
+                       nandi->bch_ecc_mode = ecc_mode;
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
 static void nandi_set_mtd_defaults(struct nandi_controller *nandi,
                                   struct mtd_info *mtd, struct nand_chip *chip)
 {
@@ -939,6 +965,23 @@ static int stm_nand_bch_probe(struct platform_device *pdev)
                             0x10000) ? true : false;
        mtd->writebufsize = mtd->writesize;
 
+       /* Set ECC mode */
+       if (pdata->bch_ecc_cfg == BCH_ECC_AUTO) {
+               err = bch_set_ecc_auto(nandi, mtd);
+               if (err) {
+                       dev_err(nandi->dev, "insufficient OOB for BCH ECC\n");
+                       return err;
+               }
+       } else {
+               nandi->bch_ecc_mode = pdata->bch_ecc_cfg;
+       }
+
+       chip->ecc.size = NANDI_BCH_SECTOR_SIZE;
+       chip->ecc.bytes = mtd->oobsize;
+
+       info->ecclayout.eccbytes =
+               nandi->sectors_per_page * bch_ecc_sizes[nandi->bch_ecc_mode];
+
        return 0;
 }
 
-- 
1.8.3.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to