All of lore.kernel.org
 help / color / mirror / Atom feed
From: JaimeLiao <jaimeliao.tw@gmail.com>
To: linux-mtd@lists.infradead.org, miquel.raynal@bootlin.com, richard@nod.at
Cc: jaimeliao@mxic.com.tw, JaimeLiao <jaimeliao.tw@gmail.com>
Subject: [PATCH v2 1/1] mtd: rawnand: Cache read sequential
Date: Mon, 29 Aug 2022 15:24:52 +0800	[thread overview]
Message-ID: <20220829072452.15342-2-jaimeliao.tw@gmail.com> (raw)
In-Reply-To: <20220829072452.15342-1-jaimeliao.tw@gmail.com>

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


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

  reply	other threads:[~2022-08-29  7:26 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-08-29  7:24 [PATCH v2 0/1] mtd: rawnand: Cache read sequential JaimeLiao
2022-08-29  7:24 ` JaimeLiao [this message]
2022-11-07 13:56   ` [PATCH v2 1/1] " Miquel Raynal
2022-11-07 14:41     ` Miquel Raynal

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220829072452.15342-2-jaimeliao.tw@gmail.com \
    --to=jaimeliao.tw@gmail.com \
    --cc=jaimeliao@mxic.com.tw \
    --cc=linux-mtd@lists.infradead.org \
    --cc=miquel.raynal@bootlin.com \
    --cc=richard@nod.at \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.