SPI Flash: Add "sf" command
authorHaavard Skinnemoen <haavard.skinnemoen@atmel.com>
Fri, 16 May 2008 09:10:34 +0000 (11:10 +0200)
committerWolfgang Denk <wd@denx.de>
Tue, 3 Jun 2008 18:32:25 +0000 (20:32 +0200)
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>
common/Makefile
common/cmd_sf.c [new file with mode: 0644]

index 9678799..d90b5f2 100644 (file)
@@ -143,6 +143,7 @@ COBJS-y += xyzModem.o
 COBJS-y += cmd_mac.o
 COBJS-$(CONFIG_CMD_MFSL) += cmd_mfsl.o
 COBJS-$(CONFIG_MP) += cmd_mp.o
+COBJS-$(CONFIG_CMD_SF) += cmd_sf.o
 
 COBJS  := $(COBJS-y)
 SRCS   := $(AOBJS:.o=.S) $(COBJS:.o=.c)
diff --git a/common/cmd_sf.c b/common/cmd_sf.c
new file mode 100644 (file)
index 0000000..8c0a751
--- /dev/null
@@ -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");