SPI Flash: Add "sf" command
This adds a new command, "sf" which can be used to manipulate SPI
flash. Currently, initialization, reading, writing and erasing is
supported.
Signed-off-by: Haavard Skinnemoen <haavard.skinnemoen@atmel.com>
diff --git a/common/cmd_sf.c b/common/cmd_sf.c
new file mode 100644
index 0000000..8c0a751
--- /dev/null
+++ b/common/cmd_sf.c
@@ -0,0 +1,191 @@
+/*
+ * Command for accessing SPI flash.
+ *
+ * Copyright (C) 2008 Atmel Corporation
+ */
+#include <common.h>
+#include <spi_flash.h>
+
+#include <asm/io.h>
+
+#ifndef CONFIG_SF_DEFAULT_SPEED
+# define CONFIG_SF_DEFAULT_SPEED 1000000
+#endif
+#ifndef CONFIG_SF_DEFAULT_MODE
+# define CONFIG_SF_DEFAULT_MODE SPI_MODE_3
+#endif
+
+static struct spi_flash *flash;
+
+static int do_spi_flash_probe(int argc, char *argv[])
+{
+ unsigned int bus = 0;
+ unsigned int cs;
+ unsigned int speed = CONFIG_SF_DEFAULT_SPEED;
+ unsigned int mode = CONFIG_SF_DEFAULT_MODE;
+ char *endp;
+ struct spi_flash *new;
+
+ if (argc < 2)
+ goto usage;
+
+ cs = simple_strtoul(argv[1], &endp, 0);
+ if (*argv[1] == 0 || (*endp != 0 && *endp != ':'))
+ goto usage;
+ if (*endp == ':') {
+ if (endp[1] == 0)
+ goto usage;
+
+ bus = cs;
+ cs = simple_strtoul(endp + 1, &endp, 0);
+ if (*endp != 0)
+ goto usage;
+ }
+
+ if (argc >= 3) {
+ speed = simple_strtoul(argv[2], &endp, 0);
+ if (*argv[2] == 0 || *endp != 0)
+ goto usage;
+ }
+ if (argc >= 4) {
+ mode = simple_strtoul(argv[3], &endp, 0);
+ if (*argv[3] == 0 || *endp != 0)
+ goto usage;
+ }
+
+ new = spi_flash_probe(bus, cs, speed, mode);
+ if (!new) {
+ printf("Failed to initialize SPI flash at %u:%u\n", bus, cs);
+ return 1;
+ }
+
+ if (flash)
+ spi_flash_free(flash);
+ flash = new;
+
+ printf("%u KiB %s at %u:%u is now current device\n",
+ flash->size >> 10, flash->name, bus, cs);
+
+ return 0;
+
+usage:
+ puts("Usage: sf probe [bus:]cs [hz] [mode]\n");
+ return 1;
+}
+
+static int do_spi_flash_read_write(int argc, char *argv[])
+{
+ unsigned long addr;
+ unsigned long offset;
+ unsigned long len;
+ void *buf;
+ char *endp;
+ int ret;
+
+ if (argc < 4)
+ goto usage;
+
+ addr = simple_strtoul(argv[1], &endp, 16);
+ if (*argv[1] == 0 || *endp != 0)
+ goto usage;
+ offset = simple_strtoul(argv[2], &endp, 16);
+ if (*argv[2] == 0 || *endp != 0)
+ goto usage;
+ len = simple_strtoul(argv[3], &endp, 16);
+ if (*argv[3] == 0 || *endp != 0)
+ goto usage;
+
+ buf = map_physmem(addr, len, MAP_WRBACK);
+ if (!buf) {
+ puts("Failed to map physical memory\n");
+ return 1;
+ }
+
+ if (strcmp(argv[0], "read") == 0)
+ ret = spi_flash_read(flash, offset, len, buf);
+ else
+ ret = spi_flash_write(flash, offset, len, buf);
+
+ unmap_physmem(buf, len);
+
+ if (ret) {
+ printf("SPI flash %s failed\n", argv[0]);
+ return 1;
+ }
+
+ return 0;
+
+usage:
+ printf("Usage: sf %s addr offset len\n", argv[0]);
+ return 1;
+}
+
+static int do_spi_flash_erase(int argc, char *argv[])
+{
+ unsigned long offset;
+ unsigned long len;
+ char *endp;
+ int ret;
+
+ if (argc < 3)
+ goto usage;
+
+ offset = simple_strtoul(argv[1], &endp, 16);
+ if (*argv[1] == 0 || *endp != 0)
+ goto usage;
+ len = simple_strtoul(argv[2], &endp, 16);
+ if (*argv[2] == 0 || *endp != 0)
+ goto usage;
+
+ ret = spi_flash_erase(flash, offset, len);
+ if (ret) {
+ printf("SPI flash %s failed\n", argv[0]);
+ return 1;
+ }
+
+ return 0;
+
+usage:
+ puts("Usage: sf erase offset len\n");
+ return 1;
+}
+
+static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ const char *cmd;
+
+ /* need at least two arguments */
+ if (argc < 2)
+ goto usage;
+
+ cmd = argv[1];
+
+ if (strcmp(cmd, "probe") == 0)
+ return do_spi_flash_probe(argc - 1, argv + 1);
+
+ /* The remaining commands require a selected device */
+ if (!flash) {
+ puts("No SPI flash selected. Please run `sf probe'\n");
+ return 1;
+ }
+
+ if (strcmp(cmd, "read") == 0 || strcmp(cmd, "write") == 0)
+ return do_spi_flash_read_write(argc - 1, argv + 1);
+ if (strcmp(cmd, "erase") == 0)
+ return do_spi_flash_erase(argc - 1, argv + 1);
+
+usage:
+ printf("Usage:\n%s\n", cmdtp->usage);
+ return 1;
+}
+
+U_BOOT_CMD(
+ sf, 5, 1, do_spi_flash,
+ "sf - SPI flash sub-system\n",
+ "probe [bus:]cs [hz] [mode] - init flash device on given SPI bus\n"
+ " and chip select\n"
+ "sf read addr offset len - read `len' bytes starting at\n"
+ " `offset' to memory at `addr'\n"
+ "sf write addr offset len - write `len' bytes from memory\n"
+ " at `addr' to flash at `offset'\n"
+ "sf erase offset len - erase `len' bytes from `offset'\n");