From b6368467e6a97f225e0a5fd7bfc5c7598ef5ddc4 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Fri, 16 May 2008 11:10:34 +0200 Subject: [PATCH] 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 --- common/Makefile | 1 + common/cmd_sf.c | 191 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 192 insertions(+) create mode 100644 common/cmd_sf.c diff --git a/common/Makefile b/common/Makefile index 9678799..d90b5f2 100644 --- a/common/Makefile +++ b/common/Makefile @@ -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 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 +#include + +#include + +#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");