Commit a9e849ef authored by Roger Quadros's avatar Roger Quadros Committed by Miquel Raynal
Browse files

mtd: rawnand: omap2: move to exec_op interface



Stop using legacy interface and move to the exec_op interface.

Signed-off-by: default avatarRoger Quadros <rogerq@kernel.org>
Signed-off-by: default avatarMiquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20211209090458.24830-4-rogerq@kernel.org
parent 35da0c45
Loading
Loading
Loading
Loading
+211 −279
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@
#include <linux/mtd/rawnand.h>
#include <linux/mtd/partitions.h>
#include <linux/omap-dma.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -164,6 +164,7 @@ struct omap_nand_info {
	u_char				*buf;
	int					buf_len;
	/* Interface to GPMC */
	void __iomem			*fifo;
	struct gpmc_nand_regs		reg;
	struct gpmc_nand_ops		*ops;
	bool				flash_bbt;
@@ -175,6 +176,11 @@ struct omap_nand_info {
	unsigned int			nsteps_per_eccpg;
	unsigned int			eccpg_size;
	unsigned int			eccpg_bytes;
	void (*data_in)(struct nand_chip *chip, void *buf,
			unsigned int len, bool force_8bit);
	void (*data_out)(struct nand_chip *chip,
			 const void *buf, unsigned int len,
			 bool force_8bit);
};

static inline struct omap_nand_info *mtd_to_omap(struct mtd_info *mtd)
@@ -182,6 +188,13 @@ static inline struct omap_nand_info *mtd_to_omap(struct mtd_info *mtd)
	return container_of(mtd_to_nand(mtd), struct omap_nand_info, nand);
}

static void omap_nand_data_in(struct nand_chip *chip, void *buf,
			      unsigned int len, bool force_8bit);

static void omap_nand_data_out(struct nand_chip *chip,
			       const void *buf, unsigned int len,
			       bool force_8bit);

/**
 * omap_prefetch_enable - configures and starts prefetch transfer
 * @cs: cs (chip select) number
@@ -241,169 +254,70 @@ static int omap_prefetch_reset(int cs, struct omap_nand_info *info)
}

/**
 * omap_hwcontrol - hardware specific access to control-lines
 * @chip: NAND chip object
 * @cmd: command to device
 * @ctrl:
 * NAND_NCE: bit 0 -> don't care
 * NAND_CLE: bit 1 -> Command Latch
 * NAND_ALE: bit 2 -> Address Latch
 *
 * NOTE: boards may use different bits for these!!
 * omap_nand_data_in_pref - NAND data in using prefetch engine
 */
static void omap_hwcontrol(struct nand_chip *chip, int cmd, unsigned int ctrl)
static void omap_nand_data_in_pref(struct nand_chip *chip, void *buf,
				   unsigned int len, bool force_8bit)
{
	struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));

	if (cmd != NAND_CMD_NONE) {
		if (ctrl & NAND_CLE)
			writeb(cmd, info->reg.gpmc_nand_command);

		else if (ctrl & NAND_ALE)
			writeb(cmd, info->reg.gpmc_nand_address);

		else /* NAND_NCE */
			writeb(cmd, info->reg.gpmc_nand_data);
	}
}

/**
 * omap_read_buf8 - read data from NAND controller into buffer
 * @mtd: MTD device structure
 * @buf: buffer to store date
 * @len: number of bytes to read
 */
static void omap_read_buf8(struct mtd_info *mtd, u_char *buf, int len)
{
	struct nand_chip *nand = mtd_to_nand(mtd);

	ioread8_rep(nand->legacy.IO_ADDR_R, buf, len);
}

/**
 * omap_write_buf8 - write buffer to NAND controller
 * @mtd: MTD device structure
 * @buf: data buffer
 * @len: number of bytes to write
 */
static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
{
	struct omap_nand_info *info = mtd_to_omap(mtd);
	u_char *p = (u_char *)buf;
	bool status;

	while (len--) {
		iowrite8(*p++, info->nand.legacy.IO_ADDR_W);
		/* wait until buffer is available for write */
		do {
			status = info->ops->nand_writebuffer_empty();
		} while (!status);
	}
}

