diff options
author | Haavard Skinnemoen <haavard.skinnemoen@atmel.com> | 2008-05-16 11:10:34 +0200 |
---|---|---|
committer | Wolfgang Denk <wd@denx.de> | 2008-06-03 20:32:25 +0200 |
commit | b6368467e6a97f225e0a5fd7bfc5c7598ef5ddc4 (patch) | |
tree | 52c7753fe2a5a5c6fba8d115e37638ea66a8b7f2 /common/cmd_sf.c | |
parent | d25ce7d24cc0f93881559f4009175ea305af65e8 (diff) |
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>
Diffstat (limited to 'common/cmd_sf.c')
-rw-r--r-- | common/cmd_sf.c | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/common/cmd_sf.c b/common/cmd_sf.c new file mode 100644 index 00000000000..8c0a7514dfa --- /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"); |