Patchwork [U-Boot,06/12] cmd_sf: Add QPP(Quad-input Page Program) write instruction support

login
register
mail settings
Submitter Jagannadha Sutradharudu Teki
Date Dec. 31, 2012, 11:13 a.m.
Message ID <1356952428-19824-7-git-send-email-jagannadh.teki@gmail.com>
Download mbox | patch
Permalink /patch/208837/
State Superseded
Delegated to: Jagannadha Sutradharudu Teki
Headers show

Comments

Jagannadha Sutradharudu Teki - Dec. 31, 2012, 11:13 a.m.
This patch provides a support to program a flash using 'qpp'
write instruction(wr_inst) for 'sf write' and 'sf update' commands.

'qpp' will effectively increases the data transfer rate
by up to four times, as compared to the pp( Page Program).

Example:
write 0x2000 length bytes from memory at 0x10000 address to
flash offset at 0x0 using qpp write instruction.
u-boot> sf write qpp 0x10000 0x0 0x2000

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

Signed-off-by: Jagannadha Sutradharudu Teki <jagannadh.teki@gmail.com>
---
 common/cmd_sf.c                      |   41 ++++++++++++++++++++++-----------
 drivers/mtd/spi/spi_flash.c          |   12 ++++++++-
 drivers/mtd/spi/spi_flash_internal.h |    4 +-
 include/spi_flash.h                  |    7 +++--
 include/spi_flash_inst.h             |    1 +
 5 files changed, 44 insertions(+), 21 deletions(-)

Patch

diff --git a/common/cmd_sf.c b/common/cmd_sf.c
index d59ecce..b1f19ef 100644
--- a/common/cmd_sf.c
+++ b/common/cmd_sf.c
@@ -143,6 +143,7 @@  static int do_spi_flash_probe(int argc, char * const argv[])
  * @param flash		flash context pointer
  * @param wr_inst	write instruction
  * @param rd_inst	read instruction
+ * @param wr_qeb_req	quad enable bit is required for this write operation?
  * @param offset	flash offset to write
  * @param len		number of bytes to write
  * @param buf		buffer to write from
@@ -151,8 +152,8 @@  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, u32 offset, size_t len, const char *buf,
-		char *cmp_buf, size_t *skipped)
+		u8 rd_inst, u8 wr_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);
@@ -166,7 +167,7 @@  static const char *spi_flash_update_block(struct spi_flash *flash, u8 wr_inst,
 	}
 	if (spi_flash_erase(flash, offset, len))
 		return "erase";
-	if (spi_flash_write(flash, wr_inst, offset, len, buf))
+	if (spi_flash_write(flash, wr_inst, wr_qeb_req, offset, len, buf))
 		return "write";
 	return NULL;
 }
