diff options
Diffstat (limited to 'drivers/mtd/nand')
46 files changed, 1886 insertions, 671 deletions
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 3324281d1..289664089 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -393,7 +393,7 @@ config MTD_NAND_GPMI_NAND config MTD_NAND_BRCMNAND tristate "Broadcom STB NAND controller" - depends on ARM || MIPS + depends on ARM || ARM64 || MIPS help Enables the Broadcom NAND controller driver. The controller was originally designed for Set-Top Box but is used on various BCM7xxx, @@ -460,6 +460,17 @@ config MTD_NAND_MPC5121_NFC This enables the driver for the NAND flash controller on the MPC5121 SoC. +config MTD_NAND_VF610_NFC + tristate "Support for Freescale NFC for VF610/MPC5125" + depends on (SOC_VF610 || COMPILE_TEST) + help + Enables support for NAND Flash Controller on some Freescale + processors like the VF610, MPC5125, MCF54418 or Kinetis K70. + The driver supports a maximum 2k page size. With 2k pages and + 64 bytes or more of OOB, hardware ECC with up to 32-bit error + correction is supported. Hardware ECC is only enabled through + device tree. + config MTD_NAND_MXC tristate "MXC NAND support" depends on ARCH_MXC diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 075a02763..2c7f014b3 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o obj-$(CONFIG_MTD_NAND_NUC900) += nuc900_nand.o obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o +obj-$(CONFIG_MTD_NAND_VF610_NFC) += vf610_nfc.o obj-$(CONFIG_MTD_NAND_RICOH) += r852.o obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/ diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 46010bd89..583cdd9bb 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -954,7 +954,8 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, } static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, int oob_required) + struct nand_chip *chip, const uint8_t *buf, int oob_required, + int page) { struct atmel_nand_host *host = chip->priv; uint32_t *eccpos = chip->ecc.layout->eccpos; @@ -2005,7 +2006,8 @@ static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip, if (likely(!raw)) /* Need to write ecc into oob */ - status = chip->ecc.write_page(mtd, chip, buf, oob_required); + status = chip->ecc.write_page(mtd, chip, buf, oob_required, + page); if (status < 0) return status; @@ -2126,7 +2128,7 @@ static int atmel_nand_probe(struct platform_device *pdev) nand_chip->priv = host; /* link the private data structures */ mtd->priv = nand_chip; - mtd->owner = THIS_MODULE; + mtd->dev.parent = &pdev->dev; /* Set address of NAND IO lines */ nand_chip->IO_ADDR_R = host->io_base; diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index c0c3be180..08a130f63 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -439,7 +439,7 @@ static int au1550nd_probe(struct platform_device *pdev) this = &ctx->chip; ctx->info.priv = this; - ctx->info.owner = THIS_MODULE; + ctx->info.dev.parent = &pdev->dev; /* figure out which CS# r->start belongs to */ cs = find_nand_cs(r->start); diff --git a/drivers/mtd/nand/bcm47xxnflash/main.c b/drivers/mtd/nand/bcm47xxnflash/main.c index 461577cfb..9ba0c0f2c 100644 --- a/drivers/mtd/nand/bcm47xxnflash/main.c +++ b/drivers/mtd/nand/bcm47xxnflash/main.c @@ -34,7 +34,7 @@ static int bcm47xxnflash_probe(struct platform_device *pdev) return -ENOMEM; b47n->nand_chip.priv = b47n; - b47n->mtd.owner = THIS_MODULE; + b47n->mtd.dev.parent = &pdev->dev; b47n->mtd.priv = &b47n->nand_chip; /* Required */ b47n->cc = container_of(nflash, struct bcma_drv_cc, nflash); diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index 4d8d4ba4b..61bd21607 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -566,7 +566,8 @@ static int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip } static int bf5xx_nand_write_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, int oob_required) + struct nand_chip *chip, const uint8_t *buf, int oob_required, + int page) { bf5xx_nand_write_buf(mtd, buf, mtd->writesize); bf5xx_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize); @@ -782,7 +783,7 @@ static int bf5xx_nand_probe(struct platform_device *pdev) /* initialise mtd info data struct */ mtd = &info->mtd; mtd->priv = chip; - mtd->owner = THIS_MODULE; + mtd->dev.parent = &pdev->dev; /* initialise the hardware */ err = bf5xx_nand_hw_init(info); diff --git a/drivers/mtd/nand/brcmnand/bcm63138_nand.c b/drivers/mtd/nand/brcmnand/bcm63138_nand.c index 3f4c44c24..59444b3a6 100644 --- a/drivers/mtd/nand/brcmnand/bcm63138_nand.c +++ b/drivers/mtd/nand/brcmnand/bcm63138_nand.c @@ -22,7 +22,8 @@ #include "brcmnand.h" -struct bcm63138_nand_soc_priv { +struct bcm63138_nand_soc { + struct brcmnand_soc soc; void __iomem *base; }; @@ -35,7 +36,8 @@ enum { static bool bcm63138_nand_intc_ack(struct brcmnand_soc *soc) { - struct bcm63138_nand_soc_priv *priv = soc->priv; + struct bcm63138_nand_soc *priv = + container_of(soc, struct bcm63138_nand_soc, soc); void __iomem *mmio = priv->base + BCM63138_NAND_INT_STATUS; u32 val = brcmnand_readl(mmio); @@ -49,7 +51,8 @@ static bool bcm63138_nand_intc_ack(struct brcmnand_soc *soc) static void bcm63138_nand_intc_set(struct brcmnand_soc *soc, bool en) { - struct bcm63138_nand_soc_priv *priv = soc->priv; + struct bcm63138_nand_soc *priv = + container_of(soc, struct bcm63138_nand_soc, soc); void __iomem *mmio = priv->base + BCM63138_NAND_INT_EN; u32 val = brcmnand_readl(mmio); @@ -64,25 +67,20 @@ static void bcm63138_nand_intc_set(struct brcmnand_soc *soc, bool en) static int bcm63138_nand_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct bcm63138_nand_soc_priv *priv; + struct bcm63138_nand_soc *priv; struct brcmnand_soc *soc; struct resource *res; - soc = devm_kzalloc(dev, sizeof(*soc), GFP_KERNEL); - if (!soc) - return -ENOMEM; - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + soc = &priv->soc; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand-int-base"); priv->base = devm_ioremap_resource(dev, res); if (IS_ERR(priv->base)) return PTR_ERR(priv->base); - soc->pdev = pdev; - soc->priv = priv; soc->ctlrdy_ack = bcm63138_nand_intc_ack; soc->ctlrdy_set_enabled = bcm63138_nand_intc_set; diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c index fddb795ee..12c6190c6 100644 --- a/drivers/mtd/nand/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/brcmnand/brcmnand.c @@ -344,6 +344,28 @@ static const u8 brcmnand_cs_offsets_cs0[] = { [BRCMNAND_CS_TIMING2] = 0x14, }; +/* + * Bitfields for the CFG and CFG_EXT registers. Pre-v7.1 controllers only had + * one config register, but once the bitfields overflowed, newer controllers + * (v7.1 and newer) added a CFG_EXT register and shuffled a few fields around. + */ +enum { + CFG_BLK_ADR_BYTES_SHIFT = 8, + CFG_COL_ADR_BYTES_SHIFT = 12, + CFG_FUL_ADR_BYTES_SHIFT = 16, + CFG_BUS_WIDTH_SHIFT = 23, + CFG_BUS_WIDTH = BIT(CFG_BUS_WIDTH_SHIFT), + CFG_DEVICE_SIZE_SHIFT = 24, + + /* Only for pre-v7.1 (with no CFG_EXT register) */ + CFG_PAGE_SIZE_SHIFT = 20, + CFG_BLK_SIZE_SHIFT = 28, + + /* Only for v7.1+ (with CFG_EXT register) */ + CFG_EXT_PAGE_SIZE_SHIFT = 0, + CFG_EXT_BLK_SIZE_SHIFT = 4, +}; + /* BRCMNAND_INTFC_STATUS */ enum { INTFC_FLASH_STATUS = GENMASK(7, 0), @@ -1544,9 +1566,9 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip, dev_dbg(ctrl->dev, "write %llx <- %p\n", (unsigned long long)addr, buf); - if (unlikely((u32)buf & 0x03)) { + if (unlikely((unsigned long)buf & 0x03)) { dev_warn(ctrl->dev, "unaligned buffer: %p\n", buf); - buf = (u32 *)((u32)buf & ~0x03); + buf = (u32 *)((unsigned long)buf & ~0x03); } brcmnand_wp(mtd, 0); @@ -1606,7 +1628,7 @@ out: } static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf, int oob_required, int page) { struct brcmnand_host *host = chip->priv; void *oob = oob_required ? chip->oob_poi : NULL; @@ -1617,7 +1639,7 @@ static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip, static int brcmnand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, - int oob_required) + int oob_required, int page) { struct brcmnand_host *host = chip->priv; void *oob = oob_required ? chip->oob_poi : NULL; @@ -1720,17 +1742,19 @@ static int brcmnand_set_cfg(struct brcmnand_host *host, } device_size = fls64(cfg->device_size) - fls64(BRCMNAND_MIN_DEVSIZE); - tmp = (cfg->blk_adr_bytes << 8) | - (cfg->col_adr_bytes << 12) | - (cfg->ful_adr_bytes << 16) | - (!!(cfg->device_width == 16) << 23) | - (device_size << 24); + tmp = (cfg->blk_adr_bytes << CFG_BLK_ADR_BYTES_SHIFT) | + (cfg->col_adr_bytes << CFG_COL_ADR_BYTES_SHIFT) | + (cfg->ful_adr_bytes << CFG_FUL_ADR_BYTES_SHIFT) | + (!!(cfg->device_width == 16) << CFG_BUS_WIDTH_SHIFT) | + (device_size << CFG_DEVICE_SIZE_SHIFT); if (cfg_offs == cfg_ext_offs) { - tmp |= (page_size << 20) | (block_size << 28); + tmp |= (page_size << CFG_PAGE_SIZE_SHIFT) | + (block_size << CFG_BLK_SIZE_SHIFT); nand_writereg(ctrl, cfg_offs, tmp); } else { nand_writereg(ctrl, cfg_offs, tmp); - tmp = page_size | (block_size << 4); + tmp = (page_size << CFG_EXT_PAGE_SIZE_SHIFT) | + (block_size << CFG_EXT_BLK_SIZE_SHIFT); nand_writereg(ctrl, cfg_ext_offs, tmp); } @@ -1792,7 +1816,8 @@ static int brcmnand_setup_dev(struct brcmnand_host *host) memset(cfg, 0, sizeof(*cfg)); - ret = of_property_read_u32(chip->dn, "brcm,nand-oob-sector-size", + ret = of_property_read_u32(chip->flash_node, + "brcm,nand-oob-sector-size", &oob_sector); if (ret) { /* Use detected size */ @@ -1888,6 +1913,7 @@ static int brcmnand_init_cs(struct brcmnand_host *host) struct mtd_info *mtd; struct nand_chip *chip; int ret; + u16 cfg_offs; struct mtd_part_parser_data ppdata = { .of_node = dn }; ret = of_property_read_u32(dn, "reg", &host->cs); @@ -1899,7 +1925,7 @@ static int brcmnand_init_cs(struct brcmnand_host *host) mtd = &host->mtd; chip = &host->chip; - chip->dn = dn; + chip->flash_node = dn; chip->priv = host; mtd->priv = chip; mtd->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "brcmnand.%d", @@ -1930,6 +1956,15 @@ static int brcmnand_init_cs(struct brcmnand_host *host) chip->controller = &ctrl->controller; + /* + * The bootloader might have configured 16bit mode but + * NAND READID command only works in 8bit mode. We force + * 8bit mode here to ensure that NAND READID commands works. + */ + cfg_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_CFG); + nand_writereg(ctrl, cfg_offs, + nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH); + if (nand_scan_ident(mtd, 1, NULL)) return -ENXIO; diff --git a/drivers/mtd/nand/brcmnand/brcmnand.h b/drivers/mtd/nand/brcmnand/brcmnand.h index 169f99e38..ef5eabba8 100644 --- a/drivers/mtd/nand/brcmnand/brcmnand.h +++ b/drivers/mtd/nand/brcmnand/brcmnand.h @@ -21,8 +21,6 @@ struct platform_device; struct dev_pm_ops; struct brcmnand_soc { - struct platform_device *pdev; - void *priv; bool (*ctlrdy_ack)(struct brcmnand_soc *soc); void (*ctlrdy_set_enabled)(struct brcmnand_soc *soc, bool en); void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare); diff --git a/drivers/mtd/nand/brcmnand/iproc_nand.c b/drivers/mtd/nand/brcmnand/iproc_nand.c index 683495c74..585596c54 100644 --- a/drivers/mtd/nand/brcmnand/iproc_nand.c +++ b/drivers/mtd/nand/brcmnand/iproc_nand.c @@ -22,7 +22,9 @@ #include "brcmnand.h" -struct iproc_nand_soc_priv { +struct iproc_nand_soc { + struct brcmnand_soc soc; + void __iomem *idm_base; void __iomem *ext_base; spinlock_t idm_lock; @@ -37,7 +39,8 @@ struct iproc_nand_soc_priv { static bool iproc_nand_intc_ack(struct brcmnand_soc *soc) { - struct iproc_nand_soc_priv *priv = soc->priv; + struct iproc_nand_soc *priv = + container_of(soc, struct iproc_nand_soc, soc); void __iomem *mmio = priv->ext_base + IPROC_NAND_CTLR_READY_OFFSET; u32 val = brcmnand_readl(mmio); @@ -51,7 +54,8 @@ static bool iproc_nand_intc_ack(struct brcmnand_soc *soc) static void iproc_nand_intc_set(struct brcmnand_soc *soc, bool en) { - struct iproc_nand_soc_priv *priv = soc->priv; + struct iproc_nand_soc *priv = + container_of(soc, struct iproc_nand_soc, soc); void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET; u32 val; unsigned long flags; @@ -72,7 +76,8 @@ static void iproc_nand_intc_set(struct brcmnand_soc *soc, bool en) static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare) { - struct iproc_nand_soc_priv *priv = soc->priv; + struct iproc_nand_soc *priv = + container_of(soc, struct iproc_nand_soc, soc); void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET; u32 val; unsigned long flags; @@ -94,17 +99,14 @@ static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare) static int iproc_nand_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct iproc_nand_soc_priv *priv; + struct iproc_nand_soc *priv; struct brcmnand_soc *soc; struct resource *res; - soc = devm_kzalloc(dev, sizeof(*soc), GFP_KERNEL); - if (!soc) - return -ENOMEM; - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + soc = &priv->soc; spin_lock_init(&priv->idm_lock); @@ -118,8 +120,6 @@ static int iproc_nand_probe(struct platform_device *pdev) if (IS_ERR(priv->ext_base)) return PTR_ERR(priv->ext_base); - soc->pdev = pdev; - soc->priv = priv; soc->ctlrdy_ack = iproc_nand_intc_ack; soc->ctlrdy_set_enabled = iproc_nand_intc_set; soc->prepare_data_bus = iproc_nand_apb_access; diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index 9a0f45f1d..9de78d2a2 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -516,7 +516,8 @@ static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = { static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf, int oob_required, + int page) { struct cafe_priv *cafe = mtd->priv; @@ -604,7 +605,6 @@ static int cafe_nand_probe(struct pci_dev *pdev, mtd->dev.parent = &pdev->dev; mtd->priv = cafe; - mtd->owner = THIS_MODULE; cafe->pdev = pdev; cafe->mmio = pci_iomap(pdev, 0, 0); diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index b90801302..c72313d66 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -683,9 +683,6 @@ static int nand_davinci_probe(struct platform_device *pdev) info->vaddr = vaddr; info->mtd.priv = &info->chip; - info->mtd.name = dev_name(&pdev->dev); - info->mtd.owner = THIS_MODULE; - info->mtd.dev.parent = &pdev->dev; info->chip.IO_ADDR_R = vaddr; diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 870c7fc0f..67eb2be0d 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -458,8 +458,17 @@ static void find_valid_banks(struct denali_nand_info *denali) static void detect_max_banks(struct denali_nand_info *denali) { uint32_t features = ioread32(denali->flash_reg + FEATURES); + /* + * Read the revision register, so we can calculate the max_banks + * properly: the encoding changed from rev 5.0 to 5.1 + */ + u32 revision = MAKE_COMPARABLE_REVISION( + ioread32(denali->flash_reg + REVISION)); - denali->max_banks = 2 << (features & FEATURES__N_BANKS); + if (revision < REVISION_5_1) + denali->max_banks = 2 << (features & FEATURES__N_BANKS); + else + denali->max_banks = 1 << (features & FEATURES__N_BANKS); } static void detect_partition_feature(struct denali_nand_info *denali) @@ -1105,7 +1114,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, * by write_page above. */ static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf, int oob_required, int page) { /* * for regular page writes, we let HW handle all the ECC @@ -1120,7 +1129,8 @@ static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, * write_page() function above. */ static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf, int oob_required, + int page) { /* * for raw page writes, we want to disable ECC and simply write @@ -1304,7 +1314,7 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, */ addr = MODE_11 | BANK(denali->flash_bank); index_addr(denali, addr | 0, 0x90); - index_addr(denali, addr | 1, 0); + index_addr(denali, addr | 1, col); for (i = 0; i < 8; i++) { index_addr_read_data(denali, addr | 2, &id); write_byte_to_buf(denali, id); @@ -1454,7 +1464,6 @@ int denali_init(struct denali_nand_info *denali) /* now that our ISR is registered, we can enable interrupts */ denali_set_intr_modes(denali, true); denali->mtd.name = "denali-nand"; - denali->mtd.owner = THIS_MODULE; denali->mtd.priv = &denali->nand; /* register the driver with the NAND core subsystem */ diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 145bf8893..4b12cd302 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -178,6 +178,8 @@ #define REVISION 0x370 #define REVISION__VALUE 0xffff +#define MAKE_COMPARABLE_REVISION(x) swab16((x) & REVISION__VALUE) +#define REVISION_5_1 0x00000501 #define ONFI_DEVICE_FEATURES 0x380 #define ONFI_DEVICE_FEATURES__VALUE 0x003f diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c index e5d7bcaaf..408cf69b8 100644 --- a/drivers/mtd/nand/docg4.c +++ b/drivers/mtd/nand/docg4.c @@ -977,13 +977,13 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *nand, } static int docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand, - const uint8_t *buf, int oob_required) + const uint8_t *buf, int oob_required, int page) { return write_page(mtd, nand, buf, false); } static int docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand, - const uint8_t *buf, int oob_required) + const uint8_t *buf, int oob_required, int page) { return write_page(mtd, nand, buf, true); } @@ -1113,7 +1113,7 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs) /* write first page of block */ write_page_prologue(mtd, g4_addr); - docg4_write_page(mtd, nand, buf, 1); + docg4_write_page(mtd, nand, buf, 1, page); ret = pageprog(mtd); kfree(buf); @@ -1316,7 +1316,7 @@ static int __init probe_docg4(struct platform_device *pdev) doc = (struct docg4_priv *) (nand + 1); mtd->priv = nand; nand->priv = doc; - mtd->owner = THIS_MODULE; + mtd->dev.parent = &pdev->dev; doc->virtadr = virtadr; doc->dev = dev; diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 04b22fd37..dcb1f7f48 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -715,7 +715,7 @@ static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip, * waitfunc. */ static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf, int oob_required, int page) { fsl_elbc_write_buf(mtd, buf, mtd->writesize); fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); @@ -728,7 +728,7 @@ static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip, */ static int fsl_elbc_write_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t offset, uint32_t data_len, - const uint8_t *buf, int oob_required) + const uint8_t *buf, int oob_required, int page) { fsl_elbc_write_buf(mtd, buf, mtd->writesize); fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); @@ -747,7 +747,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) /* Fill in fsl_elbc_mtd structure */ priv->mtd.priv = chip; - priv->mtd.owner = THIS_MODULE; + priv->mtd.dev.parent = priv->dev; /* set timeout to maximum */ priv->fmr = 15 << FMR_CWTO_SHIFT; @@ -946,6 +946,7 @@ static const struct of_device_id fsl_elbc_nand_match[] = { { .compatible = "fsl,elbc-fcm-nand", }, {} }; +MODULE_DEVICE_TABLE(of, fsl_elbc_nand_match); static struct platform_driver fsl_elbc_nand_driver = { .driver = { diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index a4e27e891..7f4ac8c19 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -772,7 +772,7 @@ static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip, * waitfunc. */ static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf, int oob_required, int page) { fsl_ifc_write_buf(mtd, buf, mtd->writesize); fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize); @@ -882,7 +882,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) /* Fill in fsl_ifc_mtd structure */ priv->mtd.priv = chip; - priv->mtd.owner = THIS_MODULE; + priv->mtd.dev.parent = priv->dev; /* fill in nand_chip structure */ /* set up function call table */ @@ -1163,6 +1163,7 @@ static const struct of_device_id fsl_ifc_nand_match[] = { }, {} }; +MODULE_DEVICE_TABLE(of, fsl_ifc_nand_match); static struct platform_driver fsl_ifc_nand_driver = { .driver = { diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index 72755d7ec..d32636998 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c @@ -176,7 +176,7 @@ static int fun_chip_init(struct fsl_upm_nand *fun, fun->chip.dev_ready = fun_chip_ready; fun->mtd.priv = &fun->chip; - fun->mtd.owner = THIS_MODULE; + fun->mtd.dev.parent = fun->dev; flash_np = of_get_next_child(upm_np, NULL); if (!flash_np) diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 793872f18..07af3dc7a 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -348,7 +348,7 @@ static void fsmc_select_chip(struct mtd_info *mtd, int chipnr) break; default: - BUG(); + dev_err(host->dev, "unsupported chip-select %d\n", chipnr); } } @@ -960,7 +960,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) host->data_va = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(host->data_va)) return PTR_ERR(host->data_va); - + host->data_pa = (dma_addr_t)res->start; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr"); @@ -1017,18 +1017,23 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) mtd->priv = nand; nand->priv = host; - host->mtd.owner = THIS_MODULE; + host->mtd.dev.parent = &pdev->dev; nand->IO_ADDR_R = host->data_va; nand->IO_ADDR_W = host->data_va; nand->cmd_ctrl = fsmc_cmd_ctrl; nand->chip_delay = 30; + /* + * Setup default ECC mode. nand_dt_init() called from nand_scan_ident() + * can overwrite this value if the DT provides a different value. + */ nand->ecc.mode = NAND_ECC_HW; nand->ecc.hwctl = fsmc_enable_hwecc; nand->ecc.size = 512; nand->options = pdata->options; nand->select_chip = fsmc_select_chip; nand->badblockbits = 7; + nand->flash_node = np; if (pdata->width == FSMC_NAND_BW16) nand->options |= NAND_BUSWIDTH_16; @@ -1070,11 +1075,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) nand->ecc.correct = fsmc_bch8_correct_data; nand->ecc.bytes = 13; nand->ecc.strength = 8; - } else { - nand->ecc.calculate = fsmc_read_hwecc_ecc1; - nand->ecc.correct = nand_correct_data; - nand->ecc.bytes = 3; - nand->ecc.strength = 1; } /* @@ -1111,23 +1111,50 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) default: dev_warn(&pdev->dev, "No oob scheme defined for oobsize %d\n", mtd->oobsize); - BUG(); + ret = -EINVAL; + goto err_probe; } } else { - switch (host->mtd.oobsize) { - case 16: - nand->ecc.layout = &fsmc_ecc1_16_layout; - break; - case 64: - nand->ecc.layout = &fsmc_ecc1_64_layout; + switch (nand->ecc.mode) { + case NAND_ECC_HW: + dev_info(&pdev->dev, "Using 1-bit HW ECC scheme\n"); + nand->ecc.calculate = fsmc_read_hwecc_ecc1; + nand->ecc.correct = nand_correct_data; + nand->ecc.bytes = 3; + nand->ecc.strength = 1; break; - case 128: - nand->ecc.layout = &fsmc_ecc1_128_layout; + + case NAND_ECC_SOFT_BCH: + dev_info(&pdev->dev, "Using 4-bit SW BCH ECC scheme\n"); break; + default: - dev_warn(&pdev->dev, "No oob scheme defined for oobsize %d\n", - mtd->oobsize); - BUG(); + dev_err(&pdev->dev, "Unsupported ECC mode!\n"); + goto err_probe; + } + + /* + * Don't set layout for BCH4 SW ECC. This will be + * generated later in nand_bch_init() later. + */ + if (nand->ecc.mode != NAND_ECC_SOFT_BCH) { + switch (host->mtd.oobsize) { + case 16: + nand->ecc.layout = &fsmc_ecc1_16_layout; + break; + case 64: + nand->ecc.layout = &fsmc_ecc1_64_layout; + break; + case 128: + nand->ecc.layout = &fsmc_ecc1_128_layout; + break; + default: + dev_warn(&pdev->dev, + "No oob scheme defined for oobsize %d\n", + mtd->oobsize); + ret = -EINVAL; + goto err_probe; + } } } diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c index 73c4048c3..9ab97f934 100644 --- a/drivers/mtd/nand/gpio.c +++ b/drivers/mtd/nand/gpio.c @@ -275,7 +275,7 @@ static int gpio_nand_probe(struct platform_device *pdev) chip->cmd_ctrl = gpio_nand_cmd_ctrl; gpiomtd->mtd_info.priv = chip; - gpiomtd->mtd_info.owner = THIS_MODULE; + gpiomtd->mtd_info.dev.parent = &pdev->dev; platform_set_drvdata(pdev, gpiomtd); diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 1b8f3500e..2064adac1 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -1160,7 +1160,7 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, } static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf, int oob_required, int page) { struct gpmi_nand_data *this = chip->priv; struct bch_geometry *nfc_geo = &this->bch_geometry; @@ -1446,7 +1446,7 @@ static int gpmi_ecc_read_page_raw(struct mtd_info *mtd, static int gpmi_ecc_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, - int oob_required) + int oob_required, int page) { struct gpmi_nand_data *this = chip->priv; struct bch_geometry *nfc_geo = &this->bch_geometry; @@ -1533,7 +1533,7 @@ static int gpmi_ecc_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip, { chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page); - return gpmi_ecc_write_page_raw(mtd, chip, NULL, 1); + return gpmi_ecc_write_page_raw(mtd, chip, NULL, 1, page); } static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs) @@ -1717,7 +1717,7 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this) /* Write the first page of the current stride. */ dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page); chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); - chip->ecc.write_page_raw(mtd, chip, buffer, 0); + chip->ecc.write_page_raw(mtd, chip, buffer, 0, page); chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); /* Wait for the write to finish. */ @@ -1897,7 +1897,7 @@ static int gpmi_nand_init(struct gpmi_nand_data *this) /* init the MTD data structures */ mtd->priv = chip; mtd->name = "gpmi-nand"; - mtd->owner = THIS_MODULE; + mtd->dev.parent = this->dev; /* init the nand_chip{}, we don't support a 16-bit NAND Flash bus. */ chip->priv = this; diff --git a/drivers/mtd/nand/hisi504_nand.c b/drivers/mtd/nand/hisi504_nand.c index 8dcc7b8fe..0cb2e8869 100644 --- a/drivers/mtd/nand/hisi504_nand.c +++ b/drivers/mtd/nand/hisi504_nand.c @@ -590,7 +590,8 @@ static int hisi_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, } static int hisi_nand_write_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, int oob_required) + struct nand_chip *chip, const uint8_t *buf, int oob_required, + int page) { chip->write_buf(mtd, buf, mtd->writesize); if (oob_required) @@ -737,7 +738,6 @@ static int hisi_nfc_probe(struct platform_device *pdev) } mtd->priv = chip; - mtd->owner = THIS_MODULE; mtd->name = "hisi_nand"; mtd->dev.parent = &pdev->dev; diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index ebf2cce04..5a99a93ed 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -25,6 +25,7 @@ #include <linux/gpio.h> +#include <asm/mach-jz4740/gpio.h> #include <asm/mach-jz4740/jz4740_nand.h> #define JZ_REG_NAND_CTRL 0x50 @@ -434,7 +435,7 @@ static int jz_nand_probe(struct platform_device *pdev) mtd = &nand->mtd; chip = &nand->chip; mtd->priv = chip; - mtd->owner = THIS_MODULE; + mtd->dev.parent = &pdev->dev; mtd->name = "jz4740-nand"; chip->ecc.hwctl = jz_nand_hwctl; diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c index 79c3b7801..347510978 100644 --- a/drivers/mtd/nand/lpc32xx_mlc.c +++ b/drivers/mtd/nand/lpc32xx_mlc.c @@ -495,7 +495,8 @@ static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip, static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf, int oob_required, + int page) { struct lpc32xx_nand_host *host = chip->priv; const uint8_t *oobbuf = chip->oob_poi; @@ -682,7 +683,6 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) nand_chip->priv = host; /* link the private data structures */ mtd->priv = nand_chip; - mtd->owner = THIS_MODULE; mtd->dev.parent = &pdev->dev; /* Get NAND clock */ @@ -692,7 +692,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) res = -ENOENT; goto err_exit1; } - clk_enable(host->clk); + clk_prepare_enable(host->clk); nand_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl; nand_chip->dev_ready = lpc32xx_nand_device_ready; @@ -800,7 +800,7 @@ err_exit3: if (use_dma) dma_release_channel(host->dma_chan); err_exit2: - clk_disable(host->clk); + clk_disable_unprepare(host->clk); clk_put(host->clk); err_exit1: lpc32xx_wp_enable(host); @@ -822,7 +822,7 @@ static int lpc32xx_nand_remove(struct platform_device *pdev) if (use_dma) dma_release_channel(host->dma_chan); - clk_disable(host->clk); + clk_disable_unprepare(host->clk); clk_put(host->clk); lpc32xx_wp_enable(host); @@ -837,7 +837,7 @@ static int lpc32xx_nand_resume(struct platform_device *pdev) struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); /* Re-enable NAND clock */ - clk_enable(host->clk); + clk_prepare_enable(host->clk); /* Fresh init of NAND controller */ lpc32xx_nand_setup(host); @@ -856,7 +856,7 @@ static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm) lpc32xx_wp_enable(host); /* Disable clock */ - clk_disable(host->clk); + clk_disable_unprepare(host->clk); return 0; } diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c index abfec1386..4f3d4eb17 100644 --- a/drivers/mtd/nand/lpc32xx_slc.c +++ b/drivers/mtd/nand/lpc32xx_slc.c @@ -94,22 +94,25 @@ /********************************************************************** * slc_tac register definitions **********************************************************************/ +/* Computation of clock cycles on basis of controller and device clock rates */ +#define SLCTAC_CLOCKS(c, n, s) (min_t(u32, DIV_ROUND_UP(c, n) - 1, 0xF) << s) + /* Clock setting for RDY write sample wait time in 2*n clocks */ #define SLCTAC_WDR(n) (((n) & 0xF) << 28) /* Write pulse width in clock cycles, 1 to 16 clocks */ -#define SLCTAC_WWIDTH(n) (((n) & 0xF) << 24) +#define SLCTAC_WWIDTH(c, n) (SLCTAC_CLOCKS(c, n, 24)) /* Write hold time of control and data signals, 1 to 16 clocks */ -#define SLCTAC_WHOLD(n) (((n) & 0xF) << 20) +#define SLCTAC_WHOLD(c, n) (SLCTAC_CLOCKS(c, n, 20)) /* Write setup time of control and data signals, 1 to 16 clocks */ -#define SLCTAC_WSETUP(n) (((n) & 0xF) << 16) +#define SLCTAC_WSETUP(c, n) (SLCTAC_CLOCKS(c, n, 16)) /* Clock setting for RDY read sample wait time in 2*n clocks */ #define SLCTAC_RDR(n) (((n) & 0xF) << 12) /* Read pulse width in clock cycles, 1 to 16 clocks */ -#define SLCTAC_RWIDTH(n) (((n) & 0xF) << 8) +#define SLCTAC_RWIDTH(c, n) (SLCTAC_CLOCKS(c, n, 8)) /* Read hold time of control and data signals, 1 to 16 clocks */ -#define SLCTAC_RHOLD(n) (((n) & 0xF) << 4) +#define SLCTAC_RHOLD(c, n) (SLCTAC_CLOCKS(c, n, 4)) /* Read setup time of control and data signals, 1 to 16 clocks */ -#define SLCTAC_RSETUP(n) (((n) & 0xF) << 0) +#define SLCTAC_RSETUP(c, n) (SLCTAC_CLOCKS(c, n, 0)) /********************************************************************** * slc_ecc register definitions @@ -240,13 +243,13 @@ static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host) /* Compute clock setup values */ tmp = SLCTAC_WDR(host->ncfg->wdr_clks) | - SLCTAC_WWIDTH(1 + (clkrate / host->ncfg->wwidth)) | - SLCTAC_WHOLD(1 + (clkrate / host->ncfg->whold)) | - SLCTAC_WSETUP(1 + (clkrate / host->ncfg->wsetup)) | + SLCTAC_WWIDTH(clkrate, host->ncfg->wwidth) | + SLCTAC_WHOLD(clkrate, host->ncfg->whold) | + SLCTAC_WSETUP(clkrate, host->ncfg->wsetup) | SLCTAC_RDR(host->ncfg->rdr_clks) | - SLCTAC_RWIDTH(1 + (clkrate / host->ncfg->rwidth)) | - SLCTAC_RHOLD(1 + (clkrate / host->ncfg->rhold)) | - SLCTAC_RSETUP(1 + (clkrate / host->ncfg->rsetup)); + SLCTAC_RWIDTH(clkrate, host->ncfg->rwidth) | + SLCTAC_RHOLD(clkrate, host->ncfg->rhold) | + SLCTAC_RSETUP(clkrate, host->ncfg->rsetup); writel(tmp, SLC_TAC(host->io_base)); } @@ -660,7 +663,8 @@ static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd, */ static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf, + int oob_required, int page) { struct lpc32xx_nand_host *host = chip->priv; uint8_t *pb = chip->oob_poi + chip->ecc.layout->eccpos[0]; @@ -689,7 +693,7 @@ static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd, static int lpc32xx_nand_write_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, - int oob_required) + int oob_required, int page) { /* Raw writes can just use the FIFO interface */ chip->write_buf(mtd, buf, chip->ecc.size * chip->ecc.steps); @@ -810,7 +814,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) res = -ENOENT; goto err_exit1; } - clk_enable(host->clk); + clk_prepare_enable(host->clk); /* Set NAND IO addresses and command/ready functions */ chip->IO_ADDR_R = SLC_DATA(host->io_base); @@ -915,7 +919,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) err_exit3: dma_release_channel(host->dma_chan); err_exit2: - clk_disable(host->clk); + clk_disable_unprepare(host->clk); err_exit1: lpc32xx_wp_enable(host); @@ -939,7 +943,7 @@ static int lpc32xx_nand_remove(struct platform_device *pdev) tmp &= ~SLCCFG_CE_LOW; writel(tmp, SLC_CTRL(host->io_base)); - clk_disable(host->clk); + clk_disable_unprepare(host->clk); lpc32xx_wp_enable(host); return 0; @@ -951,7 +955,7 @@ static int lpc32xx_nand_resume(struct platform_device *pdev) struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); /* Re-enable NAND clock */ - clk_enable(host->clk); + clk_prepare_enable(host->clk); /* Fresh init of NAND controller */ lpc32xx_nand_setup(host); @@ -976,7 +980,7 @@ static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm) lpc32xx_wp_enable(host); /* Disable clock */ - clk_disable(host->clk); + clk_disable_unprepare(host->clk); return 0; } diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index 2a49b53c8..d6bbde4a5 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -659,6 +659,7 @@ static int mpc5121_nfc_probe(struct platform_device *op) chip = &prv->chip; mtd->priv = chip; + mtd->dev.parent = dev; chip->priv = prv; prv->dev = dev; @@ -841,6 +842,7 @@ static const struct of_device_id mpc5121_nfc_match[] = { { .compatible = "fsl,mpc5121-nfc", }, {}, }; +MODULE_DEVICE_TABLE(of, mpc5121_nfc_match); static struct platform_driver mpc5121_nfc_driver = { .probe = mpc5121_nfc_probe, diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index f04445b99..136e73a3e 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -1458,6 +1458,7 @@ static const struct of_device_id mxcnd_dt_ids[] = { }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, mxcnd_dt_ids); static int __init mxcnd_probe_dt(struct mxc_nand_host *host) { @@ -1516,7 +1517,6 @@ static int mxcnd_probe(struct platform_device *pdev) this = &host->nand; mtd = &host->mtd; mtd->priv = this; - mtd->owner = THIS_MODULE; mtd->dev.parent = &pdev->dev; mtd->name = DRIVER_NAME; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index ceb68ca82..ece544efc 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -543,23 +543,32 @@ static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo) } } -/* Wait for the ready pin, after a command. The timeout is caught later. */ +/** + * nand_wait_ready - [GENERIC] Wait for the ready pin after commands. + * @mtd: MTD device structure + * + * Wait for the ready pin after a command, and warn if a timeout occurs. + */ void nand_wait_ready(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; - unsigned long timeo = jiffies + msecs_to_jiffies(20); + unsigned long timeo = 400; - /* 400ms timeout */ if (in_interrupt() || oops_in_progress) - return panic_nand_wait_ready(mtd, 400); + return panic_nand_wait_ready(mtd, timeo); led_trigger_event(nand_led_trigger, LED_FULL); /* Wait until command is processed or timeout occurs */ + timeo = jiffies + msecs_to_jiffies(timeo); do { if (chip->dev_ready(mtd)) - break; - touch_softlockup_watchdog(); + goto out; + cond_resched(); } while (time_before(jiffies, timeo)); + + pr_warn_ratelimited( + "timeout while waiting for chip to become ready\n"); +out: led_trigger_event(nand_led_trigger, LED_OFF); } EXPORT_SYMBOL_GPL(nand_wait_ready); @@ -885,15 +894,13 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip, * @mtd: MTD device structure * @chip: NAND chip structure * - * Wait for command done. This applies to erase and program only. Erase can - * take up to 400ms and program up to 20ms according to general NAND and - * SmartMedia specs. + * Wait for command done. This applies to erase and program only. */ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) { - int status, state = chip->state; - unsigned long timeo = (state == FL_ERASING ? 400 : 20); + int status; + unsigned long timeo = 400; led_trigger_event(nand_led_trigger, LED_FULL); @@ -909,7 +916,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) panic_nand_wait(mtd, chip, timeo); else { timeo = jiffies + msecs_to_jiffies(timeo); - while (time_before(jiffies, timeo)) { + do { if (chip->dev_ready) { if (chip->dev_ready(mtd)) break; @@ -918,7 +925,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) break; } cond_resched(); - } + } while (time_before(jiffies, timeo)); } led_trigger_event(nand_led_trigger, LED_OFF); @@ -1101,6 +1108,134 @@ out: EXPORT_SYMBOL(nand_lock); /** + * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data + * @buf: buffer to test + * @len: buffer length + * @bitflips_threshold: maximum number of bitflips + * + * Check if a buffer contains only 0xff, which means the underlying region + * has been erased and is ready to be programmed. + * The bitflips_threshold specify the maximum number of bitflips before + * considering the region is not erased. + * Note: The logic of this function has been extracted from the memweight + * implementation, except that nand_check_erased_buf function exit before + * testing the whole buffer if the number of bitflips exceed the + * bitflips_threshold value. + * + * Returns a positive number of bitflips less than or equal to + * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the + * threshold. + */ +static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold) +{ + const unsigned char *bitmap = buf; + int bitflips = 0; + int weight; + + for (; len && ((uintptr_t)bitmap) % sizeof(long); + len--, bitmap++) { + weight = hweight8(*bitmap); + bitflips += BITS_PER_BYTE - weight; + if (unlikely(bitflips > bitflips_threshold)) + return -EBADMSG; + } + + for (; len >= sizeof(long); + len -= sizeof(long), bitmap += sizeof(long)) { + weight = hweight_long(*((unsigned long *)bitmap)); + bitflips += BITS_PER_LONG - weight; + if (unlikely(bitflips > bitflips_threshold)) + return -EBADMSG; + } + + for (; len > 0; len--, bitmap++) { + weight = hweight8(*bitmap); + bitflips += BITS_PER_BYTE - weight; + if (unlikely(bitflips > bitflips_threshold)) + return -EBADMSG; + } + + return bitflips; +} + +/** + * nand_check_erased_ecc_chunk - check if an ECC chunk contains (almost) only + * 0xff data + * @data: data buffer to test + * @datalen: data length + * @ecc: ECC buffer + * @ecclen: ECC length + * @extraoob: extra OOB buffer + * @extraooblen: extra OOB length + * @bitflips_threshold: maximum number of bitflips + * + * Check if a data buffer and its associated ECC and OOB data contains only + * 0xff pattern, which means the underlying region has been erased and is + * ready to be programmed. + * The bitflips_threshold specify the maximum number of bitflips before + * considering the region as not erased. + * + * Note: + * 1/ ECC algorithms are working on pre-defined block sizes which are usually + * different from the NAND page size. When fixing bitflips, ECC engines will + * report the number of errors per chunk, and the NAND core infrastructure + * expect you to return the maximum number of bitflips for the whole page. + * This is why you should always use this function on a single chunk and + * not on the whole page. After checking each chunk you should update your + * max_bitflips value accordingly. + * 2/ When checking for bitflips in erased pages you should not only check + * the payload data but also their associated ECC data, because a user might + * have programmed almost all bits to 1 but a few. In this case, we + * shouldn't consider the chunk as erased, and checking ECC bytes prevent + * this case. + * 3/ The extraoob argument is optional, and should be used if some of your OOB + * data are protected by the ECC engine. + * It could also be used if you support subpages and want to attach some + * extra OOB data to an ECC chunk. + * + * Returns a positive number of bitflips less than or equal to + * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the + * threshold. In case of success, the passed buffers are filled with 0xff. + */ +int nand_check_erased_ecc_chunk(void *data, int datalen, + void *ecc, int ecclen, + void *extraoob, int extraooblen, + int bitflips_threshold) +{ + int data_bitflips = 0, ecc_bitflips = 0, extraoob_bitflips = 0; + + data_bitflips = nand_check_erased_buf(data, datalen, + bitflips_threshold); + if (data_bitflips < 0) + return data_bitflips; + + bitflips_threshold -= data_bitflips; + + ecc_bitflips = nand_check_erased_buf(ecc, ecclen, bitflips_threshold); + if (ecc_bitflips < 0) + return ecc_bitflips; + + bitflips_threshold -= ecc_bitflips; + + extraoob_bitflips = nand_check_erased_buf(extraoob, extraooblen, + bitflips_threshold); + if (extraoob_bitflips < 0) + return extraoob_bitflips; + + if (data_bitflips) + memset(data, 0xff, datalen); + + if (ecc_bitflips) + memset(ecc, 0xff, ecclen); + + if (extraoob_bitflips) + memset(extraoob, 0xff, extraooblen); + + return data_bitflips + ecc_bitflips + extraoob_bitflips; +} +EXPORT_SYMBOL(nand_check_erased_ecc_chunk); + +/** * nand_read_page_raw - [INTERN] read raw page data without ecc * @mtd: mtd info structure * @chip: nand chip info structure @@ -2027,11 +2162,12 @@ out: * @chip: nand chip info structure * @buf: data buffer * @oob_required: must write chip->oob_poi to OOB + * @page: page number to write * * Not for syndrome calculating ECC controllers, which use a special oob layout. */ static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf, int oob_required, int page) { chip->write_buf(mtd, buf, mtd->writesize); if (oob_required) @@ -2046,12 +2182,14 @@ static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, * @chip: nand chip info structure * @buf: data buffer * @oob_required: must write chip->oob_poi to OOB + * @page: page number to write * * We need a special oob layout and handling even when ECC isn't checked. */ static int nand_write_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf, int oob_required, + int page) { int eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -2088,9 +2226,11 @@ static int nand_write_page_raw_syndrome(struct mtd_info *mtd, * @chip: nand chip info structure * @buf: data buffer * @oob_required: must write chip->oob_poi to OOB + * @page: page number to write */ static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf, int oob_required, + int page) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -2106,7 +2246,7 @@ static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, for (i = 0; i < chip->ecc.total; i++) chip->oob_poi[eccpos[i]] = ecc_calc[i]; - return chip->ecc.write_page_raw(mtd, chip, buf, 1); + return chip->ecc.write_page_raw(mtd, chip, buf, 1, page); } /** @@ -2115,9 +2255,11 @@ static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, * @chip: nand chip info structure * @buf: data buffer * @oob_required: must write chip->oob_poi to OOB + * @page: page number to write */ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf, int oob_required, + int page) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -2149,11 +2291,12 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, * @data_len: data length * @buf: data buffer * @oob_required: must write chip->oob_poi to OOB + * @page: page number to write */ static int nand_write_subpage_hwecc(struct mtd_info *mtd, struct nand_chip *chip, uint32_t offset, uint32_t data_len, const uint8_t *buf, - int oob_required) + int oob_required, int page) { uint8_t *oob_buf = chip->oob_poi; uint8_t *ecc_calc = chip->buffers->ecccalc; @@ -2208,13 +2351,15 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd, * @chip: nand chip info structure * @buf: data buffer * @oob_required: must write chip->oob_poi to OOB + * @page: page number to write * * The hw generator calculates the error syndrome automatically. Therefore we * need a special oob layout and handling. */ static int nand_write_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf, int oob_required, + int page) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -2278,12 +2423,13 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, if (unlikely(raw)) status = chip->ecc.write_page_raw(mtd, chip, buf, - oob_required); + oob_required, page); else if (subpage) status = chip->ecc.write_subpage(mtd, chip, offset, data_len, - buf, oob_required); + buf, oob_required, page); else - status = chip->ecc.write_page(mtd, chip, buf, oob_required); + status = chip->ecc.write_page(mtd, chip, buf, oob_required, + page); if (status < 0) return status; @@ -2964,7 +3110,7 @@ static void nand_resume(struct mtd_info *mtd) */ static void nand_shutdown(struct mtd_info *mtd) { - nand_get_device(mtd, FL_SHUTDOWN); + nand_get_device(mtd, FL_PM_SUSPENDED); } /* Set default functions */ @@ -3708,10 +3854,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->chipsize = (uint64_t)type->chipsize << 20; - if (!type->pagesize && chip->init_size) { - /* Set the pagesize, oobsize, erasesize by the driver */ - busw = chip->init_size(mtd, chip, id_data); - } else if (!type->pagesize) { + if (!type->pagesize) { /* Decode parameters from extended ID */ nand_decode_ext_id(mtd, chip, id_data, &busw); } else { @@ -3846,8 +3989,8 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, struct nand_flash_dev *type; int ret; - if (chip->dn) { - ret = nand_dt_init(mtd, chip, chip->dn); + if (chip->flash_node) { + ret = nand_dt_init(mtd, chip, chip->flash_node); if (ret) return ret; } diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 63a1a36a3..b1d4f813a 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -1080,7 +1080,7 @@ static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) struct nand_bbt_descr *td = this->bbt_td; struct nand_bbt_descr *md = this->bbt_md; - len = mtd->size >> (this->bbt_erase_shift + 2); + len = (mtd->size >> (this->bbt_erase_shift + 2)) ? : 1; /* * Allocate memory (2bit per block) and clear the memory bad block * table. diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 95d0cc49c..b16d70aaf 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -649,8 +649,7 @@ static void free_device(struct nandsim *ns) kmem_cache_free(ns->nand_pages_slab, ns->pages[i].byte); } - if (ns->nand_pages_slab) - kmem_cache_destroy(ns->nand_pages_slab); + kmem_cache_destroy(ns->nand_pages_slab); vfree(ns->pages); } } diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 67a1b3f91..4f0d62f9d 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -169,7 +169,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc, chip->priv = ndfc; ndfc->mtd.priv = chip; - ndfc->mtd.owner = THIS_MODULE; + ndfc->mtd.dev.parent = &ndfc->ofdev->dev; flash_np = of_get_next_child(node, NULL); if (!flash_np) diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c index e58c644dd..f0687f71f 100644 --- a/drivers/mtd/nand/nuc900_nand.c +++ b/drivers/mtd/nand/nuc900_nand.c @@ -250,7 +250,7 @@ static int nuc900_nand_probe(struct platform_device *pdev) chip = &(nuc900_nand->chip); nuc900_nand->mtd.priv = chip; - nuc900_nand->mtd.owner = THIS_MODULE; + nuc900_nand->mtd.dev.parent = &pdev->dev; spin_lock_init(&nuc900_nand->lock); nuc900_nand->clk = devm_clk_get(&pdev->dev, NULL); diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 60fa89939..93f664cd1 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1500,11 +1500,12 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, * @chip: nand chip info structure * @buf: data buffer * @oob_required: must write chip->oob_poi to OOB + * @page: page * * Custom write page method evolved to support multi sector writing in one shot */ static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf, int oob_required, int page) { int i; uint8_t *ecc_calc = chip->buffers->ecccalc; @@ -1684,8 +1685,7 @@ static int omap_nand_probe(struct platform_device *pdev) info->ecc_opt = pdata->ecc_opt; mtd = &info->mtd; mtd->priv = &info->nand; - mtd->name = dev_name(&pdev->dev); - mtd->owner = THIS_MODULE; + mtd->dev.parent = &pdev->dev; nand_chip = &info->nand; nand_chip->ecc.priv = NULL; diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index c3c6d305c..ee83749fb 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -124,7 +124,7 @@ static int __init orion_nand_probe(struct platform_device *pdev) } mtd->priv = nc; - mtd->owner = THIS_MODULE; + mtd->dev.parent = &pdev->dev; nc->priv = board; nc->IO_ADDR_R = nc->IO_ADDR_W = io_base; @@ -201,6 +201,7 @@ static const struct of_device_id orion_nand_of_match_table[] = { { .compatible = "marvell,orion-nand", }, {}, }; +MODULE_DEVICE_TABLE(of, orion_nand_of_match_table); #endif static struct platform_driver orion_nand_driver = { diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c index 66c345b42..83cf021b9 100644 --- a/drivers/mtd/nand/pasemi_nand.c +++ b/drivers/mtd/nand/pasemi_nand.c @@ -124,7 +124,7 @@ static int pasemi_nand_probe(struct platform_device *ofdev) /* Link the private data with the MTD structure */ pasemi_nand_mtd->priv = chip; - pasemi_nand_mtd->owner = THIS_MODULE; + pasemi_nand_mtd->dev.parent = &ofdev->dev; chip->IO_ADDR_R = of_iomap(np, 0); chip->IO_ADDR_W = chip->IO_ADDR_R; diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index 717cf623f..65b9dbbe6 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c @@ -59,8 +59,7 @@ static int plat_nand_probe(struct platform_device *pdev) data->chip.priv = &data; data->mtd.priv = &data->chip; - data->mtd.owner = THIS_MODULE; - data->mtd.name = dev_name(&pdev->dev); + data->mtd.dev.parent = &pdev->dev; data->chip.IO_ADDR_R = data->io_base; data->chip.IO_ADDR_W = data->io_base; diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 740983a34..e453ae9a1 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -15,7 +15,9 @@ #include <linux/module.h> #include <linux/interrupt.h> #include <linux/platform_device.h> +#include <linux/dmaengine.h> #include <linux/dma-mapping.h> +#include <linux/dma/pxa-dma.h> #include <linux/delay.h> #include <linux/clk.h> #include <linux/mtd/mtd.h> @@ -33,10 +35,6 @@ #define ARCH_HAS_DMA #endif -#ifdef ARCH_HAS_DMA -#include <mach/dma.h> -#endif - #include <linux/platform_data/mtd-nand-pxa3xx.h> #define CHIP_DELAY_TIMEOUT msecs_to_jiffies(200) @@ -78,7 +76,8 @@ #define NDCR_ND_MODE (0x3 << 21) #define NDCR_NAND_MODE (0x0) #define NDCR_CLR_PG_CNT (0x1 << 20) -#define NDCR_STOP_ON_UNCOR (0x1 << 19) +#define NFCV1_NDCR_ARB_CNTL (0x1 << 19) +#define NFCV2_NDCR_STOP_ON_UNCOR (0x1 << 19) #define NDCR_RD_ID_CNT_MASK (0x7 << 16) #define NDCR_RD_ID_CNT(x) (((x) << 16) & NDCR_RD_ID_CNT_MASK) @@ -201,6 +200,10 @@ struct pxa3xx_nand_info { unsigned int oob_buff_pos; /* DMA information */ + struct scatterlist sg; + enum dma_data_direction dma_dir; + struct dma_chan *dma_chan; + dma_cookie_t dma_cookie; int drcmr_dat; int drcmr_cmd; @@ -208,8 +211,6 @@ struct pxa3xx_nand_info { unsigned char *oob_buff; dma_addr_t data_buff_phys; int data_dma_ch; - struct pxa_dma_desc *data_desc; - dma_addr_t data_desc_addr; struct pxa3xx_nand_host *host[NUM_CHIP_SELECT]; unsigned int state; @@ -252,6 +253,25 @@ static bool use_dma = 1; module_param(use_dma, bool, 0444); MODULE_PARM_DESC(use_dma, "enable DMA for data transferring to/from NAND HW"); +struct pxa3xx_nand_timing { + unsigned int tCH; /* Enable signal hold time */ + unsigned int tCS; /* Enable signal setup time */ + unsigned int tWH; /* ND_nWE high duration */ + unsigned int tWP; /* ND_nWE pulse time */ + unsigned int tRH; /* ND_nRE high duration */ + unsigned int tRP; /* ND_nRE pulse width */ + unsigned int tR; /* ND_nWE high to ND_nRE low for read */ + unsigned int tWHR; /* ND_nWE high to ND_nRE low for status read */ + unsigned int tAR; /* ND_ALE low to ND_nRE low delay */ +}; + +struct pxa3xx_nand_flash { + uint32_t chip_id; + unsigned int flash_width; /* Width of Flash memory (DWIDTH_M) */ + unsigned int dfc_width; /* Width of flash controller(DWIDTH_C) */ + struct pxa3xx_nand_timing *timing; /* NAND Flash timing */ +}; + static struct pxa3xx_nand_timing timing[] = { { 40, 80, 60, 100, 80, 100, 90000, 400, 40, }, { 10, 0, 20, 40, 30, 40, 11123, 110, 10, }, @@ -260,15 +280,14 @@ static struct pxa3xx_nand_timing timing[] = { }; static struct pxa3xx_nand_flash builtin_flash_types[] = { -{ "DEFAULT FLASH", 0, 0, 2048, 8, 8, 0, &timing[0] }, -{ "64MiB 16-bit", 0x46ec, 32, 512, 16, 16, 4096, &timing[1] }, -{ "256MiB 8-bit", 0xdaec, 64, 2048, 8, 8, 2048, &timing[1] }, -{ "4GiB 8-bit", 0xd7ec, 128, 4096, 8, 8, 8192, &timing[1] }, -{ "128MiB 8-bit", 0xa12c, 64, 2048, 8, 8, 1024, &timing[2] }, -{ "128MiB 16-bit", 0xb12c, 64, 2048, 16, 16, 1024, &timing[2] }, -{ "512MiB 8-bit", 0xdc2c, 64, 2048, 8, 8, 4096, &timing[2] }, -{ "512MiB 16-bit", 0xcc2c, 64, 2048, 16, 16, 4096, &timing[2] }, -{ "256MiB 16-bit", 0xba20, 64, 2048, 16, 16, 2048, &timing[3] }, + { 0x46ec, 16, 16, &timing[1] }, + { 0xdaec, 8, 8, &timing[1] }, + { 0xd7ec, 8, 8, &timing[1] }, + { 0xa12c, 8, 8, &timing[2] }, + { 0xb12c, 16, 16, &timing[2] }, + { 0xdc2c, 8, 8, &timing[2] }, + { 0xcc2c, 16, 16, &timing[2] }, + { 0xba20, 16, 16, &timing[3] }, }; static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' }; @@ -329,9 +348,6 @@ static struct nand_ecclayout ecc_layout_4KB_bch8bit = { .oobfree = { } }; -/* Define a default flash type setting serve as flash detecting only */ -#define DEFAULT_FLASH_TYPE (&builtin_flash_types[0]) - #define NDTR0_tCH(c) (min((c), 7) << 19) #define NDTR0_tCS(c) (min((c), 7) << 16) #define NDTR0_tWH(c) (min((c), 7) << 11) @@ -393,6 +409,128 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host, nand_writel(info, NDTR1CS0, ndtr1); } +static void pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host, + const struct nand_sdr_timings *t) +{ + struct pxa3xx_nand_info *info = host->info_data; + struct nand_chip *chip = &host->chip; + unsigned long nand_clk = clk_get_rate(info->clk); + uint32_t ndtr0, ndtr1; + + u32 tCH_min = DIV_ROUND_UP(t->tCH_min, 1000); + u32 tCS_min = DIV_ROUND_UP(t->tCS_min, 1000); + u32 tWH_min = DIV_ROUND_UP(t->tWH_min, 1000); + u32 tWP_min = DIV_ROUND_UP(t->tWC_min - t->tWH_min, 1000); + u32 tREH_min = DIV_ROUND_UP(t->tREH_min, 1000); + u32 tRP_min = DIV_ROUND_UP(t->tRC_min - t->tREH_min, 1000); + u32 tR = chip->chip_delay * 1000; + u32 tWHR_min = DIV_ROUND_UP(t->tWHR_min, 1000); + u32 tAR_min = DIV_ROUND_UP(t->tAR_min, 1000); + + /* fallback to a default value if tR = 0 */ + if (!tR) + tR = 20000; + + ndtr0 = NDTR0_tCH(ns2cycle(tCH_min, nand_clk)) | + NDTR0_tCS(ns2cycle(tCS_min, nand_clk)) | + NDTR0_tWH(ns2cycle(tWH_min, nand_clk)) | + NDTR0_tWP(ns2cycle(tWP_min, nand_clk)) | + NDTR0_tRH(ns2cycle(tREH_min, nand_clk)) | + NDTR0_tRP(ns2cycle(tRP_min, nand_clk)); + + ndtr1 = NDTR1_tR(ns2cycle(tR, nand_clk)) | + NDTR1_tWHR(ns2cycle(tWHR_min, nand_clk)) | + NDTR1_tAR(ns2cycle(tAR_min, nand_clk)); + + info->ndtr0cs0 = ndtr0; + info->ndtr1cs0 = ndtr1; + nand_writel(info, NDTR0CS0, ndtr0); + nand_writel(info, NDTR1CS0, ndtr1); +} + +static int pxa3xx_nand_init_timings_compat(struct pxa3xx_nand_host *host, + unsigned int *flash_width, + unsigned int *dfc_width) +{ + struct nand_chip *chip = &host->chip; + struct pxa3xx_nand_info *info = host->info_data; + const struct pxa3xx_nand_flash *f = NULL; + int i, id, ntypes; + + ntypes = ARRAY_SIZE(builtin_flash_types); + + chip->cmdfunc(host->mtd, NAND_CMD_READID, 0x00, -1); + + id = chip->read_byte(host->mtd); + id |= chip->read_byte(host->mtd) << 0x8; + + for (i = 0; i < ntypes; i++) { + f = &builtin_flash_types[i]; + + if (f->chip_id == id) + break; + } + + if (i == ntypes) { + dev_err(&info->pdev->dev, "Error: timings not found\n"); + return -EINVAL; + } + + pxa3xx_nand_set_timing(host, f->timing); + + *flash_width = f->flash_width; + *dfc_width = f->dfc_width; + + return 0; +} + +static int pxa3xx_nand_init_timings_onfi(struct pxa3xx_nand_host *host, + int mode) +{ + const struct nand_sdr_timings *timings; + + mode = fls(mode) - 1; + if (mode < 0) + mode = 0; + + timings = onfi_async_timing_mode_to_sdr_timings(mode); + if (IS_ERR(timings)) + return PTR_ERR(timings); + + pxa3xx_nand_set_sdr_timing(host, timings); + + return 0; +} + +static int pxa3xx_nand_init(struct pxa3xx_nand_host *host) +{ + struct nand_chip *chip = &host->chip; + struct pxa3xx_nand_info *info = host->info_data; + unsigned int flash_width = 0, dfc_width = 0; + int mode, err; + + mode = onfi_get_async_timing_mode(chip); + if (mode == ONFI_TIMING_MODE_UNKNOWN) { + err = pxa3xx_nand_init_timings_compat(host, &flash_width, + &dfc_width); + if (err) + return err; + + if (flash_width == 16) { + info->reg_ndcr |= NDCR_DWIDTH_M; + chip->options |= NAND_BUSWIDTH_16; + } + + info->reg_ndcr |= (dfc_width == 16) ? NDCR_DWIDTH_C : 0; + } else { + err = pxa3xx_nand_init_timings_onfi(host, mode); + if (err) + return err; + } + + return 0; +} + /* * Set the data and OOB size, depending on the selected * spare and ECC configuration. @@ -468,6 +606,9 @@ static void pxa3xx_nand_stop(struct pxa3xx_nand_info *info) ndcr &= ~NDCR_ND_RUN; nand_writel(info, NDCR, ndcr); } + if (info->dma_chan) + dmaengine_terminate_all(info->dma_chan); + /* clear status bits */ nand_writel(info, NDSR, NDSR_MASK); } @@ -504,7 +645,7 @@ static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len) * the polling on the last read. */ while (len > 8) { - readsl(info->mmio_base + NDDB, data, 8); + ioread32_rep(info->mmio_base + NDDB, data, 8); ret = readl_relaxed_poll_timeout(info->mmio_base + NDSR, val, val & NDSR_RDDREQ, 1000, 5000); @@ -519,7 +660,7 @@ static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len) } } - readsl(info->mmio_base + NDDB, data, len); + ioread32_rep(info->mmio_base + NDDB, data, len); } static void handle_data_pio(struct pxa3xx_nand_info *info) @@ -559,57 +700,61 @@ static void handle_data_pio(struct pxa3xx_nand_info *info) info->data_size -= do_bytes; } -#ifdef ARCH_HAS_DMA -static void start_data_dma(struct pxa3xx_nand_info *info) +static void pxa3xx_nand_data_dma_irq(void *data) { - struct pxa_dma_desc *desc = info->data_desc; - int dma_len = ALIGN(info->data_size + info->oob_size, 32); + struct pxa3xx_nand_info *info = data; + struct dma_tx_state state; + enum dma_status status; - desc->ddadr = DDADR_STOP; - desc->dcmd = DCMD_ENDIRQEN | DCMD_WIDTH4 | DCMD_BURST32 | dma_len; + status = dmaengine_tx_status(info->dma_chan, info->dma_cookie, &state); + if (likely(status == DMA_COMPLETE)) { + info->state = STATE_DMA_DONE; + } else { + dev_err(&info->pdev->dev, "DMA error on data channel\n"); + info->retcode = ERR_DMABUSERR; + } + dma_unmap_sg(info->dma_chan->device->dev, &info->sg, 1, info->dma_dir); + + nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ); + enable_int(info, NDCR_INT_MASK); +} + +static void start_data_dma(struct pxa3xx_nand_info *info) +{ + enum dma_transfer_direction direction; + struct dma_async_tx_descriptor *tx; switch (info->state) { case STATE_DMA_WRITING: - desc->dsadr = info->data_buff_phys; - desc->dtadr = info->mmio_phys + NDDB; - desc->dcmd |= DCMD_INCSRCADDR | DCMD_FLOWTRG; + info->dma_dir = DMA_TO_DEVICE; + direction = DMA_MEM_TO_DEV; break; case STATE_DMA_READING: - desc->dtadr = info->data_buff_phys; - desc->dsadr = info->mmio_phys + NDDB; - desc->dcmd |= DCMD_INCTRGADDR | DCMD_FLOWSRC; + info->dma_dir = DMA_FROM_DEVICE; + direction = DMA_DEV_TO_MEM; break; default: dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__, info->state); BUG(); } - - DRCMR(info->drcmr_dat) = DRCMR_MAPVLD | info->data_dma_ch; - DDADR(info->data_dma_ch) = info->data_desc_addr; - DCSR(info->data_dma_ch) |= DCSR_RUN; -} - -static void pxa3xx_nand_data_dma_irq(int channel, void *data) -{ - struct pxa3xx_nand_info *info = data; - uint32_t dcsr; - - dcsr = DCSR(channel); - DCSR(channel) = dcsr; - - if (dcsr & DCSR_BUSERR) { - info->retcode = ERR_DMABUSERR; + info->sg.length = info->data_size + + (info->oob_size ? info->spare_size + info->ecc_size : 0); + dma_map_sg(info->dma_chan->device->dev, &info->sg, 1, info->dma_dir); + + tx = dmaengine_prep_slave_sg(info->dma_chan, &info->sg, 1, direction, + DMA_PREP_INTERRUPT); + if (!tx) { + dev_err(&info->pdev->dev, "prep_slave_sg() failed\n"); + return; } - - info->state = STATE_DMA_DONE; - enable_int(info, NDCR_INT_MASK); - nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ); + tx->callback = pxa3xx_nand_data_dma_irq; + tx->callback_param = info; + info->dma_cookie = dmaengine_submit(tx); + dma_async_issue_pending(info->dma_chan); + dev_dbg(&info->pdev->dev, "%s(dir=%d cookie=%x size=%u)\n", + __func__, direction, info->dma_cookie, info->sg.length); } -#else -static void start_data_dma(struct pxa3xx_nand_info *info) -{} -#endif static irqreturn_t pxa3xx_nand_irq_thread(int irq, void *data) { @@ -1128,7 +1273,8 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd, } static int pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, int oob_required) + struct nand_chip *chip, const uint8_t *buf, int oob_required, + int page) { chip->write_buf(mtd, buf, mtd->writesize); chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); @@ -1241,45 +1387,23 @@ static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) return NAND_STATUS_READY; } -static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, - const struct pxa3xx_nand_flash *f) +static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info) { struct platform_device *pdev = info->pdev; struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev); struct pxa3xx_nand_host *host = info->host[info->cs]; - uint32_t ndcr = 0x0; /* enable all interrupts */ - - if (f->page_size != 2048 && f->page_size != 512) { - dev_err(&pdev->dev, "Current only support 2048 and 512 size\n"); - return -EINVAL; - } - - if (f->flash_width != 16 && f->flash_width != 8) { - dev_err(&pdev->dev, "Only support 8bit and 16 bit!\n"); - return -EINVAL; - } - - /* calculate addressing information */ - host->col_addr_cycles = (f->page_size == 2048) ? 2 : 1; - - if (f->num_blocks * f->page_per_block > 65536) - host->row_addr_cycles = 3; - else - host->row_addr_cycles = 2; - - ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; - ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0; - ndcr |= (f->page_per_block == 64) ? NDCR_PG_PER_BLK : 0; - ndcr |= (f->page_size == 2048) ? NDCR_PAGE_SZ : 0; - ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0; - ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0; - - ndcr |= NDCR_RD_ID_CNT(READ_ID_BYTES); - ndcr |= NDCR_SPARE_EN; /* enable spare by default */ + struct mtd_info *mtd = host->mtd; + struct nand_chip *chip = mtd->priv; - info->reg_ndcr = ndcr; + /* configure default flash values */ + info->reg_ndcr = 0x0; /* enable all interrupts */ + info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; + info->reg_ndcr |= NDCR_RD_ID_CNT(READ_ID_BYTES); + info->reg_ndcr |= NDCR_SPARE_EN; /* enable spare by default */ + info->reg_ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0; + info->reg_ndcr |= (chip->page_shift == 6) ? NDCR_PG_PER_BLK : 0; + info->reg_ndcr |= (mtd->writesize == 2048) ? NDCR_PAGE_SZ : 0; - pxa3xx_nand_set_timing(host, f->timing); return 0; } @@ -1289,42 +1413,57 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) /* Set an initial chunk size */ info->chunk_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; - info->reg_ndcr = ndcr & ~NDCR_INT_MASK; + info->reg_ndcr = ndcr & + ~(NDCR_INT_MASK | NDCR_ND_ARB_EN | NFCV1_NDCR_ARB_CNTL); info->ndtr0cs0 = nand_readl(info, NDTR0CS0); info->ndtr1cs0 = nand_readl(info, NDTR1CS0); return 0; } -#ifdef ARCH_HAS_DMA static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) { struct platform_device *pdev = info->pdev; - int data_desc_offset = info->buf_size - sizeof(struct pxa_dma_desc); + struct dma_slave_config config; + dma_cap_mask_t mask; + struct pxad_param param; + int ret; - if (use_dma == 0) { - info->data_buff = kmalloc(info->buf_size, GFP_KERNEL); - if (info->data_buff == NULL) - return -ENOMEM; + info->data_buff = kmalloc(info->buf_size, GFP_KERNEL); + if (info->data_buff == NULL) + return -ENOMEM; + if (use_dma == 0) return 0; - } - info->data_buff = dma_alloc_coherent(&pdev->dev, info->buf_size, - &info->data_buff_phys, GFP_KERNEL); - if (info->data_buff == NULL) { - dev_err(&pdev->dev, "failed to allocate dma buffer\n"); - return -ENOMEM; - } + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; - info->data_desc = (void *)info->data_buff + data_desc_offset; - info->data_desc_addr = info->data_buff_phys + data_desc_offset; + sg_init_one(&info->sg, info->data_buff, info->buf_size); + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + param.prio = PXAD_PRIO_LOWEST; + param.drcmr = info->drcmr_dat; + info->dma_chan = dma_request_slave_channel_compat(mask, pxad_filter_fn, + ¶m, &pdev->dev, + "data"); + if (!info->dma_chan) { + dev_err(&pdev->dev, "unable to request data dma channel\n"); + return -ENODEV; + } - info->data_dma_ch = pxa_request_dma("nand-data", DMA_PRIO_LOW, - pxa3xx_nand_data_dma_irq, info); - if (info->data_dma_ch < 0) { - dev_err(&pdev->dev, "failed to request data dma\n"); - dma_free_coherent(&pdev->dev, info->buf_size, - info->data_buff, info->data_buff_phys); - return info->data_dma_ch; + memset(&config, 0, sizeof(config)); + config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + config.src_addr = info->mmio_phys + NDDB; + config.dst_addr = info->mmio_phys + NDDB; + config.src_maxburst = 32; + config.dst_maxburst = 32; + ret = dmaengine_slave_config(info->dma_chan, &config); + if (ret < 0) { + dev_err(&info->pdev->dev, + "dma channel configuration failed: %d\n", + ret); + return ret; } /* @@ -1337,43 +1476,30 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info) { - struct platform_device *pdev = info->pdev; if (info->use_dma) { - pxa_free_dma(info->data_dma_ch); - dma_free_coherent(&pdev->dev, info->buf_size, - info->data_buff, info->data_buff_phys); - } else { - kfree(info->data_buff); + dmaengine_terminate_all(info->dma_chan); + dma_release_channel(info->dma_chan); } -} -#else -static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) -{ - info->data_buff = kmalloc(info->buf_size, GFP_KERNEL); - if (info->data_buff == NULL) - return -ENOMEM; - return 0; -} - -static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info) -{ kfree(info->data_buff); } -#endif -static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info) +static int pxa3xx_nand_sensing(struct pxa3xx_nand_host *host) { + struct pxa3xx_nand_info *info = host->info_data; struct mtd_info *mtd; struct nand_chip *chip; + const struct nand_sdr_timings *timings; int ret; mtd = info->host[info->cs]->mtd; chip = mtd->priv; /* use the common timing to make a try */ - ret = pxa3xx_nand_config_flash(info, &builtin_flash_types[0]); - if (ret) - return ret; + timings = onfi_async_timing_mode_to_sdr_timings(0); + if (IS_ERR(timings)) + return PTR_ERR(timings); + + pxa3xx_nand_set_sdr_timing(host, timings); chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0); ret = chip->waitfunc(mtd, chip); @@ -1458,12 +1584,8 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) struct pxa3xx_nand_info *info = host->info_data; struct platform_device *pdev = info->pdev; struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct nand_flash_dev pxa3xx_flash_ids[2], *def = NULL; - const struct pxa3xx_nand_flash *f = NULL; struct nand_chip *chip = mtd->priv; - uint32_t id = -1; - uint64_t chipsize; - int i, ret, num; + int ret; uint16_t ecc_strength, ecc_step; if (pdata->keep_config && !pxa3xx_nand_detect_config(info)) @@ -1472,7 +1594,11 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) /* Set a default chunk size */ info->chunk_size = 512; - ret = pxa3xx_nand_sensing(info); + ret = pxa3xx_nand_config_flash(info); + if (ret) + return ret; + + ret = pxa3xx_nand_sensing(host); if (ret) { dev_info(&info->pdev->dev, "There is no chip on cs %d!\n", info->cs); @@ -1480,54 +1606,8 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) return ret; } - chip->cmdfunc(mtd, NAND_CMD_READID, 0, 0); - id = *((uint16_t *)(info->data_buff)); - if (id != 0) - dev_info(&info->pdev->dev, "Detect a flash id %x\n", id); - else { - dev_warn(&info->pdev->dev, - "Read out ID 0, potential timing set wrong!!\n"); - - return -EINVAL; - } - - num = ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1; - for (i = 0; i < num; i++) { - if (i < pdata->num_flash) - f = pdata->flash + i; - else - f = &builtin_flash_types[i - pdata->num_flash + 1]; - - /* find the chip in default list */ - if (f->chip_id == id) - break; - } - - if (i >= (ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1)) { - dev_err(&info->pdev->dev, "ERROR!! flash not defined!!!\n"); - - return -EINVAL; - } - - ret = pxa3xx_nand_config_flash(info, f); - if (ret) { - dev_err(&info->pdev->dev, "ERROR! Configure failed\n"); - return ret; - } - - memset(pxa3xx_flash_ids, 0, sizeof(pxa3xx_flash_ids)); - - pxa3xx_flash_ids[0].name = f->name; - pxa3xx_flash_ids[0].dev_id = (f->chip_id >> 8) & 0xffff; - pxa3xx_flash_ids[0].pagesize = f->page_size; - chipsize = (uint64_t)f->num_blocks * f->page_per_block * f->page_size; - pxa3xx_flash_ids[0].chipsize = chipsize >> 20; - pxa3xx_flash_ids[0].erasesize = f->page_size * f->page_per_block; - if (f->flash_width == 16) - pxa3xx_flash_ids[0].options = NAND_BUSWIDTH_16; - pxa3xx_flash_ids[1].name = NULL; - def = pxa3xx_flash_ids; KEEP_CONFIG: + info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; if (info->reg_ndcr & NDCR_DWIDTH_M) chip->options |= NAND_BUSWIDTH_16; @@ -1535,9 +1615,18 @@ KEEP_CONFIG: if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) nand_writel(info, NDECCCTRL, 0x0); - if (nand_scan_ident(mtd, 1, def)) + if (nand_scan_ident(mtd, 1, NULL)) return -ENODEV; + if (!pdata->keep_config) { + ret = pxa3xx_nand_init(host); + if (ret) { + dev_err(&info->pdev->dev, "Failed to init nand: %d\n", + ret); + return ret; + } + } + if (pdata->flash_bbt) { /* * We'll use a bad block table stored in-flash and don't @@ -1635,7 +1724,7 @@ static int alloc_nand_resource(struct platform_device *pdev) host->cs = cs; host->info_data = info; mtd->priv = host; - mtd->owner = THIS_MODULE; + mtd->dev.parent = &pdev->dev; chip->ecc.read_page = pxa3xx_nand_read_page_hwecc; chip->ecc.write_page = pxa3xx_nand_write_page_hwecc; @@ -1662,34 +1751,23 @@ static int alloc_nand_resource(struct platform_device *pdev) return ret; if (use_dma) { - /* - * This is a dirty hack to make this driver work from - * devicetree bindings. It can be removed once we have - * a prober DMA controller framework for DT. - */ - if (pdev->dev.of_node && - of_machine_is_compatible("marvell,pxa3xx")) { - info->drcmr_dat = 97; - info->drcmr_cmd = 99; - } else { - r = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (r == NULL) { - dev_err(&pdev->dev, - "no resource defined for data DMA\n"); - ret = -ENXIO; - goto fail_disable_clk; - } - info->drcmr_dat = r->start; - - r = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (r == NULL) { - dev_err(&pdev->dev, - "no resource defined for cmd DMA\n"); - ret = -ENXIO; - goto fail_disable_clk; - } - info->drcmr_cmd = r->start; + r = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (r == NULL) { + dev_err(&pdev->dev, + "no resource defined for data DMA\n"); + ret = -ENXIO; + goto fail_disable_clk; + } + info->drcmr_dat = r->start; + + r = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (r == NULL) { + dev_err(&pdev->dev, + "no resource defined for cmd DMA\n"); + ret = -ENXIO; + goto fail_disable_clk; } + info->drcmr_cmd = r->start; } irq = platform_get_irq(pdev, 0); @@ -1754,6 +1832,16 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) free_irq(irq, info); pxa3xx_nand_free_buff(info); + /* + * In the pxa3xx case, the DFI bus is shared between the SMC and NFC. + * In order to prevent a lockup of the system bus, the DFI bus + * arbitration is granted to SMC upon driver removal. This is done by + * setting the x_ARB_CNTL bit, which also prevents the NAND to have + * access to the bus anymore. + */ + nand_writel(info, NDCR, + (nand_readl(info, NDCR) & ~NDCR_ND_ARB_EN) | + NFCV1_NDCR_ARB_CNTL); clk_disable_unprepare(info->clk); for (cs = 0; cs < pdata->num_cs; cs++) @@ -1800,15 +1888,16 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) struct pxa3xx_nand_platform_data *pdata; struct mtd_part_parser_data ppdata = {}; struct pxa3xx_nand_info *info; - int ret, cs, probe_success; + int ret, cs, probe_success, dma_available; -#ifndef ARCH_HAS_DMA - if (use_dma) { + dma_available = IS_ENABLED(CONFIG_ARM) && + (IS_ENABLED(CONFIG_ARCH_PXA) || IS_ENABLED(CONFIG_ARCH_MMP)); + if (use_dma && !dma_available) { use_dma = 0; dev_warn(&pdev->dev, "This platform can't do DMA on this device\n"); } -#endif + ret = pxa3xx_nand_probe_dt(pdev); if (ret) return ret; @@ -1861,35 +1950,22 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) } #ifdef CONFIG_PM -static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state) +static int pxa3xx_nand_suspend(struct device *dev) { - struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); - struct pxa3xx_nand_platform_data *pdata; - struct mtd_info *mtd; - int cs; + struct pxa3xx_nand_info *info = dev_get_drvdata(dev); - pdata = dev_get_platdata(&pdev->dev); if (info->state) { - dev_err(&pdev->dev, "driver busy, state = %d\n", info->state); + dev_err(dev, "driver busy, state = %d\n", info->state); return -EAGAIN; } - for (cs = 0; cs < pdata->num_cs; cs++) { - mtd = info->host[cs]->mtd; - mtd_suspend(mtd); - } - return 0; } -static int pxa3xx_nand_resume(struct platform_device *pdev) +static int pxa3xx_nand_resume(struct device *dev) { - struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); - struct pxa3xx_nand_platform_data *pdata; - struct mtd_info *mtd; - int cs; + struct pxa3xx_nand_info *info = dev_get_drvdata(dev); - pdata = dev_get_platdata(&pdev->dev); /* We don't want to handle interrupt without calling mtd routine */ disable_int(info, NDCR_INT_MASK); @@ -1907,10 +1983,6 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) * all status before resume */ nand_writel(info, NDSR, NDSR_MASK); - for (cs = 0; cs < pdata->num_cs; cs++) { - mtd = info->host[cs]->mtd; - mtd_resume(mtd); - } return 0; } @@ -1919,15 +1991,19 @@ static int pxa3xx_nand_resume(struct platform_device *pdev) #define pxa3xx_nand_resume NULL #endif +static const struct dev_pm_ops pxa3xx_nand_pm_ops = { + .suspend = pxa3xx_nand_suspend, + .resume = pxa3xx_nand_resume, +}; + static struct platform_driver pxa3xx_nand_driver = { .driver = { .name = "pxa3xx-nand", .of_match_table = pxa3xx_nand_dt_ids, + .pm = &pxa3xx_nand_pm_ops, }, .probe = pxa3xx_nand_probe, .remove = pxa3xx_nand_remove, - .suspend = pxa3xx_nand_suspend, - .resume = pxa3xx_nand_resume, }; module_platform_driver(pxa3xx_nand_driver); diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index cc6bac537..d8bb2be32 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -641,7 +641,6 @@ static int r852_register_nand_device(struct r852_device *dev) WARN_ON(dev->card_registred); - dev->mtd->owner = THIS_MODULE; dev->mtd->priv = dev->chip; dev->mtd->dev.parent = &dev->pci_dev->dev; diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 381f67ac6..05105cadd 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -832,7 +832,6 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, nmtd->info = info; nmtd->mtd.priv = chip; - nmtd->mtd.owner = THIS_MODULE; nmtd->set = set; #ifdef CONFIG_MTD_NAND_S3C2410_HWECC @@ -1016,6 +1015,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) pr_debug("initialising set %d (%p, info %p)\n", setno, nmtd, info); + nmtd->mtd.dev.parent = &pdev->dev; s3c2410_nand_init_chip(info, nmtd, sets); nmtd->scan_res = nand_scan_ident(&nmtd->mtd, diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index c3ce81c1a..bcba1a924 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -569,7 +569,8 @@ static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, } static int flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf, int oob_required, + int page) { chip->write_buf(mtd, buf, mtd->writesize); chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); @@ -1123,6 +1124,7 @@ static int flctl_probe(struct platform_device *pdev) flctl_mtd = &flctl->mtd; nand = &flctl->chip; flctl_mtd->priv = nand; + flctl_mtd->dev.parent = &pdev->dev; flctl->pdev = pdev; flctl->hwecc = pdata->has_hwecc; flctl->holden = pdata->use_holden; diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 842c47a45..082b60097 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -144,7 +144,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev) /* Link the private data with the MTD structure */ sharpsl->mtd.priv = this; - sharpsl->mtd.owner = THIS_MODULE; + sharpsl->mtd.dev.parent = &pdev->dev; platform_set_drvdata(pdev, sharpsl); diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c index d71062273..b94f53427 100644 --- a/drivers/mtd/nand/socrates_nand.c +++ b/drivers/mtd/nand/socrates_nand.c @@ -167,7 +167,6 @@ static int socrates_nand_probe(struct platform_device *ofdev) nand_chip->priv = host; /* link the private data structures */ mtd->priv = nand_chip; mtd->name = "socrates_nand"; - mtd->owner = THIS_MODULE; mtd->dev.parent = &ofdev->dev; ppdata.of_node = ofdev->dev.of_node; diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c index e7d333c16..824711845 100644 --- a/drivers/mtd/nand/sunxi_nand.c +++ b/drivers/mtd/nand/sunxi_nand.c @@ -57,11 +57,8 @@ #define NFC_REG_ECC_CTL 0x0034 #define NFC_REG_ECC_ST 0x0038 #define NFC_REG_DEBUG 0x003C -#define NFC_REG_ECC_CNT0 0x0040 -#define NFC_REG_ECC_CNT1 0x0044 -#define NFC_REG_ECC_CNT2 0x0048 -#define NFC_REG_ECC_CNT3 0x004c -#define NFC_REG_USER_DATA_BASE 0x0050 +#define NFC_REG_ECC_ERR_CNT(x) ((0x0040 + (x)) & ~0x3) +#define NFC_REG_USER_DATA(x) (0x0050 + ((x) * 4)) #define NFC_REG_SPARE_AREA 0x00A0 #define NFC_RAM0_BASE 0x0400 #define NFC_RAM1_BASE 0x0800 @@ -69,12 +66,16 @@ /* define bit use in NFC_CTL */ #define NFC_EN BIT(0) #define NFC_RESET BIT(1) -#define NFC_BUS_WIDYH BIT(2) -#define NFC_RB_SEL BIT(3) -#define NFC_CE_SEL GENMASK(26, 24) +#define NFC_BUS_WIDTH_MSK BIT(2) +#define NFC_BUS_WIDTH_8 (0 << 2) +#define NFC_BUS_WIDTH_16 (1 << 2) +#define NFC_RB_SEL_MSK BIT(3) +#define NFC_RB_SEL(x) ((x) << 3) +#define NFC_CE_SEL_MSK GENMASK(26, 24) +#define NFC_CE_SEL(x) ((x) << 24) #define NFC_CE_CTL BIT(6) -#define NFC_CE_CTL1 BIT(7) -#define NFC_PAGE_SIZE GENMASK(11, 8) +#define NFC_PAGE_SHIFT_MSK GENMASK(11, 8) +#define NFC_PAGE_SHIFT(x) (((x) < 10 ? 0 : (x) - 10) << 8) #define NFC_SAM BIT(12) #define NFC_RAM_METHOD BIT(14) #define NFC_DEBUG_CTL BIT(31) @@ -86,10 +87,7 @@ #define NFC_CMD_FIFO_STATUS BIT(3) #define NFC_STA BIT(4) #define NFC_NATCH_INT_FLAG BIT(5) -#define NFC_RB_STATE0 BIT(8) -#define NFC_RB_STATE1 BIT(9) -#define NFC_RB_STATE2 BIT(10) -#define NFC_RB_STATE3 BIT(11) +#define NFC_RB_STATE(x) BIT(x + 8) /* define bit use in NFC_INT */ #define NFC_B2R_INT_ENABLE BIT(0) @@ -109,9 +107,11 @@ (((tCAD) & 0x7) << 8)) /* define bit use in NFC_CMD */ -#define NFC_CMD_LOW_BYTE GENMASK(7, 0) -#define NFC_CMD_HIGH_BYTE GENMASK(15, 8) -#define NFC_ADR_NUM GENMASK(18, 16) +#define NFC_CMD_LOW_BYTE_MSK GENMASK(7, 0) +#define NFC_CMD_HIGH_BYTE_MSK GENMASK(15, 8) +#define NFC_CMD(x) (x) +#define NFC_ADR_NUM_MSK GENMASK(18, 16) +#define NFC_ADR_NUM(x) (((x) - 1) << 16) #define NFC_SEND_ADR BIT(19) #define NFC_ACCESS_DIR BIT(20) #define NFC_DATA_TRANS BIT(21) @@ -123,33 +123,38 @@ #define NFC_ROW_AUTO_INC BIT(27) #define NFC_SEND_CMD3 BIT(28) #define NFC_SEND_CMD4 BIT(29) -#define NFC_CMD_TYPE GENMASK(31, 30) +#define NFC_CMD_TYPE_MSK GENMASK(31, 30) +#define NFC_NORMAL_OP (0 << 30) +#define NFC_ECC_OP (1 << 30) +#define NFC_PAGE_OP (2 << 30) /* define bit use in NFC_RCMD_SET */ -#define NFC_READ_CMD GENMASK(7, 0) -#define NFC_RANDOM_READ_CMD0 GENMASK(15, 8) -#define NFC_RANDOM_READ_CMD1 GENMASK(23, 16) +#define NFC_READ_CMD_MSK GENMASK(7, 0) +#define NFC_RND_READ_CMD0_MSK GENMASK(15, 8) +#define NFC_RND_READ_CMD1_MSK GENMASK(23, 16) /* define bit use in NFC_WCMD_SET */ -#define NFC_PROGRAM_CMD GENMASK(7, 0) -#define NFC_RANDOM_WRITE_CMD GENMASK(15, 8) -#define NFC_READ_CMD0 GENMASK(23, 16) -#define NFC_READ_CMD1 GENMASK(31, 24) +#define NFC_PROGRAM_CMD_MSK GENMASK(7, 0) +#define NFC_RND_WRITE_CMD_MSK GENMASK(15, 8) +#define NFC_READ_CMD0_MSK GENMASK(23, 16) +#define NFC_READ_CMD1_MSK GENMASK(31, 24) /* define bit use in NFC_ECC_CTL */ #define NFC_ECC_EN BIT(0) #define NFC_ECC_PIPELINE BIT(3) #define NFC_ECC_EXCEPTION BIT(4) -#define NFC_ECC_BLOCK_SIZE BIT(5) +#define NFC_ECC_BLOCK_SIZE_MSK BIT(5) #define NFC_RANDOM_EN BIT(9) #define NFC_RANDOM_DIRECTION BIT(10) -#define NFC_ECC_MODE_SHIFT 12 -#define NFC_ECC_MODE GENMASK(15, 12) -#define NFC_RANDOM_SEED GENMASK(30, 16) +#define NFC_ECC_MODE_MSK GENMASK(15, 12) +#define NFC_ECC_MODE(x) ((x) << 12) +#define NFC_RANDOM_SEED_MSK GENMASK(30, 16) +#define NFC_RANDOM_SEED(x) ((x) << 16) -/* NFC_USER_DATA helper macros */ -#define NFC_BUF_TO_USER_DATA(buf) ((buf)[0] | ((buf)[1] << 8) | \ - ((buf)[2] << 16) | ((buf)[3] << 24)) +/* define bit use in NFC_ECC_ST */ +#define NFC_ECC_ERR(x) BIT(x) +#define NFC_ECC_PAT_FOUND(x) BIT(x + 16) +#define NFC_ECC_ERR_CNT(b, x) (((x) >> ((b) * 8)) & 0xff) #define NFC_DEFAULT_TIMEOUT_MS 1000 @@ -360,13 +365,13 @@ static int sunxi_nfc_dev_ready(struct mtd_info *mtd) switch (rb->type) { case RB_NATIVE: ret = !!(readl(nfc->regs + NFC_REG_ST) & - (NFC_RB_STATE0 << rb->info.nativeid)); + NFC_RB_STATE(rb->info.nativeid)); if (ret) break; sunxi_nfc_wait_int(nfc, NFC_RB_B2R, timeo); ret = !!(readl(nfc->regs + NFC_REG_ST) & - (NFC_RB_STATE0 << rb->info.nativeid)); + NFC_RB_STATE(rb->info.nativeid)); break; case RB_GPIO: ret = gpio_get_value(rb->info.gpio); @@ -396,19 +401,19 @@ static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip) return; ctl = readl(nfc->regs + NFC_REG_CTL) & - ~(NFC_CE_SEL | NFC_RB_SEL | NFC_EN); + ~(NFC_PAGE_SHIFT_MSK | NFC_CE_SEL_MSK | NFC_RB_SEL_MSK | NFC_EN); if (chip >= 0) { sel = &sunxi_nand->sels[chip]; - ctl |= (sel->cs << 24) | NFC_EN | - (((nand->page_shift - 10) & 0xf) << 8); + ctl |= NFC_CE_SEL(sel->cs) | NFC_EN | + NFC_PAGE_SHIFT(nand->page_shift - 10); if (sel->rb.type == RB_NONE) { nand->dev_ready = NULL; } else { nand->dev_ready = sunxi_nfc_dev_ready; if (sel->rb.type == RB_NATIVE) - ctl |= (sel->rb.info.nativeid << 3); + ctl |= NFC_RB_SEL(sel->rb.info.nativeid); } writel(mtd->writesize, nfc->regs + NFC_REG_SPARE_AREA); @@ -534,155 +539,244 @@ static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); } -static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, - int oob_required, int page) +static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd) { - struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller); - struct nand_ecc_ctrl *ecc = &chip->ecc; - struct nand_ecclayout *layout = ecc->layout; - struct sunxi_nand_hw_ecc *data = ecc->priv; - unsigned int max_bitflips = 0; - int offset; - int ret; - u32 tmp; - int i; - int cnt; + struct nand_chip *nand = mtd->priv; + struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); + struct sunxi_nand_hw_ecc *data = nand->ecc.priv; + u32 ecc_ctl; - tmp = readl(nfc->regs + NFC_REG_ECC_CTL); - tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE); - tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) | - NFC_ECC_EXCEPTION; + ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL); + ecc_ctl &= ~(NFC_ECC_MODE_MSK | NFC_ECC_PIPELINE | + NFC_ECC_BLOCK_SIZE_MSK); + ecc_ctl |= NFC_ECC_EN | NFC_ECC_MODE(data->mode) | NFC_ECC_EXCEPTION; - writel(tmp, nfc->regs + NFC_REG_ECC_CTL); + writel(ecc_ctl, nfc->regs + NFC_REG_ECC_CTL); +} - for (i = 0; i < ecc->steps; i++) { - if (i) - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, i * ecc->size, -1); +static void sunxi_nfc_hw_ecc_disable(struct mtd_info *mtd) +{ + struct nand_chip *nand = mtd->priv; + struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); - offset = mtd->writesize + layout->eccpos[i * ecc->bytes] - 4; + writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN, + nfc->regs + NFC_REG_ECC_CTL); +} - chip->read_buf(mtd, NULL, ecc->size); +static inline void sunxi_nfc_user_data_to_buf(u32 user_data, u8 *buf) +{ + buf[0] = user_data; + buf[1] = user_data >> 8; + buf[2] = user_data >> 16; + buf[3] = user_data >> 24; +} - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1); +static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd, + u8 *data, int data_off, + u8 *oob, int oob_off, + int *cur_off, + unsigned int *max_bitflips) +{ + struct nand_chip *nand = mtd->priv; + struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); + struct nand_ecc_ctrl *ecc = &nand->ecc; + u32 status; + int ret; - ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); - if (ret) - return ret; + if (*cur_off != data_off) + nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1); - tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | (1 << 30); - writel(tmp, nfc->regs + NFC_REG_CMD); + sunxi_nfc_read_buf(mtd, NULL, ecc->size); - ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); - if (ret) - return ret; + if (data_off + ecc->size != oob_off) + nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1); - memcpy_fromio(buf + (i * ecc->size), - nfc->regs + NFC_RAM0_BASE, ecc->size); + ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); + if (ret) + return ret; - if (readl(nfc->regs + NFC_REG_ECC_ST) & 0x1) { - mtd->ecc_stats.failed++; - } else { - tmp = readl(nfc->regs + NFC_REG_ECC_CNT0) & 0xff; - mtd->ecc_stats.corrected += tmp; - max_bitflips = max_t(unsigned int, max_bitflips, tmp); - } + writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP, + nfc->regs + NFC_REG_CMD); - if (oob_required) { - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1); + ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); + if (ret) + return ret; - ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); - if (ret) - return ret; + status = readl(nfc->regs + NFC_REG_ECC_ST); + ret = NFC_ECC_ERR_CNT(0, readl(nfc->regs + NFC_REG_ECC_ERR_CNT(0))); - offset -= mtd->writesize; - chip->read_buf(mtd, chip->oob_poi + offset, - ecc->bytes + 4); - } + memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size); + + nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1); + sunxi_nfc_read_buf(mtd, oob, ecc->bytes + 4); + + if (status & NFC_ECC_ERR(0)) { + ret = nand_check_erased_ecc_chunk(data, ecc->size, + oob, ecc->bytes + 4, + NULL, 0, ecc->strength); + } else { + /* + * The engine protects 4 bytes of OOB data per chunk. + * Retrieve the corrected OOB bytes. + */ + sunxi_nfc_user_data_to_buf(readl(nfc->regs + NFC_REG_USER_DATA(0)), + oob); } - if (oob_required) { - cnt = ecc->layout->oobfree[ecc->steps].length; - if (cnt > 0) { - offset = mtd->writesize + - ecc->layout->oobfree[ecc->steps].offset; - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1); - offset -= mtd->writesize; - chip->read_buf(mtd, chip->oob_poi + offset, cnt); - } + if (ret < 0) { + mtd->ecc_stats.failed++; + } else { + mtd->ecc_stats.corrected += ret; + *max_bitflips = max_t(unsigned int, *max_bitflips, ret); } - tmp = readl(nfc->regs + NFC_REG_ECC_CTL); - tmp &= ~NFC_ECC_EN; + *cur_off = oob_off + ecc->bytes + 4; - writel(tmp, nfc->regs + NFC_REG_ECC_CTL); + return 0; +} - return max_bitflips; +static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd, + u8 *oob, int *cur_off) +{ + struct nand_chip *nand = mtd->priv; + struct nand_ecc_ctrl *ecc = &nand->ecc; + int offset = ((ecc->bytes + 4) * ecc->steps); + int len = mtd->oobsize - offset; + + if (len <= 0) + return; + + if (*cur_off != offset) + nand->cmdfunc(mtd, NAND_CMD_RNDOUT, + offset + mtd->writesize, -1); + + sunxi_nfc_read_buf(mtd, oob + offset, len); + + *cur_off = mtd->oobsize + mtd->writesize; } -static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd, - struct nand_chip *chip, - const uint8_t *buf, int oob_required) +static inline u32 sunxi_nfc_buf_to_user_data(const u8 *buf) { - struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller); - struct nand_ecc_ctrl *ecc = &chip->ecc; - struct nand_ecclayout *layout = ecc->layout; - struct sunxi_nand_hw_ecc *data = ecc->priv; - int offset; + return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); +} + +static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd, + const u8 *data, int data_off, + const u8 *oob, int oob_off, + int *cur_off) +{ + struct nand_chip *nand = mtd->priv; + struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); + struct nand_ecc_ctrl *ecc = &nand->ecc; int ret; - u32 tmp; - int i; - int cnt; - tmp = readl(nfc->regs + NFC_REG_ECC_CTL); - tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE); - tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) | - NFC_ECC_EXCEPTION; + if (data_off != *cur_off) + nand->cmdfunc(mtd, NAND_CMD_RNDIN, data_off, -1); - writel(tmp, nfc->regs + NFC_REG_ECC_CTL); + sunxi_nfc_write_buf(mtd, data, ecc->size); - for (i = 0; i < ecc->steps; i++) { - if (i) - chip->cmdfunc(mtd, NAND_CMD_RNDIN, i * ecc->size, -1); + /* Fill OOB data in */ + writel(sunxi_nfc_buf_to_user_data(oob), + nfc->regs + NFC_REG_USER_DATA(0)); - chip->write_buf(mtd, buf + (i * ecc->size), ecc->size); + if (data_off + ecc->size != oob_off) + nand->cmdfunc(mtd, NAND_CMD_RNDIN, oob_off, -1); - offset = layout->eccpos[i * ecc->bytes] - 4 + mtd->writesize; + ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); + if (ret) + return ret; - /* Fill OOB data in */ - writel(NFC_BUF_TO_USER_DATA(chip->oob_poi + - layout->oobfree[i].offset), - nfc->regs + NFC_REG_USER_DATA_BASE); + writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | + NFC_ACCESS_DIR | NFC_ECC_OP, + nfc->regs + NFC_REG_CMD); - chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1); + ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); + if (ret) + return ret; - ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); - if (ret) - return ret; + *cur_off = oob_off + ecc->bytes + 4; - tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ACCESS_DIR | - (1 << 30); - writel(tmp, nfc->regs + NFC_REG_CMD); - ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); + return 0; +} + +static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd, + u8 *oob, int *cur_off) +{ + struct nand_chip *nand = mtd->priv; + struct nand_ecc_ctrl *ecc = &nand->ecc; + int offset = ((ecc->bytes + 4) * ecc->steps); + int len = mtd->oobsize - offset; + + if (len <= 0) + return; + + if (*cur_off != offset) + nand->cmdfunc(mtd, NAND_CMD_RNDIN, + offset + mtd->writesize, -1); + + sunxi_nfc_write_buf(mtd, oob + offset, len); + + *cur_off = mtd->oobsize + mtd->writesize; +} + +static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) +{ + struct nand_ecc_ctrl *ecc = &chip->ecc; + unsigned int max_bitflips = 0; + int ret, i, cur_off = 0; + + sunxi_nfc_hw_ecc_enable(mtd); + + for (i = 0; i < ecc->steps; i++) { + int data_off = i * ecc->size; + int oob_off = i * (ecc->bytes + 4); + u8 *data = buf + data_off; + u8 *oob = chip->oob_poi + oob_off; + + ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob, + oob_off + mtd->writesize, + &cur_off, &max_bitflips); if (ret) return ret; } - if (oob_required) { - cnt = ecc->layout->oobfree[i].length; - if (cnt > 0) { - offset = mtd->writesize + - ecc->layout->oobfree[i].offset; - chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1); - offset -= mtd->writesize; - chip->write_buf(mtd, chip->oob_poi + offset, cnt); - } + if (oob_required) + sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off); + + sunxi_nfc_hw_ecc_disable(mtd); + + return max_bitflips; +} + +static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf, int oob_required, + int page) +{ + struct nand_ecc_ctrl *ecc = &chip->ecc; + int ret, i, cur_off = 0; + + sunxi_nfc_hw_ecc_enable(mtd); + + for (i = 0; i < ecc->steps; i++) { + int data_off = i * ecc->size; + int oob_off = i * (ecc->bytes + 4); + const u8 *data = buf + data_off; + const u8 *oob = chip->oob_poi + oob_off; + + ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob, + oob_off + mtd->writesize, + &cur_off); + if (ret) + return ret; } - tmp = readl(nfc->regs + NFC_REG_ECC_CTL); - tmp &= ~NFC_ECC_EN; + if (oob_required) + sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi, &cur_off); - writel(tmp, nfc->regs + NFC_REG_ECC_CTL); + sunxi_nfc_hw_ecc_disable(mtd); return 0; } @@ -692,65 +786,29 @@ static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd, uint8_t *buf, int oob_required, int page) { - struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller); struct nand_ecc_ctrl *ecc = &chip->ecc; - struct sunxi_nand_hw_ecc *data = ecc->priv; unsigned int max_bitflips = 0; - uint8_t *oob = chip->oob_poi; - int offset = 0; - int ret; - int cnt; - u32 tmp; - int i; + int ret, i, cur_off = 0; - tmp = readl(nfc->regs + NFC_REG_ECC_CTL); - tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE); - tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) | - NFC_ECC_EXCEPTION; - - writel(tmp, nfc->regs + NFC_REG_ECC_CTL); + sunxi_nfc_hw_ecc_enable(mtd); for (i = 0; i < ecc->steps; i++) { - chip->read_buf(mtd, NULL, ecc->size); - - tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | (1 << 30); - writel(tmp, nfc->regs + NFC_REG_CMD); - - ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); + int data_off = i * (ecc->size + ecc->bytes + 4); + int oob_off = data_off + ecc->size; + u8 *data = buf + (i * ecc->size); + u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4)); + + ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob, + oob_off, &cur_off, + &max_bitflips); if (ret) return ret; - - memcpy_fromio(buf, nfc->regs + NFC_RAM0_BASE, ecc->size); - buf += ecc->size; - offset += ecc->size; - - if (readl(nfc->regs + NFC_REG_ECC_ST) & 0x1) { - mtd->ecc_stats.failed++; - } else { - tmp = readl(nfc->regs + NFC_REG_ECC_CNT0) & 0xff; - mtd->ecc_stats.corrected += tmp; - max_bitflips = max_t(unsigned int, max_bitflips, tmp); - } - - if (oob_required) { - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1); - chip->read_buf(mtd, oob, ecc->bytes + ecc->prepad); - oob += ecc->bytes + ecc->prepad; - } - - offset += ecc->bytes + ecc->prepad; } - if (oob_required) { - cnt = mtd->oobsize - (oob - chip->oob_poi); - if (cnt > 0) { - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1); - chip->read_buf(mtd, oob, cnt); - } - } + if (oob_required) + sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off); - writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN, - nfc->regs + NFC_REG_ECC_CTL); + sunxi_nfc_hw_ecc_disable(mtd); return max_bitflips; } @@ -758,57 +816,29 @@ static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd, static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, - int oob_required) + int oob_required, int page) { - struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller); struct nand_ecc_ctrl *ecc = &chip->ecc; - struct sunxi_nand_hw_ecc *data = ecc->priv; - uint8_t *oob = chip->oob_poi; - int offset = 0; - int ret; - int cnt; - u32 tmp; - int i; + int ret, i, cur_off = 0; - tmp = readl(nfc->regs + NFC_REG_ECC_CTL); - tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE); - tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) | - NFC_ECC_EXCEPTION; - - writel(tmp, nfc->regs + NFC_REG_ECC_CTL); + sunxi_nfc_hw_ecc_enable(mtd); for (i = 0; i < ecc->steps; i++) { - chip->write_buf(mtd, buf + (i * ecc->size), ecc->size); - offset += ecc->size; - - /* Fill OOB data in */ - writel(NFC_BUF_TO_USER_DATA(oob), - nfc->regs + NFC_REG_USER_DATA_BASE); + int data_off = i * (ecc->size + ecc->bytes + 4); + int oob_off = data_off + ecc->size; + const u8 *data = buf + (i * ecc->size); + const u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4)); - tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ACCESS_DIR | - (1 << 30); - writel(tmp, nfc->regs + NFC_REG_CMD); - - ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); + ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, + oob, oob_off, &cur_off); if (ret) return ret; - - offset += ecc->bytes + ecc->prepad; - oob += ecc->bytes + ecc->prepad; - } - - if (oob_required) { - cnt = mtd->oobsize - (oob - chip->oob_poi); - if (cnt > 0) { - chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1); - chip->write_buf(mtd, oob, cnt); - } } - tmp = readl(nfc->regs + NFC_REG_ECC_CTL); - tmp &= ~NFC_ECC_EN; + if (oob_required) + sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi, &cur_off); - writel(tmp, nfc->regs + NFC_REG_ECC_CTL); + sunxi_nfc_hw_ecc_disable(mtd); return 0; } @@ -970,17 +1000,23 @@ static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip, mode = chip->nand.onfi_timing_mode_default; } else { uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {}; + int i; mode = fls(mode) - 1; if (mode < 0) mode = 0; feature[0] = mode; - ret = chip->nand.onfi_set_features(&chip->mtd, &chip->nand, + for (i = 0; i < chip->nsels; i++) { + chip->nand.select_chip(&chip->mtd, i); + ret = chip->nand.onfi_set_features(&chip->mtd, + &chip->nand, ONFI_FEATURE_ADDR_TIMING_MODE, feature); - if (ret) - return ret; + chip->nand.select_chip(&chip->mtd, -1); + if (ret) + return ret; + } } timings = onfi_async_timing_mode_to_sdr_timings(mode); @@ -1154,16 +1190,9 @@ static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc, struct device_node *np) { struct nand_chip *nand = mtd->priv; - int strength; - int blk_size; int ret; - blk_size = of_get_nand_ecc_step_size(np); - strength = of_get_nand_ecc_strength(np); - if (blk_size > 0 && strength > 0) { - ecc->size = blk_size; - ecc->strength = strength; - } else { + if (!ecc->size) { ecc->size = nand->ecc_step_ds; ecc->strength = nand->ecc_strength_ds; } @@ -1171,12 +1200,6 @@ static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc, if (!ecc->size || !ecc->strength) return -EINVAL; - ecc->mode = NAND_ECC_HW; - - ret = of_get_nand_ecc_mode(np); - if (ret >= 0) - ecc->mode = ret; - switch (ecc->mode) { case NAND_ECC_SOFT_BCH: break; @@ -1302,24 +1325,29 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc, /* Default tR value specified in the ONFI spec (chapter 4.15.1) */ nand->chip_delay = 200; nand->controller = &nfc->controller; + /* + * Set the ECC mode to the default value in case nothing is specified + * in the DT. + */ + nand->ecc.mode = NAND_ECC_HW; + nand->flash_node = np; nand->select_chip = sunxi_nfc_select_chip; nand->cmd_ctrl = sunxi_nfc_cmd_ctrl; nand->read_buf = sunxi_nfc_read_buf; nand->write_buf = sunxi_nfc_write_buf; nand->read_byte = sunxi_nfc_read_byte; - if (of_get_nand_on_flash_bbt(np)) - nand->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; - mtd = &chip->mtd; mtd->dev.parent = dev; mtd->priv = nand; - mtd->owner = THIS_MODULE; ret = nand_scan_ident(mtd, nsels, NULL); if (ret) return ret; + if (nand->bbt_options & NAND_BBT_USE_FLASH) + nand->bbt_options |= NAND_BBT_NO_OOB; + ret = sunxi_nand_chip_init_timings(chip, np); if (ret) { dev_err(dev, "could not configure chip timings: %d\n", ret); diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c index fb8fd35fa..befddf077 100644 --- a/drivers/mtd/nand/tmio_nand.c +++ b/drivers/mtd/nand/tmio_nand.c @@ -382,6 +382,7 @@ static int tmio_probe(struct platform_device *dev) nand_chip = &tmio->chip; mtd->priv = nand_chip; mtd->name = "tmio-nand"; + mtd->dev.parent = &dev->dev; tmio->ccr = devm_ioremap(&dev->dev, ccr->start, resource_size(ccr)); if (!tmio->ccr) diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c index 9c0bc45e2..8572519b8 100644 --- a/drivers/mtd/nand/txx9ndfmc.c +++ b/drivers/mtd/nand/txx9ndfmc.c @@ -323,7 +323,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev) continue; chip = &txx9_priv->chip; mtd = &txx9_priv->mtd; - mtd->owner = THIS_MODULE; + mtd->dev.parent = &dev->dev; mtd->priv = chip; diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c new file mode 100644 index 000000000..8805d6325 --- /dev/null +++ b/drivers/mtd/nand/vf610_nfc.c @@ -0,0 +1,878 @@ +/* + * Copyright 2009-2015 Freescale Semiconductor, Inc. and others + * + * Description: MPC5125, VF610, MCF54418 and Kinetis K70 Nand driver. + * Jason ported to M54418TWR and MVFA5 (VF610). + * Authors: Stefan Agner <stefan.agner@toradex.com> + * Bill Pringlemeir <bpringlemeir@nbsps.com> + * Shaohui Xie <b21989@freescale.com> + * Jason Jin <Jason.jin@freescale.com> + * + * Based on original driver mpc5121_nfc.c. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Limitations: + * - Untested on MPC5125 and M54418. + * - DMA and pipelining not used. + * - 2K pages or less. + * - HW ECC: Only 2K page with 64+ OOB. + * - HW ECC: Only 24 and 32-bit error correction implemented. + */ + +#include <linux/module.h> +#include <linux/bitops.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> +#include <linux/of_mtd.h> +#include <linux/of_device.h> +#include <linux/pinctrl/consumer.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#define DRV_NAME "vf610_nfc" + +/* Register Offsets */ +#define NFC_FLASH_CMD1 0x3F00 +#define NFC_FLASH_CMD2 0x3F04 +#define NFC_COL_ADDR 0x3F08 +#define NFC_ROW_ADDR 0x3F0c +#define NFC_ROW_ADDR_INC 0x3F14 +#define NFC_FLASH_STATUS1 0x3F18 +#define NFC_FLASH_STATUS2 0x3F1c +#define NFC_CACHE_SWAP 0x3F28 +#define NFC_SECTOR_SIZE 0x3F2c +#define NFC_FLASH_CONFIG 0x3F30 +#define NFC_IRQ_STATUS 0x3F38 + +/* Addresses for NFC MAIN RAM BUFFER areas */ +#define NFC_MAIN_AREA(n) ((n) * 0x1000) + +#define PAGE_2K 0x0800 +#define OOB_64 0x0040 +#define OOB_MAX 0x0100 + +/* + * NFC_CMD2[CODE] values. See section: + * - 31.4.7 Flash Command Code Description, Vybrid manual + * - 23.8.6 Flash Command Sequencer, MPC5125 manual + * + * Briefly these are bitmasks of controller cycles. + */ +#define READ_PAGE_CMD_CODE 0x7EE0 +#define READ_ONFI_PARAM_CMD_CODE 0x4860 +#define PROGRAM_PAGE_CMD_CODE 0x7FC0 +#define ERASE_CMD_CODE 0x4EC0 +#define READ_ID_CMD_CODE 0x4804 +#define RESET_CMD_CODE 0x4040 +#define STATUS_READ_CMD_CODE 0x4068 + +/* NFC ECC mode define */ +#define ECC_BYPASS 0 +#define ECC_45_BYTE 6 +#define ECC_60_BYTE 7 + +/*** Register Mask and bit definitions */ + +/* NFC_FLASH_CMD1 Field */ +#define CMD_BYTE2_MASK 0xFF000000 +#define CMD_BYTE2_SHIFT 24 + +/* NFC_FLASH_CM2 Field */ +#define CMD_BYTE1_MASK 0xFF000000 +#define CMD_BYTE1_SHIFT 24 +#define CMD_CODE_MASK 0x00FFFF00 +#define CMD_CODE_SHIFT 8 +#define BUFNO_MASK 0x00000006 +#define BUFNO_SHIFT 1 +#define START_BIT BIT(0) + +/* NFC_COL_ADDR Field */ +#define COL_ADDR_MASK 0x0000FFFF +#define COL_ADDR_SHIFT 0 + +/* NFC_ROW_ADDR Field */ +#define ROW_ADDR_MASK 0x00FFFFFF +#define ROW_ADDR_SHIFT 0 +#define ROW_ADDR_CHIP_SEL_RB_MASK 0xF0000000 +#define ROW_ADDR_CHIP_SEL_RB_SHIFT 28 +#define ROW_ADDR_CHIP_SEL_MASK 0x0F000000 +#define ROW_ADDR_CHIP_SEL_SHIFT 24 + +/* NFC_FLASH_STATUS2 Field */ +#define STATUS_BYTE1_MASK 0x000000FF + +/* NFC_FLASH_CONFIG Field */ +#define CONFIG_ECC_SRAM_ADDR_MASK 0x7FC00000 +#define CONFIG_ECC_SRAM_ADDR_SHIFT 22 +#define CONFIG_ECC_SRAM_REQ_BIT BIT(21) +#define CONFIG_DMA_REQ_BIT BIT(20) +#define CONFIG_ECC_MODE_MASK 0x000E0000 +#define CONFIG_ECC_MODE_SHIFT 17 +#define CONFIG_FAST_FLASH_BIT BIT(16) +#define CONFIG_16BIT BIT(7) +#define CONFIG_BOOT_MODE_BIT BIT(6) +#define CONFIG_ADDR_AUTO_INCR_BIT BIT(5) +#define CONFIG_BUFNO_AUTO_INCR_BIT BIT(4) +#define CONFIG_PAGE_CNT_MASK 0xF +#define CONFIG_PAGE_CNT_SHIFT 0 + +/* NFC_IRQ_STATUS Field */ +#define IDLE_IRQ_BIT BIT(29) +#define IDLE_EN_BIT BIT(20) +#define CMD_DONE_CLEAR_BIT BIT(18) +#define IDLE_CLEAR_BIT BIT(17) + +/* + * ECC status - seems to consume 8 bytes (double word). The documented + * status byte is located in the lowest byte of the second word (which is + * the 4th or 7th byte depending on endianness). + * Calculate an offset to store the ECC status at the end of the buffer. + */ +#define ECC_SRAM_ADDR (PAGE_2K + OOB_MAX - 8) + +#define ECC_STATUS 0x4 +#define ECC_STATUS_MASK 0x80 +#define ECC_STATUS_ERR_COUNT 0x3F + +enum vf610_nfc_alt_buf { + ALT_BUF_DATA = 0, + ALT_BUF_ID = 1, + ALT_BUF_STAT = 2, + ALT_BUF_ONFI = 3, +}; + +enum vf610_nfc_variant { + NFC_VFC610 = 1, +}; + +struct vf610_nfc { + struct mtd_info mtd; + struct nand_chip chip; + struct device *dev; + void __iomem *regs; + struct completion cmd_done; + uint buf_offset; + int write_sz; + /* Status and ID are in alternate locations. */ + enum vf610_nfc_alt_buf alt_buf; + enum vf610_nfc_variant variant; + struct clk *clk; + bool use_hw_ecc; + u32 ecc_mode; +}; + +#define mtd_to_nfc(_mtd) container_of(_mtd, struct vf610_nfc, mtd) + +static struct nand_ecclayout vf610_nfc_ecc45 = { + .eccbytes = 45, + .eccpos = {19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63}, + .oobfree = { + {.offset = 2, + .length = 17} } +}; + +static struct nand_ecclayout vf610_nfc_ecc60 = { + .eccbytes = 60, + .eccpos = { 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63 }, + .oobfree = { + {.offset = 2, + .length = 2} } +}; + +static inline u32 vf610_nfc_read(struct vf610_nfc *nfc, uint reg) +{ + return readl(nfc->regs + reg); +} + +static inline void vf610_nfc_write(struct vf610_nfc *nfc, uint reg, u32 val) +{ + writel(val, nfc->regs + reg); +} + +static inline void vf610_nfc_set(struct vf610_nfc *nfc, uint reg, u32 bits) +{ + vf610_nfc_write(nfc, reg, vf610_nfc_read(nfc, reg) | bits); +} + +static inline void vf610_nfc_clear(struct vf610_nfc *nfc, uint reg, u32 bits) +{ + vf610_nfc_write(nfc, reg, vf610_nfc_read(nfc, reg) & ~bits); +} + +static inline void vf610_nfc_set_field(struct vf610_nfc *nfc, u32 reg, + u32 mask, u32 shift, u32 val) +{ + vf610_nfc_write(nfc, reg, + (vf610_nfc_read(nfc, reg) & (~mask)) | val << shift); +} + +static inline void vf610_nfc_memcpy(void *dst, const void __iomem *src, + size_t n) +{ + /* + * Use this accessor for the internal SRAM buffers. On the ARM + * Freescale Vybrid SoC it's known that the driver can treat + * the SRAM buffer as if it's memory. Other platform might need + * to treat the buffers differently. + * + * For the time being, use memcpy + */ + memcpy(dst, src, n); +} + +/* Clear flags for upcoming command */ +static inline void vf610_nfc_clear_status(struct vf610_nfc *nfc) +{ + u32 tmp = vf610_nfc_read(nfc, NFC_IRQ_STATUS); + + tmp |= CMD_DONE_CLEAR_BIT | IDLE_CLEAR_BIT; + vf610_nfc_write(nfc, NFC_IRQ_STATUS, tmp); +} + +static void vf610_nfc_done(struct vf610_nfc *nfc) +{ + unsigned long timeout = msecs_to_jiffies(100); + + /* + * Barrier is needed after this write. This write need + * to be done before reading the next register the first + * time. + * vf610_nfc_set implicates such a barrier by using writel + * to write to the register. + */ + vf610_nfc_set(nfc, NFC_IRQ_STATUS, IDLE_EN_BIT); + vf610_nfc_set(nfc, NFC_FLASH_CMD2, START_BIT); + + if (!wait_for_completion_timeout(&nfc->cmd_done, timeout)) + dev_warn(nfc->dev, "Timeout while waiting for BUSY.\n"); + + vf610_nfc_clear_status(nfc); +} + +static u8 vf610_nfc_get_id(struct vf610_nfc *nfc, int col) +{ + u32 flash_id; + + if (col < 4) { + flash_id = vf610_nfc_read(nfc, NFC_FLASH_STATUS1); + flash_id >>= (3 - col) * 8; + } else { + flash_id = vf610_nfc_read(nfc, NFC_FLASH_STATUS2); + flash_id >>= 24; + } + + return flash_id & 0xff; +} + +static u8 vf610_nfc_get_status(struct vf610_nfc *nfc) +{ + return vf610_nfc_read(nfc, NFC_FLASH_STATUS2) & STATUS_BYTE1_MASK; +} + +static void vf610_nfc_send_command(struct vf610_nfc *nfc, u32 cmd_byte1, + u32 cmd_code) +{ + u32 tmp; + + vf610_nfc_clear_status(nfc); + + tmp = vf610_nfc_read(nfc, NFC_FLASH_CMD2); + tmp &= ~(CMD_BYTE1_MASK | CMD_CODE_MASK | BUFNO_MASK); + tmp |= cmd_byte1 << CMD_BYTE1_SHIFT; + tmp |= cmd_code << CMD_CODE_SHIFT; + vf610_nfc_write(nfc, NFC_FLASH_CMD2, tmp); +} + +static void vf610_nfc_send_commands(struct vf610_nfc *nfc, u32 cmd_byte1, + u32 cmd_byte2, u32 cmd_code) +{ + u32 tmp; + + vf610_nfc_send_command(nfc, cmd_byte1, cmd_code); + + tmp = vf610_nfc_read(nfc, NFC_FLASH_CMD1); + tmp &= ~CMD_BYTE2_MASK; + tmp |= cmd_byte2 << CMD_BYTE2_SHIFT; + vf610_nfc_write(nfc, NFC_FLASH_CMD1, tmp); +} + +static irqreturn_t vf610_nfc_irq(int irq, void *data) +{ + struct mtd_info *mtd = data; + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + + vf610_nfc_clear(nfc, NFC_IRQ_STATUS, IDLE_EN_BIT); + complete(&nfc->cmd_done); + + return IRQ_HANDLED; +} + +static void vf610_nfc_addr_cycle(struct vf610_nfc *nfc, int column, int page) +{ + if (column != -1) { + if (nfc->chip.options & NAND_BUSWIDTH_16) + column = column / 2; + vf610_nfc_set_field(nfc, NFC_COL_ADDR, COL_ADDR_MASK, + COL_ADDR_SHIFT, column); + } + if (page != -1) + vf610_nfc_set_field(nfc, NFC_ROW_ADDR, ROW_ADDR_MASK, + ROW_ADDR_SHIFT, page); +} + +static inline void vf610_nfc_ecc_mode(struct vf610_nfc *nfc, int ecc_mode) +{ + vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG, + CONFIG_ECC_MODE_MASK, + CONFIG_ECC_MODE_SHIFT, ecc_mode); +} + +static inline void vf610_nfc_transfer_size(struct vf610_nfc *nfc, int size) +{ + vf610_nfc_write(nfc, NFC_SECTOR_SIZE, size); +} + +static void vf610_nfc_command(struct mtd_info *mtd, unsigned command, + int column, int page) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + int trfr_sz = nfc->chip.options & NAND_BUSWIDTH_16 ? 1 : 0; + + nfc->buf_offset = max(column, 0); + nfc->alt_buf = ALT_BUF_DATA; + + switch (command) { + case NAND_CMD_SEQIN: + /* Use valid column/page from preread... */ + vf610_nfc_addr_cycle(nfc, column, page); + nfc->buf_offset = 0; + + /* + * SEQIN => data => PAGEPROG sequence is done by the controller + * hence we do not need to issue the command here... + */ + return; + case NAND_CMD_PAGEPROG: + trfr_sz += nfc->write_sz; + vf610_nfc_transfer_size(nfc, trfr_sz); + vf610_nfc_send_commands(nfc, NAND_CMD_SEQIN, + command, PROGRAM_PAGE_CMD_CODE); + if (nfc->use_hw_ecc) + vf610_nfc_ecc_mode(nfc, nfc->ecc_mode); + else + vf610_nfc_ecc_mode(nfc, ECC_BYPASS); + break; + + case NAND_CMD_RESET: + vf610_nfc_transfer_size(nfc, 0); + vf610_nfc_send_command(nfc, command, RESET_CMD_CODE); + break; + + case NAND_CMD_READOOB: + trfr_sz += mtd->oobsize; + column = mtd->writesize; + vf610_nfc_transfer_size(nfc, trfr_sz); + vf610_nfc_send_commands(nfc, NAND_CMD_READ0, + NAND_CMD_READSTART, READ_PAGE_CMD_CODE); + vf610_nfc_addr_cycle(nfc, column, page); + vf610_nfc_ecc_mode(nfc, ECC_BYPASS); + break; + + case NAND_CMD_READ0: + trfr_sz += mtd->writesize + mtd->oobsize; + vf610_nfc_transfer_size(nfc, trfr_sz); + vf610_nfc_send_commands(nfc, NAND_CMD_READ0, + NAND_CMD_READSTART, READ_PAGE_CMD_CODE); + vf610_nfc_addr_cycle(nfc, column, page); + vf610_nfc_ecc_mode(nfc, nfc->ecc_mode); + break; + + case NAND_CMD_PARAM: + nfc->alt_buf = ALT_BUF_ONFI; + trfr_sz = 3 * sizeof(struct nand_onfi_params); + vf610_nfc_transfer_size(nfc, trfr_sz); + vf610_nfc_send_command(nfc, command, READ_ONFI_PARAM_CMD_CODE); + vf610_nfc_addr_cycle(nfc, -1, column); + vf610_nfc_ecc_mode(nfc, ECC_BYPASS); + break; + + case NAND_CMD_ERASE1: + vf610_nfc_transfer_size(nfc, 0); + vf610_nfc_send_commands(nfc, command, + NAND_CMD_ERASE2, ERASE_CMD_CODE); + vf610_nfc_addr_cycle(nfc, column, page); + break; + + case NAND_CMD_READID: + nfc->alt_buf = ALT_BUF_ID; + nfc->buf_offset = 0; + vf610_nfc_transfer_size(nfc, 0); + vf610_nfc_send_command(nfc, command, READ_ID_CMD_CODE); + vf610_nfc_addr_cycle(nfc, -1, column); + break; + + case NAND_CMD_STATUS: + nfc->alt_buf = ALT_BUF_STAT; + vf610_nfc_transfer_size(nfc, 0); + vf610_nfc_send_command(nfc, command, STATUS_READ_CMD_CODE); + break; + default: + return; + } + + vf610_nfc_done(nfc); + + nfc->use_hw_ecc = false; + nfc->write_sz = 0; +} + +static void vf610_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + uint c = nfc->buf_offset; + + /* Alternate buffers are only supported through read_byte */ + WARN_ON(nfc->alt_buf); + + vf610_nfc_memcpy(buf, nfc->regs + NFC_MAIN_AREA(0) + c, len); + + nfc->buf_offset += len; +} + +static void vf610_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, + int len) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + uint c = nfc->buf_offset; + uint l; + + l = min_t(uint, len, mtd->writesize + mtd->oobsize - c); + vf610_nfc_memcpy(nfc->regs + NFC_MAIN_AREA(0) + c, buf, l); + + nfc->write_sz += l; + nfc->buf_offset += l; +} + +static uint8_t vf610_nfc_read_byte(struct mtd_info *mtd) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + u8 tmp; + uint c = nfc->buf_offset; + + switch (nfc->alt_buf) { + case ALT_BUF_ID: + tmp = vf610_nfc_get_id(nfc, c); + break; + case ALT_BUF_STAT: + tmp = vf610_nfc_get_status(nfc); + break; +#ifdef __LITTLE_ENDIAN + case ALT_BUF_ONFI: + /* Reverse byte since the controller uses big endianness */ + c = nfc->buf_offset ^ 0x3; + /* fall-through */ +#endif + default: + tmp = *((u8 *)(nfc->regs + NFC_MAIN_AREA(0) + c)); + break; + } + nfc->buf_offset++; + return tmp; +} + +static u16 vf610_nfc_read_word(struct mtd_info *mtd) +{ + u16 tmp; + + vf610_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp)); + return tmp; +} + +/* If not provided, upper layers apply a fixed delay. */ +static int vf610_nfc_dev_ready(struct mtd_info *mtd) +{ + /* NFC handles R/B internally; always ready. */ + return 1; +} + +/* + * This function supports Vybrid only (MPC5125 would have full RB and four CS) + */ +static void vf610_nfc_select_chip(struct mtd_info *mtd, int chip) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + u32 tmp = vf610_nfc_read(nfc, NFC_ROW_ADDR); + + /* Vybrid only (MPC5125 would have full RB and four CS) */ + if (nfc->variant != NFC_VFC610) + return; + + tmp &= ~(ROW_ADDR_CHIP_SEL_RB_MASK | ROW_ADDR_CHIP_SEL_MASK); + + if (chip >= 0) { + tmp |= 1 << ROW_ADDR_CHIP_SEL_RB_SHIFT; + tmp |= BIT(chip) << ROW_ADDR_CHIP_SEL_SHIFT; + } + + vf610_nfc_write(nfc, NFC_ROW_ADDR, tmp); +} + +/* Count the number of 0's in buff up to max_bits */ +static inline int count_written_bits(uint8_t *buff, int size, int max_bits) +{ + uint32_t *buff32 = (uint32_t *)buff; + int k, written_bits = 0; + + for (k = 0; k < (size / 4); k++) { + written_bits += hweight32(~buff32[k]); + if (unlikely(written_bits > max_bits)) + break; + } + + return written_bits; +} + +static inline int vf610_nfc_correct_data(struct mtd_info *mtd, uint8_t *dat, + uint8_t *oob, int page) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + u32 ecc_status_off = NFC_MAIN_AREA(0) + ECC_SRAM_ADDR + ECC_STATUS; + u8 ecc_status; + u8 ecc_count; + int flips_threshold = nfc->chip.ecc.strength / 2; + + ecc_status = vf610_nfc_read(nfc, ecc_status_off) & 0xff; + ecc_count = ecc_status & ECC_STATUS_ERR_COUNT; + + if (!(ecc_status & ECC_STATUS_MASK)) + return ecc_count; + + /* Read OOB without ECC unit enabled */ + vf610_nfc_command(mtd, NAND_CMD_READOOB, 0, page); + vf610_nfc_read_buf(mtd, oob, mtd->oobsize); + + /* + * On an erased page, bit count (including OOB) should be zero or + * at least less then half of the ECC strength. + */ + return nand_check_erased_ecc_chunk(dat, nfc->chip.ecc.size, oob, + mtd->oobsize, NULL, 0, + flips_threshold); +} + +static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + int eccsize = chip->ecc.size; + int stat; + + vf610_nfc_read_buf(mtd, buf, eccsize); + if (oob_required) + vf610_nfc_read_buf(mtd, chip->oob_poi, mtd->oobsize); + + stat = vf610_nfc_correct_data(mtd, buf, chip->oob_poi, page); + + if (stat < 0) { + mtd->ecc_stats.failed++; + return 0; + } else { + mtd->ecc_stats.corrected += stat; + return stat; + } +} + +static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int oob_required, int page) +{ + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + + vf610_nfc_write_buf(mtd, buf, mtd->writesize); + if (oob_required) + vf610_nfc_write_buf(mtd, chip->oob_poi, mtd->oobsize); + + /* Always write whole page including OOB due to HW ECC */ + nfc->use_hw_ecc = true; + nfc->write_sz = mtd->writesize + mtd->oobsize; + + return 0; +} + +static const struct of_device_id vf610_nfc_dt_ids[] = { + { .compatible = "fsl,vf610-nfc", .data = (void *)NFC_VFC610 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, vf610_nfc_dt_ids); + +static void vf610_nfc_preinit_controller(struct vf610_nfc *nfc) +{ + vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT); + vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_ADDR_AUTO_INCR_BIT); + vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_BUFNO_AUTO_INCR_BIT); + vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_BOOT_MODE_BIT); + vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_DMA_REQ_BIT); + vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_FAST_FLASH_BIT); + + /* Disable virtual pages, only one elementary transfer unit */ + vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG, CONFIG_PAGE_CNT_MASK, + CONFIG_PAGE_CNT_SHIFT, 1); +} + +static void vf610_nfc_init_controller(struct vf610_nfc *nfc) +{ + if (nfc->chip.options & NAND_BUSWIDTH_16) + vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT); + else + vf610_nfc_clear(nfc, NFC_FLASH_CONFIG, CONFIG_16BIT); + + if (nfc->chip.ecc.mode == NAND_ECC_HW) { + /* Set ECC status offset in SRAM */ + vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG, + CONFIG_ECC_SRAM_ADDR_MASK, + CONFIG_ECC_SRAM_ADDR_SHIFT, + ECC_SRAM_ADDR >> 3); + + /* Enable ECC status in SRAM */ + vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_ECC_SRAM_REQ_BIT); + } +} + +static int vf610_nfc_probe(struct platform_device *pdev) +{ + struct vf610_nfc *nfc; + struct resource *res; + struct mtd_info *mtd; + struct nand_chip *chip; + struct device_node *child; + const struct of_device_id *of_id; + int err; + int irq; + + nfc = devm_kzalloc(&pdev->dev, sizeof(*nfc), GFP_KERNEL); + if (!nfc) + return -ENOMEM; + + nfc->dev = &pdev->dev; + mtd = &nfc->mtd; + chip = &nfc->chip; + + mtd->priv = chip; + mtd->owner = THIS_MODULE; + mtd->dev.parent = nfc->dev; + mtd->name = DRV_NAME; + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) + return -EINVAL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + nfc->regs = devm_ioremap_resource(nfc->dev, res); + if (IS_ERR(nfc->regs)) + return PTR_ERR(nfc->regs); + + nfc->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(nfc->clk)) + return PTR_ERR(nfc->clk); + + err = clk_prepare_enable(nfc->clk); + if (err) { + dev_err(nfc->dev, "Unable to enable clock!\n"); + return err; + } + + of_id = of_match_device(vf610_nfc_dt_ids, &pdev->dev); + nfc->variant = (enum vf610_nfc_variant)of_id->data; + + for_each_available_child_of_node(nfc->dev->of_node, child) { + if (of_device_is_compatible(child, "fsl,vf610-nfc-nandcs")) { + + if (chip->flash_node) { + dev_err(nfc->dev, + "Only one NAND chip supported!\n"); + err = -EINVAL; + goto error; + } + + chip->flash_node = child; + } + } + + if (!chip->flash_node) { + dev_err(nfc->dev, "NAND chip sub-node missing!\n"); + err = -ENODEV; + goto err_clk; + } + + chip->dev_ready = vf610_nfc_dev_ready; + chip->cmdfunc = vf610_nfc_command; + chip->read_byte = vf610_nfc_read_byte; + chip->read_word = vf610_nfc_read_word; + chip->read_buf = vf610_nfc_read_buf; + chip->write_buf = vf610_nfc_write_buf; + chip->select_chip = vf610_nfc_select_chip; + + chip->options |= NAND_NO_SUBPAGE_WRITE; + + init_completion(&nfc->cmd_done); + + err = devm_request_irq(nfc->dev, irq, vf610_nfc_irq, 0, DRV_NAME, mtd); + if (err) { + dev_err(nfc->dev, "Error requesting IRQ!\n"); + goto error; + } + + vf610_nfc_preinit_controller(nfc); + + /* first scan to find the device and get the page size */ + if (nand_scan_ident(mtd, 1, NULL)) { + err = -ENXIO; + goto error; + } + + vf610_nfc_init_controller(nfc); + + /* Bad block options. */ + if (chip->bbt_options & NAND_BBT_USE_FLASH) + chip->bbt_options |= NAND_BBT_NO_OOB; + + /* Single buffer only, max 256 OOB minus ECC status */ + if (mtd->writesize + mtd->oobsize > PAGE_2K + OOB_MAX - 8) { + dev_err(nfc->dev, "Unsupported flash page size\n"); + err = -ENXIO; + goto error; + } + + if (chip->ecc.mode == NAND_ECC_HW) { + if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) { + dev_err(nfc->dev, "Unsupported flash with hwecc\n"); + err = -ENXIO; + goto error; + } + + if (chip->ecc.size != mtd->writesize) { + dev_err(nfc->dev, "Step size needs to be page size\n"); + err = -ENXIO; + goto error; + } + + /* Only 64 byte ECC layouts known */ + if (mtd->oobsize > 64) + mtd->oobsize = 64; + + if (chip->ecc.strength == 32) { + nfc->ecc_mode = ECC_60_BYTE; + chip->ecc.bytes = 60; + chip->ecc.layout = &vf610_nfc_ecc60; + } else if (chip->ecc.strength == 24) { + nfc->ecc_mode = ECC_45_BYTE; + chip->ecc.bytes = 45; + chip->ecc.layout = &vf610_nfc_ecc45; + } else { + dev_err(nfc->dev, "Unsupported ECC strength\n"); + err = -ENXIO; + goto error; + } + + /* propagate ecc.layout to mtd_info */ + mtd->ecclayout = chip->ecc.layout; + chip->ecc.read_page = vf610_nfc_read_page; + chip->ecc.write_page = vf610_nfc_write_page; + + chip->ecc.size = PAGE_2K; + } + + /* second phase scan */ + if (nand_scan_tail(mtd)) { + err = -ENXIO; + goto error; + } + + platform_set_drvdata(pdev, mtd); + + /* Register device in MTD */ + return mtd_device_parse_register(mtd, NULL, + &(struct mtd_part_parser_data){ + .of_node = chip->flash_node, + }, + NULL, 0); + +error: + of_node_put(chip->flash_node); +err_clk: + clk_disable_unprepare(nfc->clk); + return err; +} + +static int vf610_nfc_remove(struct platform_device *pdev) +{ + struct mtd_info *mtd = platform_get_drvdata(pdev); + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + + nand_release(mtd); + clk_disable_unprepare(nfc->clk); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int vf610_nfc_suspend(struct device *dev) +{ + struct mtd_info *mtd = dev_get_drvdata(dev); + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + + clk_disable_unprepare(nfc->clk); + return 0; +} + +static int vf610_nfc_resume(struct device *dev) +{ + struct mtd_info *mtd = dev_get_drvdata(dev); + struct vf610_nfc *nfc = mtd_to_nfc(mtd); + + pinctrl_pm_select_default_state(dev); + + clk_prepare_enable(nfc->clk); + + vf610_nfc_preinit_controller(nfc); + vf610_nfc_init_controller(nfc); + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(vf610_nfc_pm_ops, vf610_nfc_suspend, vf610_nfc_resume); + +static struct platform_driver vf610_nfc_driver = { + .driver = { + .name = DRV_NAME, + .of_match_table = vf610_nfc_dt_ids, + .pm = &vf610_nfc_pm_ops, + }, + .probe = vf610_nfc_probe, + .remove = vf610_nfc_remove, +}; + +module_platform_driver(vf610_nfc_driver); + +MODULE_AUTHOR("Stefan Agner <stefan.agner@toradex.com>"); +MODULE_DESCRIPTION("Freescale VF610/MPC5125 NFC MTD NAND driver"); +MODULE_LICENSE("GPL"); |