/**
 * omap_read_buf16 - read data from NAND controller into buffer
 * @mtd: MTD device structure
 * @buf: buffer to store date
 * @len: number of bytes to read
 */
static void omap_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
{
	struct nand_chip *nand = mtd_to_nand(mtd);

	ioread16_rep(nand->legacy.IO_ADDR_R, buf, len / 2);
}

/**
 * omap_write_buf16 - write buffer to NAND controller
 * @mtd: MTD device structure
 * @buf: data buffer
 * @len: number of bytes to write
 */
static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
{
	struct omap_nand_info *info = mtd_to_omap(mtd);
	u16 *p = (u16 *) buf;
	bool status;
	/* FIXME try bursts of writesw() or DMA ... */
	len >>= 1;

	while (len--) {
		iowrite16(*p++, info->nand.legacy.IO_ADDR_W);
		/* wait until buffer is available for write */
		do {
			status = info->ops->nand_writebuffer_empty();
		} while (!status);
	}
}

/**
 * omap_read_buf_pref - read data from NAND controller into buffer
 * @chip: NAND chip object
 * @buf: buffer to store date
 * @len: number of bytes to read
 */
static void omap_read_buf_pref(struct nand_chip *chip, u_char *buf, int len)
{
	struct mtd_info *mtd = nand_to_mtd(chip);
	struct omap_nand_info *info = mtd_to_omap(mtd);
	uint32_t r_count = 0;
	int ret = 0;
	u32 *p = (u32 *)buf;
	unsigned int pref_len;

	/* take care of subpage reads */
	if (len % 4) {
		if (info->nand.options & NAND_BUSWIDTH_16)
			omap_read_buf16(mtd, buf, len % 4);
		else
			omap_read_buf8(mtd, buf, len % 4);
		p = (u32 *) (buf + len % 4);
		len -= len % 4;
	if (force_8bit) {
		omap_nand_data_in(chip, buf, len, force_8bit);
		return;
	}

	/* read 32-bit words using prefetch and remaining bytes normally */

	/* configure and start prefetch transfer */
	pref_len = len - (len & 3);
	ret = omap_prefetch_enable(info->gpmc_cs,
			PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x0, info);
			PREFETCH_FIFOTHRESHOLD_MAX, 0x0, pref_len, 0x0, info);
	if (ret) {
		/* PFPW engine is busy, use cpu copy method */
		if (info->nand.options & NAND_BUSWIDTH_16)
			omap_read_buf16(mtd, (u_char *)p, len);
		else
			omap_read_buf8(mtd, (u_char *)p, len);
		/* prefetch engine is busy, use CPU copy method */
		omap_nand_data_in(chip, buf, len, false);
	} else {
		do {
			r_count = readl(info->reg.gpmc_prefetch_status);
			r_count = PREFETCH_STATUS_FIFO_CNT(r_count);
			r_count = r_count >> 2;
			ioread32_rep(info->nand.legacy.IO_ADDR_R, p, r_count);
			ioread32_rep(info->fifo, p, r_count);
			p += r_count;
			len -= r_count << 2;
		} while (len);
		/* disable and stop the PFPW engine */
			pref_len -= r_count << 2;
		} while (pref_len);
		/* disable and stop the Prefetch engine */
		omap_prefetch_reset(info->gpmc_cs, info);
		/* fetch any remaining bytes */
		if (len & 3)
			omap_nand_data_in(chip, p, len & 3, false);
	}
}

/**
 * omap_write_buf_pref - write buffer to NAND controller
 * @chip: NAND chip object
 * @buf: data buffer
 * @len: number of bytes to write
 * omap_nand_data_out_pref - NAND data out using Write Posting engine
 */
static void omap_write_buf_pref(struct nand_chip *chip, const u_char *buf,
				int len)