@@ -178,13 +179,14 @@  static const char *spi_flash_update_block(struct spi_flash *flash, u8 wr_inst,
  * @param flash		flash context pointer
  * @param wr_inst	write instruction
  * @param rd_inst	read instruction
+ * @param wr_qeb_req	quad enable bit is required for this write 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,
-		u32 offset, size_t len, const char *buf)
+		u8 wr_qeb_req, u32 offset, size_t len, const char *buf)
 {
 	const char *err_oper = NULL;
 	char *cmp_buf;
@@ -212,7 +214,8 @@  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, offset, todo, buf,
+					rd_inst, wr_qeb_req,
+					offset, todo, buf,
 					cmp_buf, &skipped);
 		}
 	} else {
@@ -241,15 +244,21 @@  static int spi_flash_update(struct spi_flash *flash, u8 wr_inst, u8 rd_inst,
  *    arg: specified write instruction from user
  * Output:
  *    wr_inst: parsed write instruction for write operation
+ *    wr_qeb_req: assign to 1 if this instruction require quad enable bit
+ *		need to set prior to actual write operation
  * Return:
  *    1: for Unknown wr_inst from user
  *    0: Success
  */
-static int sf_parse_wr_inst_arg(char *arg, u8 *wr_inst)
+static int sf_parse_wr_inst_arg(char *arg, u8 *wr_inst, u8 *wr_qeb_req)
 {
-	if (strcmp(arg, "pp") == 0)
+	if (strcmp(arg, "pp") == 0) {
 		*wr_inst = CMD_PAGE_PROGRAM;
-	else
+		*wr_qeb_req = 0;
+	} else if (strcmp(arg, "qpp") == 0) {
+		*wr_inst = CMD_QUAD_PAGE_PROGRAM;
+		*wr_qeb_req = 1;
+	} else
 		return 1;
 
 	return 0;
@@ -284,6 +293,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;
 	int update_rd_inst;
 	int ret;
 
@@ -323,7 +333,7 @@  static int do_spi_flash_read_write(int argc, char * const argv[])
 	}
 
 	if (strcmp(argv[0], "update") == 0) {
-		ret = sf_parse_wr_inst_arg(argv[1], &wr_inst);
+		ret = sf_parse_wr_inst_arg(argv[1], &wr_inst, &wr_qeb_req);
 		if (ret) {
 			printf("SF: Unknown %s wr_inst on 'sf update'\n",
 					argv[1]);
@@ -338,7 +348,7 @@  static int do_spi_flash_read_write(int argc, char * const argv[])
 		}
 
 		ret = spi_flash_update(flash, wr_inst, rd_inst,
-					offset, len, buf);
+				wr_qeb_req, offset, len, buf);
 	} else if (strcmp(argv[0], "read") == 0) {
 		ret = sf_parse_rd_inst_arg(argv[1], &rd_inst);
 		if (ret) {
@@ -349,14 +359,15 @@  static int do_spi_flash_read_write(int argc, char * const argv[])
 
 		ret = spi_flash_read(flash, rd_inst, offset, len, buf);
 	} else {
-		ret = sf_parse_wr_inst_arg(argv[1], &wr_inst);
+		ret = sf_parse_wr_inst_arg(argv[1], &wr_inst, &wr_qeb_req);
 		if (ret) {
 			printf("SF: Unknown %s wr_inst on 'sf write'\n",
 					argv[1]);
 			return ret;
 		}
 
-		ret = spi_flash_write(flash, wr_inst, offset, len, buf);
+		ret = spi_flash_write(flash, wr_inst, wr_qeb_req,
+				offset, len, buf);
 	}
 
 	unmap_physmem(buf, len);
@@ -622,15 +633,17 @@  U_BOOT_CMD(
 	"sf write wr_inst addr offset len\n"
 	"				- write `len' bytes from memory\n"
 	"				  at `addr' to flash at `offset' using\n"
-	"				  pp `wr_inst' write instruction\n"
+	"				  pp | qpp `wr_inst' write instructions\n"
 	"				  pp (Page Program, 02h)\n"
+	"				  qpp (Quad Page Program, 32h)\n"
 	"sf erase offset [+]len		- erase `len' bytes from `offset'\n"
 	"				  `+len' round up `len' to block size\n"
 	"sf update wr_inst rd_inst addr offset len\n"
 	"				- erase and write `len' bytes from memory\n"
 	"				  at `addr' to flash at `offset' using\n"
-	"				  pp `wr_inst' write instruction and\n"
+	"				  pp | qpp `wr_inst' write instructions and\n"
 	"				  pp (Page Program, 02h)\n"
+	"				  qpp (Quad Page Program, 32h)\n"
 	"				  afr `rd_inst' read instruction\n"
 	"				  afr (Array Fast Read, 0bh)"
 	SF_TEST_HELP
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 0c64ac2..3d57863 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -65,8 +65,8 @@  int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len,
 	return spi_flash_read_write(spi, cmd, cmd_len, data, NULL, data_len);
 }
 
-int spi_flash_cmd_write_multi(struct spi_flash *flash, u8 wr_inst, u32 offset,
-		size_t len, const void *buf)
+int spi_flash_cmd_write_multi(struct spi_flash *flash, u8 wr_inst,
+		u8 wr_qeb_req, u32 offset, size_t len, const void *buf)
 {
 	unsigned long page_addr, byte_addr, page_size;
 	size_t chunk_len, actual;
@@ -83,6 +83,14 @@  int spi_flash_cmd_write_multi(struct spi_flash *flash, u8 wr_inst, u32 offset,
 		return ret;
 	}
 
+	if (wr_qeb_req) {
+		ret = spi_flash_set_quad_enable_bit(flash);
+		if (ret) {
+			debug("SF: set quad enable bit failed\n");
+			return ret;
+		}
+	}
+
 	cmd[0] = wr_inst;
 	for (actual = 0; actual < len; actual += chunk_len) {
 		chunk_len = min(len - actual, page_size - byte_addr);
diff --git a/drivers/mtd/spi/spi_flash_internal.h b/drivers/mtd/spi/spi_flash_internal.h
index dcf8813..e36f216 100644
--- a/drivers/mtd/spi/spi_flash_internal.h
+++ b/drivers/mtd/spi/spi_flash_internal.h
@@ -57,8 +57,8 @@  int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len,
  * Write the requested data out breaking it up into multiple write
  * commands as needed per the write size.
  */
-int spi_flash_cmd_write_multi(struct spi_flash *flash, u8 wr_inst, u32 offset,
-		size_t len, const void *buf);
+int spi_flash_cmd_write_multi(struct spi_flash *flash, u8 wr_inst,
+		u8 wr_qeb_req, u32 offset, size_t len, const void *buf);
 
 /*
  * Enable writing on the SPI flash.
diff --git a/include/spi_flash.h b/include/spi_flash.h
index 6728796..31e7d9e 100644
--- a/include/spi_flash.h
+++ b/include/spi_flash.h
@@ -42,7 +42,8 @@  struct spi_flash {
 	int		(*read)(struct spi_flash *flash, u8 rd_inst,
 				u32 offset, size_t len, void *buf);
 	int		(*write)(struct spi_flash *flash, u8 wr_inst,
-				u32 offset, size_t len, const void *buf);
+				u8 wr_qeb_req, u32 offset, size_t len,
+				const void *buf);
 	int		(*erase)(struct spi_flash *flash, u32 offset,
 				size_t len);
 };
@@ -58,9 +59,9 @@  static inline int spi_flash_read(struct spi_flash *flash, u8 rd_inst,
 }
 
 static inline int spi_flash_write(struct spi_flash *flash, u8 wr_inst,
-		u32 offset, size_t len, const void *buf)
+		u8 wr_qeb_req, u32 offset, size_t len, const void *buf)
 {
-	return flash->write(flash, wr_inst, offset, len, buf);
+	return flash->write(flash, wr_inst, wr_qeb_req, offset, len, buf);
 }
 
 static inline int spi_flash_erase(struct spi_flash *flash, u32 offset,
diff --git a/include/spi_flash_inst.h b/include/spi_flash_inst.h
index 7c1b910..a530842 100644
--- a/include/spi_flash_inst.h
+++ b/include/spi_flash_inst.h
@@ -26,6 +26,7 @@ 
 
 /* Write commands */
 #define CMD_PAGE_PROGRAM		0x02
+#define CMD_QUAD_PAGE_PROGRAM		0x32
 
 /* Read commands */
 #define CMD_READ_ARRAY_FAST		0x0b