[PATCH v2 1/1] mtd: rawnand: Cache read sequential

JaimeLiao jaimeliao.tw at gmail.com
Mon Aug 29 00:24:52 PDT 2022


For reducing instruction in command operation and time of read sequence
which address are continuous.
Adding cache read sequential feature support 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-ADDR-30-31-DATA_IN, it means read cache sequential enabled and next
page data can be prepare while cache data reading.

Second part is 31-DATA_IN, means flash will prepare next page data for reducing
time cost.

Last part is 3F-DATA_IN, means the last cache read and flash don't need to prepare
next page data.

Example for 2 page read operation, as below is the NAND operation instructions:
Normal read mode:
        00 -- ADDR1 -- 30 -- WAIT_RDY(tR+tRR) -- DATA1_IN
        00 -- ADDR2 -- 30 -- WAIT_RDY(tR+tRR) -- DATA2_IN

Cache read sequential mode:
        00 -- ADDR1 -- 30 -- WAIT_RDY(tR) -- 31 -- WAIT_RDY(tRCBSY+tRR) -- DATA1_IN
        3F -- WAIT_RDY(tRCBSY+tRR) -- DATA2_IN

tR     is about 20 microsecond
tRCBSY is about 5 microsecond
tRR    is about 20 nanosecond

As below is mtd_speedtest result between normale read and cache read
sequential on NXP i.MX6 VAR-SOM-SOLO mapping mode.

===============Normal read 33M===================
mtd_speedtest: MTD device: 0
mtd_speedtest: MTD device size 2097152, eraseblock size 131072, page size 2048,
count of eraseblocks 16, pages per eraseblock 64, OOB size 64
mtd_test: scanning for bad eraseblocks
mtd_test: scanned 16 eraseblocks, 0 are bad
mtd_speedtest: testing eraseblock write speed
mtd_speedtest: eraseblock write speed is 3864 KiB/s
mtd_speedtest: testing eraseblock read speed
mtd_speedtest: eraseblock read speed is 15633 KiB/s
mtd_speedtest: testing page write speed
mtd_speedtest: page write speed is 3561 KiB/s
mtd_speedtest: testing page read speed
mtd_speedtest: page read speed is 15515 KiB/s
mtd_speedtest: testing 2 page write speed
mtd_speedtest: 2 page write speed is 3690 KiB/s
mtd_speedtest: testing 2 page read speed
mtd_speedtest: 2 page read speed is 15398 KiB/s
mtd_speedtest: Testing erase speed
mtd_speedtest: erase speed is 227555 KiB/s
mtd_speedtest: Testing 2x multi-block erase speed
mtd_speedtest: 2x multi-block erase speed is 204800 KiB/s
mtd_speedtest: Testing 4x multi-block erase speed
mtd_speedtest: 4x multi-block erase speed is 204800 KiB/s
mtd_speedtest: Testing 8x multi-block erase speed
mtd_speedtest: 8x multi-block erase speed is 204800 KiB/s
mtd_speedtest: Testing 16x multi-block erase speed
mtd_speedtest: 16x multi-block erase speed is 204800 KiB/s
mtd_speedtest: Testing 32x multi-block erase speed
mtd_speedtest: 32x multi-block erase speed is 204800 KiB/s
mtd_speedtest: Testing 64x multi-block erase speed
mtd_speedtest: 64x multi-block erase speed is 227555 KiB/s
mtd_speedtest: finished
=================================================

============Cache reade Sequential 33MHz===========
mtd_speedtest: MTD device: 0
mtd_speedtest: MTD device size 2097152, eraseblock size 131072, page size 2048,
count of eraseblocks 16, pages per eraseblock 64, OOB size 64
mtd_test: scanning for bad eraseblocks
mtd_test: scanned 16 eraseblocks, 0 are bad
mtd_speedtest: testing eraseblock write speed
mtd_speedtest: eraseblock write speed is 4120 KiB/s
mtd_speedtest: testing eraseblock read speed
mtd_speedtest: eraseblock read speed is 18285 KiB/s
mtd_speedtest: testing page write speed
mtd_speedtest: page write speed is 4031 KiB/s
mtd_speedtest: testing page read speed
mtd_speedtest: page read speed is 15875 KiB/s
mtd_speedtest: testing 2 page write speed
mtd_speedtest: 2 page write speed is 3946 KiB/s
mtd_speedtest: testing 2 page read speed
mtd_speedtest: 2 page read speed is 16253 KiB/s
mtd_speedtest: Testing erase speed
mtd_speedtest: erase speed is 227555 KiB/s
mtd_speedtest: Testing 2x multi-block erase speed
mtd_speedtest: 2x multi-block erase speed is 227555 KiB/s
mtd_speedtest: Testing 4x multi-block erase speed
mtd_speedtest: 4x multi-block erase speed is 204800 KiB/s
mtd_speedtest: Testing 8x multi-block erase speed
mtd_speedtest: 8x multi-block erase speed is 204800 KiB/s
mtd_speedtest: Testing 16x multi-block erase speed
mtd_speedtest: 16x multi-block erase speed is 227555 KiB/s
mtd_speedtest: Testing 32x multi-block erase speed
mtd_speedtest: 32x multi-block erase speed is 204800 KiB/s
mtd_speedtest: Testing 64x multi-block erase speed
mtd_speedtest: 64x multi-block erase speed is 204800 KiB/s
mtd_speedtest: finished
=================================================

