mtd: rawnand: Separate the ECC engine type and the ECC byte placement
authorMiquel Raynal <miquel.raynal@bootlin.com>
Thu, 27 Aug 2020 08:51:57 +0000 (10:51 +0200)
committerMiquel Raynal <miquel.raynal@bootlin.com>
Mon, 28 Sep 2020 13:56:34 +0000 (15:56 +0200)
The use of "syndrome" placement should not be encoded in the ECC
engine mode/type.

Create a "placement" field in NAND chip and change all occurrences of
the NAND_ECC_HW_SYNDROME enumeration to be just NAND_ECC_HW and
possibly a placement entry like NAND_ECC_PLACEMENT_INTERLEAVED.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Link: https://lore.kernel.org/linux-mtd/20200827085208.16276-10-miquel.raynal@bootlin.com
arch/arm/mach-davinci/board-dm355-leopard.c
drivers/mtd/nand/raw/cafe_nand.c
drivers/mtd/nand/raw/davinci_nand.c
drivers/mtd/nand/raw/denali.c
drivers/mtd/nand/raw/diskonchip.c
drivers/mtd/nand/raw/lpc32xx_slc.c
drivers/mtd/nand/raw/nand_base.c
drivers/mtd/nand/raw/r852.c
include/linux/mtd/rawnand.h
include/linux/platform_data/mtd-davinci.h

index b9e9950..4c8a592 100644 (file)
@@ -76,7 +76,8 @@ static struct davinci_nand_pdata davinci_nand_data = {
        .mask_chipsel           = BIT(14),
        .parts                  = davinci_nand_partitions,
        .nr_parts               = ARRAY_SIZE(davinci_nand_partitions),
-       .ecc_mode               = NAND_ECC_HW_SYNDROME,
+       .ecc_mode               = NAND_HW_ECC_ENGINE,
+       .ecc_placement          = NAND_ECC_PLACEMENT_INTERLEAVED,
        .ecc_bits               = 4,
        .bbt_options            = NAND_BBT_USE_FLASH,
 };
index 9217379..2bf8ab5 100644 (file)
@@ -629,7 +629,8 @@ static int cafe_nand_attach_chip(struct nand_chip *chip)
                goto out_free_dma;
        }
 
-       cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
+       cafe->nand.ecc.mode = NAND_ECC_HW;
+       cafe->nand.ecc.placement = NAND_ECC_PLACEMENT_INTERLEAVED;
        cafe->nand.ecc.size = mtd->writesize;
        cafe->nand.ecc.bytes = 14;
        cafe->nand.ecc.strength = 4;
index 551515c..3640c7e 100644 (file)
@@ -168,7 +168,7 @@ static int nand_davinci_correct_1bit(struct nand_chip *chip, u_char *dat,
 /*
  * 4-bit hardware ECC ... context maintained over entire AEMIF
  *
- * This is a syndrome engine, but we avoid NAND_ECC_HW_SYNDROME
+ * This is a syndrome engine, but we avoid NAND_ECC_PLACEMENT_INTERLEAVED
  * since that forces use of a problematic "infix OOB" layout.
  * Among other things, it trashes manufacturer bad block markers.
  * Also, and specific to this hardware, it ECC-protects the "prepad"
@@ -851,6 +851,7 @@ static int nand_davinci_probe(struct platform_device *pdev)
 
        /* Use board-specific ECC config */
        info->chip.ecc.mode     = pdata->ecc_mode;
+       info->chip.ecc.placement = pdata->ecc_placement;
 
        spin_lock_irq(&davinci_nand_lock);
 
@@ -897,7 +898,7 @@ static int nand_davinci_remove(struct platform_device *pdev)
        int ret;
 
        spin_lock_irq(&davinci_nand_lock);
-       if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME)
+       if (info->chip.ecc.placement == NAND_ECC_PLACEMENT_INTERLEAVED)
                ecc4_busy = false;
        spin_unlock_irq(&davinci_nand_lock);
 
