[PATCH] mtd: rawnand: cache read suquential
JaimeLiao
jaimeliao.tw at gmail.com
Thu Jan 6 00:10:43 PST 2022
For reducing time of read sequence which address are continuous.
Adding cache read suquential features in raw nand existing architecture.
Creating nand_exec_continue_read_page_op function for read command extend.
Adding command select in nand_lp_exec_read_page_op and taking readlen to
judge the last page for read.
Command of read cache sequential can be separate 3 parts.
First part is 00-30-31, it means read cache sequential enabled and next
page data can be prepare while cache data reading.
Second part is 31-3F, means flash will prepare next page data for reducing
time cost.
Last part is 3F, means the last cache read and flash don't need to prepare
next page data.
Signed-off-by: JaimeLiao <jaimeliao.tw at gmail.com>
---
drivers/mtd/nand/raw/nand_base.c | 95 ++++++++++++++++++++++++++++++--
include/linux/mtd/rawnand.h | 5 ++
2 files changed, 95 insertions(+), 5 deletions(-)
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 3d6c6e880520..ddaba40b58a7 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -1176,6 +1176,39 @@ static int nand_lp_exec_read_page_op(struct nand_chip *chip, unsigned int page,
const struct nand_interface_config *conf =
nand_get_interface_config(chip);
u8 addrs[5];
+
+ /* Command sequence select to 00-30-31 when read cache sequential is enabled */
+ if (chip->ops.conti_read_require) {
+ struct nand_op_instr instrs[] = {
+ NAND_OP_CMD(NAND_CMD_READ0, 0),
+ NAND_OP_ADDR(4, addrs, 0),
+ NAND_OP_CMD(NAND_CMD_READSTART, NAND_COMMON_TIMING_NS(conf, tWB_max)),
+ NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tR_max), 0),
+ NAND_OP_CMD(NAND_CMD_READCONTI, NAND_COMMON_TIMING_NS(conf, tWB_max)),
+ NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tR_max),
+ NAND_COMMON_TIMING_NS(conf, tRR_min)),
+ NAND_OP_DATA_IN(len, buf, 0),
+ };
+ struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
+ int ret;
+
+ if (!len)
+ op.ninstrs--;
+
+ ret = nand_fill_column_cycles(chip, addrs, offset_in_page);
+ if (ret < 0)
+ return ret;
+
+ addrs[2] = page;
+ addrs[3] = page >> 8;
+
+ if (chip->options & NAND_ROW_ADDR_3) {
+ addrs[4] = page >> 16;
+ instrs[1].ctx.addr.naddrs++;
+ }
+
+ return nand_exec_op(chip, &op);
+ }
struct nand_op_instr instrs[] = {
NAND_OP_CMD(NAND_CMD_READ0, 0),
NAND_OP_ADDR(4, addrs, 0),
@@ -1206,6 +1239,31 @@ static int nand_lp_exec_read_page_op(struct nand_chip *chip, unsigned int page,
return nand_exec_op(chip, &op);
}
+static int nand_exec_continue_read_page_op(struct nand_chip *chip,
+ void *buf, unsigned int len)
+{
+ bool conti_read_last = false;
+ const struct nand_interface_config *conf =
+ nand_get_interface_config(chip);
+ /* Set conti_read_last true before the last aligned page reading */
+ if (chip->ops.conti_readlen >= len && chip->ops.conti_readlen < 2*len)
+ conti_read_last = true;
+ struct nand_op_instr instrs[] = {
+ NAND_OP_CMD(conti_read_last?NAND_CMD_READLAST:NAND_CMD_READCONTI,
+ NAND_COMMON_TIMING_NS(conf, tWB_max)),
+ NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tR_max),
+ NAND_COMMON_TIMING_NS(conf, tRR_min)),
+ NAND_OP_DATA_IN(len, buf, 0),
+ };
+ struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
+
+ /* Drop the DATA_IN instruction if len is set to 0. */
+ if (!len)
+ op.ninstrs--;
+
+ return nand_exec_op(chip, &op);
+}
+
/**
* nand_read_page_op - Do a READ PAGE operation
* @chip: The NAND chip
@@ -1231,10 +1289,15 @@ int nand_read_page_op(struct nand_chip *chip, unsigned int page,
return -EINVAL;
if (nand_has_exec_op(chip)) {
- if (mtd->writesize > 512)
- return nand_lp_exec_read_page_op(chip, page,
- offset_in_page, buf,
- len);
+ if (mtd->writesize > 512) {
+ /* Selecting read command sequence */
+ if (!chip->ops.conti_read_first_page && chip->ops.conti_read_require)
+ return nand_exec_continue_read_page_op(chip, buf, mtd->writesize);
+ else
+ return nand_lp_exec_read_page_op(chip, page,
+ offset_in_page, buf,
+ len);
+ }
return nand_sp_exec_read_page_op(chip, page, offset_in_page,
buf, len);
@@ -3362,7 +3425,6 @@ static int nand_do_read_ops(struct nand_chip *chip, loff_t from,
bytes = min(mtd->writesize - col, readlen);
aligned = (bytes == mtd->writesize);
-
if (!aligned)
use_bounce_buf = 1;
else if (chip->options & NAND_USES_DMA)
@@ -3381,6 +3443,25 @@ static int nand_do_read_ops(struct nand_chip *chip, loff_t from,
__func__, buf);
read_retry:
+ /*
+ * Read cache sequential command can be separate 3 parts.
+ * For distinguishing that flash driver set value to
+ * conti_read_first_page for checking whether the first page
+ * and set conti_read_require to select command sequence.
+ * And take readlen to conti_readlen for checking whether the
+ * last page or not.
+ */
+ if (!col && readlen >= (2*mtd->writesize)) {
+ if (chip->ops.conti_read_require == 0)
+ chip->ops.conti_read_first_page = 1;
+ else
+ chip->ops.conti_read_first_page = 0;
+ chip->ops.conti_read_require = 1;
+ chip->ops.conti_readlen = readlen;
+ } else if (chip->ops.conti_read_require) {
+ chip->ops.conti_read_first_page = 0;
+ chip->ops.conti_readlen = readlen;
+ }
/*
* Now read the page into the buffer. Absent an error,
* the read methods return max bitflips per ecc step.
@@ -3468,6 +3549,10 @@ static int nand_do_read_ops(struct nand_chip *chip, loff_t from,
retry_mode = 0;
}
+ /* set conti_read_require 0 when finish the last aligned page read */
+ if (readlen < mtd->writesize)
+ chip->ops.conti_read_require = 0;
+
if (!readlen)
break;
diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
index b2f9dd3cbd69..a5dccccdf65e 100644
--- a/include/linux/mtd/rawnand.h
+++ b/include/linux/mtd/rawnand.h
@@ -67,6 +67,8 @@ struct gpio_desc;
/* Extended commands for large page devices */
#define NAND_CMD_READSTART 0x30
+#define NAND_CMD_READCONTI 0x31
+#define NAND_CMD_READLAST 0x3f
#define NAND_CMD_RNDOUTSTART 0xE0
#define NAND_CMD_CACHEDPROG 0x15
@@ -1173,6 +1175,9 @@ struct nand_chip_ops {
int (*setup_read_retry)(struct nand_chip *chip, int retry_mode);
int (*choose_interface_config)(struct nand_chip *chip,
struct nand_interface_config *iface);
+ bool conti_read_require;
+ bool conti_read_first_page;
+ int conti_readlen;
};
/**
--
2.17.1
More information about the linux-mtd
mailing list