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