public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v3] Add 'sf update' command to do smart SPI flash update
@ 2011-08-19 19:28 Simon Glass
  2011-08-19 21:15 ` Mike Frysinger
  2011-08-20 22:35 ` [U-Boot] [PATCH v4] cmd_sf: add "update" subcommand " Mike Frysinger
  0 siblings, 2 replies; 15+ messages in thread
From: Simon Glass @ 2011-08-19 19:28 UTC (permalink / raw)
  To: u-boot

This adds a new SPI flash command which only rewrites blocks if the contents
need to change. This can speed up SPI flash programming when much of the
data is unchanged from what is already there.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
Changes in v2:
-Moved loop into a function
-Moved malloc outside loop
-Other minor changes from review comments

Changes in v3:
-Change error message
-Style and function name change

 common/cmd_sf.c |   82 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 80 insertions(+), 2 deletions(-)

diff --git a/common/cmd_sf.c b/common/cmd_sf.c
index 11a491d..69f04e5 100644
--- a/common/cmd_sf.c
+++ b/common/cmd_sf.c
@@ -6,6 +6,7 @@
  */
 
 #include <common.h>
+#include <malloc.h>
 #include <spi_flash.h>
 
 #include <asm/io.h>
@@ -109,6 +110,78 @@ static int do_spi_flash_probe(int argc, char * const argv[])
 	return 0;
 }
 
+/**
+ * Write a block of data to SPI flash, first checking if it is different from
+ * what is already there.
+ *
+ * If the data being written is the same, then *skipped is incremented by len.
+ *
+ * @param flash		flash context pointer
+ * @param offset	flash offset to write
+ * @param len		number of bytes to write
+ * @param buf		buffer to write from
+ * @param cmp_buf	read buffer to use to compare data
+ * @param skipped	Count of skipped data (incremented by this function)
+ * @return NULL if OK, else a string containing the stage which failed
+ */
+static const char *spi_flash_update_block(struct spi_flash *flash, u32 offset,
+		size_t len, const char *buf, char *cmp_buf, size_t *skipped)
+{
+	debug("offset=%#x, sector_size=%#x, len=%#x\n",
+		offset, flash->sector_size, len);
+	if (spi_flash_read(flash, offset, len, cmp_buf))
+		return "read";
+	if (memcmp(cmp_buf, buf, len) == 0) {
+		debug("Skip region %x size %x: no change\n",
+			offset, len);
+		*skipped += len;
+		return NULL;
+	}
+	if (spi_flash_erase(flash, offset, len))
+		return "erase";
+	if (spi_flash_write(flash, offset, len, buf))
+		return "write";
+	return NULL;
+}
+
+/**
+ * Update an area of SPI flash by erasing and writing any blocks which need
+ * to change. Existing blocks with the correct data are left unchanged.
+ *
+ * @param flash		flash context pointer
+ * @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, u32 offset,
+		size_t len, const char *buf)
+{
+	const char *err_oper = NULL;
+	char *cmp_buf;
+	const char *end = buf + len;
+	size_t todo;		/* number of bytes to do in this pass */
+	size_t skipped;		/* statistics */
+
+	cmp_buf = malloc(flash->sector_size);
+	if (cmp_buf) {
+		for (skipped = 0; buf < end; buf += todo, offset += todo) {
+			todo = min(end - buf, flash->sector_size);
+			err_oper = spi_flash_update_block(flash, offset, todo,
+					buf, cmp_buf, &skipped);
+		}
+	} else {
+		err_oper = "malloc";
+	}
+	free(cmp_buf);
+	if (err_oper) {
+		printf("SPI flash failed in %s step\n", err_oper);
+		return 1;
+	}
+	printf("%d bytes written, %d bytes skipped\n", len - skipped, skipped);
+	return 0;
+}
+
 static int do_spi_flash_read_write(int argc, char * const argv[])
 {
 	unsigned long addr;
@@ -137,7 +210,9 @@ static int do_spi_flash_read_write(int argc, char * const argv[])
 		return 1;
 	}
 
-	if (strcmp(argv[0], "read") == 0)
+	if (strcmp(argv[0], "update") == 0)
+		ret = spi_flash_update(flash, offset, len, buf);
+	else if (strcmp(argv[0], "read") == 0)
 		ret = spi_flash_read(flash, offset, len, buf);
 	else
 		ret = spi_flash_write(flash, offset, len, buf);
@@ -203,7 +278,8 @@ static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[
 		return 1;
 	}
 
-	if (strcmp(cmd, "read") == 0 || strcmp(cmd, "write") == 0)
+	if (strcmp(cmd, "read") == 0 || strcmp(cmd, "write") == 0 ||
+			strcmp(cmd, "update") == 0)
 		ret = do_spi_flash_read_write(argc, argv);
 	else if (strcmp(cmd, "erase") == 0)
 		ret = do_spi_flash_erase(argc, argv);
@@ -229,4 +305,6 @@ U_BOOT_CMD(
 	"				  at `addr' to flash at `offset'\n"
 	"sf erase offset [+]len		- erase `len' bytes from `offset'\n"
 	"				  `+len' round up `len' to block size"
+	"sf update addr offset len	- erase and write `len' bytes from memory\n"
+	"				  at `addr' to flash at `offset'\n"
 );
-- 
1.7.3.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2011-08-24  4:11 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-08-19 19:28 [U-Boot] [PATCH v3] Add 'sf update' command to do smart SPI flash update Simon Glass
2011-08-19 21:15 ` Mike Frysinger
2011-08-19 21:25   ` Simon Glass
2011-08-19 22:28     ` Mike Frysinger
2011-08-23 22:01       ` Simon Glass
2011-08-23 22:16         ` Mike Frysinger
2011-08-24  3:41           ` Che-liang Chiou
2011-08-24  4:11             ` Simon Glass
2011-08-20 22:35 ` [U-Boot] [PATCH v4] cmd_sf: add "update" subcommand " Mike Frysinger
2011-08-20 23:04   ` Marek Vasut
2011-08-21 10:37     ` Simon Glass
2011-08-21 16:35       ` Mike Frysinger
2011-08-22 22:53         ` Simon Glass
2011-08-21 10:27   ` Simon Glass
2011-08-21 16:34     ` Mike Frysinger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox