[U-Boot] [PATCH 09/12] cmd_sf: Add QOFR(Quad Output Fast Read) read instruction support

Jagannadha Sutradharudu Teki jagannadh.teki at gmail.com
Mon Dec 31 12:13:48 CET 2012


This patch provides a support to read a flash using 'qofr'
read instruction(rd_inst) for 'sf read' and 'sf update' commands.

'qofr' will effectively increases the data transfer rate
by up to four times, as compared to the afr(Array Fast Read).

Example:
read 0x2000 length bytes starting at offset 0x0 to memory at 0x10000
using qofr read instruction.
u-boot> sf read qofr 0x10000 0x0 0x2000

erase and write 0x2000 length bytes from memory at 0x10000 address to
flash offset at 0x0 using pp write instruction and qofr read instruction.
u-boot> sf update pp qofr 0x10000 0x0 0x2000

Signed-off-by: Jagannadha Sutradharudu Teki <jagannadh.teki at gmail.com>
---
 common/cmd_sf.c                      |   43 ++++++++++++++++++++++------------
 drivers/mtd/spi/spi_flash.c          |   18 +++++++++++---
 drivers/mtd/spi/spi_flash_internal.h |    6 ++--
 include/spi_flash.h                  |    7 +++--
 include/spi_flash_inst.h             |    1 +
 5 files changed, 50 insertions(+), 25 deletions(-)

diff --git a/common/cmd_sf.c b/common/cmd_sf.c
index b971d2a..a07effd 100644
--- a/common/cmd_sf.c
+++ b/common/cmd_sf.c
@@ -144,6 +144,7 @@ static int do_spi_flash_probe(int argc, char * const argv[])
  * @param wr_inst	write instruction
  * @param rd_inst	read instruction
  * @param wr_qeb_req	quad enable bit is required for this write operation?
+ * @param rd_qeb_req	quad enable bit is required for this read operation?
  * @param offset	flash offset to write
  * @param len		number of bytes to write
  * @param buf		buffer to write from
@@ -152,12 +153,12 @@ static int do_spi_flash_probe(int argc, char * const argv[])
  * @return NULL if OK, else a string containing the stage which failed
  */
 static const char *spi_flash_update_block(struct spi_flash *flash, u8 wr_inst,
-		u8 rd_inst, u8 wr_qeb_req, u32 offset, size_t len,
-		const char *buf, char *cmp_buf, size_t *skipped)
+		u8 rd_inst, u8 wr_qeb_req, u8 rd_qeb_req, u32 offset,
+		size_t len, const char *buf, char *cmp_buf, size_t *skipped)
 {
 	debug("offset=%#x, sector_size=%#x, len=%#zx\n",
 		offset, flash->sector_size, len);
-	if (spi_flash_read(flash, rd_inst, offset, len, cmp_buf))
+	if (spi_flash_read(flash, rd_inst, rd_qeb_req, offset, len, cmp_buf))
 		return "read";
 	if (memcmp(cmp_buf, buf, len) == 0) {
 		debug("Skip region %x size %zx: no change\n",
@@ -180,13 +181,15 @@ static const char *spi_flash_update_block(struct spi_flash *flash, u8 wr_inst,
  * @param wr_inst	write instruction
  * @param rd_inst	read instruction
  * @param wr_qeb_req	quad enable bit is required for this write operation?
+ * @param rd_qeb_req	quad enable bit is required for this read operation?
  * @param offset	flash offset to write
  * @param len		number of bytes to write
  * @param buf		buffer to write from
  * @return 0 if ok, 1 on error
  */
 static int spi_flash_update(struct spi_flash *flash, u8 wr_inst, u8 rd_inst,
-		u8 wr_qeb_req, u32 offset, size_t len, const char *buf)
+		u8 wr_qeb_req, u8 rd_qeb_req, u32 offset,
+		size_t len, const char *buf)
 {
 	const char *err_oper = NULL;
 	char *cmp_buf;
@@ -214,7 +217,7 @@ static int spi_flash_update(struct spi_flash *flash, u8 wr_inst, u8 rd_inst,
 				last_update = get_timer(0);
 			}
 			err_oper = spi_flash_update_block(flash, wr_inst,
-					rd_inst, wr_qeb_req,
+					rd_inst, wr_qeb_req, rd_qeb_req,
 					offset, todo, buf,
 					cmp_buf, &skipped);
 		}
@@ -271,19 +274,26 @@ static int sf_parse_wr_inst_arg(char *arg, u8 *wr_inst, u8 *wr_qeb_req)
  *    arg: specified read instruction from user
  * Output:
  *    rd_inst: parsed read instruction for write operation
+ *    rd_qeb_req: assign to 1 if this instruction require quad enable bit
+ *		need to set prior to actual read operation
  * Return:
  *    1: for Unknown rd_inst from user
  *    0: Success
  */
-static int sf_parse_rd_inst_arg(char *arg, u8 *rd_inst)
+static int sf_parse_rd_inst_arg(char *arg, u8 *rd_inst, u8 *rd_qeb_req)
 {
+	*rd_qeb_req = 0;
+
 	if (strcmp(arg, "afr") == 0)
 		*rd_inst = CMD_READ_ARRAY_FAST;
 	else if (strcmp(arg, "asr") == 0)
 		*rd_inst = CMD_READ_ARRAY_SLOW;
 	else if (strcmp(arg, "dofr") == 0)
 		*rd_inst = CMD_READ_DUAL_OUTPUT_FAST;
-	else
+	else if (strcmp(arg, "qofr") == 0) {
+		*rd_inst = CMD_READ_QUAD_OUTPUT_FAST;
+		*rd_qeb_req = 1;
+	} else
 		return 1;
 
 	return 0;
@@ -297,7 +307,7 @@ static int do_spi_flash_read_write(int argc, char * const argv[])
 	void *buf;
 	char *endp;
 	u8 wr_inst, rd_inst;
-	u8 wr_qeb_req;
+	u8 wr_qeb_req, rd_qeb_req;
 	int update_rd_inst;
 	int ret;
 
@@ -344,7 +354,7 @@ static int do_spi_flash_read_write(int argc, char * const argv[])
 			return ret;
 		}
 
-		ret = sf_parse_rd_inst_arg(argv[2], &rd_inst);
+		ret = sf_parse_rd_inst_arg(argv[2], &rd_inst, &rd_qeb_req);
 		if (ret) {
 			printf("SF: Unknown %s rd_inst on 'sf update'\n",
 					argv[2]);
@@ -352,16 +362,17 @@ static int do_spi_flash_read_write(int argc, char * const argv[])
 		}
 
 		ret = spi_flash_update(flash, wr_inst, rd_inst,
-				wr_qeb_req, offset, len, buf);
+				wr_qeb_req, rd_qeb_req, offset, len, buf);
 	} else if (strcmp(argv[0], "read") == 0) {
-		ret = sf_parse_rd_inst_arg(argv[1], &rd_inst);
+		ret = sf_parse_rd_inst_arg(argv[1], &rd_inst, &rd_qeb_req);
 		if (ret) {
 			printf("SF: Unknown %s rd_inst on 'sf read'\n",
 					argv[1]);
 			return ret;
 		}
 
-		ret = spi_flash_read(flash, rd_inst, offset, len, buf);
+		ret = spi_flash_read(flash, rd_inst, rd_qeb_req,
+				offset, len, buf);
 	} else {
 		ret = sf_parse_wr_inst_arg(argv[1], &wr_inst, &wr_qeb_req);
 		if (ret) {
@@ -632,10 +643,11 @@ U_BOOT_CMD(
 	"sf read rd_inst addr offset len\n"
 	"				- read `len' bytes starting at\n"
 	"				  `offset' to memory at `addr' using\n"
-	"				  afr | asr | dofr `rd_inst' read instructions\n"
+	"				  afr | asr | dofr | qofr `rd_inst' read instructions\n"
 	"				  afr (Array Fast Read, 0bh)\n"
 	"				  asr (Array Slow Read, 02b)\n"
 	"				  dofr (Dual Output Fast Read, 3bh)\n"
+	"				  qofr (Quad Output Fast Read, 6bh)\n"
 	"sf write wr_inst addr offset len\n"
 	"				- write `len' bytes from memory\n"
 	"				  at `addr' to flash at `offset' using\n"
@@ -650,9 +662,10 @@ U_BOOT_CMD(
 	"				  pp | qpp `wr_inst' write instructions and\n"
 	"				  pp (Page Program, 02h)\n"
 	"				  qpp (Quad Page Program, 32h)\n"
-	"				  afr | asr | dofr `rd_inst' read instructions\n"
+	"				  afr | asr | dofr | qofr `rd_inst' read instructions\n"
 	"				  afr (Array Fast Read, 0bh)\n"
 	"				  asr (Array Slow Read, 02b)\n"
-	"				  dofr (Dual Output Fast Read, 3bh)"
+	"				  dofr (Dual Output Fast Read, 3bh)\n"
+	"				  qofr (Quad Output Fast Read, 6bh)"
 	SF_TEST_HELP
 );
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 3d57863..15ad05c 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -130,21 +130,30 @@ int spi_flash_cmd_write_multi(struct spi_flash *flash, u8 wr_inst,
 	return ret;
 }
 
-int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
+int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, u8 rd_qeb_req,
 		size_t cmd_len, void *data, size_t data_len)
 {
 	struct spi_slave *spi = flash->spi;
 	int ret;
 
 	spi_claim_bus(spi);
+
+	if (rd_qeb_req) {
+		ret = spi_flash_set_quad_enable_bit(flash);
+		if (ret) {
+			debug("SF: set quad enable bit failed\n");
+			return ret;
+		}
+	}
+
 	ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len);
 	spi_release_bus(spi);
 
 	return ret;
 }
 
-int spi_flash_cmd_read_fast(struct spi_flash *flash, u8 rd_inst, u32 offset,
-		size_t len, void *data)
+int spi_flash_cmd_read_fast(struct spi_flash *flash, u8 rd_inst,
+		u8 rd_qeb_req, u32 offset, size_t len, void *data)
 {
 	u8 cmd[5];
 
@@ -152,7 +161,8 @@ int spi_flash_cmd_read_fast(struct spi_flash *flash, u8 rd_inst, u32 offset,
 	spi_flash_addr(offset, cmd);
 	cmd[4] = 0x00;
 
-	return spi_flash_read_common(flash, cmd, sizeof(cmd), data, len);
+	return spi_flash_read_common(flash, cmd, rd_qeb_req,
+				sizeof(cmd), data, len);
 }
 
 int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout,
diff --git a/drivers/mtd/spi/spi_flash_internal.h b/drivers/mtd/spi/spi_flash_internal.h
index e36f216..feefdee 100644
--- a/drivers/mtd/spi/spi_flash_internal.h
+++ b/drivers/mtd/spi/spi_flash_internal.h
@@ -43,8 +43,8 @@ int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len);
 int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd,
 		size_t cmd_len, void *data, size_t data_len);
 
-int spi_flash_cmd_read_fast(struct spi_flash *flash, u8 rd_inst, u32 offset,
-		size_t len, void *data);
+int spi_flash_cmd_read_fast(struct spi_flash *flash, u8 rd_inst, u8 rd_qeb_req,
+		u32 offset, size_t len, void *data);
 
 /*
  * Send a multi-byte command to the device followed by (optional)
@@ -96,7 +96,7 @@ int spi_flash_set_quad_enable_bit(struct spi_flash *flash);
  * bus. Used as common part of the ->read() operation.
  */
 int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
-		size_t cmd_len, void *data, size_t data_len);
+		u8 rd_qeb_req, size_t cmd_len, void *data, size_t data_len);
 
 /* Send a command to the device and wait for some bit to clear itself. */
 int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout,
diff --git a/include/spi_flash.h b/include/spi_flash.h
index 31e7d9e..d3e6ca5 100644
--- a/include/spi_flash.h
+++ b/include/spi_flash.h
@@ -40,7 +40,8 @@ struct spi_flash {
 	u32		sector_size;
 
 	int		(*read)(struct spi_flash *flash, u8 rd_inst,
-				u32 offset, size_t len, void *buf);
+				u8 rd_qeb_req, u32 offset, size_t len,
+				void *buf);
 	int		(*write)(struct spi_flash *flash, u8 wr_inst,
 				u8 wr_qeb_req, u32 offset, size_t len,
 				const void *buf);
@@ -53,9 +54,9 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
 void spi_flash_free(struct spi_flash *flash);
 
 static inline int spi_flash_read(struct spi_flash *flash, u8 rd_inst,
-		u32 offset, size_t len, void *buf)
+		u8 rd_qeb_req, u32 offset, size_t len, void *buf)
 {
-	return flash->read(flash, rd_inst, offset, len, buf);
+	return flash->read(flash, rd_inst, rd_qeb_req, offset, len, buf);
 }
 
 static inline int spi_flash_write(struct spi_flash *flash, u8 wr_inst,
diff --git a/include/spi_flash_inst.h b/include/spi_flash_inst.h
index f8fcf5e..67b22c8 100644
--- a/include/spi_flash_inst.h
+++ b/include/spi_flash_inst.h
@@ -32,5 +32,6 @@
 #define CMD_READ_ARRAY_FAST		0x0b
 #define CMD_READ_ARRAY_SLOW		0x03
 #define CMD_READ_DUAL_OUTPUT_FAST	0x3b
+#define CMD_READ_QUAD_OUTPUT_FAST	0x6b
 
 #endif /* _SPI_FLASH_INST_H_ */
-- 
1.7.0.4



More information about the U-Boot mailing list