From: Miquel Raynal Date: Mon, 30 Dec 2019 17:31:03 +0000 (+0100) Subject: mtd: onenand: Rename omap2 driver to avoid a build warning X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=d85339d9ea2660b550f12aca8bd040be4395c963;p=linux.git mtd: onenand: Rename omap2 driver to avoid a build warning As previously reported by Sudip Mukherjee for the Samsung driver, the omap2 onenand driver is called omap2.c in our directory and omap2.c in the tty/serial/ directory. If both drivers are compiled as modules, it would produce the following warning: warning: same module names found: drivers/tty/serial/omap2.ko drivers/mtd/nand/onenand/omap2.ko Rename the onenand omap2 driver so that it fits the folder's convention: onenand_omap2.c. Signed-off-by: Miquel Raynal --- diff --git a/drivers/mtd/nand/onenand/Makefile b/drivers/mtd/nand/onenand/Makefile index 0f2f460adbe40..a0761c7e02884 100644 --- a/drivers/mtd/nand/onenand/Makefile +++ b/drivers/mtd/nand/onenand/Makefile @@ -8,7 +8,7 @@ obj-$(CONFIG_MTD_ONENAND) += onenand.o # Board specific. obj-$(CONFIG_MTD_ONENAND_GENERIC) += generic.o -obj-$(CONFIG_MTD_ONENAND_OMAP2) += omap2.o +obj-$(CONFIG_MTD_ONENAND_OMAP2) += onenand_omap2.o obj-$(CONFIG_MTD_ONENAND_SAMSUNG) += onenand_samsung.o onenand-objs = onenand_base.o onenand_bbt.o diff --git a/drivers/mtd/nand/onenand/omap2.c b/drivers/mtd/nand/onenand/omap2.c deleted file mode 100644 index aa9368bf7a0c8..0000000000000 --- a/drivers/mtd/nand/onenand/omap2.c +++ /dev/null @@ -1,620 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * OneNAND driver for OMAP2 / OMAP3 - * - * Copyright © 2005-2006 Nokia Corporation - * - * Author: Jarkko Lavinen and Juha Yrjölä - * IRQ and DMA support written by Timo Teras - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define DRIVER_NAME "omap2-onenand" - -#define ONENAND_BUFRAM_SIZE (1024 * 5) - -struct omap2_onenand { - struct platform_device *pdev; - int gpmc_cs; - unsigned long phys_base; - struct gpio_desc *int_gpiod; - struct mtd_info mtd; - struct onenand_chip onenand; - struct completion irq_done; - struct completion dma_done; - struct dma_chan *dma_chan; -}; - -static void omap2_onenand_dma_complete_func(void *completion) -{ - complete(completion); -} - -static irqreturn_t omap2_onenand_interrupt(int irq, void *dev_id) -{ - struct omap2_onenand *c = dev_id; - - complete(&c->irq_done); - - return IRQ_HANDLED; -} - -static inline unsigned short read_reg(struct omap2_onenand *c, int reg) -{ - return readw(c->onenand.base + reg); -} - -static inline void write_reg(struct omap2_onenand *c, unsigned short value, - int reg) -{ - writew(value, c->onenand.base + reg); -} - -static int omap2_onenand_set_cfg(struct omap2_onenand *c, - bool sr, bool sw, - int latency, int burst_len) -{ - unsigned short reg = ONENAND_SYS_CFG1_RDY | ONENAND_SYS_CFG1_INT; - - reg |= latency << ONENAND_SYS_CFG1_BRL_SHIFT; - - switch (burst_len) { - case 0: /* continuous */ - break; - case 4: - reg |= ONENAND_SYS_CFG1_BL_4; - break; - case 8: - reg |= ONENAND_SYS_CFG1_BL_8; - break; - case 16: - reg |= ONENAND_SYS_CFG1_BL_16; - break; - case 32: - reg |= ONENAND_SYS_CFG1_BL_32; - break; - default: - return -EINVAL; - } - - if (latency > 5) - reg |= ONENAND_SYS_CFG1_HF; - if (latency > 7) - reg |= ONENAND_SYS_CFG1_VHF; - if (sr) - reg |= ONENAND_SYS_CFG1_SYNC_READ; - if (sw) - reg |= ONENAND_SYS_CFG1_SYNC_WRITE; - - write_reg(c, reg, ONENAND_REG_SYS_CFG1); - - return 0; -} - -static int omap2_onenand_get_freq(int ver) -{ - switch ((ver >> 4) & 0xf) { - case 0: - return 40; - case 1: - return 54; - case 2: - return 66; - case 3: - return 83; - case 4: - return 104; - } - - return -EINVAL; -} - -static void wait_err(char *msg, int state, unsigned int ctrl, unsigned int intr) -{ - printk(KERN_ERR "onenand_wait: %s! state %d ctrl 0x%04x intr 0x%04x\n", - msg, state, ctrl, intr); -} - -static void wait_warn(char *msg, int state, unsigned int ctrl, - unsigned int intr) -{ - printk(KERN_WARNING "onenand_wait: %s! state %d ctrl 0x%04x " - "intr 0x%04x\n", msg, state, ctrl, intr); -} - -static int omap2_onenand_wait(struct mtd_info *mtd, int state) -{ - struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); - struct onenand_chip *this = mtd->priv; - unsigned int intr = 0; - unsigned int ctrl, ctrl_mask; - unsigned long timeout; - u32 syscfg; - - if (state == FL_RESETTING || state == FL_PREPARING_ERASE || - state == FL_VERIFYING_ERASE) { - int i = 21; - unsigned int intr_flags = ONENAND_INT_MASTER; - - switch (state) { - case FL_RESETTING: - intr_flags |= ONENAND_INT_RESET; - break; - case FL_PREPARING_ERASE: - intr_flags |= ONENAND_INT_ERASE; - break; - case FL_VERIFYING_ERASE: - i = 101; - break; - } - - while (--i) { - udelay(1); - intr = read_reg(c, ONENAND_REG_INTERRUPT); - if (intr & ONENAND_INT_MASTER) - break; - } - ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); - if (ctrl & ONENAND_CTRL_ERROR) { - wait_err("controller error", state, ctrl, intr); - return -EIO; - } - if ((intr & intr_flags) == intr_flags) - return 0; - /* Continue in wait for interrupt branch */ - } - - if (state != FL_READING) { - int result; - - /* Turn interrupts on */ - syscfg = read_reg(c, ONENAND_REG_SYS_CFG1); - if (!(syscfg & ONENAND_SYS_CFG1_IOBE)) { - syscfg |= ONENAND_SYS_CFG1_IOBE; - write_reg(c, syscfg, ONENAND_REG_SYS_CFG1); - /* Add a delay to let GPIO settle */ - syscfg = read_reg(c, ONENAND_REG_SYS_CFG1); - } - - reinit_completion(&c->irq_done); - result = gpiod_get_value(c->int_gpiod); - if (result < 0) { - ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); - intr = read_reg(c, ONENAND_REG_INTERRUPT); - wait_err("gpio error", state, ctrl, intr); - return result; - } else if (result == 0) { - int retry_cnt = 0; -retry: - if (!wait_for_completion_io_timeout(&c->irq_done, - msecs_to_jiffies(20))) { - /* Timeout after 20ms */ - ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); - if (ctrl & ONENAND_CTRL_ONGO && - !this->ongoing) { - /* - * The operation seems to be still going - * so give it some more time. - */ - retry_cnt += 1; - if (retry_cnt < 3) - goto retry; - intr = read_reg(c, - ONENAND_REG_INTERRUPT); - wait_err("timeout", state, ctrl, intr); - return -EIO; - } - intr = read_reg(c, ONENAND_REG_INTERRUPT); - if ((intr & ONENAND_INT_MASTER) == 0) - wait_warn("timeout", state, ctrl, intr); - } - } - } else { - int retry_cnt = 0; - - /* Turn interrupts off */ - syscfg = read_reg(c, ONENAND_REG_SYS_CFG1); - syscfg &= ~ONENAND_SYS_CFG1_IOBE; - write_reg(c, syscfg, ONENAND_REG_SYS_CFG1); - - timeout = jiffies + msecs_to_jiffies(20); - while (1) { - if (time_before(jiffies, timeout)) { - intr = read_reg(c, ONENAND_REG_INTERRUPT); - if (intr & ONENAND_INT_MASTER) - break; - } else { - /* Timeout after 20ms */ - ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); - if (ctrl & ONENAND_CTRL_ONGO) { - /* - * The operation seems to be still going - * so give it some more time. - */ - retry_cnt += 1; - if (retry_cnt < 3) { - timeout = jiffies + - msecs_to_jiffies(20); - continue; - } - } - break; - } - } - } - - intr = read_reg(c, ONENAND_REG_INTERRUPT); - ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); - - if (intr & ONENAND_INT_READ) { - int ecc = read_reg(c, ONENAND_REG_ECC_STATUS); - - if (ecc) { - unsigned int addr1, addr8; - - addr1 = read_reg(c, ONENAND_REG_START_ADDRESS1); - addr8 = read_reg(c, ONENAND_REG_START_ADDRESS8); - if (ecc & ONENAND_ECC_2BIT_ALL) { - printk(KERN_ERR "onenand_wait: ECC error = " - "0x%04x, addr1 %#x, addr8 %#x\n", - ecc, addr1, addr8); - mtd->ecc_stats.failed++; - return -EBADMSG; - } else if (ecc & ONENAND_ECC_1BIT_ALL) { - printk(KERN_NOTICE "onenand_wait: correctable " - "ECC error = 0x%04x, addr1 %#x, " - "addr8 %#x\n", ecc, addr1, addr8); - mtd->ecc_stats.corrected++; - } - } - } else if (state == FL_READING) { - wait_err("timeout", state, ctrl, intr); - return -EIO; - } - - if (ctrl & ONENAND_CTRL_ERROR) { - wait_err("controller error", state, ctrl, intr); - if (ctrl & ONENAND_CTRL_LOCK) - printk(KERN_ERR "onenand_wait: " - "Device is write protected!!!\n"); - return -EIO; - } - - ctrl_mask = 0xFE9F; - if (this->ongoing) - ctrl_mask &= ~0x8000; - - if (ctrl & ctrl_mask) - wait_warn("unexpected controller status", state, ctrl, intr); - - return 0; -} - -static inline int omap2_onenand_bufferram_offset(struct mtd_info *mtd, int area) -{ - struct onenand_chip *this = mtd->priv; - - if (ONENAND_CURRENT_BUFFERRAM(this)) { - if (area == ONENAND_DATARAM) - return this->writesize; - if (area == ONENAND_SPARERAM) - return mtd->oobsize; - } - - return 0; -} - -static inline int omap2_onenand_dma_transfer(struct omap2_onenand *c, - dma_addr_t src, dma_addr_t dst, - size_t count) -{ - struct dma_async_tx_descriptor *tx; - dma_cookie_t cookie; - - tx = dmaengine_prep_dma_memcpy(c->dma_chan, dst, src, count, - DMA_CTRL_ACK | DMA_PREP_INTERRUPT); - if (!tx) { - dev_err(&c->pdev->dev, "Failed to prepare DMA memcpy\n"); - return -EIO; - } - - reinit_completion(&c->dma_done); - - tx->callback = omap2_onenand_dma_complete_func; - tx->callback_param = &c->dma_done; - - cookie = tx->tx_submit(tx); - if (dma_submit_error(cookie)) { - dev_err(&c->pdev->dev, "Failed to do DMA tx_submit\n"); - return -EIO; - } - - dma_async_issue_pending(c->dma_chan); - - if (!wait_for_completion_io_timeout(&c->dma_done, - msecs_to_jiffies(20))) { - dmaengine_terminate_sync(c->dma_chan); - return -ETIMEDOUT; - } - - return 0; -} - -static int omap2_onenand_read_bufferram(struct mtd_info *mtd, int area, - unsigned char *buffer, int offset, - size_t count) -{ - struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); - struct onenand_chip *this = mtd->priv; - struct device *dev = &c->pdev->dev; - void *buf = (void *)buffer; - dma_addr_t dma_src, dma_dst; - int bram_offset, err; - size_t xtra; - - bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset; - /* - * If the buffer address is not DMA-able, len is not long enough to make - * DMA transfers profitable or panic_write() may be in an interrupt - * context fallback to PIO mode. - */ - if (!virt_addr_valid(buf) || bram_offset & 3 || (size_t)buf & 3 || - count < 384 || in_interrupt() || oops_in_progress) - goto out_copy; - - xtra = count & 3; - if (xtra) { - count -= xtra; - memcpy(buf + count, this->base + bram_offset + count, xtra); - } - - dma_dst = dma_map_single(dev, buf, count, DMA_FROM_DEVICE); - dma_src = c->phys_base + bram_offset; - - if (dma_mapping_error(dev, dma_dst)) { - dev_err(dev, "Couldn't DMA map a %d byte buffer\n", count); - goto out_copy; - } - - err = omap2_onenand_dma_transfer(c, dma_src, dma_dst, count); - dma_unmap_single(dev, dma_dst, count, DMA_FROM_DEVICE); - if (!err) - return 0; - - dev_err(dev, "timeout waiting for DMA\n"); - -out_copy: - memcpy(buf, this->base + bram_offset, count); - return 0; -} - -static int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area, - const unsigned char *buffer, - int offset, size_t count) -{ - struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); - struct onenand_chip *this = mtd->priv; - struct device *dev = &c->pdev->dev; - void *buf = (void *)buffer; - dma_addr_t dma_src, dma_dst; - int bram_offset, err; - - bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset; - /* - * If the buffer address is not DMA-able, len is not long enough to make - * DMA transfers profitable or panic_write() may be in an interrupt - * context fallback to PIO mode. - */ - if (!virt_addr_valid(buf) || bram_offset & 3 || (size_t)buf & 3 || - count < 384 || in_interrupt() || oops_in_progress) - goto out_copy; - - dma_src = dma_map_single(dev, buf, count, DMA_TO_DEVICE); - dma_dst = c->phys_base + bram_offset; - if (dma_mapping_error(dev, dma_src)) { - dev_err(dev, "Couldn't DMA map a %d byte buffer\n", count); - goto out_copy; - } - - err = omap2_onenand_dma_transfer(c, dma_src, dma_dst, count); - dma_unmap_page(dev, dma_src, count, DMA_TO_DEVICE); - if (!err) - return 0; - - dev_err(dev, "timeout waiting for DMA\n"); - -out_copy: - memcpy(this->base + bram_offset, buf, count); - return 0; -} - -static void omap2_onenand_shutdown(struct platform_device *pdev) -{ - struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); - - /* With certain content in the buffer RAM, the OMAP boot ROM code - * can recognize the flash chip incorrectly. Zero it out before - * soft reset. - */ - memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE); -} - -static int omap2_onenand_probe(struct platform_device *pdev) -{ - u32 val; - dma_cap_mask_t mask; - int freq, latency, r; - struct resource *res; - struct omap2_onenand *c; - struct gpmc_onenand_info info; - struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "error getting memory resource\n"); - return -EINVAL; - } - - r = of_property_read_u32(np, "reg", &val); - if (r) { - dev_err(dev, "reg not found in DT\n"); - return r; - } - - c = devm_kzalloc(dev, sizeof(struct omap2_onenand), GFP_KERNEL); - if (!c) - return -ENOMEM; - - init_completion(&c->irq_done); - init_completion(&c->dma_done); - c->gpmc_cs = val; - c->phys_base = res->start; - - c->onenand.base = devm_ioremap_resource(dev, res); - if (IS_ERR(c->onenand.base)) - return PTR_ERR(c->onenand.base); - - c->int_gpiod = devm_gpiod_get_optional(dev, "int", GPIOD_IN); - if (IS_ERR(c->int_gpiod)) { - r = PTR_ERR(c->int_gpiod); - /* Just try again if this happens */ - if (r != -EPROBE_DEFER) - dev_err(dev, "error getting gpio: %d\n", r); - return r; - } - - if (c->int_gpiod) { - r = devm_request_irq(dev, gpiod_to_irq(c->int_gpiod), - omap2_onenand_interrupt, - IRQF_TRIGGER_RISING, "onenand", c); - if (r) - return r; - - c->onenand.wait = omap2_onenand_wait; - } - - dma_cap_zero(mask); - dma_cap_set(DMA_MEMCPY, mask); - - c->dma_chan = dma_request_channel(mask, NULL, NULL); - if (c->dma_chan) { - c->onenand.read_bufferram = omap2_onenand_read_bufferram; - c->onenand.write_bufferram = omap2_onenand_write_bufferram; - } - - c->pdev = pdev; - c->mtd.priv = &c->onenand; - c->mtd.dev.parent = dev; - mtd_set_of_node(&c->mtd, dev->of_node); - - dev_info(dev, "initializing on CS%d (0x%08lx), va %p, %s mode\n", - c->gpmc_cs, c->phys_base, c->onenand.base, - c->dma_chan ? "DMA" : "PIO"); - - r = onenand_scan(&c->mtd, 1); - if (r < 0) - goto err_release_dma; - - freq = omap2_onenand_get_freq(c->onenand.version_id); - if (freq > 0) { - switch (freq) { - case 104: - latency = 7; - break; - case 83: - latency = 6; - break; - case 66: - latency = 5; - break; - case 56: - latency = 4; - break; - default: /* 40 MHz or lower */ - latency = 3; - break; - } - - r = gpmc_omap_onenand_set_timings(dev, c->gpmc_cs, - freq, latency, &info); - if (r) - goto err_release_onenand; - - r = omap2_onenand_set_cfg(c, info.sync_read, info.sync_write, - latency, info.burst_len); - if (r) - goto err_release_onenand; - - if (info.sync_read || info.sync_write) - dev_info(dev, "optimized timings for %d MHz\n", freq); - } - - r = mtd_device_register(&c->mtd, NULL, 0); - if (r) - goto err_release_onenand; - - platform_set_drvdata(pdev, c); - - return 0; - -err_release_onenand: - onenand_release(&c->mtd); -err_release_dma: - if (c->dma_chan) - dma_release_channel(c->dma_chan); - - return r; -} - -static int omap2_onenand_remove(struct platform_device *pdev) -{ - struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); - - onenand_release(&c->mtd); - if (c->dma_chan) - dma_release_channel(c->dma_chan); - omap2_onenand_shutdown(pdev); - - return 0; -} - -static const struct of_device_id omap2_onenand_id_table[] = { - { .compatible = "ti,omap2-onenand", }, - {}, -}; -MODULE_DEVICE_TABLE(of, omap2_onenand_id_table); - -static struct platform_driver omap2_onenand_driver = { - .probe = omap2_onenand_probe, - .remove = omap2_onenand_remove, - .shutdown = omap2_onenand_shutdown, - .driver = { - .name = DRIVER_NAME, - .of_match_table = omap2_onenand_id_table, - }, -}; - -module_platform_driver(omap2_onenand_driver); - -MODULE_ALIAS("platform:" DRIVER_NAME); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jarkko Lavinen "); -MODULE_DESCRIPTION("Glue layer for OneNAND flash on OMAP2 / OMAP3"); diff --git a/drivers/mtd/nand/onenand/onenand_omap2.c b/drivers/mtd/nand/onenand/onenand_omap2.c new file mode 100644 index 0000000000000..aa9368bf7a0c8 --- /dev/null +++ b/drivers/mtd/nand/onenand/onenand_omap2.c @@ -0,0 +1,620 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * OneNAND driver for OMAP2 / OMAP3 + * + * Copyright © 2005-2006 Nokia Corporation + * + * Author: Jarkko Lavinen and Juha Yrjölä + * IRQ and DMA support written by Timo Teras + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DRIVER_NAME "omap2-onenand" + +#define ONENAND_BUFRAM_SIZE (1024 * 5) + +struct omap2_onenand { + struct platform_device *pdev; + int gpmc_cs; + unsigned long phys_base; + struct gpio_desc *int_gpiod; + struct mtd_info mtd; + struct onenand_chip onenand; + struct completion irq_done; + struct completion dma_done; + struct dma_chan *dma_chan; +}; + +static void omap2_onenand_dma_complete_func(void *completion) +{ + complete(completion); +} + +static irqreturn_t omap2_onenand_interrupt(int irq, void *dev_id) +{ + struct omap2_onenand *c = dev_id; + + complete(&c->irq_done); + + return IRQ_HANDLED; +} + +static inline unsigned short read_reg(struct omap2_onenand *c, int reg) +{ + return readw(c->onenand.base + reg); +} + +static inline void write_reg(struct omap2_onenand *c, unsigned short value, + int reg) +{ + writew(value, c->onenand.base + reg); +} + +static int omap2_onenand_set_cfg(struct omap2_onenand *c, + bool sr, bool sw, + int latency, int burst_len) +{ + unsigned short reg = ONENAND_SYS_CFG1_RDY | ONENAND_SYS_CFG1_INT; + + reg |= latency << ONENAND_SYS_CFG1_BRL_SHIFT; + + switch (burst_len) { + case 0: /* continuous */ + break; + case 4: + reg |= ONENAND_SYS_CFG1_BL_4; + break; + case 8: + reg |= ONENAND_SYS_CFG1_BL_8; + break; + case 16: + reg |= ONENAND_SYS_CFG1_BL_16; + break; + case 32: + reg |= ONENAND_SYS_CFG1_BL_32; + break; + default: + return -EINVAL; + } + + if (latency > 5) + reg |= ONENAND_SYS_CFG1_HF; + if (latency > 7) + reg |= ONENAND_SYS_CFG1_VHF; + if (sr) + reg |= ONENAND_SYS_CFG1_SYNC_READ; + if (sw) + reg |= ONENAND_SYS_CFG1_SYNC_WRITE; + + write_reg(c, reg, ONENAND_REG_SYS_CFG1); + + return 0; +} + +static int omap2_onenand_get_freq(int ver) +{ + switch ((ver >> 4) & 0xf) { + case 0: + return 40; + case 1: + return 54; + case 2: + return 66; + case 3: + return 83; + case 4: + return 104; + } + + return -EINVAL; +} + +static void wait_err(char *msg, int state, unsigned int ctrl, unsigned int intr) +{ + printk(KERN_ERR "onenand_wait: %s! state %d ctrl 0x%04x intr 0x%04x\n", + msg, state, ctrl, intr); +} + +static void wait_warn(char *msg, int state, unsigned int ctrl, + unsigned int intr) +{ + printk(KERN_WARNING "onenand_wait: %s! state %d ctrl 0x%04x " + "intr 0x%04x\n", msg, state, ctrl, intr); +} + +static int omap2_onenand_wait(struct mtd_info *mtd, int state) +{ + struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); + struct onenand_chip *this = mtd->priv; + unsigned int intr = 0; + unsigned int ctrl, ctrl_mask; + unsigned long timeout; + u32 syscfg; + + if (state == FL_RESETTING || state == FL_PREPARING_ERASE || + state == FL_VERIFYING_ERASE) { + int i = 21; + unsigned int intr_flags = ONENAND_INT_MASTER; + + switch (state) { + case FL_RESETTING: + intr_flags |= ONENAND_INT_RESET; + break; + case FL_PREPARING_ERASE: + intr_flags |= ONENAND_INT_ERASE; + break; + case FL_VERIFYING_ERASE: + i = 101; + break; + } + + while (--i) { + udelay(1); + intr = read_reg(c, ONENAND_REG_INTERRUPT); + if (intr & ONENAND_INT_MASTER) + break; + } + ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); + if (ctrl & ONENAND_CTRL_ERROR) { + wait_err("controller error", state, ctrl, intr); + return -EIO; + } + if ((intr & intr_flags) == intr_flags) + return 0; + /* Continue in wait for interrupt branch */ + } + + if (state != FL_READING) { + int result; + + /* Turn interrupts on */ + syscfg = read_reg(c, ONENAND_REG_SYS_CFG1); + if (!(syscfg & ONENAND_SYS_CFG1_IOBE)) { + syscfg |= ONENAND_SYS_CFG1_IOBE; + write_reg(c, syscfg, ONENAND_REG_SYS_CFG1); + /* Add a delay to let GPIO settle */ + syscfg = read_reg(c, ONENAND_REG_SYS_CFG1); + } + + reinit_completion(&c->irq_done); + result = gpiod_get_value(c->int_gpiod); + if (result < 0) { + ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); + intr = read_reg(c, ONENAND_REG_INTERRUPT); + wait_err("gpio error", state, ctrl, intr); + return result; + } else if (result == 0) { + int retry_cnt = 0; +retry: + if (!wait_for_completion_io_timeout(&c->irq_done, + msecs_to_jiffies(20))) { + /* Timeout after 20ms */ + ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); + if (ctrl & ONENAND_CTRL_ONGO && + !this->ongoing) { + /* + * The operation seems to be still going + * so give it some more time. + */ + retry_cnt += 1; + if (retry_cnt < 3) + goto retry; + intr = read_reg(c, + ONENAND_REG_INTERRUPT); + wait_err("timeout", state, ctrl, intr); + return -EIO; + } + intr = read_reg(c, ONENAND_REG_INTERRUPT); + if ((intr & ONENAND_INT_MASTER) == 0) + wait_warn("timeout", state, ctrl, intr); + } + } + } else { + int retry_cnt = 0; + + /* Turn interrupts off */ + syscfg = read_reg(c, ONENAND_REG_SYS_CFG1); + syscfg &= ~ONENAND_SYS_CFG1_IOBE; + write_reg(c, syscfg, ONENAND_REG_SYS_CFG1); + + timeout = jiffies + msecs_to_jiffies(20); + while (1) { + if (time_before(jiffies, timeout)) { + intr = read_reg(c, ONENAND_REG_INTERRUPT); + if (intr & ONENAND_INT_MASTER) + break; + } else { + /* Timeout after 20ms */ + ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); + if (ctrl & ONENAND_CTRL_ONGO) { + /* + * The operation seems to be still going + * so give it some more time. + */ + retry_cnt += 1; + if (retry_cnt < 3) { + timeout = jiffies + + msecs_to_jiffies(20); + continue; + } + } + break; + } + } + } + + intr = read_reg(c, ONENAND_REG_INTERRUPT); + ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); + + if (intr & ONENAND_INT_READ) { + int ecc = read_reg(c, ONENAND_REG_ECC_STATUS); + + if (ecc) { + unsigned int addr1, addr8; + + addr1 = read_reg(c, ONENAND_REG_START_ADDRESS1); + addr8 = read_reg(c, ONENAND_REG_START_ADDRESS8); + if (ecc & ONENAND_ECC_2BIT_ALL) { + printk(KERN_ERR "onenand_wait: ECC error = " + "0x%04x, addr1 %#x, addr8 %#x\n", + ecc, addr1, addr8); + mtd->ecc_stats.failed++; + return -EBADMSG; + } else if (ecc & ONENAND_ECC_1BIT_ALL) { + printk(KERN_NOTICE "onenand_wait: correctable " + "ECC error = 0x%04x, addr1 %#x, " + "addr8 %#x\n", ecc, addr1, addr8); + mtd->ecc_stats.corrected++; + } + } + } else if (state == FL_READING) { + wait_err("timeout", state, ctrl, intr); + return -EIO; + } + + if (ctrl & ONENAND_CTRL_ERROR) { + wait_err("controller error", state, ctrl, intr); + if (ctrl & ONENAND_CTRL_LOCK) + printk(KERN_ERR "onenand_wait: " + "Device is write protected!!!\n"); + return -EIO; + } + + ctrl_mask = 0xFE9F; + if (this->ongoing) + ctrl_mask &= ~0x8000; + + if (ctrl & ctrl_mask) + wait_warn("unexpected controller status", state, ctrl, intr); + + return 0; +} + +static inline int omap2_onenand_bufferram_offset(struct mtd_info *mtd, int area) +{ + struct onenand_chip *this = mtd->priv; + + if (ONENAND_CURRENT_BUFFERRAM(this)) { + if (area == ONENAND_DATARAM) + return this->writesize; + if (area == ONENAND_SPARERAM) + return mtd->oobsize; + } + + return 0; +} + +static inline int omap2_onenand_dma_transfer(struct omap2_onenand *c, + dma_addr_t src, dma_addr_t dst, + size_t count) +{ + struct dma_async_tx_descriptor *tx; + dma_cookie_t cookie; + + tx = dmaengine_prep_dma_memcpy(c->dma_chan, dst, src, count, + DMA_CTRL_ACK | DMA_PREP_INTERRUPT); + if (!tx) { + dev_err(&c->pdev->dev, "Failed to prepare DMA memcpy\n"); + return -EIO; + } + + reinit_completion(&c->dma_done); + + tx->callback = omap2_onenand_dma_complete_func; + tx->callback_param = &c->dma_done; + + cookie = tx->tx_submit(tx); + if (dma_submit_error(cookie)) { + dev_err(&c->pdev->dev, "Failed to do DMA tx_submit\n"); + return -EIO; + } + + dma_async_issue_pending(c->dma_chan); + + if (!wait_for_completion_io_timeout(&c->dma_done, + msecs_to_jiffies(20))) { + dmaengine_terminate_sync(c->dma_chan); + return -ETIMEDOUT; + } + + return 0; +} + +static int omap2_onenand_read_bufferram(struct mtd_info *mtd, int area, + unsigned char *buffer, int offset, + size_t count) +{ + struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); + struct onenand_chip *this = mtd->priv; + struct device *dev = &c->pdev->dev; + void *buf = (void *)buffer; + dma_addr_t dma_src, dma_dst; + int bram_offset, err; + size_t xtra; + + bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset; + /* + * If the buffer address is not DMA-able, len is not long enough to make + * DMA transfers profitable or panic_write() may be in an interrupt + * context fallback to PIO mode. + */ + if (!virt_addr_valid(buf) || bram_offset & 3 || (size_t)buf & 3 || + count < 384 || in_interrupt() || oops_in_progress) + goto out_copy; + + xtra = count & 3; + if (xtra) { + count -= xtra; + memcpy(buf + count, this->base + bram_offset + count, xtra); + } + + dma_dst = dma_map_single(dev, buf, count, DMA_FROM_DEVICE); + dma_src = c->phys_base + bram_offset; + + if (dma_mapping_error(dev, dma_dst)) { + dev_err(dev, "Couldn't DMA map a %d byte buffer\n", count); + goto out_copy; + } + + err = omap2_onenand_dma_transfer(c, dma_src, dma_dst, count); + dma_unmap_single(dev, dma_dst, count, DMA_FROM_DEVICE); + if (!err) + return 0; + + dev_err(dev, "timeout waiting for DMA\n"); + +out_copy: + memcpy(buf, this->base + bram_offset, count); + return 0; +} + +static int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area, + const unsigned char *buffer, + int offset, size_t count) +{ + struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); + struct onenand_chip *this = mtd->priv; + struct device *dev = &c->pdev->dev; + void *buf = (void *)buffer; + dma_addr_t dma_src, dma_dst; + int bram_offset, err; + + bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset; + /* + * If the buffer address is not DMA-able, len is not long enough to make + * DMA transfers profitable or panic_write() may be in an interrupt + * context fallback to PIO mode. + */ + if (!virt_addr_valid(buf) || bram_offset & 3 || (size_t)buf & 3 || + count < 384 || in_interrupt() || oops_in_progress) + goto out_copy; + + dma_src = dma_map_single(dev, buf, count, DMA_TO_DEVICE); + dma_dst = c->phys_base + bram_offset; + if (dma_mapping_error(dev, dma_src)) { + dev_err(dev, "Couldn't DMA map a %d byte buffer\n", count); + goto out_copy; + } + + err = omap2_onenand_dma_transfer(c, dma_src, dma_dst, count); + dma_unmap_page(dev, dma_src, count, DMA_TO_DEVICE); + if (!err) + return 0; + + dev_err(dev, "timeout waiting for DMA\n"); + +out_copy: + memcpy(this->base + bram_offset, buf, count); + return 0; +} + +static void omap2_onenand_shutdown(struct platform_device *pdev) +{ + struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); + + /* With certain content in the buffer RAM, the OMAP boot ROM code + * can recognize the flash chip incorrectly. Zero it out before + * soft reset. + */ + memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE); +} + +static int omap2_onenand_probe(struct platform_device *pdev) +{ + u32 val; + dma_cap_mask_t mask; + int freq, latency, r; + struct resource *res; + struct omap2_onenand *c; + struct gpmc_onenand_info info; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "error getting memory resource\n"); + return -EINVAL; + } + + r = of_property_read_u32(np, "reg", &val); + if (r) { + dev_err(dev, "reg not found in DT\n"); + return r; + } + + c = devm_kzalloc(dev, sizeof(struct omap2_onenand), GFP_KERNEL); + if (!c) + return -ENOMEM; + + init_completion(&c->irq_done); + init_completion(&c->dma_done); + c->gpmc_cs = val; + c->phys_base = res->start; + + c->onenand.base = devm_ioremap_resource(dev, res); + if (IS_ERR(c->onenand.base)) + return PTR_ERR(c->onenand.base); + + c->int_gpiod = devm_gpiod_get_optional(dev, "int", GPIOD_IN); + if (IS_ERR(c->int_gpiod)) { + r = PTR_ERR(c->int_gpiod); + /* Just try again if this happens */ + if (r != -EPROBE_DEFER) + dev_err(dev, "error getting gpio: %d\n", r); + return r; + } + + if (c->int_gpiod) { + r = devm_request_irq(dev, gpiod_to_irq(c->int_gpiod), + omap2_onenand_interrupt, + IRQF_TRIGGER_RISING, "onenand", c); + if (r) + return r; + + c->onenand.wait = omap2_onenand_wait; + } + + dma_cap_zero(mask); + dma_cap_set(DMA_MEMCPY, mask); + + c->dma_chan = dma_request_channel(mask, NULL, NULL); + if (c->dma_chan) { + c->onenand.read_bufferram = omap2_onenand_read_bufferram; + c->onenand.write_bufferram = omap2_onenand_write_bufferram; + } + + c->pdev = pdev; + c->mtd.priv = &c->onenand; + c->mtd.dev.parent = dev; + mtd_set_of_node(&c->mtd, dev->of_node); + + dev_info(dev, "initializing on CS%d (0x%08lx), va %p, %s mode\n", + c->gpmc_cs, c->phys_base, c->onenand.base, + c->dma_chan ? "DMA" : "PIO"); + + r = onenand_scan(&c->mtd, 1); + if (r < 0) + goto err_release_dma; + + freq = omap2_onenand_get_freq(c->onenand.version_id); + if (freq > 0) { + switch (freq) { + case 104: + latency = 7; + break; + case 83: + latency = 6; + break; + case 66: + latency = 5; + break; + case 56: + latency = 4; + break; + default: /* 40 MHz or lower */ + latency = 3; + break; + } + + r = gpmc_omap_onenand_set_timings(dev, c->gpmc_cs, + freq, latency, &info); + if (r) + goto err_release_onenand; + + r = omap2_onenand_set_cfg(c, info.sync_read, info.sync_write, + latency, info.burst_len); + if (r) + goto err_release_onenand; + + if (info.sync_read || info.sync_write) + dev_info(dev, "optimized timings for %d MHz\n", freq); + } + + r = mtd_device_register(&c->mtd, NULL, 0); + if (r) + goto err_release_onenand; + + platform_set_drvdata(pdev, c); + + return 0; + +err_release_onenand: + onenand_release(&c->mtd); +err_release_dma: + if (c->dma_chan) + dma_release_channel(c->dma_chan); + + return r; +} + +static int omap2_onenand_remove(struct platform_device *pdev) +{ + struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); + + onenand_release(&c->mtd); + if (c->dma_chan) + dma_release_channel(c->dma_chan); + omap2_onenand_shutdown(pdev); + + return 0; +} + +static const struct of_device_id omap2_onenand_id_table[] = { + { .compatible = "ti,omap2-onenand", }, + {}, +}; +MODULE_DEVICE_TABLE(of, omap2_onenand_id_table); + +static struct platform_driver omap2_onenand_driver = { + .probe = omap2_onenand_probe, + .remove = omap2_onenand_remove, + .shutdown = omap2_onenand_shutdown, + .driver = { + .name = DRIVER_NAME, + .of_match_table = omap2_onenand_id_table, + }, +}; + +module_platform_driver(omap2_onenand_driver); + +MODULE_ALIAS("platform:" DRIVER_NAME); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jarkko Lavinen "); +MODULE_DESCRIPTION("Glue layer for OneNAND flash on OMAP2 / OMAP3");