The result could have about 5% improvement between 2 modes when 2 pages read.

Signed-off-by: JaimeLiao <jaimeliao.tw at gmail.com>
---
 drivers/mtd/nand/raw/nand_base.c    | 96 +++++++++++++++++++++++++++--
 drivers/mtd/nand/raw/nand_timings.c | 12 ++++
 include/linux/mtd/rawnand.h         |  7 +++
 3 files changed, 110 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 3d6c6e880520..7400816f0627 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, tRCBSY_min),
+					 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,32 @@ 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)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	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 >= mtd->writesize && chip->ops.conti_readlen < 2*mtd->writesize)
+		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, tRCBSY_min),
+				 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 +1290,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, len);
+			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 +3426,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 +3444,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 +3550,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/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c
index 7b41afc372d2..cec5d9e526fe 100644
--- a/drivers/mtd/nand/raw/nand_timings.c
+++ b/drivers/mtd/nand/raw/nand_timings.c
@@ -27,6 +27,7 @@ static const struct nand_interface_config onfi_sdr_timings[] = {
 		.timings.sdr = {
 			.tCCS_min = 500000,
 			.tR_max = 200000000,
+			.tRCBSY_min = 40000000,
 			.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
 			.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
 			.tADL_min = 400000,
@@ -72,6 +73,7 @@ static const struct nand_interface_config onfi_sdr_timings[] = {
 		.timings.sdr = {
 			.tCCS_min = 500000,
 			.tR_max = 200000000,
+			.tRCBSY_min = 40000000,
 			.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
 			.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
 			.tADL_min = 400000,
@@ -117,6 +119,7 @@ static const struct nand_interface_config onfi_sdr_timings[] = {
 		.timings.sdr = {
 			.tCCS_min = 500000,
 			.tR_max = 200000000,
+			.tRCBSY_min = 40000000,
 			.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
 			.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
 			.tADL_min = 400000,
@@ -162,6 +165,7 @@ static const struct nand_interface_config onfi_sdr_timings[] = {
 		.timings.sdr = {
 			.tCCS_min = 500000,
 			.tR_max = 200000000,
+			.tRCBSY_min = 40000000,
 			.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
 			.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
 			.tADL_min = 400000,
@@ -207,6 +211,7 @@ static const struct nand_interface_config onfi_sdr_timings[] = {
 		.timings.sdr = {
 			.tCCS_min = 500000,
 			.tR_max = 200000000,
+			.tRCBSY_min = 40000000,
 			.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
 			.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
 			.tADL_min = 400000,
@@ -252,6 +257,7 @@ static const struct nand_interface_config onfi_sdr_timings[] = {
 		.timings.sdr = {
 			.tCCS_min = 500000,
 			.tR_max = 200000000,
+			.tRCBSY_min = 40000000,
 			.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
 			.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
 			.tADL_min = 400000,
@@ -300,6 +306,7 @@ static const struct nand_interface_config onfi_nvddr_timings[] = {
 		.timings.nvddr = {
 			.tCCS_min = 500000,
 			.tR_max = 200000000,
+			.tRCBSY_min = 40000000,
 			.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
 			.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
 			.tAC_min = 3000,
@@ -342,6 +349,7 @@ static const struct nand_interface_config onfi_nvddr_timings[] = {
 		.timings.nvddr = {
 			.tCCS_min = 500000,
 			.tR_max = 200000000,
+			.tRCBSY_min = 40000000,
 			.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
 			.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
 			.tAC_min = 3000,
@@ -384,6 +392,7 @@ static const struct nand_interface_config onfi_nvddr_timings[] = {
 		.timings.nvddr = {
 			.tCCS_min = 500000,
 			.tR_max = 200000000,
+			.tRCBSY_min = 40000000,
 			.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
 			.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
 			.tAC_min = 3000,
@@ -426,6 +435,7 @@ static const struct nand_interface_config onfi_nvddr_timings[] = {
 		.timings.nvddr = {
 			.tCCS_min = 500000,
 			.tR_max = 200000000,
+			.tRCBSY_min = 40000000,
 			.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
 			.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
 			.tAC_min = 3000,
@@ -468,6 +478,7 @@ static const struct nand_interface_config onfi_nvddr_timings[] = {
 		.timings.nvddr = {
 			.tCCS_min = 500000,
 			.tR_max = 200000000,
+			.tRCBSY_min = 40000000,
 			.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
 			.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
 			.tAC_min = 3000,
@@ -510,6 +521,7 @@ static const struct nand_interface_config onfi_nvddr_timings[] = {
 		.timings.nvddr = {
 			.tCCS_min = 500000,
 			.tR_max = 200000000,
+			.tRCBSY_min = 40000000,
 			.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
 			.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
 			.tAC_min = 3000,
diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
index b2f9dd3cbd69..49f1249ba852 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
 
@@ -436,6 +438,7 @@ struct nand_sdr_timings {
 	u32 tCCS_min;
 	u64 tPROG_max;
 	u64 tR_max;
+	u64 tRCBSY_min;
 	u32 tALH_min;
 	u32 tADL_min;
 	u32 tALS_min;
@@ -525,6 +528,7 @@ struct nand_nvddr_timings {
 	u32 tCCS_min;
 	u64 tPROG_max;
 	u64 tR_max;
+	u64 tRCBSY_min;
 	u32 tAC_min;
 	u32 tAC_max;
 	u32 tADL_min;
@@ -1173,6 +1177,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