diff options
Diffstat (limited to 'drivers/mtd/nand/lpc32xx_slc.c')
-rw-r--r-- | drivers/mtd/nand/lpc32xx_slc.c | 83 |
1 files changed, 56 insertions, 27 deletions
diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c index 3b8f3735f3e8..8d3edc34958e 100644 --- a/drivers/mtd/nand/lpc32xx_slc.c +++ b/drivers/mtd/nand/lpc32xx_slc.c @@ -35,7 +35,6 @@ #include <linux/mtd/nand_ecc.h> #include <linux/gpio.h> #include <linux/of.h> -#include <linux/of_mtd.h> #include <linux/of_gpio.h> #include <linux/mtd/lpc32xx_slc.h> @@ -146,13 +145,38 @@ * NAND ECC Layout for small page NAND devices * Note: For large and huge page devices, the default layouts are used */ -static struct nand_ecclayout lpc32xx_nand_oob_16 = { - .eccbytes = 6, - .eccpos = {10, 11, 12, 13, 14, 15}, - .oobfree = { - { .offset = 0, .length = 4 }, - { .offset = 6, .length = 4 }, - }, +static int lpc32xx_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + if (section) + return -ERANGE; + + oobregion->length = 6; + oobregion->offset = 10; + + return 0; +} + +static int lpc32xx_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + if (section > 1) + return -ERANGE; + + if (!section) { + oobregion->offset = 0; + oobregion->length = 4; + } else { + oobregion->offset = 6; + oobregion->length = 4; + } + + return 0; +} + +static const struct mtd_ooblayout_ops lpc32xx_ooblayout_ops = { + .ecc = lpc32xx_ooblayout_ecc, + .free = lpc32xx_ooblayout_free, }; static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; @@ -194,7 +218,6 @@ struct lpc32xx_nand_cfg_slc { uint32_t rwidth; uint32_t rhold; uint32_t rsetup; - bool use_bbt; int wp_gpio; struct mtd_partition *parts; unsigned num_parts; @@ -604,7 +627,8 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd, int oob_required, int page) { struct lpc32xx_nand_host *host = nand_get_controller_data(chip); - int stat, i, status; + struct mtd_oob_region oobregion = { }; + int stat, i, status, error; uint8_t *oobecc, tmpecc[LPC32XX_ECC_SAVE_SIZE]; /* Issue read command */ @@ -620,7 +644,11 @@ static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd, lpc32xx_slc_ecc_copy(tmpecc, (uint32_t *) host->ecc_buf, chip->ecc.steps); /* Pointer to ECC data retrieved from NAND spare area */ - oobecc = chip->oob_poi + chip->ecc.layout->eccpos[0]; + error = mtd_ooblayout_ecc(mtd, 0, &oobregion); + if (error) + return error; + + oobecc = chip->oob_poi + oobregion.offset; for (i = 0; i < chip->ecc.steps; i++) { stat = chip->ecc.correct(mtd, buf, oobecc, @@ -666,7 +694,8 @@ static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd, int oob_required, int page) { struct lpc32xx_nand_host *host = nand_get_controller_data(chip); - uint8_t *pb = chip->oob_poi + chip->ecc.layout->eccpos[0]; + struct mtd_oob_region oobregion = { }; + uint8_t *pb; int error; /* Write data, calculate ECC on outbound data */ @@ -678,6 +707,11 @@ static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd, * The calculated ECC needs some manual work done to it before * committing it to NAND. Process the calculated ECC and place * the resultant values directly into the OOB buffer. */ + error = mtd_ooblayout_ecc(mtd, 0, &oobregion); + if (error) + return error; + + pb = chip->oob_poi + oobregion.offset; lpc32xx_slc_ecc_copy(pb, (uint32_t *)host->ecc_buf, chip->ecc.steps); /* Write ECC data to device */ @@ -747,7 +781,6 @@ static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev) return NULL; } - ncfg->use_bbt = of_get_nand_on_flash_bbt(np); ncfg->wp_gpio = of_get_named_gpio(np, "gpios", 0); return ncfg; @@ -875,26 +908,22 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) * custom BBT marker layout. */ if (mtd->writesize <= 512) - chip->ecc.layout = &lpc32xx_nand_oob_16; + mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops); /* These sizes remain the same regardless of page size */ chip->ecc.size = 256; chip->ecc.bytes = LPC32XX_SLC_DEV_ECC_BYTES; chip->ecc.prepad = chip->ecc.postpad = 0; - /* Avoid extra scan if using BBT, setup BBT support */ - if (host->ncfg->use_bbt) { - chip->bbt_options |= NAND_BBT_USE_FLASH; - - /* - * Use a custom BBT marker setup for small page FLASH that - * won't interfere with the ECC layout. Large and huge page - * FLASH use the standard layout. - */ - if (mtd->writesize <= 512) { - chip->bbt_td = &bbt_smallpage_main_descr; - chip->bbt_md = &bbt_smallpage_mirror_descr; - } + /* + * Use a custom BBT marker setup for small page FLASH that + * won't interfere with the ECC layout. Large and huge page + * FLASH use the standard layout. + */ + if ((chip->bbt_options & NAND_BBT_USE_FLASH) && + mtd->writesize <= 512) { + chip->bbt_td = &bbt_smallpage_main_descr; + chip->bbt_md = &bbt_smallpage_mirror_descr; } /* |