mtd: rawnand: omap2: move to exec_op interface

Stop using legacy interface and move to the exec_op interface.

Signed-off-by: Roger Quadros <rogerq@kernel.org>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20211209090458.24830-4-rogerq@kernel.org
This commit is contained in:
Roger Quadros
2021-12-09 11:04:55 +02:00
committed by Miquel Raynal
parent 35da0c4545
commit a9e849efca

View File

@@ -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;