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 b9e9950dd300a1e0917cd136d00357d83097a027..4c8a592754ace4bc8934deb5839e16dd30f60e8b 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 92173790f20ba63fd9fab37945c563f693b2726d..2bf8ab542e38000e1ebeb8a5b698214a6c4fb199 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 551515c223bb652159184a0d339a8cc8c00218cb..3640c7e45e150bfe847734990fcf5efe26479844 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 9d99dade95ce0e7e87ac6e54c48859b91c00a2cb..0e54b8a61cf00a9f9482f10155f5e6a32effa7af 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 43721863a0d8ec1faa02090aa79a35b5977aed1d..40360352136bff2098e358cd105f9ee102e6396f 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 b151fd00081566c09213922cb19aa229e6034c05..ccb189c8e3430d3b7049228620841ad200a3c810 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 e22a7f9986b12dbfb677b743f58ef375bc8bcab5..172852a29a50feaa0ca82f08da969a2b89ce4b7e 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 f865e3a47b01d71434c644b9f19d75e3bae502dc..f0988cda44796fd00fee93c95a086f78f8221b57 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 10bbfbf4ad7feb076c95f5c6b61d02504556e8c8..cfd75a12f8027b2769c87307e7f47c45b26ca0b6 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 03e92c71b3faafdaa86977b06ee0f5d12e0d4c2b..6e2b252a4ce6c5cd09ad584f6baa974b5b8cec17 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 */