Patchwork [U-Boot,v2,2/2] spi: Add SPI flash test

login
register
mail settings
Submitter Simon Glass
Date Oct. 8, 2012, 11:16 p.m.
Message ID <1349738163-18983-2-git-send-email-sjg@chromium.org>
Download mbox | patch
Permalink /patch/190164/
State Accepted, archived
Delegated to: Tom Rini
Headers show

Comments

Simon Glass - Oct. 8, 2012, 11:16 p.m.
It is useful to have a basic SPI flash test, which tests that the SPI chip,
the SPI bus and the driver are behaving.

This test erases part of the flash, writes data and reads it back as a
sanity check that all is well.

Use CONFIG_SF_TEST to enable it.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
Changes in v2:
- Add arguments to 'sf test' (may as well do this TODO now)

 README          |    5 ++
 common/cmd_sf.c |  168 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 173 insertions(+), 0 deletions(-)
Tom Rini - Dec. 19, 2012, 10:59 p.m.
On Mon, Oct 08, 2012 at 01:16:02PM -0000, Simon Glass wrote:

> It is useful to have a basic SPI flash test, which tests that the SPI chip,
> the SPI bus and the driver are behaving.
> 
> This test erases part of the flash, writes data and reads it back as a
> sanity check that all is well.
> 
> Use CONFIG_SF_TEST to enable it.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>

Applied to u-boot/master, thanks!
Wolfgang Denk - Dec. 19, 2012, 11:19 p.m.
Dear Tom Rini,

In message <20121219225956.GG14589@bill-the-cat> you wrote:
> 
> Applied to u-boot/master, thanks!

Please see my comment from a few minutes ago.

We're adding just dead code here.  This makes no sense to me.

Best regards,

Wolfgang Denk
Tom Rini - Dec. 20, 2012, 1:07 a.m.
On Thu, Dec 20, 2012 at 12:19:24AM +0100, Wolfgang Denk wrote:
> Dear Tom Rini,
> 
> In message <20121219225956.GG14589@bill-the-cat> you wrote:
> > 
> > Applied to u-boot/master, thanks!
> 
> Please see my comment from a few minutes ago.
> 
> We're adding just dead code here.  This makes no sense to me.

I'll add this option to am335x_evm as soon as I can sneak over to the
office, flip the dip switches so that the SPI flash is available and
double check that yes, really, Simon tested the code one point before
posting.  Yeah, -1 to me for adding this before we added a board using
it, but it's a useful thing.  Q/A folks here at least will be all 'oh
boy!' when I tell them that starting with the next release they can use
this.
Simon Glass - Dec. 26, 2012, 8:01 p.m.
Hi,

On Wed, Dec 19, 2012 at 5:07 PM, Tom Rini <trini@ti.com> wrote:
> On Thu, Dec 20, 2012 at 12:19:24AM +0100, Wolfgang Denk wrote:
>> Dear Tom Rini,
>>
>> In message <20121219225956.GG14589@bill-the-cat> you wrote:
>> >
>> > Applied to u-boot/master, thanks!
>>
>> Please see my comment from a few minutes ago.
>>
>> We're adding just dead code here.  This makes no sense to me.
>
> I'll add this option to am335x_evm as soon as I can sneak over to the
> office, flip the dip switches so that the SPI flash is available and
> double check that yes, really, Simon tested the code one point before
> posting.  Yeah, -1 to me for adding this before we added a board using
> it, but it's a useful thing.  Q/A folks here at least will be all 'oh
> boy!' when I tell them that starting with the next release they can use
> this.

Sorry about this. It can be enabled on any board I think - my SPI
patches for coreboot got held up a bit by a bug and I missed the merge
window. I will send these patches out in the next few weeks.

Regards,
Simon

>
> --
> Tom
>
> _______________________________________________
> U-Boot mailing list
> U-Boot@lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
>

Patch

diff --git a/README b/README
index 0d17e7d..193986e 100644
--- a/README
+++ b/README
@@ -2315,6 +2315,11 @@  The following options need to be configured:
 		CONFIG_SF_DEFAULT_MODE 		(see include/spi.h)
 		CONFIG_SF_DEFAULT_SPEED		in Hz
 
+		CONFIG_CMD_SF_TEST
+
+		Define this option to include a destructive SPI flash
+		test ('sf test').
+
 - SystemACE Support:
 		CONFIG_SYSTEMACE
 
diff --git a/common/cmd_sf.c b/common/cmd_sf.c
index e22a45e..269afcc 100644
--- a/common/cmd_sf.c
+++ b/common/cmd_sf.c
@@ -5,6 +5,7 @@ 
  * Licensed under the GPL-2 or later.
  */
 
+#include <div64.h>
 #include <common.h>
 #include <malloc.h>
 #include <spi_flash.h>
@@ -312,6 +313,161 @@  static int do_spi_flash_erase(int argc, char * const argv[])
 	return 0;
 }
 
