summaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/raw/tango_nand.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-08-09 12:38:51 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2020-08-09 12:38:51 -0700
commitdec1fbbc1d7c46aed9fc1d3ee1f7f4fc04d6ed51 (patch)
treea2d88e9bb259c7866be2129dedf77a828ca8911a /drivers/mtd/nand/raw/tango_nand.c
parent71fa1a4489ff93ac4acd7e6c5b00098ba53a4485 (diff)
parent6a1380271b75e0d9a961e192e56b733fedf7a23a (diff)
downloadlinux-dec1fbbc1d7c46aed9fc1d3ee1f7f4fc04d6ed51.tar.bz2
Merge tag 'mtd/for-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux
Pull mtd updates from Miquel Raynal: "MTD core changes: - Spelling - http to https updates NAND core changes: - Drop useless 'depends on' in Kconfig - Add an extra level in the Kconfig hierarchy - Trivial spellings - Dynamic allocation of the interface configurations - Dropping the default ONFI timing mode - Various cleanup (types, structures, naming, comments) - Hide the chip->data_interface indirection - Add the generic rb-gpios property - Add the ->choose_interface_config() hook - Introduce nand_choose_best_sdr_timings() - Use default values for tPROG_max and tBERS_max - Avoid redefining tR_max and tCCS_min - Add a helper to find the closest ONFI mode - bcm63xx MTD parsers: simplify CFE detection Raw NAND controller drivers changes: - fsl-upm: Deprecation of specific DT properties - fsl_upm: Driver rework and cleanup in favor of ->exec_op() - Ingenic: Cleanup ARRAY_SIZE() vs sizeof() use - brcmnand: ECC error handling on EDU transfers - brcmnand: Don't default to EDU transfers - qcom: Set BAM mode only if not set already - qcom: Avoid write to unavailable register - gpio: Driver rework in favor of ->exec_op() - tango: ->exec_op() conversion - mtk: ->exec_op() conversion Raw NAND chip drivers changes: - toshiba: Implement ->choose_interface_config() for TH58NVG2S3HBAI4, TC58NVG0S3E, and TC58TEG5DCLTA00 - hynix: Implement ->choose_interface_config() for H27UCG8T2ATR-BC SPI NOR core changes: - Disable Quad Mode in spi_nor_restore(). - Don't abort BFPT parsing when QER reserved value is used. - Add support/update capabilities for few flashes. - Drop s70fl01gs flash: it does not support RDSR(05h) which is critical for erase/write. - Merge the SPIMEM DTR bits in spi-nor/next to avoid conflicts during the release cycle. SPI NOR controller drivers changes: - Move the cadence-quadspi driver to spi-mem. The series was taken through the SPI tree. Merge it also in spi-nor/next to avoid conflicts during the release cycle. - intel-spi: - Add new PCI IDs. - Ignore the Write Disable command, the controller doesn't support it. - Fix performance regression" * tag 'mtd/for-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux: (79 commits) MTD: pfow.h: drop a duplicated word MTD: mtd-abi.h: drop a duplicated word mtd: rawnand: omap_elm: Replace HTTP links with HTTPS ones mtd: Replace HTTP links with HTTPS ones mtd: hyperbus: Replace HTTP links with HTTPS ones mtd: revert "spi-nor: intel: provide a range for poll_timout" mtd: spi-nor: update read capabilities for w25q64 and s25fl064k mtd: spi-nor: micron: Add SPI_NOR_DUAL_READ flag on mt25qu02g mtd: spi-nor: macronix: Add support for mx66u2g45g mtd: spi-nor: intel-spi: Simulate WRDI command mtd: spi-nor: Disable the flash quad mode in spi_nor_restore() mtd: spi-nor: Add capability to disable flash quad mode mtd: spi-nor: spansion: Remove s70fl01gs from flash_info mtd: spi-nor: sfdp: do not make invalid quad enable fatal dt-bindings: mtd: fsl-upm-nand: Deprecate chip-delay and fsl, upm-wait-flags mtd: rawnand: stm32_fmc2: get resources from parent node mtd: rawnand: stm32_fmc2: use regmap APIs memory: stm32-fmc2-ebi: add STM32 FMC2 EBI controller driver dt-bindings: memory-controller: add STM32 FMC2 EBI controller documentation dt-bindings: mtd: update STM32 FMC2 NAND controller documentation ...
Diffstat (limited to 'drivers/mtd/nand/raw/tango_nand.c')
-rw-r--r--drivers/mtd/nand/raw/tango_nand.c129
1 files changed, 81 insertions, 48 deletions
diff --git a/drivers/mtd/nand/raw/tango_nand.c b/drivers/mtd/nand/raw/tango_nand.c
index 246871e01027..bdb965ae7a4a 100644
--- a/drivers/mtd/nand/raw/tango_nand.c
+++ b/drivers/mtd/nand/raw/tango_nand.c
@@ -113,59 +113,80 @@ struct tango_chip {
#define TIMING(t0, t1, t2, t3) ((t0) << 24 | (t1) << 16 | (t2) << 8 | (t3))
-static void tango_cmd_ctrl(struct nand_chip *chip, int dat, unsigned int ctrl)
+static void tango_select_target(struct nand_chip *chip, unsigned int cs)
{
+ struct tango_nfc *nfc = to_tango_nfc(chip->controller);
struct tango_chip *tchip = to_tango_chip(chip);
- if (ctrl & NAND_CLE)
- writeb_relaxed(dat, tchip->base + PBUS_CMD);
-
- if (ctrl & NAND_ALE)
- writeb_relaxed(dat, tchip->base + PBUS_ADDR);
+ writel_relaxed(tchip->timing1, nfc->reg_base + NFC_TIMING1);
+ writel_relaxed(tchip->timing2, nfc->reg_base + NFC_TIMING2);
+ writel_relaxed(tchip->xfer_cfg, nfc->reg_base + NFC_XFER_CFG);
+ writel_relaxed(tchip->pkt_0_cfg, nfc->reg_base + NFC_PKT_0_CFG);
+ writel_relaxed(tchip->pkt_n_cfg, nfc->reg_base + NFC_PKT_N_CFG);
+ writel_relaxed(tchip->bb_cfg, nfc->reg_base + NFC_BB_CFG);
}
-static int tango_dev_ready(struct nand_chip *chip)
+static int tango_waitrdy(struct nand_chip *chip, unsigned int timeout_ms)
{
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
+ u32 status;
- return readl_relaxed(nfc->pbus_base + PBUS_CS_CTRL) & PBUS_IORDY;
+ return readl_relaxed_poll_timeout(nfc->pbus_base + PBUS_CS_CTRL,
+ status, status & PBUS_IORDY, 20,
+ timeout_ms);
}
-static u8 tango_read_byte(struct nand_chip *chip)
+static int tango_exec_instr(struct nand_chip *chip,
+ const struct nand_op_instr *instr)
{
struct tango_chip *tchip = to_tango_chip(chip);
+ unsigned int i;
- return readb_relaxed(tchip->base + PBUS_DATA);
-}
-
-static void tango_read_buf(struct nand_chip *chip, u8 *buf, int len)
-{
- struct tango_chip *tchip = to_tango_chip(chip);
+ switch (instr->type) {
+ case NAND_OP_CMD_INSTR:
+ writeb_relaxed(instr->ctx.cmd.opcode, tchip->base + PBUS_CMD);
+ return 0;
+ case NAND_OP_ADDR_INSTR:
+ for (i = 0; i < instr->ctx.addr.naddrs; i++)
+ writeb_relaxed(instr->ctx.addr.addrs[i],
+ tchip->base + PBUS_ADDR);
+ return 0;
+ case NAND_OP_DATA_IN_INSTR:
+ ioread8_rep(tchip->base + PBUS_DATA, instr->ctx.data.buf.in,
+ instr->ctx.data.len);
+ return 0;
+ case NAND_OP_DATA_OUT_INSTR:
+ iowrite8_rep(tchip->base + PBUS_DATA, instr->ctx.data.buf.out,
+ instr->ctx.data.len);
+ return 0;
+ case NAND_OP_WAITRDY_INSTR:
+ return tango_waitrdy(chip,
+ instr->ctx.waitrdy.timeout_ms);
+ default:
+ break;
+ }
- ioread8_rep(tchip->base + PBUS_DATA, buf, len);
+ return -EINVAL;
}
-static void tango_write_buf(struct nand_chip *chip, const u8 *buf, int len)
+static int tango_exec_op(struct nand_chip *chip,
+ const struct nand_operation *op,
+ bool check_only)
{
- struct tango_chip *tchip = to_tango_chip(chip);
-
- iowrite8_rep(tchip->base + PBUS_DATA, buf, len);
-}
+ unsigned int i;
+ int ret = 0;
-static void tango_select_chip(struct nand_chip *chip, int idx)
-{
- struct tango_nfc *nfc = to_tango_nfc(chip->controller);
- struct tango_chip *tchip = to_tango_chip(chip);
+ if (check_only)
+ return 0;
- if (idx < 0)
- return; /* No "chip unselect" function */
+ tango_select_target(chip, op->cs);
+ for (i = 0; i < op->ninstrs; i++) {
+ ret = tango_exec_instr(chip, &op->instrs[i]);
+ if (ret)
+ break;
+ }
- writel_relaxed(tchip->timing1, nfc->reg_base + NFC_TIMING1);
- writel_relaxed(tchip->timing2, nfc->reg_base + NFC_TIMING2);
- writel_relaxed(tchip->xfer_cfg, nfc->reg_base + NFC_XFER_CFG);
- writel_relaxed(tchip->pkt_0_cfg, nfc->reg_base + NFC_PKT_0_CFG);
- writel_relaxed(tchip->pkt_n_cfg, nfc->reg_base + NFC_PKT_N_CFG);
- writel_relaxed(tchip->bb_cfg, nfc->reg_base + NFC_BB_CFG);
+ return ret;
}
/*
@@ -279,6 +300,7 @@ static int tango_read_page(struct nand_chip *chip, u8 *buf,
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
int err, res, len = mtd->writesize;
+ tango_select_target(chip, chip->cur_cs);
if (oob_required)
chip->ecc.read_oob(chip, page);
@@ -300,22 +322,30 @@ static int tango_write_page(struct nand_chip *chip, const u8 *buf,
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
- int err, status, len = mtd->writesize;
+ const struct nand_sdr_timings *timings;
+ int err, len = mtd->writesize;
+ u8 status;
/* Calling tango_write_oob() would send PAGEPROG twice */
if (oob_required)
return -ENOTSUPP;
+ tango_select_target(chip, chip->cur_cs);
writel_relaxed(0xffffffff, nfc->mem_base + METADATA);
err = do_dma(nfc, DMA_TO_DEVICE, NFC_WRITE, buf, len, page);
if (err)
return err;
- status = chip->legacy.waitfunc(chip);
- if (status & NAND_STATUS_FAIL)
- return -EIO;
+ timings = nand_get_sdr_timings(nand_get_interface_config(chip));
+ err = tango_waitrdy(chip, PSEC_TO_MSEC(timings->tR_max));
+ if (err)
+ return err;
- return 0;
+ err = nand_status_op(chip, &status);
+ if (err)
+ return err;
+
+ return (status & NAND_STATUS_FAIL) ? -EIO : 0;
}
static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
@@ -326,7 +356,9 @@ static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos)
/* skip over "len" bytes */
nand_change_read_column_op(chip, *pos, NULL, 0, false);
} else {
- tango_read_buf(chip, *buf, len);
+ struct tango_chip *tchip = to_tango_chip(chip);
+
+ ioread8_rep(tchip->base + PBUS_DATA, *buf, len);
*buf += len;
}
}
@@ -339,7 +371,9 @@ static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos)
/* skip over "len" bytes */
nand_change_write_column_op(chip, *pos, NULL, 0, false);
} else {
- tango_write_buf(chip, *buf, len);
+ struct tango_chip *tchip = to_tango_chip(chip);
+
+ iowrite8_rep(tchip->base + PBUS_DATA, *buf, len);
*buf += len;
}
}
@@ -420,6 +454,7 @@ static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob)
static int tango_read_page_raw(struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
+ tango_select_target(chip, chip->cur_cs);
nand_read_page_op(chip, page, 0, NULL, 0);
raw_read(chip, buf, chip->oob_poi);
return 0;
@@ -428,6 +463,7 @@ static int tango_read_page_raw(struct nand_chip *chip, u8 *buf,
static int tango_write_page_raw(struct nand_chip *chip, const u8 *buf,
int oob_required, int page)
{
+ tango_select_target(chip, chip->cur_cs);
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
raw_write(chip, buf, chip->oob_poi);
return nand_prog_page_end_op(chip);
@@ -435,6 +471,7 @@ static int tango_write_page_raw(struct nand_chip *chip, const u8 *buf,
static int tango_read_oob(struct nand_chip *chip, int page)
{
+ tango_select_target(chip, chip->cur_cs);
nand_read_page_op(chip, page, 0, NULL, 0);
raw_read(chip, NULL, chip->oob_poi);
return 0;
@@ -442,6 +479,7 @@ static int tango_read_oob(struct nand_chip *chip, int page)
static int tango_write_oob(struct nand_chip *chip, int page)
{
+ tango_select_target(chip, chip->cur_cs);
nand_prog_page_begin_op(chip, page, 0, NULL, 0);
raw_write(chip, NULL, chip->oob_poi);
return nand_prog_page_end_op(chip);
@@ -477,7 +515,7 @@ static u32 to_ticks(int kHz, int ps)
}
static int tango_set_timings(struct nand_chip *chip, int csline,
- const struct nand_data_interface *conf)
+ const struct nand_interface_config *conf)
{
const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf);
struct tango_nfc *nfc = to_tango_nfc(chip->controller);
@@ -527,7 +565,8 @@ static int tango_attach_chip(struct nand_chip *chip)
static const struct nand_controller_ops tango_controller_ops = {
.attach_chip = tango_attach_chip,
- .setup_data_interface = tango_set_timings,
+ .setup_interface = tango_set_timings,
+ .exec_op = tango_exec_op,
};
static int chip_init(struct device *dev, struct device_node *np)
@@ -562,12 +601,6 @@ static int chip_init(struct device *dev, struct device_node *np)
ecc = &chip->ecc;
mtd = nand_to_mtd(chip);
- chip->legacy.read_byte = tango_read_byte;
- chip->legacy.write_buf = tango_write_buf;
- chip->legacy.read_buf = tango_read_buf;
- chip->legacy.select_chip = tango_select_chip;
- chip->legacy.cmd_ctrl = tango_cmd_ctrl;
- chip->legacy.dev_ready = tango_dev_ready;
chip->options = NAND_USES_DMA |
NAND_NO_SUBPAGE_WRITE |
NAND_WAIT_TCCS;