blob: 6e7be818ebe8cae981d2cfe2f68991dfac20603c [file] [log] [blame]
Haavard Skinnemoen21266a32008-05-16 11:10:34 +02001/*
2 * Command for accessing SPI flash.
3 *
4 * Copyright (C) 2008 Atmel Corporation
Mike Frysinger22f8b682009-10-09 17:12:44 -04005 * Licensed under the GPL-2 or later.
Haavard Skinnemoen21266a32008-05-16 11:10:34 +02006 */
Mike Frysinger22f8b682009-10-09 17:12:44 -04007
Haavard Skinnemoen21266a32008-05-16 11:10:34 +02008#include <common.h>
9#include <spi_flash.h>
10
11#include <asm/io.h>
12
13#ifndef CONFIG_SF_DEFAULT_SPEED
14# define CONFIG_SF_DEFAULT_SPEED 1000000
15#endif
16#ifndef CONFIG_SF_DEFAULT_MODE
17# define CONFIG_SF_DEFAULT_MODE SPI_MODE_3
18#endif
19
20static struct spi_flash *flash;
21
Wolfgang Denk6262d0212010-06-28 22:00:46 +020022static int do_spi_flash_probe(int argc, char * const argv[])
Haavard Skinnemoen21266a32008-05-16 11:10:34 +020023{
24 unsigned int bus = 0;
25 unsigned int cs;
26 unsigned int speed = CONFIG_SF_DEFAULT_SPEED;
27 unsigned int mode = CONFIG_SF_DEFAULT_MODE;
28 char *endp;
29 struct spi_flash *new;
30
31 if (argc < 2)
32 goto usage;
33
34 cs = simple_strtoul(argv[1], &endp, 0);
35 if (*argv[1] == 0 || (*endp != 0 && *endp != ':'))
36 goto usage;
37 if (*endp == ':') {
38 if (endp[1] == 0)
39 goto usage;
40
41 bus = cs;
42 cs = simple_strtoul(endp + 1, &endp, 0);
43 if (*endp != 0)
44 goto usage;
45 }
46
47 if (argc >= 3) {
48 speed = simple_strtoul(argv[2], &endp, 0);
49 if (*argv[2] == 0 || *endp != 0)
50 goto usage;
51 }
52 if (argc >= 4) {
TsiChung Liewef4a5622009-06-30 14:30:19 +000053 mode = simple_strtoul(argv[3], &endp, 16);
Haavard Skinnemoen21266a32008-05-16 11:10:34 +020054 if (*argv[3] == 0 || *endp != 0)
55 goto usage;
56 }
57
58 new = spi_flash_probe(bus, cs, speed, mode);
59 if (!new) {
60 printf("Failed to initialize SPI flash at %u:%u\n", bus, cs);
61 return 1;
62 }
63
64 if (flash)
65 spi_flash_free(flash);
66 flash = new;
67
68 printf("%u KiB %s at %u:%u is now current device\n",
69 flash->size >> 10, flash->name, bus, cs);
70
71 return 0;
72
73usage:
74 puts("Usage: sf probe [bus:]cs [hz] [mode]\n");
75 return 1;
76}
77
Wolfgang Denk6262d0212010-06-28 22:00:46 +020078static int do_spi_flash_read_write(int argc, char * const argv[])
Haavard Skinnemoen21266a32008-05-16 11:10:34 +020079{
80 unsigned long addr;
81 unsigned long offset;
82 unsigned long len;
83 void *buf;
84 char *endp;
85 int ret;
86
87 if (argc < 4)
88 goto usage;
89
90 addr = simple_strtoul(argv[1], &endp, 16);
91 if (*argv[1] == 0 || *endp != 0)
92 goto usage;
93 offset = simple_strtoul(argv[2], &endp, 16);
94 if (*argv[2] == 0 || *endp != 0)
95 goto usage;
96 len = simple_strtoul(argv[3], &endp, 16);
97 if (*argv[3] == 0 || *endp != 0)
98 goto usage;
99
100 buf = map_physmem(addr, len, MAP_WRBACK);
101 if (!buf) {
102 puts("Failed to map physical memory\n");
103 return 1;
104 }
105
106 if (strcmp(argv[0], "read") == 0)
107 ret = spi_flash_read(flash, offset, len, buf);
108 else
109 ret = spi_flash_write(flash, offset, len, buf);
110
111 unmap_physmem(buf, len);
112
113 if (ret) {
114 printf("SPI flash %s failed\n", argv[0]);
115 return 1;
116 }
117
118 return 0;
119
120usage:
121 printf("Usage: sf %s addr offset len\n", argv[0]);
122 return 1;
123}
124
Wolfgang Denk6262d0212010-06-28 22:00:46 +0200125static int do_spi_flash_erase(int argc, char * const argv[])
Haavard Skinnemoen21266a32008-05-16 11:10:34 +0200126{
127 unsigned long offset;
128 unsigned long len;
129 char *endp;
130 int ret;
131
132 if (argc < 3)
133 goto usage;
134
135 offset = simple_strtoul(argv[1], &endp, 16);
136 if (*argv[1] == 0 || *endp != 0)
137 goto usage;
138 len = simple_strtoul(argv[2], &endp, 16);
139 if (*argv[2] == 0 || *endp != 0)
140 goto usage;
141
142 ret = spi_flash_erase(flash, offset, len);
143 if (ret) {
144 printf("SPI flash %s failed\n", argv[0]);
145 return 1;
146 }
147
148 return 0;
149
150usage:
151 puts("Usage: sf erase offset len\n");
152 return 1;
153}
154
Wolfgang Denk6262d0212010-06-28 22:00:46 +0200155static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
Haavard Skinnemoen21266a32008-05-16 11:10:34 +0200156{
157 const char *cmd;
158
159 /* need at least two arguments */
160 if (argc < 2)
161 goto usage;
162
163 cmd = argv[1];
164
165 if (strcmp(cmd, "probe") == 0)
166 return do_spi_flash_probe(argc - 1, argv + 1);
167
168 /* The remaining commands require a selected device */
169 if (!flash) {
170 puts("No SPI flash selected. Please run `sf probe'\n");
171 return 1;
172 }
173
174 if (strcmp(cmd, "read") == 0 || strcmp(cmd, "write") == 0)
175 return do_spi_flash_read_write(argc - 1, argv + 1);
176 if (strcmp(cmd, "erase") == 0)
177 return do_spi_flash_erase(argc - 1, argv + 1);
178
179usage:
Wolfgang Denk3b683112010-07-17 01:06:04 +0200180 return cmd_usage(cmdtp);
Haavard Skinnemoen21266a32008-05-16 11:10:34 +0200181}
182
183U_BOOT_CMD(
184 sf, 5, 1, do_spi_flash,
Peter Tyserdfb72b82009-01-27 18:03:12 -0600185 "SPI flash sub-system",
Haavard Skinnemoen21266a32008-05-16 11:10:34 +0200186 "probe [bus:]cs [hz] [mode] - init flash device on given SPI bus\n"
187 " and chip select\n"
188 "sf read addr offset len - read `len' bytes starting at\n"
189 " `offset' to memory at `addr'\n"
190 "sf write addr offset len - write `len' bytes from memory\n"
191 " at `addr' to flash at `offset'\n"
Wolfgang Denkc54781c2009-05-24 17:06:54 +0200192 "sf erase offset len - erase `len' bytes from `offset'"
193);