MLK-10657: mtd: NAND: correct bitflip for erased NAND page
authorHan Xu <b45815@freescale.com>
Tue, 14 Apr 2015 15:29:15 +0000 (10:29 -0500)
committerNitin Garg <nitin.garg@nxp.com>
Mon, 19 Mar 2018 19:47:31 +0000 (14:47 -0500)
i.MX6QP and i.MX7D BCH module integrated a new feature to detect the
bitflip number for erased NAND page. So for these two platform, set the
erase threshold to gf/2 and if bitflip detected, GPMI driver will
correct the data to all 0xFF.

Also updated the imx6qp dts file to ditinguish the GPMI module for i.MX6Q
with the one for i.MX6QP.

Signed-off-by: Han Xu <b45815@freescale.com>
(cherry picked from commit: 4302ab74a301626e7e0b9cb398a23b2e488cfa6b)

drivers/mtd/nand/gpmi-nand/bch-regs.h
drivers/mtd/nand/gpmi-nand/gpmi-lib.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.h

index 53e58bc..a84d72b 100644 (file)
 #define BM_BCH_CTRL_COMPLETE_IRQ               (1 << 0)
 
 #define HW_BCH_STATUS0                         0x00000010
+
 #define HW_BCH_MODE                            0x00000020
+#define BP_BCH_MODE_ERASE_THRESHOLD            0
+#define BM_BCH_MODE_ERASE_THRESHOLD    (0xff << BP_BCH_MODE_ERASE_THRESHOLD)
+#define BF_BCH_MODE_ERASE_THRESHOLD(v)         \
+       (((v) << BP_BCH_MODE_ERASE_THRESHOLD) & BM_BCH_MODE_ERASE_THRESHOLD)
+
 #define HW_BCH_ENCODEPTR                       0x00000030
 #define HW_BCH_DATAPTR                         0x00000040
 #define HW_BCH_METAPTR                         0x00000050
        )
 
 #define HW_BCH_VERSION                         0x00000160
+#define HW_BCH_DEBUG1                          0x00000170
+#define BP_BCH_DEBUG1_ERASED_ZERO_COUNT        0
+#define BM_BCH_DEBUG1_ERASED_ZERO_COUNT                \
+               (0x1ff << BP_BCH_DEBUG1_ERASED_ZERO_COUNT)
 #endif
index f027117..50955c9 100644 (file)
@@ -299,6 +299,11 @@ int bch_set_geometry(struct gpmi_nand_data *this)
                        | BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size, this),
                        r->bch_regs + HW_BCH_FLASH0LAYOUT1);
 
+       /* Set erase threshold to gf/2 for mx6qp and mx7 */
+       if (GPMI_IS_MX6QP(this) || GPMI_IS_MX7(this))
+               writel(BF_BCH_MODE_ERASE_THRESHOLD(gf_len/2),
+                       r->bch_regs + HW_BCH_MODE);
+
        /* Set *all* chip selects to use layout 0. */
        writel(0, r->bch_regs + HW_BCH_LAYOUTSELECT);
 
index 8e72ffa..4e2e642 100644 (file)
@@ -104,6 +104,12 @@ static const struct gpmi_devdata gpmi_devdata_imx6q = {
        .max_chain_delay = 12,
 };
 
+static const struct gpmi_devdata gpmi_devdata_imx6qp = {
+       .type = IS_MX6QP,
+       .bch_max_ecc_strength = 40,
+       .max_chain_delay = 12,
+};
+
 static const struct gpmi_devdata gpmi_devdata_imx6sx = {
        .type = IS_MX6SX,
        .bch_max_ecc_strength = 62,
@@ -1038,6 +1044,7 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
 {
        struct gpmi_nand_data *this = nand_get_controller_data(chip);
        struct bch_geometry *nfc_geo = &this->bch_geometry;
+       void __iomem *bch_regs = this->resources.bch_regs;
        void          *payload_virt;
        dma_addr_t    payload_phys;
        void          *auxiliary_virt;
@@ -1046,6 +1053,7 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
        unsigned char *status;
        unsigned int  max_bitflips = 0;
        int           ret;
+       int flag = 0;
 
        dev_dbg(this->dev, "page number is : %d\n", page);
        ret = read_page_prepare(this, buf, nfc_geo->payload_size,
@@ -1080,9 +1088,16 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
                           payload_virt, payload_phys);
 
        for (i = 0; i < nfc_geo->ecc_chunk_count; i++, status++) {
-               if ((*status == STATUS_GOOD) || (*status == STATUS_ERASED))
+               if (*status == STATUS_GOOD)
                        continue;
 
+               if (*status == STATUS_ERASED) {
+                       if (GPMI_IS_MX6QP(this) || GPMI_IS_MX7(this))
+                               if (readl(bch_regs + HW_BCH_DEBUG1))
+                                       flag = 1;
+                       continue;
+               }
+
                if (*status == STATUS_UNCORRECTABLE) {
                        int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
                        u8 *eccbuf = this->raw_buffer;
@@ -1177,6 +1192,10 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
                chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0];
        }
 
+       /* if bitflip occurred in erased page, change data to all 0xff */
+       if (flag)
+               memset(buf, 0xff, nfc_geo->payload_size);
+
        return max_bitflips;
 }
 
@@ -2084,6 +2103,9 @@ static const struct of_device_id gpmi_nand_id_table[] = {
        }, {
                .compatible = "fsl,imx6q-gpmi-nand",
                .data = &gpmi_devdata_imx6q,
+       }, {
+               .compatible = "fsl,imx6qp-gpmi-nand",
+               .data = (void *)&gpmi_devdata_imx6qp,
        }, {
                .compatible = "fsl,imx6sx-gpmi-nand",
                .data = &gpmi_devdata_imx6sx,
index 499a07f..b571a7b 100644 (file)
@@ -123,6 +123,7 @@ enum gpmi_type {
        IS_MX23,
        IS_MX28,
        IS_MX6Q,
+       IS_MX6QP,
        IS_MX6SX,
        IS_MX7D
 };
@@ -305,9 +306,11 @@ void gpmi_copy_bits(u8 *dst, size_t dst_bit_off,
 #define GPMI_IS_MX23(x)                ((x)->devdata->type == IS_MX23)
 #define GPMI_IS_MX28(x)                ((x)->devdata->type == IS_MX28)
 #define GPMI_IS_MX6Q(x)                ((x)->devdata->type == IS_MX6Q)
+#define GPMI_IS_MX6QP(x)       ((x)->devdata->type == IS_MX6QP)
 #define GPMI_IS_MX6SX(x)       ((x)->devdata->type == IS_MX6SX)
 #define GPMI_IS_MX7D(x)                ((x)->devdata->type == IS_MX7D)
 
-#define GPMI_IS_MX6(x)         (GPMI_IS_MX6Q(x) || GPMI_IS_MX6SX(x))
+#define GPMI_IS_MX6(x)         (GPMI_IS_MX6Q(x) || GPMI_IS_MX6QP(x)\
+          || GPMI_IS_MX6SX(x))
 #define GPMI_IS_MX7(x)         (GPMI_IS_MX7D(x))
 #endif