]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/mtd/nand/gpmi-nand/gpmi-nand.c
of/mtd/nand: add generic binding and helper for NAND_BBT_NO_OOB_BBM
[karo-tx-linux.git] / drivers / mtd / nand / gpmi-nand / gpmi-nand.c
index f638cd8077ca4e3aa3f5f626553a2fdf75d15736..37537b4406ac3101de3a640745c08b7b5003946c 100644 (file)
@@ -285,9 +285,8 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
        geo->ecc_strength = get_ecc_strength(this);
        if (!gpmi_check_ecc(this)) {
                dev_err(this->dev,
-                       "We can not support this nand chip."
-                       " Its required ecc strength(%d) is beyond our"
-                       " capability(%d).\n", geo->ecc_strength,
+                       "required ecc strength of the NAND chip: %d is not supported by the GPMI controller (%d)\n",
+                       geo->ecc_strength,
                        this->devdata->bch_max_ecc_strength);
                return -EINVAL;
        }
@@ -1082,6 +1081,7 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
        int first, last, marker_pos;
        int ecc_parity_size;
        int col = 0;
+       int old_swap_block_mark = this->swap_block_mark;
 
        /* The size of ECC parity */
        ecc_parity_size = geo->gf_len * geo->ecc_strength / 8;
@@ -1090,17 +1090,21 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
        first = offs / size;
        last = (offs + len - 1) / size;
 
-       /*
-        * Find the chunk which contains the Block Marker. If this chunk is
-        * in the range of [first, last], we have to read out the whole page.
-        * Why? since we had swapped the data at the position of Block Marker
-        * to the metadata which is bound with the chunk 0.
-        */
-       marker_pos = geo->block_mark_byte_offset / size;
-       if (last >= marker_pos && first <= marker_pos) {
-               dev_dbg(this->dev, "page:%d, first:%d, last:%d, marker at:%d\n",
+       if (this->swap_block_mark) {
+               /*
+                * Find the chunk which contains the Block Marker.
+                * If this chunk is in the range of [first, last],
+                * we have to read out the whole page.
+                * Why? since we had swapped the data at the position of Block
+                * Marker to the metadata which is bound with the chunk 0.
+                */
+               marker_pos = geo->block_mark_byte_offset / size;
+               if (last >= marker_pos && first <= marker_pos) {
+                       dev_dbg(this->dev,
+                               "page:%d, first:%d, last:%d, marker at:%d\n",
                                page, first, last, marker_pos);
-               return gpmi_ecc_read_page(mtd, chip, buf, 0, page);
+                       return gpmi_ecc_read_page(mtd, chip, buf, 0, page);
+               }
        }
 
        meta = geo->metadata_size;
@@ -1146,7 +1150,7 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
        writel(r1_old, bch_regs + HW_BCH_FLASH0LAYOUT0);
        writel(r2_old, bch_regs + HW_BCH_FLASH0LAYOUT1);
        this->bch_geometry = old_geo;
-       this->swap_block_mark = true;
+       this->swap_block_mark = old_swap_block_mark;
 
        return max_bitflips;
 }
@@ -1180,7 +1184,7 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 
                /* Handle block mark swapping. */
                block_mark_swapping(this,
-                               (void *) payload_virt, (void *) auxiliary_virt);
+                               (void *)payload_virt, (void *)auxiliary_virt);
        } else {
                /*
                 * If control arrives here, we're not doing block mark swapping,
@@ -1310,10 +1314,10 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
 
        /*
         * Now, we want to make sure the block mark is correct. In the
-        * Swapping/Raw case, we already have it. Otherwise, we need to
-        * explicitly read it.
+        * non-transcribing case (!GPMI_IS_MX23()), we already have it.
+        * Otherwise, we need to explicitly read it.
         */
-       if (!this->swap_block_mark) {
+       if (GPMI_IS_MX23(this)) {
                /* Read the block mark into the first byte of the OOB buffer. */
                chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
                chip->oob_poi[0] = chip->read_byte(mtd);
@@ -1354,7 +1358,7 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
        chipnr = (int)(ofs >> chip->chip_shift);
        chip->select_chip(mtd, chipnr);
 
-       column = this->swap_block_mark ? mtd->writesize : 0;
+       column = !GPMI_IS_MX23(this) ? mtd->writesize : 0;
 
        /* Write the block mark. */
        block_mark = this->data_buffer_dma;
@@ -1597,8 +1601,9 @@ static int mx23_boot_init(struct gpmi_nand_data  *this)
                        dev_dbg(dev, "Transcribing mark in block %u\n", block);
                        ret = chip->block_markbad(mtd, byte);
                        if (ret)
-                               dev_err(dev, "Failed to mark block bad with "
-                                                       "ret %d\n", ret);
+                               dev_err(dev,
+                                       "Failed to mark block bad with ret %d\n",
+                                       ret);
                }
        }
 
@@ -1649,9 +1654,6 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
        struct bch_geometry *bch_geo = &this->bch_geometry;
        int ret;
 
-       /* Set up swap_block_mark, must be set before the gpmi_set_geometry() */
-       this->swap_block_mark = !GPMI_IS_MX23(this);
-
        /* Set up the medium geometry */
        ret = gpmi_set_geometry(this);
        if (ret)
@@ -1715,9 +1717,23 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
        chip->badblock_pattern  = &gpmi_bbt_descr;
        chip->block_markbad     = gpmi_block_markbad;
        chip->options           |= NAND_NO_SUBPAGE_WRITE;
-       if (of_get_nand_on_flash_bbt(this->dev->of_node))
+
+       /* Set up swap_block_mark, must be set before the gpmi_set_geometry() */
+       this->swap_block_mark = !GPMI_IS_MX23(this);
+
+       if (of_get_nand_on_flash_bbt(this->dev->of_node)) {
                chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
 
+               if (of_get_nand_no_oob_bbm(this->dev->of_node))
+                       chip->bbt_options |= NAND_BBT_NO_OOB_BBM;
+
+               if (of_property_read_bool(this->dev->of_node,
+                                               "fsl,no-blockmark-swap"))
+                       this->swap_block_mark = false;
+       }
+       dev_dbg(this->dev, "Blockmark swapping %sabled\n",
+               this->swap_block_mark ? "en" : "dis");
+
        /*
         * Allocate a temporary DMA buffer for reading ID in the
         * nand_scan_ident().
@@ -1760,16 +1776,16 @@ err_out:
 static const struct of_device_id gpmi_nand_id_table[] = {
        {
                .compatible = "fsl,imx23-gpmi-nand",
-               .data = (void *)&gpmi_devdata_imx23,
+               .data = &gpmi_devdata_imx23,
        }, {
                .compatible = "fsl,imx28-gpmi-nand",
-               .data = (void *)&gpmi_devdata_imx28,
+               .data = &gpmi_devdata_imx28,
        }, {
                .compatible = "fsl,imx6q-gpmi-nand",
-               .data = (void *)&gpmi_devdata_imx6q,
+               .data = &gpmi_devdata_imx6q,
        }, {
                .compatible = "fsl,imx6sx-gpmi-nand",
-               .data = (void *)&gpmi_devdata_imx6sx,
+               .data = &gpmi_devdata_imx6sx,
        }, {}
 };
 MODULE_DEVICE_TABLE(of, gpmi_nand_id_table);