Loading drivers/mtd/nand/omap2.c +121 −81 Original line number Diff line number Diff line Loading @@ -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 */ Loading Loading @@ -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); Loading Loading @@ -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; Loading @@ -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"); Loading @@ -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: Loading @@ -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) { Loading @@ -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, Loading @@ -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) { Loading @@ -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, Loading @@ -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: Loading @@ -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, Loading @@ -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"); Loading @@ -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; } Loading Loading
drivers/mtd/nand/omap2.c +121 −81 Original line number Diff line number Diff line Loading @@ -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 */ Loading Loading @@ -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); Loading Loading @@ -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; Loading @@ -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"); Loading @@ -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: Loading @@ -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) { Loading @@ -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, Loading @@ -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) { Loading @@ -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, Loading @@ -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: Loading @@ -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, Loading @@ -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"); Loading @@ -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; } Loading