+#ifdef CONFIG_CMD_SF_TEST
+enum {
+	STAGE_ERASE,
+	STAGE_CHECK,
+	STAGE_WRITE,
+	STAGE_READ,
+
+	STAGE_COUNT,
+};
+
+static char *stage_name[STAGE_COUNT] = {
+	"erase",
+	"check",
+	"write",
+	"read",
+};
+
+struct test_info {
+	int stage;
+	int bytes;
+	unsigned base_ms;
+	unsigned time_ms[STAGE_COUNT];
+};
+
+static void show_time(struct test_info *test, int stage)
+{
+	uint64_t speed;	/* KiB/s */
+	int bps;	/* Bits per second */
+
+	speed = (long long)test->bytes * 1000;
+	do_div(speed, test->time_ms[stage] * 1024);
+	bps = speed * 8;
+
+	printf("%d %s: %d ticks, %d KiB/s %d.%03d Mbps\n", stage,
+	       stage_name[stage], test->time_ms[stage],
+	       (int)speed, bps / 1000, bps % 1000);
+}
+
+static void spi_test_next_stage(struct test_info *test)
+{
+	test->time_ms[test->stage] = get_timer(test->base_ms);
+	show_time(test, test->stage);
+	test->base_ms = get_timer(0);
+	test->stage++;
+}
+
+/**
+ * Run a test on the SPI flash
+ *
+ * @param flash		SPI flash to use
+ * @param buf		Source buffer for data to write
+ * @param len		Size of data to read/write
+ * @param offset	Offset within flash to check
+ * @param vbuf		Verification buffer
+ * @return 0 if ok, -1 on error
+ */
+static int spi_flash_test(struct spi_flash *flash, char *buf, ulong len,
+			   ulong offset, char *vbuf)
+{
+	struct test_info test;
+	int i;
+
+	printf("SPI flash test:\n");
+	memset(&test, '\0', sizeof(test));
+	test.base_ms = get_timer(0);
+	test.bytes = len;
+	if (spi_flash_erase(flash, offset, len)) {
+		printf("Erase failed\n");
+		return -1;
+	}
+	spi_test_next_stage(&test);
+
+	if (spi_flash_read(flash, offset, len, vbuf)) {
+		printf("Check read failed\n");
+		return -1;
+	}
+	for (i = 0; i < len; i++) {
+		if (vbuf[i] != 0xff) {
+			printf("Check failed at %d\n", i);
+			print_buffer(i, vbuf + i, 1, min(len - i, 0x40), 0);
+			return -1;
+		}
+	}
+	spi_test_next_stage(&test);
+
+	if (spi_flash_write(flash, offset, len, buf)) {
+		printf("Write failed\n");
+		return -1;
+	}
+	memset(vbuf, '\0', len);
+	spi_test_next_stage(&test);
+
+	if (spi_flash_read(flash, offset, len, vbuf)) {
+		printf("Read failed\n");
+		return -1;
+	}
+	spi_test_next_stage(&test);
+
+	for (i = 0; i < len; i++) {
+		if (buf[i] != vbuf[i]) {
+			printf("Verify failed at %d, good data:\n", i);
+			print_buffer(i, buf + i, 1, min(len - i, 0x40), 0);
+			printf("Bad data:\n");
+			print_buffer(i, vbuf + i, 1, min(len - i, 0x40), 0);
+			return -1;
+		}
+	}
+	printf("Test passed\n");
+	for (i = 0; i < STAGE_COUNT; i++)
+		show_time(&test, i);
+
+	return 0;
+}
+
+static int do_spi_flash_test(int argc, char * const argv[])
+{
+	unsigned long offset;
+	unsigned long len;
+	char *buf = (char *)CONFIG_SYS_TEXT_BASE;
+	char *endp;
+	char *vbuf;
+	int ret;
+
+	offset = simple_strtoul(argv[1], &endp, 16);
+	if (*argv[1] == 0 || *endp != 0)
+		return -1;
+	len = simple_strtoul(argv[2], &endp, 16);
+	if (*argv[2] == 0 || *endp != 0)
+		return -1;
+
+	vbuf = malloc(len);
+	if (!vbuf) {
+		printf("Cannot allocate memory\n");
+		return 1;
+	}
+	buf = malloc(len);
+	if (!buf) {
+		free(vbuf);
+		printf("Cannot allocate memory\n");
+		return 1;
+	}
+
+	memcpy(buf, (char *)CONFIG_SYS_TEXT_BASE, len);
+	ret = spi_flash_test(flash, buf, len, offset, vbuf);
+	free(vbuf);
+	free(buf);
+	if (ret) {
+		printf("Test failed\n");
+		return 1;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_CMD_SF_TEST */
+
 static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	const char *cmd;
@@ -341,6 +497,10 @@  static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[
 		ret = do_spi_flash_read_write(argc, argv);
 	else if (strcmp(cmd, "erase") == 0)
 		ret = do_spi_flash_erase(argc, argv);
+#ifdef CONFIG_CMD_SF_TEST
+	else if (!strcmp(cmd, "test"))
+		ret = do_spi_flash_test(argc, argv);
+#endif
 	else
 		ret = -1;
 
@@ -352,6 +512,13 @@  usage:
 	return CMD_RET_USAGE;
 }
 
+#ifdef CONFIG_CMD_SF_TEST
+#define SF_TEST_HELP "\nsf test offset len		" \
+		"- run a very basic destructive test"
+#else
+#define SF_TEST_HELP
+#endif
+
 U_BOOT_CMD(
 	sf,	5,	1,	do_spi_flash,
 	"SPI flash sub-system",
@@ -365,4 +532,5 @@  U_BOOT_CMD(
 	"				  `+len' round up `len' to block size\n"
 	"sf update addr offset len	- erase and write `len' bytes from memory\n"
 	"				  at `addr' to flash at `offset'"
+	SF_TEST_HELP
 );