index 9d99dad..0e54b8a 100644 (file)
@@ -1237,7 +1237,8 @@ int denali_chip_init(struct denali_controller *denali,
        chip->bbt_options |= NAND_BBT_USE_FLASH;
        chip->bbt_options |= NAND_BBT_NO_OOB;
        chip->options |= NAND_NO_SUBPAGE_WRITE;
-       chip->ecc.mode = NAND_ECC_HW_SYNDROME;
+       chip->ecc.mode = NAND_ECC_HW;
+       chip->ecc.placement = NAND_ECC_PLACEMENT_INTERLEAVED;
        chip->ecc.read_page = denali_read_page;
        chip->ecc.write_page = denali_write_page;
        chip->ecc.read_page_raw = denali_read_page_raw;
index 4372186..4036035 100644 (file)
@@ -1456,7 +1456,8 @@ static int __init doc_probe(unsigned long physadr)
        nand->ecc.calculate     = doc200x_calculate_ecc;
        nand->ecc.correct       = doc200x_correct_data;
 
-       nand->ecc.mode          = NAND_ECC_HW_SYNDROME;
+       nand->ecc.mode          = NAND_ECC_HW;
+       nand->ecc.placement     = NAND_ECC_PLACEMENT_INTERLEAVED;
        nand->ecc.size          = 512;
        nand->ecc.bytes         = 6;
        nand->ecc.strength      = 2;
index b151fd0..ccb189c 100644 (file)
@@ -881,7 +881,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, host);
 
        /* NAND callbacks for LPC32xx SLC hardware */
-       chip->ecc.mode = NAND_ECC_HW_SYNDROME;
+       chip->ecc.mode = NAND_ECC_HW;
+       chip->ecc.placement = NAND_ECC_PLACEMENT_INTERLEAVED;
        chip->legacy.read_byte = lpc32xx_nand_read_byte;
        chip->legacy.read_buf = lpc32xx_nand_read_buf;
        chip->legacy.write_buf = lpc32xx_nand_write_buf;
index e22a7f9..172852a 100644 (file)
@@ -5790,47 +5790,59 @@ static int nand_scan_tail(struct nand_chip *chip)
 
        switch (ecc->mode) {
        case NAND_ECC_HW:
-               /* Use standard hwecc read page function? */
-               if (!ecc->read_page)
-                       ecc->read_page = nand_read_page_hwecc;
-               if (!ecc->write_page)
-                       ecc->write_page = nand_write_page_hwecc;
-               if (!ecc->read_page_raw)
-                       ecc->read_page_raw = nand_read_page_raw;
-               if (!ecc->write_page_raw)
-                       ecc->write_page_raw = nand_write_page_raw;
-               if (!ecc->read_oob)
-                       ecc->read_oob = nand_read_oob_std;
-               if (!ecc->write_oob)
-                       ecc->write_oob = nand_write_oob_std;
-               if (!ecc->read_subpage)
-                       ecc->read_subpage = nand_read_subpage;
-               if (!ecc->write_subpage && ecc->hwctl && ecc->calculate)
-                       ecc->write_subpage = nand_write_subpage_hwecc;
-               fallthrough;
-       case NAND_ECC_HW_SYNDROME:
-               if ((!ecc->calculate || !ecc->correct || !ecc->hwctl) &&
-                   (!ecc->read_page ||
-                    ecc->read_page == nand_read_page_hwecc ||
-                    !ecc->write_page ||
-                    ecc->write_page == nand_write_page_hwecc)) {
-                       WARN(1, "No ECC functions supplied; hardware ECC not possible\n");
+               switch (ecc->placement) {
+               case NAND_ECC_PLACEMENT_UNKNOWN:
+               case NAND_ECC_PLACEMENT_OOB:
+                       /* Use standard hwecc read page function? */
+                       if (!ecc->read_page)
+                               ecc->read_page = nand_read_page_hwecc;
+                       if (!ecc->write_page)
+                               ecc->write_page = nand_write_page_hwecc;
+                       if (!ecc->read_page_raw)
+                               ecc->read_page_raw = nand_read_page_raw;
+                       if (!ecc->write_page_raw)
+                               ecc->write_page_raw = nand_write_page_raw;
+                       if (!ecc->read_oob)
+                               ecc->read_oob = nand_read_oob_std;
+                       if (!ecc->write_oob)
+                               ecc->write_oob = nand_write_oob_std;
+                       if (!ecc->read_subpage)
+                               ecc->read_subpage = nand_read_subpage;
+                       if (!ecc->write_subpage && ecc->hwctl && ecc->calculate)
+                               ecc->write_subpage = nand_write_subpage_hwecc;
+                       fallthrough;
+
+               case NAND_ECC_PLACEMENT_INTERLEAVED:
+                       if ((!ecc->calculate || !ecc->correct || !ecc->hwctl) &&
+                           (!ecc->read_page ||
+                            ecc->read_page == nand_read_page_hwecc ||
+                            !ecc->write_page ||
+                            ecc->write_page == nand_write_page_hwecc)) {
+                               WARN(1, "No ECC functions supplied; hardware ECC not possible\n");
+                               ret = -EINVAL;
+                               goto err_nand_manuf_cleanup;
+                       }
+                       /* Use standard syndrome read/write page function? */
+                       if (!ecc->read_page)
+                               ecc->read_page = nand_read_page_syndrome;
+                       if (!ecc->write_page)
+                               ecc->write_page = nand_write_page_syndrome;
+                       if (!ecc->read_page_raw)
+                               ecc->read_page_raw = nand_read_page_raw_syndrome;
+                       if (!ecc->write_page_raw)
+                               ecc->write_page_raw = nand_write_page_raw_syndrome;
+                       if (!ecc->read_oob)
+                               ecc->read_oob = nand_read_oob_syndrome;
+                       if (!ecc->write_oob)
+                               ecc->write_oob = nand_write_oob_syndrome;
+                       break;
+
+               default:
+                       pr_warn("Invalid NAND_ECC_PLACEMENT %d\n",
+                               ecc->placement);
                        ret = -EINVAL;
                        goto err_nand_manuf_cleanup;
                }
-               /* Use standard syndrome read/write page function? */
-               if (!ecc->read_page)
-                       ecc->read_page = nand_read_page_syndrome;
-               if (!ecc->write_page)
-                       ecc->write_page = nand_write_page_syndrome;
-               if (!ecc->read_page_raw)
-                       ecc->read_page_raw = nand_read_page_raw_syndrome;
-               if (!ecc->write_page_raw)
-                       ecc->write_page_raw = nand_write_page_raw_syndrome;
-               if (!ecc->read_oob)
-                       ecc->read_oob = nand_read_oob_syndrome;
-               if (!ecc->write_oob)
-                       ecc->write_oob = nand_write_oob_syndrome;
 
                if (mtd->writesize >= ecc->size) {
                        if (!ecc->strength) {
@@ -5845,6 +5857,7 @@ static int nand_scan_tail(struct nand_chip *chip)
                ecc->mode = NAND_ECC_SOFT;
                ecc->algo = NAND_ECC_ALGO_HAMMING;
                fallthrough;
+
        case NAND_ECC_SOFT:
                ret = nand_set_ecc_soft_ops(chip);
                if (ret) {
index f865e3a..f0988cd 100644 (file)
@@ -859,7 +859,8 @@ static int  r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
        chip->legacy.write_buf = r852_write_buf;
 
        /* ecc */
-       chip->ecc.mode = NAND_ECC_HW_SYNDROME;
+       chip->ecc.mode = NAND_ECC_HW;
+       chip->ecc.placement = NAND_ECC_PLACEMENT_INTERLEAVED;
        chip->ecc.size = R852_DMA_LEN;
        chip->ecc.bytes = SM_OOB_SIZE;
        chip->ecc.strength = 2;
index 10bbfbf..cfd75a1 100644 (file)
@@ -304,6 +304,7 @@ static const struct nand_ecc_caps __name = {                        \
 /**
  * struct nand_ecc_ctrl - Control structure for ECC
  * @mode:      ECC mode
+ * @placement: OOB bytes placement
  * @algo:      ECC algorithm
  * @steps:     number of ECC steps per page
  * @size:      data bytes per ECC step
@@ -331,7 +332,7 @@ static const struct nand_ecc_caps __name = {                        \
  *                     controller and always return contiguous in-band and
  *                     out-of-band data even if they're not stored
  *                     contiguously on the NAND chip (e.g.
- *                     NAND_ECC_HW_SYNDROME interleaves in-band and
+ *                     NAND_ECC_PLACEMENT_INTERLEAVED interleaves in-band and
  *                     out-of-band data).
  * @write_page_raw:    function to write a raw page without ECC. This function
  *                     should hide the specific layout used by the ECC
@@ -339,7 +340,7 @@ static const struct nand_ecc_caps __name = {                        \
  *                     in-band and out-of-band data. ECC controller is
  *                     responsible for doing the appropriate transformations
  *                     to adapt to its specific layout (e.g.
- *                     NAND_ECC_HW_SYNDROME interleaves in-band and
+ *                     NAND_ECC_PLACEMENT_INTERLEAVED interleaves in-band and
  *                     out-of-band data).
  * @read_page: function to read a page according to the ECC generator
  *             requirements; returns maximum number of bitflips corrected in
@@ -356,6 +357,7 @@ static const struct nand_ecc_caps __name = {                        \
  */
 struct nand_ecc_ctrl {
        enum nand_ecc_mode mode;
+       enum nand_ecc_placement placement;
        enum nand_ecc_algo algo;
        int steps;
        int size;
index 03e92c7..6e2b252 100644 (file)
@@ -69,6 +69,7 @@ struct davinci_nand_pdata {           /* platform_data */
         * using it with large page chips.
         */
        enum nand_ecc_mode      ecc_mode;
+       enum nand_ecc_placement ecc_placement;
        u8                      ecc_bits;
 
        /* e.g. NAND_BUSWIDTH_16 */