static void omap_nand_data_out_pref(struct nand_chip *chip,
				    const void *buf, unsigned int len,
				    bool force_8bit)
{
	struct mtd_info *mtd = nand_to_mtd(chip);
	struct omap_nand_info *info = mtd_to_omap(mtd);
	struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
	uint32_t w_count = 0;
	int i = 0, ret = 0;
	u16 *p = (u16 *)buf;
	unsigned long tim, limit;
	u32 val;

	if (force_8bit) {
		omap_nand_data_out(chip, buf, len, force_8bit);
		return;
	}

	/* take care of subpage writes */
	if (len % 2 != 0) {
		writeb(*buf, info->nand.legacy.IO_ADDR_W);
		writeb(*(u8 *)buf, info->fifo);
		p = (u16 *)(buf + 1);
		len--;
	}
@@ -412,18 +326,15 @@ static void omap_write_buf_pref(struct nand_chip *chip, const u_char *buf,
	ret = omap_prefetch_enable(info->gpmc_cs,
			PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x1, info);
	if (ret) {
		/* PFPW engine is busy, use cpu copy method */
		if (info->nand.options & NAND_BUSWIDTH_16)
			omap_write_buf16(mtd, (u_char *)p, len);
		else
			omap_write_buf8(mtd, (u_char *)p, len);
		/* write posting engine is busy, use CPU copy method */
		omap_nand_data_out(chip, buf, len, false);
	} else {
		while (len) {
			w_count = readl(info->reg.gpmc_prefetch_status);
			w_count = PREFETCH_STATUS_FIFO_CNT(w_count);
			w_count = w_count >> 1;
			for (i = 0; (i < w_count) && len; i++, len -= 2)
				iowrite16(*p++, info->nand.legacy.IO_ADDR_W);
				iowrite16(*p++, info->fifo);
		}
		/* wait for data to flushed-out before reset the prefetch */
		tim = 0;
@@ -451,15 +362,16 @@ static void omap_nand_dma_callback(void *data)

/*
 * omap_nand_dma_transfer: configure and start dma transfer
 * @mtd: MTD device structure
 * @chip: nand chip structure
 * @addr: virtual address in RAM of source/destination
 * @len: number of data bytes to be transferred
 * @is_write: flag for read/write operation
 */
static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
					unsigned int len, int is_write)
static inline int omap_nand_dma_transfer(struct nand_chip *chip,
					 const void *addr, unsigned int len,
					 int is_write)
{
	struct omap_nand_info *info = mtd_to_omap(mtd);
	struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
	struct dma_async_tx_descriptor *tx;
	enum dma_data_direction dir = is_write ? DMA_TO_DEVICE :
							DMA_FROM_DEVICE;
@@ -521,49 +433,41 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
out_copy_unmap:
	dma_unmap_sg(info->dma->device->dev, &sg, 1, dir);
out_copy:
	if (info->nand.options & NAND_BUSWIDTH_16)
		is_write == 0 ? omap_read_buf16(mtd, (u_char *) addr, len)
			: omap_write_buf16(mtd, (u_char *) addr, len);
	else
		is_write == 0 ? omap_read_buf8(mtd, (u_char *) addr, len)
			: omap_write_buf8(mtd, (u_char *) addr, len);
	is_write == 0 ? omap_nand_data_in(chip, (void *)addr, len, false)
		      : omap_nand_data_out(chip, addr, len, false);

	return 0;
}

/**
 * omap_read_buf_dma_pref - read data from NAND controller into buffer
 * @chip: NAND chip object
 * @buf: buffer to store date
 * @len: number of bytes to read
 * omap_nand_data_in_dma_pref - NAND data in using DMA and Prefetch
 */
static void omap_read_buf_dma_pref(struct nand_chip *chip, u_char *buf,
				   int len)
static void omap_nand_data_in_dma_pref(struct nand_chip *chip, void *buf,
				       unsigned int len, bool force_8bit)
{
	struct mtd_info *mtd = nand_to_mtd(chip);

	if (len <= mtd->oobsize)
		omap_read_buf_pref(chip, buf, len);
		omap_nand_data_in_pref(chip, buf, len, false);
	else
		/* start transfer in DMA mode */
		omap_nand_dma_transfer(mtd, buf, len, 0x0);
		omap_nand_dma_transfer(chip, buf, len, 0x0);
}

/**
 * omap_write_buf_dma_pref - write buffer to NAND controller
 * @chip: NAND chip object
 * @buf: data buffer
 * @len: number of bytes to write
 * omap_nand_data_out_dma_pref - NAND data out using DMA and write posting
 */
static void omap_write_buf_dma_pref(struct nand_chip *chip, const u_char *buf,
				    int len)
static void omap_nand_data_out_dma_pref(struct nand_chip *chip,
					const void *buf, unsigned int len,
					bool force_8bit)
{
	struct mtd_info *mtd = nand_to_mtd(chip);

	if (len <= mtd->oobsize)
		omap_write_buf_pref(chip, buf, len);
		omap_nand_data_out_pref(chip, buf, len, false);
	else
		/* start transfer in DMA mode */
		omap_nand_dma_transfer(mtd, (u_char *)buf, len, 0x1);
		omap_nand_dma_transfer(chip, buf, len, 0x1);
}

/*
@@ -587,13 +491,13 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev)
			bytes = info->buf_len;
		else if (!info->buf_len)
			bytes = 0;
		iowrite32_rep(info->nand.legacy.IO_ADDR_W, (u32 *)info->buf,
		iowrite32_rep(info->fifo, (u32 *)info->buf,
			      bytes >> 2);
		info->buf = info->buf + bytes;
		info->buf_len -= bytes;

	} else {
		ioread32_rep(info->nand.legacy.IO_ADDR_R, (u32 *)info->buf,
		ioread32_rep(info->fifo, (u32 *)info->buf,
			     bytes >> 2);
		info->buf = info->buf + bytes;

@@ -613,20 +517,17 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev)
}

/*
 * omap_read_buf_irq_pref - read data from NAND controller into buffer
 * @chip: NAND chip object
 * @buf: buffer to store date
 * @len: number of bytes to read
 * omap_nand_data_in_irq_pref - NAND data in using Prefetch and IRQ
 */
static void omap_read_buf_irq_pref(struct nand_chip *chip, u_char *buf,
				   int len)
static void omap_nand_data_in_irq_pref(struct nand_chip *chip, void *buf,
				       unsigned int len, bool force_8bit)
{
	struct mtd_info *mtd = nand_to_mtd(chip);
	struct omap_nand_info *info = mtd_to_omap(mtd);
	struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
	struct mtd_info *mtd = nand_to_mtd(&info->nand);
	int ret = 0;

	if (len <= mtd->oobsize) {
		omap_read_buf_pref(chip, buf, len);
	if (len <= mtd->oobsize || force_8bit) {
		omap_nand_data_in(chip, buf, len, force_8bit);
		return;
	}

@@ -637,9 +538,11 @@ static void omap_read_buf_irq_pref(struct nand_chip *chip, u_char *buf,
	/*  configure and start prefetch transfer */
	ret = omap_prefetch_enable(info->gpmc_cs,
			PREFETCH_FIFOTHRESHOLD_MAX/2, 0x0, len, 0x0, info);
	if (ret)
	if (ret) {
		/* PFPW engine is busy, use cpu copy method */
		goto out_copy;
		omap_nand_data_in(chip, buf, len, false);
		return;
	}

	info->buf_len = len;

@@ -652,31 +555,23 @@ static void omap_read_buf_irq_pref(struct nand_chip *chip, u_char *buf,
	/* disable and stop the PFPW engine */
	omap_prefetch_reset(info->gpmc_cs, info);
	return;

out_copy:
	if (info->nand.options & NAND_BUSWIDTH_16)
		omap_read_buf16(mtd, buf, len);
	else
		omap_read_buf8(mtd, buf, len);
}

/*
 * omap_write_buf_irq_pref - write buffer to NAND controller
 * @chip: NAND chip object
 * @buf: data buffer
 * @len: number of bytes to write
 * omap_nand_data_out_irq_pref - NAND out using write posting and IRQ
 */
static void omap_write_buf_irq_pref(struct nand_chip *chip, const u_char *buf,
				    int len)
static void omap_nand_data_out_irq_pref(struct nand_chip *chip,
					const void *buf, unsigned int len,
					bool force_8bit)
{
	struct mtd_info *mtd = nand_to_mtd(chip);
	struct omap_nand_info *info = mtd_to_omap(mtd);
	struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
	struct mtd_info *mtd = nand_to_mtd(&info->nand);
	int ret = 0;
	unsigned long tim, limit;
	u32 val;

	if (len <= mtd->oobsize) {
		omap_write_buf_pref(chip, buf, len);
	if (len <= mtd->oobsize || force_8bit) {
		omap_nand_data_out(chip, buf, len, force_8bit);
		return;
	}

@@ -687,9 +582,11 @@ static void omap_write_buf_irq_pref(struct nand_chip *chip, const u_char *buf,
	/* configure and start prefetch transfer : size=24 */
	ret = omap_prefetch_enable(info->gpmc_cs,
		(PREFETCH_FIFOTHRESHOLD_MAX * 3) / 8, 0x0, len, 0x1, info);
	if (ret)
	if (ret) {
		/* PFPW engine is busy, use cpu copy method */
		goto out_copy;
		omap_nand_data_out(chip, buf, len, false);
		return;
	}

	info->buf_len = len;

@@ -711,12 +608,6 @@ static void omap_write_buf_irq_pref(struct nand_chip *chip, const u_char *buf,
	/* disable and stop the PFPW engine */
	omap_prefetch_reset(info->gpmc_cs, info);
	return;

out_copy:
	if (info->nand.options & NAND_BUSWIDTH_16)
		omap_write_buf16(mtd, buf, len);
	else
		omap_write_buf8(mtd, buf, len);
}

/**
@@ -981,50 +872,6 @@ static void omap_enable_hwecc(struct nand_chip *chip, int mode)
	writel(val, info->reg.gpmc_ecc_config);
}

/**
 * omap_wait - wait until the command is done
 * @this: NAND Chip structure
 *
 * Wait function is called during Program and erase operations and
 * the way it is called from MTD layer, we should wait till the NAND
 * chip is ready after the programming/erase operation has completed.
 *
 * Erase can take up to 400ms and program up to 20ms according to
 * general NAND and SmartMedia specs
 */
static int omap_wait(struct nand_chip *this)
{
	struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(this));
	unsigned long timeo = jiffies;
	int status;

	timeo += msecs_to_jiffies(400);

	writeb(NAND_CMD_STATUS & 0xFF, info->reg.gpmc_nand_command);
	while (time_before(jiffies, timeo)) {
		status = readb(info->reg.gpmc_nand_data);
		if (status & NAND_STATUS_READY)
			break;
		cond_resched();
	}

	status = readb(info->reg.gpmc_nand_data);
	return status;
}

/**
 * omap_dev_ready - checks the NAND Ready GPIO line
 * @chip: NAND chip object
 *
 * Returns true if ready and false if busy.
 */
static int omap_dev_ready(struct nand_chip *chip)
{
	struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));

	return gpiod_get_value(info->ready_gpiod);
}

/**
 * omap_enable_hwecc_bch - Program GPMC to perform BCH ECC calculation
 * @chip: NAND chip object
@@ -1543,8 +1390,8 @@ static int omap_write_page_bch(struct nand_chip *chip, const uint8_t *buf,
		chip->ecc.hwctl(chip, NAND_ECC_WRITE);

		/* Write data */
		chip->legacy.write_buf(chip, buf + (eccpg * info->eccpg_size),
				       info->eccpg_size);
		info->data_out(chip, buf + (eccpg * info->eccpg_size),
			       info->eccpg_size, false);

		/* Update ecc vector from GPMC result registers */
		ret = omap_calculate_ecc_bch_multi(mtd,
@@ -1562,7 +1409,7 @@ static int omap_write_page_bch(struct nand_chip *chip, const uint8_t *buf,
	}

	/* Write ecc vector to OOB area */
	chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
	info->data_out(chip, chip->oob_poi, mtd->oobsize, false);

	return nand_prog_page_end_op(chip);
}
@@ -1607,8 +1454,8 @@ static int omap_write_subpage_bch(struct nand_chip *chip, u32 offset,
		chip->ecc.hwctl(chip, NAND_ECC_WRITE);

		/* Write data */
		chip->legacy.write_buf(chip, buf + (eccpg * info->eccpg_size),
				       info->eccpg_size);
		info->data_out(chip, buf + (eccpg * info->eccpg_size),
			       info->eccpg_size, false);

		for (step = 0; step < info->nsteps_per_eccpg; step++) {
			unsigned int base_step = eccpg * info->nsteps_per_eccpg;
@@ -1641,7 +1488,7 @@ static int omap_write_subpage_bch(struct nand_chip *chip, u32 offset,
	}

	/* write OOB buffer to NAND device */
	chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize);
	info->data_out(chip, chip->oob_poi, mtd->oobsize, false);

	return nand_prog_page_end_op(chip);
}
@@ -1984,8 +1831,8 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
	/* Re-populate low-level callbacks based on xfer modes */
	switch (info->xfer_type) {
	case NAND_OMAP_PREFETCH_POLLED:
		chip->legacy.read_buf = omap_read_buf_pref;
		chip->legacy.write_buf = omap_write_buf_pref;
		info->data_in = omap_nand_data_in_pref;
		info->data_out = omap_nand_data_out_pref;
		break;

	case NAND_OMAP_POLLED:
@@ -2017,8 +1864,9 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
					err);
				return err;
			}
			chip->legacy.read_buf = omap_read_buf_dma_pref;
			chip->legacy.write_buf = omap_write_buf_dma_pref;

			info->data_in = omap_nand_data_in_dma_pref;
			info->data_out = omap_nand_data_out_dma_pref;
		}
		break;

@@ -2049,9 +1897,8 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
			return err;
		}

		chip->legacy.read_buf = omap_read_buf_irq_pref;
		chip->legacy.write_buf = omap_write_buf_irq_pref;

		info->data_in = omap_nand_data_in_irq_pref;
		info->data_out = omap_nand_data_out_irq_pref;
		break;

	default:
@@ -2217,8 +2064,105 @@ static int omap_nand_attach_chip(struct nand_chip *chip)
	return 0;
}

static void omap_nand_data_in(struct nand_chip *chip, void *buf,
			      unsigned int len, bool force_8bit)
{
	struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
	u32 alignment = ((uintptr_t)buf | len) & 3;

	if (force_8bit || (alignment & 1))
		ioread8_rep(info->fifo, buf, len);
	else if (alignment & 3)
		ioread16_rep(info->fifo, buf, len >> 1);
	else
		ioread32_rep(info->fifo, buf, len >> 2);
}

static void omap_nand_data_out(struct nand_chip *chip,
			       const void *buf, unsigned int len,
			       bool force_8bit)
{
	struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
	u32 alignment = ((uintptr_t)buf | len) & 3;

	if (force_8bit || (alignment & 1))
		iowrite8_rep(info->fifo, buf, len);
	else if (alignment & 3)
		iowrite16_rep(info->fifo, buf, len >> 1);
	else
		iowrite32_rep(info->fifo, buf, len >> 2);
}

static int omap_nand_exec_instr(struct nand_chip *chip,
				const struct nand_op_instr *instr)
{
	struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip));
	unsigned int i;
	int ret;

	switch (instr->type) {
	case NAND_OP_CMD_INSTR:
		iowrite8(instr->ctx.cmd.opcode,
			 info->reg.gpmc_nand_command);
		break;

	case NAND_OP_ADDR_INSTR:
		for (i = 0; i < instr->ctx.addr.naddrs; i++) {
			iowrite8(instr->ctx.addr.addrs[i],
				 info->reg.gpmc_nand_address);
		}
		break;

	case NAND_OP_DATA_IN_INSTR:
		info->data_in(chip, instr->ctx.data.buf.in,
			      instr->ctx.data.len,
			      instr->ctx.data.force_8bit);
		break;

	case NAND_OP_DATA_OUT_INSTR:
		info->data_out(chip, instr->ctx.data.buf.out,
			       instr->ctx.data.len,
			       instr->ctx.data.force_8bit);
		break;

	case NAND_OP_WAITRDY_INSTR:
		ret = info->ready_gpiod ?
			nand_gpio_waitrdy(chip, info->ready_gpiod, instr->ctx.waitrdy.timeout_ms) :
			nand_soft_waitrdy(chip, instr->ctx.waitrdy.timeout_ms);
		if (ret)
			return ret;
		break;
	}

	if (instr->delay_ns)
		ndelay(instr->delay_ns);

	return 0;
}

