Commit 029e728fc247bff680d202316071af64ca376aea

Authored by Eric Lee
1 parent 27b1dc5fe2

Unlock SPI NOR in sf utility.

Showing 1 changed file with 15 additions and 3 deletions Inline Diff

1 /* 1 /*
2 * Command for accessing SPI flash. 2 * Command for accessing SPI flash.
3 * 3 *
4 * Copyright (C) 2008 Atmel Corporation 4 * Copyright (C) 2008 Atmel Corporation
5 * 5 *
6 * SPDX-License-Identifier: GPL-2.0+ 6 * SPDX-License-Identifier: GPL-2.0+
7 */ 7 */
8 8
9 #include <common.h> 9 #include <common.h>
10 #include <div64.h> 10 #include <div64.h>
11 #include <malloc.h> 11 #include <malloc.h>
12 #include <spi_flash.h> 12 #include <spi_flash.h>
13 #include <asm/gpio.h>
13 14
14 #include <asm/io.h> 15 #include <asm/io.h>
15 16
16 #ifndef CONFIG_SF_DEFAULT_SPEED 17 #ifndef CONFIG_SF_DEFAULT_SPEED
17 # define CONFIG_SF_DEFAULT_SPEED 1000000 18 # define CONFIG_SF_DEFAULT_SPEED 1000000
18 #endif 19 #endif
19 #ifndef CONFIG_SF_DEFAULT_MODE 20 #ifndef CONFIG_SF_DEFAULT_MODE
20 # define CONFIG_SF_DEFAULT_MODE SPI_MODE_3 21 # define CONFIG_SF_DEFAULT_MODE SPI_MODE_3
21 #endif 22 #endif
22 #ifndef CONFIG_SF_DEFAULT_CS 23 #ifndef CONFIG_SF_DEFAULT_CS
23 # define CONFIG_SF_DEFAULT_CS 0 24 # define CONFIG_SF_DEFAULT_CS 0
24 #endif 25 #endif
25 #ifndef CONFIG_SF_DEFAULT_BUS 26 #ifndef CONFIG_SF_DEFAULT_BUS
26 # define CONFIG_SF_DEFAULT_BUS 0 27 # define CONFIG_SF_DEFAULT_BUS 0
27 #endif 28 #endif
28 29
29 static struct spi_flash *flash; 30 static struct spi_flash *flash;
30 31
31 32
32 /* 33 /*
33 * This function computes the length argument for the erase command. 34 * This function computes the length argument for the erase command.
34 * The length on which the command is to operate can be given in two forms: 35 * The length on which the command is to operate can be given in two forms:
35 * 1. <cmd> offset len - operate on <'offset', 'len') 36 * 1. <cmd> offset len - operate on <'offset', 'len')
36 * 2. <cmd> offset +len - operate on <'offset', 'round_up(len)') 37 * 2. <cmd> offset +len - operate on <'offset', 'round_up(len)')
37 * If the second form is used and the length doesn't fall on the 38 * If the second form is used and the length doesn't fall on the
38 * sector boundary, than it will be adjusted to the next sector boundary. 39 * sector boundary, than it will be adjusted to the next sector boundary.
39 * If it isn't in the flash, the function will fail (return -1). 40 * If it isn't in the flash, the function will fail (return -1).
40 * Input: 41 * Input:
41 * arg: length specification (i.e. both command arguments) 42 * arg: length specification (i.e. both command arguments)
42 * Output: 43 * Output:
43 * len: computed length for operation 44 * len: computed length for operation
44 * Return: 45 * Return:
45 * 1: success 46 * 1: success
46 * -1: failure (bad format, bad address). 47 * -1: failure (bad format, bad address).
47 */ 48 */
48 static int sf_parse_len_arg(char *arg, ulong *len) 49 static int sf_parse_len_arg(char *arg, ulong *len)
49 { 50 {
50 char *ep; 51 char *ep;
51 char round_up_len; /* indicates if the "+length" form used */ 52 char round_up_len; /* indicates if the "+length" form used */
52 ulong len_arg; 53 ulong len_arg;
53 54
54 round_up_len = 0; 55 round_up_len = 0;
55 if (*arg == '+') { 56 if (*arg == '+') {
56 round_up_len = 1; 57 round_up_len = 1;
57 ++arg; 58 ++arg;
58 } 59 }
59 60
60 len_arg = simple_strtoul(arg, &ep, 16); 61 len_arg = simple_strtoul(arg, &ep, 16);
61 if (ep == arg || *ep != '\0') 62 if (ep == arg || *ep != '\0')
62 return -1; 63 return -1;
63 64
64 if (round_up_len && flash->sector_size > 0) 65 if (round_up_len && flash->sector_size > 0)
65 *len = ROUND(len_arg, flash->sector_size); 66 *len = ROUND(len_arg, flash->sector_size);
66 else 67 else
67 *len = len_arg; 68 *len = len_arg;
68 69
69 return 1; 70 return 1;
70 } 71 }
71 72
72 /** 73 /**
73 * This function takes a byte length and a delta unit of time to compute the 74 * This function takes a byte length and a delta unit of time to compute the
74 * approximate bytes per second 75 * approximate bytes per second
75 * 76 *
76 * @param len amount of bytes currently processed 77 * @param len amount of bytes currently processed
77 * @param start_ms start time of processing in ms 78 * @param start_ms start time of processing in ms
78 * @return bytes per second if OK, 0 on error 79 * @return bytes per second if OK, 0 on error
79 */ 80 */
80 static ulong bytes_per_second(unsigned int len, ulong start_ms) 81 static ulong bytes_per_second(unsigned int len, ulong start_ms)
81 { 82 {
82 /* less accurate but avoids overflow */ 83 /* less accurate but avoids overflow */
83 if (len >= ((unsigned int) -1) / 1024) 84 if (len >= ((unsigned int) -1) / 1024)
84 return len / (max(get_timer(start_ms) / 1024, 1)); 85 return len / (max(get_timer(start_ms) / 1024, 1));
85 else 86 else
86 return 1024 * len / max(get_timer(start_ms), 1); 87 return 1024 * len / max(get_timer(start_ms), 1);
87 } 88 }
88 89
89 static int do_spi_flash_probe(int argc, char * const argv[]) 90 static int do_spi_flash_probe(int argc, char * const argv[])
90 { 91 {
91 unsigned int bus = CONFIG_SF_DEFAULT_BUS; 92 unsigned int bus = CONFIG_SF_DEFAULT_BUS;
92 unsigned int cs = CONFIG_SF_DEFAULT_CS; 93 unsigned int cs = CONFIG_SF_DEFAULT_CS;
93 unsigned int speed = CONFIG_SF_DEFAULT_SPEED; 94 unsigned int speed = CONFIG_SF_DEFAULT_SPEED;
94 unsigned int mode = CONFIG_SF_DEFAULT_MODE; 95 unsigned int mode = CONFIG_SF_DEFAULT_MODE;
95 char *endp; 96 char *endp;
96 struct spi_flash *new; 97 struct spi_flash *new;
97 98
98 if (argc >= 2) { 99 if (argc >= 2) {
99 cs = simple_strtoul(argv[1], &endp, 0); 100 cs = simple_strtoul(argv[1], &endp, 0);
100 if (*argv[1] == 0 || (*endp != 0 && *endp != ':')) 101 if (*argv[1] == 0 || (*endp != 0 && *endp != ':'))
101 return -1; 102 return -1;
102 if (*endp == ':') { 103 if (*endp == ':') {
103 if (endp[1] == 0) 104 if (endp[1] == 0)
104 return -1; 105 return -1;
105 106
106 bus = cs; 107 bus = cs;
107 cs = simple_strtoul(endp + 1, &endp, 0); 108 cs = simple_strtoul(endp + 1, &endp, 0);
108 if (*endp != 0) 109 if (*endp != 0)
109 return -1; 110 return -1;
110 } 111 }
111 } 112 }
112 113
113 if (argc >= 3) { 114 if (argc >= 3) {
114 speed = simple_strtoul(argv[2], &endp, 0); 115 speed = simple_strtoul(argv[2], &endp, 0);
115 if (*argv[2] == 0 || *endp != 0) 116 if (*argv[2] == 0 || *endp != 0)
116 return -1; 117 return -1;
117 } 118 }
118 if (argc >= 4) { 119 if (argc >= 4) {
119 mode = simple_strtoul(argv[3], &endp, 16); 120 mode = simple_strtoul(argv[3], &endp, 16);
120 if (*argv[3] == 0 || *endp != 0) 121 if (*argv[3] == 0 || *endp != 0)
121 return -1; 122 return -1;
122 } 123 }
123 124
124 new = spi_flash_probe(bus, cs, speed, mode); 125 new = spi_flash_probe(bus, cs, speed, mode);
125 if (!new) { 126 if (!new) {
126 printf("Failed to initialize SPI flash at %u:%u\n", bus, cs); 127 printf("Failed to initialize SPI flash at %u:%u\n", bus, cs);
127 return 1; 128 return 1;
128 } 129 }
129 130
130 if (flash) 131 if (flash)
131 spi_flash_free(flash); 132 spi_flash_free(flash);
132 flash = new; 133 flash = new;
133 134
134 return 0; 135 return 0;
135 } 136 }
136 137
137 /** 138 /**
138 * Write a block of data to SPI flash, first checking if it is different from 139 * Write a block of data to SPI flash, first checking if it is different from
139 * what is already there. 140 * what is already there.
140 * 141 *
141 * If the data being written is the same, then *skipped is incremented by len. 142 * If the data being written is the same, then *skipped is incremented by len.
142 * 143 *
143 * @param flash flash context pointer 144 * @param flash flash context pointer
144 * @param offset flash offset to write 145 * @param offset flash offset to write
145 * @param len number of bytes to write 146 * @param len number of bytes to write
146 * @param buf buffer to write from 147 * @param buf buffer to write from
147 * @param cmp_buf read buffer to use to compare data 148 * @param cmp_buf read buffer to use to compare data
148 * @param skipped Count of skipped data (incremented by this function) 149 * @param skipped Count of skipped data (incremented by this function)
149 * @return NULL if OK, else a string containing the stage which failed 150 * @return NULL if OK, else a string containing the stage which failed
150 */ 151 */
151 static const char *spi_flash_update_block(struct spi_flash *flash, u32 offset, 152 static const char *spi_flash_update_block(struct spi_flash *flash, u32 offset,
152 size_t len, const char *buf, char *cmp_buf, size_t *skipped) 153 size_t len, const char *buf, char *cmp_buf, size_t *skipped)
153 { 154 {
154 debug("offset=%#x, sector_size=%#x, len=%#zx\n", 155 debug("offset=%#x, sector_size=%#x, len=%#zx\n",
155 offset, flash->sector_size, len); 156 offset, flash->sector_size, len);
156 /* Read the entire sector so to allow for rewriting */ 157 /* Read the entire sector so to allow for rewriting */
157 if (spi_flash_read(flash, offset, flash->sector_size, cmp_buf)) 158 if (spi_flash_read(flash, offset, flash->sector_size, cmp_buf))
158 return "read"; 159 return "read";
159 /* Compare only what is meaningful (len) */ 160 /* Compare only what is meaningful (len) */
160 if (memcmp(cmp_buf, buf, len) == 0) { 161 if (memcmp(cmp_buf, buf, len) == 0) {
161 debug("Skip region %x size %zx: no change\n", 162 debug("Skip region %x size %zx: no change\n",
162 offset, len); 163 offset, len);
163 *skipped += len; 164 *skipped += len;
164 return NULL; 165 return NULL;
165 } 166 }
166 /* Erase the entire sector */ 167 /* Erase the entire sector */
167 if (spi_flash_erase(flash, offset, flash->sector_size)) 168 if (spi_flash_erase(flash, offset, flash->sector_size))
168 return "erase"; 169 return "erase";
169 /* Write the initial part of the block from the source */ 170 /* Write the initial part of the block from the source */
170 if (spi_flash_write(flash, offset, len, buf)) 171 if (spi_flash_write(flash, offset, len, buf))
171 return "write"; 172 return "write";
172 /* If it's a partial sector, rewrite the existing part */ 173 /* If it's a partial sector, rewrite the existing part */
173 if (len != flash->sector_size) { 174 if (len != flash->sector_size) {
174 /* Rewrite the original data to the end of the sector */ 175 /* Rewrite the original data to the end of the sector */
175 if (spi_flash_write(flash, offset + len, 176 if (spi_flash_write(flash, offset + len,
176 flash->sector_size - len, &cmp_buf[len])) 177 flash->sector_size - len, &cmp_buf[len]))
177 return "write"; 178 return "write";
178 } 179 }
179 180
180 return NULL; 181 return NULL;
181 } 182 }
182 183
183 /** 184 /**
184 * Update an area of SPI flash by erasing and writing any blocks which need 185 * Update an area of SPI flash by erasing and writing any blocks which need
185 * to change. Existing blocks with the correct data are left unchanged. 186 * to change. Existing blocks with the correct data are left unchanged.
186 * 187 *
187 * @param flash flash context pointer 188 * @param flash flash context pointer
188 * @param offset flash offset to write 189 * @param offset flash offset to write
189 * @param len number of bytes to write 190 * @param len number of bytes to write
190 * @param buf buffer to write from 191 * @param buf buffer to write from
191 * @return 0 if ok, 1 on error 192 * @return 0 if ok, 1 on error
192 */ 193 */
193 static int spi_flash_update(struct spi_flash *flash, u32 offset, 194 static int spi_flash_update(struct spi_flash *flash, u32 offset,
194 size_t len, const char *buf) 195 size_t len, const char *buf)
195 { 196 {
196 const char *err_oper = NULL; 197 const char *err_oper = NULL;
197 char *cmp_buf; 198 char *cmp_buf;
198 const char *end = buf + len; 199 const char *end = buf + len;
199 size_t todo; /* number of bytes to do in this pass */ 200 size_t todo; /* number of bytes to do in this pass */
200 size_t skipped = 0; /* statistics */ 201 size_t skipped = 0; /* statistics */
201 const ulong start_time = get_timer(0); 202 const ulong start_time = get_timer(0);
202 size_t scale = 1; 203 size_t scale = 1;
203 const char *start_buf = buf; 204 const char *start_buf = buf;
204 ulong delta; 205 ulong delta;
205 206
206 if (end - buf >= 200) 207 if (end - buf >= 200)
207 scale = (end - buf) / 100; 208 scale = (end - buf) / 100;
208 cmp_buf = malloc(flash->sector_size); 209 cmp_buf = malloc(flash->sector_size);
209 if (cmp_buf) { 210 if (cmp_buf) {
210 ulong last_update = get_timer(0); 211 ulong last_update = get_timer(0);
211 212
212 for (; buf < end && !err_oper; buf += todo, offset += todo) { 213 for (; buf < end && !err_oper; buf += todo, offset += todo) {
213 todo = min(end - buf, flash->sector_size); 214 todo = min(end - buf, flash->sector_size);
214 if (get_timer(last_update) > 100) { 215 if (get_timer(last_update) > 100) {
215 printf(" \rUpdating, %zu%% %lu B/s", 216 printf(" \rUpdating, %zu%% %lu B/s",
216 100 - (end - buf) / scale, 217 100 - (end - buf) / scale,
217 bytes_per_second(buf - start_buf, 218 bytes_per_second(buf - start_buf,
218 start_time)); 219 start_time));
219 last_update = get_timer(0); 220 last_update = get_timer(0);
220 } 221 }
221 err_oper = spi_flash_update_block(flash, offset, todo, 222 err_oper = spi_flash_update_block(flash, offset, todo,
222 buf, cmp_buf, &skipped); 223 buf, cmp_buf, &skipped);
223 } 224 }
224 } else { 225 } else {
225 err_oper = "malloc"; 226 err_oper = "malloc";
226 } 227 }
227 free(cmp_buf); 228 free(cmp_buf);
228 putc('\r'); 229 putc('\r');
229 if (err_oper) { 230 if (err_oper) {
230 printf("SPI flash failed in %s step\n", err_oper); 231 printf("SPI flash failed in %s step\n", err_oper);
231 return 1; 232 return 1;
232 } 233 }
233 234
234 delta = get_timer(start_time); 235 delta = get_timer(start_time);
235 printf("%zu bytes written, %zu bytes skipped", len - skipped, 236 printf("%zu bytes written, %zu bytes skipped", len - skipped,
236 skipped); 237 skipped);
237 printf(" in %ld.%lds, speed %ld B/s\n", 238 printf(" in %ld.%lds, speed %ld B/s\n",
238 delta / 1000, delta % 1000, bytes_per_second(len, start_time)); 239 delta / 1000, delta % 1000, bytes_per_second(len, start_time));
239 240
240 return 0; 241 return 0;
241 } 242 }
242 243
243 static int do_spi_flash_read_write(int argc, char * const argv[]) 244 static int do_spi_flash_read_write(int argc, char * const argv[])
244 { 245 {
245 unsigned long addr; 246 unsigned long addr;
246 unsigned long offset; 247 unsigned long offset;
247 unsigned long len; 248 unsigned long len;
248 void *buf; 249 void *buf;
249 char *endp; 250 char *endp;
250 int ret = 1; 251 int ret = 1;
251 252
252 if (argc < 4) 253 if (argc < 4)
253 return -1; 254 return -1;
254 255
255 addr = simple_strtoul(argv[1], &endp, 16); 256 addr = simple_strtoul(argv[1], &endp, 16);
256 if (*argv[1] == 0 || *endp != 0) 257 if (*argv[1] == 0 || *endp != 0)
257 return -1; 258 return -1;
258 offset = simple_strtoul(argv[2], &endp, 16); 259 offset = simple_strtoul(argv[2], &endp, 16);
259 if (*argv[2] == 0 || *endp != 0) 260 if (*argv[2] == 0 || *endp != 0)
260 return -1; 261 return -1;
261 len = simple_strtoul(argv[3], &endp, 16); 262 len = simple_strtoul(argv[3], &endp, 16);
262 if (*argv[3] == 0 || *endp != 0) 263 if (*argv[3] == 0 || *endp != 0)
263 return -1; 264 return -1;
264 265
265 /* Consistency checking */ 266 /* Consistency checking */
266 if (offset + len > flash->size) { 267 if (offset + len > flash->size) {
267 printf("ERROR: attempting %s past flash size (%#x)\n", 268 printf("ERROR: attempting %s past flash size (%#x)\n",
268 argv[0], flash->size); 269 argv[0], flash->size);
269 return 1; 270 return 1;
270 } 271 }
271 272
272 buf = map_physmem(addr, len, MAP_WRBACK); 273 buf = map_physmem(addr, len, MAP_WRBACK);
273 if (!buf) { 274 if (!buf) {
274 puts("Failed to map physical memory\n"); 275 puts("Failed to map physical memory\n");
275 return 1; 276 return 1;
276 } 277 }
277 278
278 if (strcmp(argv[0], "update") == 0) { 279 if (strcmp(argv[0], "update") == 0) {
279 ret = spi_flash_update(flash, offset, len, buf); 280 ret = spi_flash_update(flash, offset, len, buf);
280 } else if (strncmp(argv[0], "read", 4) == 0 || 281 } else if (strncmp(argv[0], "read", 4) == 0 ||
281 strncmp(argv[0], "write", 5) == 0) { 282 strncmp(argv[0], "write", 5) == 0) {
282 int read; 283 int read;
283 284
284 read = strncmp(argv[0], "read", 4) == 0; 285 read = strncmp(argv[0], "read", 4) == 0;
285 if (read) 286 if (read)
286 ret = spi_flash_read(flash, offset, len, buf); 287 ret = spi_flash_read(flash, offset, len, buf);
287 else 288 else
288 ret = spi_flash_write(flash, offset, len, buf); 289 ret = spi_flash_write(flash, offset, len, buf);
289 290
290 printf("SF: %zu bytes @ %#x %s: %s\n", (size_t)len, (u32)offset, 291 printf("SF: %zu bytes @ %#x %s: %s\n", (size_t)len, (u32)offset,
291 read ? "Read" : "Written", ret ? "ERROR" : "OK"); 292 read ? "Read" : "Written", ret ? "ERROR" : "OK");
292 } 293 }
293 294
294 unmap_physmem(buf, len); 295 unmap_physmem(buf, len);
295 296
296 return ret == 0 ? 0 : 1; 297 return ret == 0 ? 0 : 1;
297 } 298 }
298 299
299 static int do_spi_flash_erase(int argc, char * const argv[]) 300 static int do_spi_flash_erase(int argc, char * const argv[])
300 { 301 {
301 unsigned long offset; 302 unsigned long offset;
302 unsigned long len; 303 unsigned long len;
303 char *endp; 304 char *endp;
304 int ret; 305 int ret;
305 306
306 if (argc < 3) 307 if (argc < 3)
307 return -1; 308 return -1;
308 309
309 offset = simple_strtoul(argv[1], &endp, 16); 310 offset = simple_strtoul(argv[1], &endp, 16);
310 if (*argv[1] == 0 || *endp != 0) 311 if (*argv[1] == 0 || *endp != 0)
311 return -1; 312 return -1;
312 313
313 ret = sf_parse_len_arg(argv[2], &len); 314 ret = sf_parse_len_arg(argv[2], &len);
314 if (ret != 1) 315 if (ret != 1)
315 return -1; 316 return -1;
316 317
317 /* Consistency checking */ 318 /* Consistency checking */
318 if (offset + len > flash->size) { 319 if (offset + len > flash->size) {
319 printf("ERROR: attempting %s past flash size (%#x)\n", 320 printf("ERROR: attempting %s past flash size (%#x)\n",
320 argv[0], flash->size); 321 argv[0], flash->size);
321 return 1; 322 return 1;
322 } 323 }
323 324
324 ret = spi_flash_erase(flash, offset, len); 325 ret = spi_flash_erase(flash, offset, len);
325 printf("SF: %zu bytes @ %#x Erased: %s\n", (size_t)len, (u32)offset, 326 printf("SF: %zu bytes @ %#x Erased: %s\n", (size_t)len, (u32)offset,
326 ret ? "ERROR" : "OK"); 327 ret ? "ERROR" : "OK");
327 328
328 return ret == 0 ? 0 : 1; 329 return ret == 0 ? 0 : 1;
329 } 330 }
330 331
331 #ifdef CONFIG_CMD_SF_TEST 332 #ifdef CONFIG_CMD_SF_TEST
332 enum { 333 enum {
333 STAGE_ERASE, 334 STAGE_ERASE,
334 STAGE_CHECK, 335 STAGE_CHECK,
335 STAGE_WRITE, 336 STAGE_WRITE,
336 STAGE_READ, 337 STAGE_READ,
337 338
338 STAGE_COUNT, 339 STAGE_COUNT,
339 }; 340 };
340 341
341 static char *stage_name[STAGE_COUNT] = { 342 static char *stage_name[STAGE_COUNT] = {
342 "erase", 343 "erase",
343 "check", 344 "check",
344 "write", 345 "write",
345 "read", 346 "read",
346 }; 347 };
347 348
348 struct test_info { 349 struct test_info {
349 int stage; 350 int stage;
350 int bytes; 351 int bytes;
351 unsigned base_ms; 352 unsigned base_ms;
352 unsigned time_ms[STAGE_COUNT]; 353 unsigned time_ms[STAGE_COUNT];
353 }; 354 };
354 355
355 static void show_time(struct test_info *test, int stage) 356 static void show_time(struct test_info *test, int stage)
356 { 357 {
357 uint64_t speed; /* KiB/s */ 358 uint64_t speed; /* KiB/s */
358 int bps; /* Bits per second */ 359 int bps; /* Bits per second */
359 360
360 speed = (long long)test->bytes * 1000; 361 speed = (long long)test->bytes * 1000;
361 if (test->time_ms[stage]) 362 if (test->time_ms[stage])
362 do_div(speed, test->time_ms[stage] * 1024); 363 do_div(speed, test->time_ms[stage] * 1024);
363 bps = speed * 8; 364 bps = speed * 8;
364 365
365 printf("%d %s: %d ticks, %d KiB/s %d.%03d Mbps\n", stage, 366 printf("%d %s: %d ticks, %d KiB/s %d.%03d Mbps\n", stage,
366 stage_name[stage], test->time_ms[stage], 367 stage_name[stage], test->time_ms[stage],
367 (int)speed, bps / 1000, bps % 1000); 368 (int)speed, bps / 1000, bps % 1000);
368 } 369 }
369 370
370 static void spi_test_next_stage(struct test_info *test) 371 static void spi_test_next_stage(struct test_info *test)
371 { 372 {
372 test->time_ms[test->stage] = get_timer(test->base_ms); 373 test->time_ms[test->stage] = get_timer(test->base_ms);
373 show_time(test, test->stage); 374 show_time(test, test->stage);
374 test->base_ms = get_timer(0); 375 test->base_ms = get_timer(0);
375 test->stage++; 376 test->stage++;
376 } 377 }
377 378
378 /** 379 /**
379 * Run a test on the SPI flash 380 * Run a test on the SPI flash
380 * 381 *
381 * @param flash SPI flash to use 382 * @param flash SPI flash to use
382 * @param buf Source buffer for data to write 383 * @param buf Source buffer for data to write
383 * @param len Size of data to read/write 384 * @param len Size of data to read/write
384 * @param offset Offset within flash to check 385 * @param offset Offset within flash to check
385 * @param vbuf Verification buffer 386 * @param vbuf Verification buffer
386 * @return 0 if ok, -1 on error 387 * @return 0 if ok, -1 on error
387 */ 388 */
388 static int spi_flash_test(struct spi_flash *flash, uint8_t *buf, ulong len, 389 static int spi_flash_test(struct spi_flash *flash, uint8_t *buf, ulong len,
389 ulong offset, uint8_t *vbuf) 390 ulong offset, uint8_t *vbuf)
390 { 391 {
391 struct test_info test; 392 struct test_info test;
392 int i; 393 int i;
393 394
394 printf("SPI flash test:\n"); 395 printf("SPI flash test:\n");
395 memset(&test, '\0', sizeof(test)); 396 memset(&test, '\0', sizeof(test));
396 test.base_ms = get_timer(0); 397 test.base_ms = get_timer(0);
397 test.bytes = len; 398 test.bytes = len;
398 if (spi_flash_erase(flash, offset, len)) { 399 if (spi_flash_erase(flash, offset, len)) {
399 printf("Erase failed\n"); 400 printf("Erase failed\n");
400 return -1; 401 return -1;
401 } 402 }
402 spi_test_next_stage(&test); 403 spi_test_next_stage(&test);
403 404
404 if (spi_flash_read(flash, offset, len, vbuf)) { 405 if (spi_flash_read(flash, offset, len, vbuf)) {
405 printf("Check read failed\n"); 406 printf("Check read failed\n");
406 return -1; 407 return -1;
407 } 408 }
408 for (i = 0; i < len; i++) { 409 for (i = 0; i < len; i++) {
409 if (vbuf[i] != 0xff) { 410 if (vbuf[i] != 0xff) {
410 printf("Check failed at %d\n", i); 411 printf("Check failed at %d\n", i);
411 print_buffer(i, vbuf + i, 1, min(len - i, 0x40), 0); 412 print_buffer(i, vbuf + i, 1, min(len - i, 0x40), 0);
412 return -1; 413 return -1;
413 } 414 }
414 } 415 }
415 spi_test_next_stage(&test); 416 spi_test_next_stage(&test);
416 417
417 if (spi_flash_write(flash, offset, len, buf)) { 418 if (spi_flash_write(flash, offset, len, buf)) {
418 printf("Write failed\n"); 419 printf("Write failed\n");
419 return -1; 420 return -1;
420 } 421 }
421 memset(vbuf, '\0', len); 422 memset(vbuf, '\0', len);
422 spi_test_next_stage(&test); 423 spi_test_next_stage(&test);
423 424
424 if (spi_flash_read(flash, offset, len, vbuf)) { 425 if (spi_flash_read(flash, offset, len, vbuf)) {
425 printf("Read failed\n"); 426 printf("Read failed\n");
426 return -1; 427 return -1;
427 } 428 }
428 spi_test_next_stage(&test); 429 spi_test_next_stage(&test);
429 430
430 for (i = 0; i < len; i++) { 431 for (i = 0; i < len; i++) {
431 if (buf[i] != vbuf[i]) { 432 if (buf[i] != vbuf[i]) {
432 printf("Verify failed at %d, good data:\n", i); 433 printf("Verify failed at %d, good data:\n", i);
433 print_buffer(i, buf + i, 1, min(len - i, 0x40), 0); 434 print_buffer(i, buf + i, 1, min(len - i, 0x40), 0);
434 printf("Bad data:\n"); 435 printf("Bad data:\n");
435 print_buffer(i, vbuf + i, 1, min(len - i, 0x40), 0); 436 print_buffer(i, vbuf + i, 1, min(len - i, 0x40), 0);
436 return -1; 437 return -1;
437 } 438 }
438 } 439 }
439 printf("Test passed\n"); 440 printf("Test passed\n");
440 for (i = 0; i < STAGE_COUNT; i++) 441 for (i = 0; i < STAGE_COUNT; i++)
441 show_time(&test, i); 442 show_time(&test, i);
442 443
443 return 0; 444 return 0;
444 } 445 }
445 446
446 static int do_spi_flash_test(int argc, char * const argv[]) 447 static int do_spi_flash_test(int argc, char * const argv[])
447 { 448 {
448 unsigned long offset; 449 unsigned long offset;
449 unsigned long len; 450 unsigned long len;
450 uint8_t *buf, *from; 451 uint8_t *buf, *from;
451 char *endp; 452 char *endp;
452 uint8_t *vbuf; 453 uint8_t *vbuf;
453 int ret; 454 int ret;
454 455
455 if (argc < 3) 456 if (argc < 3)
456 return -1; 457 return -1;
457 offset = simple_strtoul(argv[1], &endp, 16); 458 offset = simple_strtoul(argv[1], &endp, 16);
458 if (*argv[1] == 0 || *endp != 0) 459 if (*argv[1] == 0 || *endp != 0)
459 return -1; 460 return -1;
460 len = simple_strtoul(argv[2], &endp, 16); 461 len = simple_strtoul(argv[2], &endp, 16);
461 if (*argv[2] == 0 || *endp != 0) 462 if (*argv[2] == 0 || *endp != 0)
462 return -1; 463 return -1;
463 464
464 vbuf = malloc(len); 465 vbuf = malloc(len);
465 if (!vbuf) { 466 if (!vbuf) {
466 printf("Cannot allocate memory (%lu bytes)\n", len); 467 printf("Cannot allocate memory (%lu bytes)\n", len);
467 return 1; 468 return 1;
468 } 469 }
469 buf = malloc(len); 470 buf = malloc(len);
470 if (!buf) { 471 if (!buf) {
471 free(vbuf); 472 free(vbuf);
472 printf("Cannot allocate memory (%lu bytes)\n", len); 473 printf("Cannot allocate memory (%lu bytes)\n", len);
473 return 1; 474 return 1;
474 } 475 }
475 476
476 from = map_sysmem(CONFIG_SYS_TEXT_BASE, 0); 477 from = map_sysmem(CONFIG_SYS_TEXT_BASE, 0);
477 memcpy(buf, from, len); 478 memcpy(buf, from, len);
478 ret = spi_flash_test(flash, buf, len, offset, vbuf); 479 ret = spi_flash_test(flash, buf, len, offset, vbuf);
479 free(vbuf); 480 free(vbuf);
480 free(buf); 481 free(buf);
481 if (ret) { 482 if (ret) {
482 printf("Test failed\n"); 483 printf("Test failed\n");
483 return 1; 484 return 1;
484 } 485 }
485 486
486 return 0; 487 return 0;
487 } 488 }
488 #endif /* CONFIG_CMD_SF_TEST */ 489 #endif /* CONFIG_CMD_SF_TEST */
489 490
490 static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc, 491 static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc,
491 char * const argv[]) 492 char * const argv[])
492 { 493 {
493 const char *cmd; 494 const char *cmd;
494 int ret; 495 int ret;
495 496
496 /* need at least two arguments */ 497 /* need at least two arguments */
497 if (argc < 2) 498 if (argc < 2)
498 goto usage; 499 goto usage;
499 500
500 cmd = argv[1]; 501 cmd = argv[1];
501 --argc; 502 --argc;
502 ++argv; 503 ++argv;
503 504
504 if (strcmp(cmd, "probe") == 0) { 505 if (strcmp(cmd, "probe") == 0) {
506 gpio_direction_output(IMX_GPIO_NR(4,20), 1);
505 ret = do_spi_flash_probe(argc, argv); 507 ret = do_spi_flash_probe(argc, argv);
508 gpio_direction_output(IMX_GPIO_NR(4,20), 0);
506 goto done; 509 goto done;
507 } 510 }
508 511
509 /* The remaining commands require a selected device */ 512 /* The remaining commands require a selected device */
510 if (!flash) { 513 if (!flash) {
511 puts("No SPI flash selected. Please run `sf probe'\n"); 514 puts("No SPI flash selected. Please run `sf probe'\n");
512 return 1; 515 return 1;
513 } 516 }
514 517
515 if (strcmp(cmd, "read") == 0 || strcmp(cmd, "write") == 0 || 518 if (strcmp(cmd, "read") == 0 || strcmp(cmd, "write") == 0 ||
516 strcmp(cmd, "update") == 0) 519 strcmp(cmd, "update") == 0){
520 gpio_direction_output(IMX_GPIO_NR(4,20), 1);
517 ret = do_spi_flash_read_write(argc, argv); 521 ret = do_spi_flash_read_write(argc, argv);
518 else if (strcmp(cmd, "erase") == 0) 522 gpio_direction_output(IMX_GPIO_NR(4,20), 0);
523 }
524 else if (strcmp(cmd, "erase") == 0){
525 gpio_direction_output(IMX_GPIO_NR(4,20), 1);
519 ret = do_spi_flash_erase(argc, argv); 526 ret = do_spi_flash_erase(argc, argv);
527 gpio_direction_output(IMX_GPIO_NR(4,20), 0);
528 }
520 #ifdef CONFIG_CMD_SF_TEST 529 #ifdef CONFIG_CMD_SF_TEST
521 else if (!strcmp(cmd, "test")) 530 else if (!strcmp(cmd, "test")){
531 gpio_direction_output(IMX_GPIO_NR(4,20), 1);
522 ret = do_spi_flash_test(argc, argv); 532 ret = do_spi_flash_test(argc, argv);
533 gpio_direction_output(IMX_GPIO_NR(4,20), 0);
534 }
523 #endif 535 #endif
524 else 536 else
525 ret = -1; 537 ret = -1;
526 538
527 done: 539 done:
528 if (ret != -1) 540 if (ret != -1)
529 return ret; 541 return ret;
530 542
531 usage: 543 usage:
532 return CMD_RET_USAGE; 544 return CMD_RET_USAGE;
533 } 545 }
534 546
535 #ifdef CONFIG_CMD_SF_TEST 547 #ifdef CONFIG_CMD_SF_TEST
536 #define SF_TEST_HELP "\nsf test offset len " \ 548 #define SF_TEST_HELP "\nsf test offset len " \
537 "- run a very basic destructive test" 549 "- run a very basic destructive test"
538 #else 550 #else
539 #define SF_TEST_HELP 551 #define SF_TEST_HELP
540 #endif 552 #endif
541 553
542 U_BOOT_CMD( 554 U_BOOT_CMD(
543 sf, 5, 1, do_spi_flash, 555 sf, 5, 1, do_spi_flash,
544 "SPI flash sub-system", 556 "SPI flash sub-system",
545 "probe [[bus:]cs] [hz] [mode] - init flash device on given SPI bus\n" 557 "probe [[bus:]cs] [hz] [mode] - init flash device on given SPI bus\n"
546 " and chip select\n" 558 " and chip select\n"
547 "sf read addr offset len - read `len' bytes starting at\n" 559 "sf read addr offset len - read `len' bytes starting at\n"
548 " `offset' to memory at `addr'\n" 560 " `offset' to memory at `addr'\n"
549 "sf write addr offset len - write `len' bytes from memory\n" 561 "sf write addr offset len - write `len' bytes from memory\n"
550 " at `addr' to flash at `offset'\n" 562 " at `addr' to flash at `offset'\n"
551 "sf erase offset [+]len - erase `len' bytes from `offset'\n" 563 "sf erase offset [+]len - erase `len' bytes from `offset'\n"
552 " `+len' round up `len' to block size\n" 564 " `+len' round up `len' to block size\n"
553 "sf update addr offset len - erase and write `len' bytes from memory\n" 565 "sf update addr offset len - erase and write `len' bytes from memory\n"
554 " at `addr' to flash at `offset'" 566 " at `addr' to flash at `offset'"
555 SF_TEST_HELP 567 SF_TEST_HELP
556 ); 568 );
557 569