diff options
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r-- | drivers/mtd/nand/jz4740_nand.c | 23 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 53 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_ids.c | 1 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_samsung.c | 3 | ||||
-rw-r--r-- | drivers/mtd/nand/tango_nand.c | 23 |
5 files changed, 60 insertions, 43 deletions
diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index 5551c36adbdf..0d06a1f07d82 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -25,7 +25,6 @@ #include <linux/gpio.h> -#include <asm/mach-jz4740/gpio.h> #include <asm/mach-jz4740/jz4740_nand.h> #define JZ_REG_NAND_CTRL 0x50 @@ -310,34 +309,20 @@ static int jz_nand_detect_bank(struct platform_device *pdev, uint8_t *nand_dev_id) { int ret; - int gpio; - char gpio_name[9]; char res_name[6]; uint32_t ctrl; struct nand_chip *chip = &nand->chip; struct mtd_info *mtd = nand_to_mtd(chip); - /* Request GPIO port. */ - gpio = JZ_GPIO_MEM_CS0 + bank - 1; - sprintf(gpio_name, "NAND CS%d", bank); - ret = gpio_request(gpio, gpio_name); - if (ret) { - dev_warn(&pdev->dev, - "Failed to request %s gpio %d: %d\n", - gpio_name, gpio, ret); - goto notfound_gpio; - } - /* Request I/O resource. */ sprintf(res_name, "bank%d", bank); ret = jz_nand_ioremap_resource(pdev, res_name, &nand->bank_mem[bank - 1], &nand->bank_base[bank - 1]); if (ret) - goto notfound_resource; + return ret; /* Enable chip in bank. */ - jz_gpio_set_function(gpio, JZ_GPIO_FUNC_MEM_CS0); ctrl = readl(nand->base + JZ_REG_NAND_CTRL); ctrl |= JZ_NAND_CTRL_ENABLE_CHIP(bank - 1); writel(ctrl, nand->base + JZ_REG_NAND_CTRL); @@ -377,12 +362,8 @@ notfound_id: dev_info(&pdev->dev, "No chip found on bank %i\n", bank); ctrl &= ~(JZ_NAND_CTRL_ENABLE_CHIP(bank - 1)); writel(ctrl, nand->base + JZ_REG_NAND_CTRL); - jz_gpio_set_function(gpio, JZ_GPIO_FUNC_NONE); jz_nand_iounmap_resource(nand->bank_mem[bank - 1], nand->bank_base[bank - 1]); -notfound_resource: - gpio_free(gpio); -notfound_gpio: return ret; } @@ -503,7 +484,6 @@ err_nand_release: err_unclaim_banks: while (chipnr--) { unsigned char bank = nand->banks[chipnr]; - gpio_free(JZ_GPIO_MEM_CS0 + bank - 1); jz_nand_iounmap_resource(nand->bank_mem[bank - 1], nand->bank_base[bank - 1]); } @@ -530,7 +510,6 @@ static int jz_nand_remove(struct platform_device *pdev) if (bank != 0) { jz_nand_iounmap_resource(nand->bank_mem[bank - 1], nand->bank_base[bank - 1]); - gpio_free(JZ_GPIO_MEM_CS0 + bank - 1); } } diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index d474378ed810..bf8486c406d3 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -202,7 +202,7 @@ static int nand_ooblayout_free_lp_hamming(struct mtd_info *mtd, int section, return 0; } -const struct mtd_ooblayout_ops nand_ooblayout_lp_hamming_ops = { +static const struct mtd_ooblayout_ops nand_ooblayout_lp_hamming_ops = { .ecc = nand_ooblayout_ecc_lp_hamming, .free = nand_ooblayout_free_lp_hamming, }; @@ -502,10 +502,12 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) * specify how to write bad block markers to OOB (chip->block_markbad). * * We try operations in the following order: + * * (1) erase the affected block, to allow OOB marker to be written cleanly * (2) write bad block marker to OOB area of affected block (unless flag * NAND_BBT_NO_OOB_BBM is present) * (3) update the BBT + * * Note that we retain the first error encountered in (2) or (3), finish the * procedures, and dump the error in the end. */ @@ -1219,9 +1221,10 @@ int nand_reset(struct nand_chip *chip, int chipnr) * @mtd: mtd info * @ofs: offset to start unlock from * @len: length to unlock - * @invert: when = 0, unlock the range of blocks within the lower and + * @invert: + * - when = 0, unlock the range of blocks within the lower and * upper boundary address - * when = 1, unlock the range of blocks outside the boundaries + * - when = 1, unlock the range of blocks outside the boundaries * of the lower and upper boundary address * * Returs unlock status. @@ -4361,7 +4364,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, /* Initialize the ->data_interface field. */ ret = nand_init_data_interface(chip); if (ret) - return ret; + goto err_nand_init; /* * Setup the data interface correctly on the chip and controller side. @@ -4373,7 +4376,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, */ ret = nand_setup_data_interface(chip); if (ret) - return ret; + goto err_nand_init; nand_maf_id = chip->id.data[0]; nand_dev_id = chip->id.data[1]; @@ -4404,6 +4407,12 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, mtd->size = i * chip->chipsize; return 0; + +err_nand_init: + /* Free manufacturer priv data. */ + nand_manufacturer_cleanup(chip); + + return ret; } EXPORT_SYMBOL(nand_scan_ident); @@ -4574,18 +4583,23 @@ int nand_scan_tail(struct mtd_info *mtd) /* New bad blocks should be marked in OOB, flash-based BBT, or both */ if (WARN_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) && - !(chip->bbt_options & NAND_BBT_USE_FLASH))) - return -EINVAL; + !(chip->bbt_options & NAND_BBT_USE_FLASH))) { + ret = -EINVAL; + goto err_ident; + } if (invalid_ecc_page_accessors(chip)) { pr_err("Invalid ECC page accessors setup\n"); - return -EINVAL; + ret = -EINVAL; + goto err_ident; } if (!(chip->options & NAND_OWN_BUFFERS)) { nbuf = kzalloc(sizeof(*nbuf), GFP_KERNEL); - if (!nbuf) - return -ENOMEM; + if (!nbuf) { + ret = -ENOMEM; + goto err_ident; + } nbuf->ecccalc = kmalloc(mtd->oobsize, GFP_KERNEL); if (!nbuf->ecccalc) { @@ -4608,8 +4622,10 @@ int nand_scan_tail(struct mtd_info *mtd) chip->buffers = nbuf; } else { - if (!chip->buffers) - return -ENOMEM; + if (!chip->buffers) { + ret = -ENOMEM; + goto err_ident; + } } /* Set the internal oob buffer location, just after the page data */ @@ -4842,7 +4858,11 @@ int nand_scan_tail(struct mtd_info *mtd) return 0; /* Build bad block table */ - return chip->scan_bbt(mtd); + ret = chip->scan_bbt(mtd); + if (ret) + goto err_free; + return 0; + err_free: if (nbuf) { kfree(nbuf->databuf); @@ -4850,6 +4870,13 @@ err_free: kfree(nbuf->ecccalc); kfree(nbuf); } + +err_ident: + /* Clean up nand_scan_ident(). */ + + /* Free manufacturer priv data. */ + nand_manufacturer_cleanup(chip); + return ret; } EXPORT_SYMBOL(nand_scan_tail); diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 9d5ca0e540b5..92e2cf8e9ff9 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -6,7 +6,6 @@ * published by the Free Software Foundation. * */ -#include <linux/module.h> #include <linux/mtd/nand.h> #include <linux/sizes.h> diff --git a/drivers/mtd/nand/nand_samsung.c b/drivers/mtd/nand/nand_samsung.c index 9cfc4035a420..1e0755997762 100644 --- a/drivers/mtd/nand/nand_samsung.c +++ b/drivers/mtd/nand/nand_samsung.c @@ -84,6 +84,9 @@ static void samsung_nand_decode_id(struct nand_chip *chip) case 7: chip->ecc_strength_ds = 60; break; + default: + WARN(1, "Could not decode ECC info"); + chip->ecc_step_ds = 0; } } } else { diff --git a/drivers/mtd/nand/tango_nand.c b/drivers/mtd/nand/tango_nand.c index 05b6e1065203..49b286c6c10f 100644 --- a/drivers/mtd/nand/tango_nand.c +++ b/drivers/mtd/nand/tango_nand.c @@ -55,10 +55,10 @@ * byte 1 for other packets in the page (PKT_N, for N > 0) * ERR_COUNT_PKT_N is the max error count over all but the first packet. */ -#define DECODE_OK_PKT_0(v) ((v) & BIT(7)) -#define DECODE_OK_PKT_N(v) ((v) & BIT(15)) #define ERR_COUNT_PKT_0(v) (((v) >> 0) & 0x3f) #define ERR_COUNT_PKT_N(v) (((v) >> 8) & 0x3f) +#define DECODE_FAIL_PKT_0(v) (((v) & BIT(7)) == 0) +#define DECODE_FAIL_PKT_N(v) (((v) & BIT(15)) == 0) /* Offsets relative to pbus_base */ #define PBUS_CS_CTRL 0x83c @@ -193,6 +193,8 @@ static int check_erased_page(struct nand_chip *chip, u8 *buf) chip->ecc.strength); if (res < 0) mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += res; bitflips = max(res, bitflips); buf += pkt_size; @@ -202,9 +204,11 @@ static int check_erased_page(struct nand_chip *chip, u8 *buf) return bitflips; } -static int decode_error_report(struct tango_nfc *nfc) +static int decode_error_report(struct nand_chip *chip) { u32 status, res; + struct mtd_info *mtd = nand_to_mtd(chip); + struct tango_nfc *nfc = to_tango_nfc(chip->controller); status = readl_relaxed(nfc->reg_base + NFC_XFER_STATUS); if (status & PAGE_IS_EMPTY) @@ -212,10 +216,14 @@ static int decode_error_report(struct tango_nfc *nfc) res = readl_relaxed(nfc->mem_base + ERROR_REPORT); - if (DECODE_OK_PKT_0(res) && DECODE_OK_PKT_N(res)) - return max(ERR_COUNT_PKT_0(res), ERR_COUNT_PKT_N(res)); + if (DECODE_FAIL_PKT_0(res) || DECODE_FAIL_PKT_N(res)) + return -EBADMSG; + + /* ERR_COUNT_PKT_N is max, not sum, but that's all we have */ + mtd->ecc_stats.corrected += + ERR_COUNT_PKT_0(res) + ERR_COUNT_PKT_N(res); - return -EBADMSG; + return max(ERR_COUNT_PKT_0(res), ERR_COUNT_PKT_N(res)); } static void tango_dma_callback(void *arg) @@ -282,7 +290,7 @@ static int tango_read_page(struct mtd_info *mtd, struct nand_chip *chip, if (err) return err; - res = decode_error_report(nfc); + res = decode_error_report(chip); if (res < 0) { chip->ecc.read_oob_raw(mtd, chip, page); res = check_erased_page(chip, buf); @@ -663,6 +671,7 @@ static const struct of_device_id tango_nand_ids[] = { { .compatible = "sigma,smp8758-nand" }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, tango_nand_ids); static struct platform_driver tango_nand_driver = { .probe = tango_nand_probe, |