]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
mtd: nand: omap2: switch to mtd_ooblayout_ops
authorBoris Brezillon <boris.brezillon@free-electrons.com>
Wed, 3 Feb 2016 19:03:04 +0000 (20:03 +0100)
committerBoris Brezillon <boris.brezillon@free-electrons.com>
Thu, 5 May 2016 21:51:46 +0000 (23:51 +0200)
Implementing the mtd_ooblayout_ops interface is the new way of exposing
ECC/OOB layout to MTD users.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
drivers/mtd/nand/omap2.c

index 38fe6b8a0b14faa31e126a66e3136cf06ea14b54..55916786d04e44bd27bfa0e5960b09714e66dab2 100644 (file)
@@ -178,8 +178,6 @@ struct omap_nand_info {
        struct gpmc_nand_regs           reg;
        struct gpmc_nand_ops            *ops;
        bool                            flash_bbt;
-       /* generated at runtime depending on ECC algorithm and layout selected */
-       struct nand_ecclayout           oobinfo;
        /* fields specific for BCHx_HW ECC scheme */
        struct device                   *elm_dev;
        /* NAND ready gpio */
@@ -1714,20 +1712,115 @@ static int omap_get_dt_info(struct device *dev, struct omap_nand_info *info)
        return 0;
 }
 
+static int omap_ooblayout_ecc(struct mtd_info *mtd, int section,
+                             struct mtd_oob_region *oobregion)
+{
+       struct omap_nand_info *info = mtd_to_omap(mtd);
+       struct nand_chip *chip = &info->nand;
+       int off = BADBLOCK_MARKER_LENGTH;
+
+       if (info->ecc_opt == OMAP_ECC_HAM1_CODE_HW &&
+           !(chip->options & NAND_BUSWIDTH_16))
+               off = 1;
+
+       if (section)
+               return -ERANGE;
+
+       oobregion->offset = off;
+       oobregion->length = chip->ecc.total;
+
+       return 0;
+}
+
+static int omap_ooblayout_free(struct mtd_info *mtd, int section,
+                              struct mtd_oob_region *oobregion)
+{
+       struct omap_nand_info *info = mtd_to_omap(mtd);
+       struct nand_chip *chip = &info->nand;
+       int off = BADBLOCK_MARKER_LENGTH;
+
+       if (info->ecc_opt == OMAP_ECC_HAM1_CODE_HW &&
+           !(chip->options & NAND_BUSWIDTH_16))
+               off = 1;
+
+       if (section)
+               return -ERANGE;
+
+       off += chip->ecc.total;
+       if (off >= mtd->oobsize)
+               return -ERANGE;
+
+       oobregion->offset = off;
+       oobregion->length = mtd->oobsize - off;
+
+       return 0;
+}
+
+static const struct mtd_ooblayout_ops omap_ooblayout_ops = {
+       .ecc = omap_ooblayout_ecc,
+       .free = omap_ooblayout_free,
+};
+
+static int omap_sw_ooblayout_ecc(struct mtd_info *mtd, int section,
+                                struct mtd_oob_region *oobregion)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       int off = BADBLOCK_MARKER_LENGTH;
+
+       if (section >= chip->ecc.steps)
+               return -ERANGE;
+
+       /*
+        * When SW correction is employed, one OMAP specific marker byte is
+        * reserved after each ECC step.
+        */
+       oobregion->offset = off + (section * (chip->ecc.bytes + 1));
+       oobregion->length = chip->ecc.bytes;
+
+       return 0;
+}
+
+static int omap_sw_ooblayout_free(struct mtd_info *mtd, int section,
+                                 struct mtd_oob_region *oobregion)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       int off = BADBLOCK_MARKER_LENGTH;
+
+       if (section)
+               return -ERANGE;
+
+       /*
+        * When SW correction is employed, one OMAP specific marker byte is
+        * reserved after each ECC step.
+        */
+       off += ((chip->ecc.bytes + 1) * chip->ecc.steps);
+       if (off >= mtd->oobsize)
+               return -ERANGE;
+
+       oobregion->offset = off;
+       oobregion->length = mtd->oobsize - off;
+
+       return 0;
+}
+
+static const struct mtd_ooblayout_ops omap_sw_ooblayout_ops = {
+       .ecc = omap_sw_ooblayout_ecc,
+       .free = omap_sw_ooblayout_free,
+};
+
 static int omap_nand_probe(struct platform_device *pdev)
 {
        struct omap_nand_info           *info;
        struct omap_nand_platform_data  *pdata = NULL;
        struct mtd_info                 *mtd;
        struct nand_chip                *nand_chip;
-       struct nand_ecclayout           *ecclayout;
        int                             err;
-       int                             i;
        dma_cap_mask_t                  mask;
        unsigned                        sig;
-       unsigned                        oob_index;
        struct resource                 *res;
        struct device                   *dev = &pdev->dev;
+       int                             min_oobbytes = BADBLOCK_MARKER_LENGTH;
+       int                             oobbytes_per_step;
 
        info = devm_kzalloc(&pdev->dev, sizeof(struct omap_nand_info),
                                GFP_KERNEL);
@@ -1915,7 +2008,7 @@ static int omap_nand_probe(struct platform_device *pdev)
 
        /*
         * Bail out earlier to let NAND_ECC_SOFT code create its own
-        * ecclayout instead of using ours.
+        * ooblayout instead of using ours.
         */
        if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW) {
                nand_chip->ecc.mode = NAND_ECC_SOFT;
@@ -1923,8 +2016,6 @@ static int omap_nand_probe(struct platform_device *pdev)
        }
 
        /* populate MTD interface based on ECC scheme */
-       ecclayout               = &info->oobinfo;
-       nand_chip->ecc.layout   = ecclayout;
        switch (info->ecc_opt) {
        case OMAP_ECC_HAM1_CODE_HW:
                pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n");
@@ -1935,19 +2026,12 @@ static int omap_nand_probe(struct platform_device *pdev)
                nand_chip->ecc.calculate        = omap_calculate_ecc;
                nand_chip->ecc.hwctl            = omap_enable_hwecc;
                nand_chip->ecc.correct          = omap_correct_data;
-               /* define ECC layout */
-               ecclayout->eccbytes             = nand_chip->ecc.bytes *
-                                                       (mtd->writesize /
-                                                       nand_chip->ecc.size);
-               if (nand_chip->options & NAND_BUSWIDTH_16)
-                       oob_index               = BADBLOCK_MARKER_LENGTH;
-               else
-                       oob_index               = 1;
-               for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
-                       ecclayout->eccpos[i]    = oob_index;
-               /* no reserved-marker in ecclayout for this ecc-scheme */
-               ecclayout->oobfree->offset      =
-                               ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
+               mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+               oobbytes_per_step               = nand_chip->ecc.bytes;
+
+               if (!(nand_chip->options & NAND_BUSWIDTH_16))
+                       min_oobbytes            = 1;
+
                break;
 
        case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
@@ -1959,19 +2043,9 @@ static int omap_nand_probe(struct platform_device *pdev)
                nand_chip->ecc.hwctl            = omap_enable_hwecc_bch;
                nand_chip->ecc.correct          = nand_bch_correct_data;
                nand_chip->ecc.calculate        = omap_calculate_ecc_bch;
-               /* define ECC layout */
-               ecclayout->eccbytes             = nand_chip->ecc.bytes *
-                                                       (mtd->writesize /
-                                                       nand_chip->ecc.size);
-               oob_index                       = BADBLOCK_MARKER_LENGTH;
-               for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) {
-                       ecclayout->eccpos[i] = oob_index;
-                       if (((i + 1) % nand_chip->ecc.bytes) == 0)
-                               oob_index++;
-               }
-               /* include reserved-marker in ecclayout->oobfree calculation */
-               ecclayout->oobfree->offset      = 1 +
-                               ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
+               mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
+               /* Reserve one byte for the OMAP marker */
+               oobbytes_per_step               = nand_chip->ecc.bytes + 1;
                /* software bch library is used for locating errors */
                nand_chip->ecc.priv             = nand_bch_init(mtd);
                if (!nand_chip->ecc.priv) {
@@ -1993,16 +2067,8 @@ static int omap_nand_probe(struct platform_device *pdev)
                nand_chip->ecc.calculate        = omap_calculate_ecc_bch;
                nand_chip->ecc.read_page        = omap_read_page_bch;
                nand_chip->ecc.write_page       = omap_write_page_bch;
-               /* define ECC layout */
-               ecclayout->eccbytes             = nand_chip->ecc.bytes *
-                                                       (mtd->writesize /
-                                                       nand_chip->ecc.size);
-               oob_index                       = BADBLOCK_MARKER_LENGTH;
-               for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
-                       ecclayout->eccpos[i]    = oob_index;
-               /* reserved marker already included in ecclayout->eccbytes */
-               ecclayout->oobfree->offset      =
-                               ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
+               mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+               oobbytes_per_step               = nand_chip->ecc.bytes;
 
                err = elm_config(info->elm_dev, BCH4_ECC,
                                 mtd->writesize / nand_chip->ecc.size,
@@ -2020,19 +2086,9 @@ static int omap_nand_probe(struct platform_device *pdev)
                nand_chip->ecc.hwctl            = omap_enable_hwecc_bch;
                nand_chip->ecc.correct          = nand_bch_correct_data;
                nand_chip->ecc.calculate        = omap_calculate_ecc_bch;
-               /* define ECC layout */
-               ecclayout->eccbytes             = nand_chip->ecc.bytes *
-                                                       (mtd->writesize /
-                                                       nand_chip->ecc.size);
-               oob_index                       = BADBLOCK_MARKER_LENGTH;
-               for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) {
-                       ecclayout->eccpos[i] = oob_index;
-                       if (((i + 1) % nand_chip->ecc.bytes) == 0)
-                               oob_index++;
-               }
-               /* include reserved-marker in ecclayout->oobfree calculation */
-               ecclayout->oobfree->offset      = 1 +
-                               ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
+               mtd_set_ooblayout(mtd, &omap_sw_ooblayout_ops);
+               /* Reserve one byte for the OMAP marker */
+               oobbytes_per_step               = nand_chip->ecc.bytes + 1;
                /* software bch library is used for locating errors */
                nand_chip->ecc.priv             = nand_bch_init(mtd);
                if (!nand_chip->ecc.priv) {
@@ -2054,6 +2110,8 @@ static int omap_nand_probe(struct platform_device *pdev)
                nand_chip->ecc.calculate        = omap_calculate_ecc_bch;
                nand_chip->ecc.read_page        = omap_read_page_bch;
                nand_chip->ecc.write_page       = omap_write_page_bch;
+               mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+               oobbytes_per_step               = nand_chip->ecc.bytes;
 
                err = elm_config(info->elm_dev, BCH8_ECC,
                                 mtd->writesize / nand_chip->ecc.size,
@@ -2061,16 +2119,6 @@ static int omap_nand_probe(struct platform_device *pdev)
                if (err < 0)
                        goto return_error;
 
-               /* define ECC layout */
-               ecclayout->eccbytes             = nand_chip->ecc.bytes *
-                                                       (mtd->writesize /
-                                                       nand_chip->ecc.size);
-               oob_index                       = BADBLOCK_MARKER_LENGTH;
-               for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
-                       ecclayout->eccpos[i]    = oob_index;
-               /* reserved marker already included in ecclayout->eccbytes */
-               ecclayout->oobfree->offset      =
-                               ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
                break;
 
        case OMAP_ECC_BCH16_CODE_HW:
@@ -2084,6 +2132,8 @@ static int omap_nand_probe(struct platform_device *pdev)
                nand_chip->ecc.calculate        = omap_calculate_ecc_bch;
                nand_chip->ecc.read_page        = omap_read_page_bch;
                nand_chip->ecc.write_page       = omap_write_page_bch;
+               mtd_set_ooblayout(mtd, &omap_ooblayout_ops);
+               oobbytes_per_step               = nand_chip->ecc.bytes;
 
                err = elm_config(info->elm_dev, BCH16_ECC,
                                 mtd->writesize / nand_chip->ecc.size,
@@ -2091,16 +2141,6 @@ static int omap_nand_probe(struct platform_device *pdev)
                if (err < 0)
                        goto return_error;
 
-               /* define ECC layout */
-               ecclayout->eccbytes             = nand_chip->ecc.bytes *
-                                                       (mtd->writesize /
-                                                       nand_chip->ecc.size);
-               oob_index                       = BADBLOCK_MARKER_LENGTH;
-               for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
-                       ecclayout->eccpos[i]    = oob_index;
-               /* reserved marker already included in ecclayout->eccbytes */
-               ecclayout->oobfree->offset      =
-                               ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
                break;
        default:
                dev_err(&info->pdev->dev, "invalid or unsupported ECC scheme\n");
@@ -2108,13 +2148,13 @@ static int omap_nand_probe(struct platform_device *pdev)
                goto return_error;
        }
 
-       /* all OOB bytes from oobfree->offset till end off OOB are free */
-       ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset;
        /* check if NAND device's OOB is enough to store ECC signatures */
-       if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) {
+       min_oobbytes += (oobbytes_per_step *
+                        (mtd->writesize / nand_chip->ecc.size));
+       if (mtd->oobsize < min_oobbytes) {
                dev_err(&info->pdev->dev,
                        "not enough OOB bytes required = %d, available=%d\n",
-                       ecclayout->eccbytes, mtd->oobsize);
+                       min_oobbytes, mtd->oobsize);
                err = -EINVAL;
                goto return_error;
        }