static int omap_nand_exec_op(struct nand_chip *chip,
			     const struct nand_operation *op,
			     bool check_only)
{
	unsigned int i;

	if (check_only)
		return 0;

	for (i = 0; i < op->ninstrs; i++) {
		int ret;

		ret = omap_nand_exec_instr(chip, &op->instrs[i]);
		if (ret)
			return ret;
	}

	return 0;
}

static const struct nand_controller_ops omap_nand_controller_ops = {
	.attach_chip = omap_nand_attach_chip,
	.exec_op = omap_nand_exec_op,
};

/* Shared among all NAND instances to synchronize access to the ECC Engine */
@@ -2233,6 +2177,7 @@ static int omap_nand_probe(struct platform_device *pdev)
	int				err;
	struct resource			*res;
	struct device			*dev = &pdev->dev;
	void __iomem *vaddr;

	info = devm_kzalloc(&pdev->dev, sizeof(struct omap_nand_info),
				GFP_KERNEL);
@@ -2266,10 +2211,11 @@ static int omap_nand_probe(struct platform_device *pdev)
	}

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	nand_chip->legacy.IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(nand_chip->legacy.IO_ADDR_R))
		return PTR_ERR(nand_chip->legacy.IO_ADDR_R);
	vaddr = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(vaddr))
		return PTR_ERR(vaddr);

	info->fifo = vaddr;
	info->phys_base = res->start;

	if (!omap_gpmc_controller_initialized) {
@@ -2280,9 +2226,6 @@ static int omap_nand_probe(struct platform_device *pdev)

	nand_chip->controller = &omap_gpmc_controller;

	nand_chip->legacy.IO_ADDR_W = nand_chip->legacy.IO_ADDR_R;
	nand_chip->legacy.cmd_ctrl  = omap_hwcontrol;

	info->ready_gpiod = devm_gpiod_get_optional(&pdev->dev, "rb",
						    GPIOD_IN);
	if (IS_ERR(info->ready_gpiod)) {
@@ -2290,27 +2233,16 @@ static int omap_nand_probe(struct platform_device *pdev)
		return PTR_ERR(info->ready_gpiod);
	}

	/*
	 * If RDY/BSY line is connected to OMAP then use the omap ready
	 * function and the generic nand_wait function which reads the status
	 * register after monitoring the RDY/BSY line. Otherwise use a standard
	 * chip delay which is slightly more than tR (AC Timing) of the NAND
	 * device and read status register until you get a failure or success
	 */
	if (info->ready_gpiod) {
		nand_chip->legacy.dev_ready = omap_dev_ready;
		nand_chip->legacy.chip_delay = 0;
	} else {
		nand_chip->legacy.waitfunc = omap_wait;
		nand_chip->legacy.chip_delay = 50;
	}

	if (info->flash_bbt)
		nand_chip->bbt_options |= NAND_BBT_USE_FLASH;

	/* scan NAND device connected to chip controller */
	nand_chip->options |= info->devsize & NAND_BUSWIDTH_16;

	/* default operations */
	info->data_in = omap_nand_data_in;
	info->data_out = omap_nand_data_out;

	err = nand_scan(nand_chip, 1);
	if (err)
		goto return_error;