OSDN Git Service

mtd: rawnand: fsl_elbc: Make SW ECC work
authorMarek Behún <marek.behun@nic.cz>
Fri, 22 Mar 2019 13:26:19 +0000 (14:26 +0100)
committerMiquel Raynal <miquel.raynal@bootlin.com>
Thu, 18 Apr 2019 06:54:02 +0000 (08:54 +0200)
Move the code that choses ECC into _attach_chip, which is executed only
after the chip->ecc.* properties were loaded from device-tree. This way
we know which ECC method was chosen by the device-tree and can set
methods appropriately.

The chip->ecc.*page methods should be set to fsl_elbc_*page only in HW
ECC mode.

Signed-off-by: Marek Behún <marek.behun@nic.cz>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
drivers/mtd/nand/raw/fsl_elbc_nand.c

index 513897c..423828f 100644 (file)
@@ -730,24 +730,6 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
        chip->controller = &elbc_fcm_ctrl->controller;
        nand_set_controller_data(chip, priv);
 
-       chip->ecc.read_page = fsl_elbc_read_page;
-       chip->ecc.write_page = fsl_elbc_write_page;
-       chip->ecc.write_subpage = fsl_elbc_write_subpage;
-
-       /* If CS Base Register selects full hardware ECC then use it */
-       if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
-           BR_DECC_CHK_GEN) {
-               chip->ecc.mode = NAND_ECC_HW;
-               mtd_set_ooblayout(mtd, &fsl_elbc_ooblayout_ops);
-               chip->ecc.size = 512;
-               chip->ecc.bytes = 3;
-               chip->ecc.strength = 1;
-       } else {
-               /* otherwise fall back to default software ECC */
-               chip->ecc.mode = NAND_ECC_SOFT;
-               chip->ecc.algo = NAND_ECC_HAMMING;
-       }
-
        return 0;
 }
 
@@ -759,6 +741,40 @@ static int fsl_elbc_attach_chip(struct nand_chip *chip)
        struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
        unsigned int al;
 
+       switch (chip->ecc.mode) {
+       /*
+        * if ECC was not chosen in DT, decide whether to use HW or SW ECC from
+        * CS Base Register
+        */
+       case NAND_ECC_NONE:
+               /* If CS Base Register selects full hardware ECC then use it */
+               if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
+                   BR_DECC_CHK_GEN) {
+                       chip->ecc.read_page = fsl_elbc_read_page;
+                       chip->ecc.write_page = fsl_elbc_write_page;
+                       chip->ecc.write_subpage = fsl_elbc_write_subpage;
+
+                       chip->ecc.mode = NAND_ECC_HW;
+                       mtd_set_ooblayout(mtd, &fsl_elbc_ooblayout_ops);
+                       chip->ecc.size = 512;
+                       chip->ecc.bytes = 3;
+                       chip->ecc.strength = 1;
+               } else {
+                       /* otherwise fall back to default software ECC */
+                       chip->ecc.mode = NAND_ECC_SOFT;
+                       chip->ecc.algo = NAND_ECC_HAMMING;
+               }
+               break;
+
+       /* if SW ECC was chosen in DT, we do not need to set anything here */
+       case NAND_ECC_SOFT:
+               break;
+
+       /* should we also implement NAND_ECC_HW to do as the code above? */
+       default:
+               return -EINVAL;
+       }
+
        /* calculate FMR Address Length field */
        al = 0;
        if (chip->pagemask & 0xffff0000)