Blame view

common/cmd_sf.c 12.8 KB
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
1
2
3
4
  /*
   * Command for accessing SPI flash.
   *
   * Copyright (C) 2008 Atmel Corporation
0c88a84ac   Jagannadha Sutradharudu Teki   sf: Add GPL-2.0+ ...
5
6
   *
   * SPDX-License-Identifier:	GPL-2.0+
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
7
   */
4166ee58d   Mike Frysinger   sf: add GPL-2 lic...
8

b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
9
  #include <common.h>
381c6e2c9   Mingkai Hu   cmd_sf: include h...
10
  #include <div64.h>
8d1af9422   Simon Glass   cmd_sf: add "upda...
11
  #include <malloc.h>
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
12
13
14
  #include <spi_flash.h>
  
  #include <asm/io.h>
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
15
  static struct spi_flash *flash;
334eb4b02   Richard Retanubun   cmd_sf: add handl...
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
  
  /*
   * This function computes the length argument for the erase command.
   * The length on which the command is to operate can be given in two forms:
   * 1. <cmd> offset len  - operate on <'offset',  'len')
   * 2. <cmd> offset +len - operate on <'offset',  'round_up(len)')
   * If the second form is used and the length doesn't fall on the
   * sector boundary, than it will be adjusted to the next sector boundary.
   * If it isn't in the flash, the function will fail (return -1).
   * Input:
   *    arg: length specification (i.e. both command arguments)
   * Output:
   *    len: computed length for operation
   * Return:
   *    1: success
   *   -1: failure (bad format, bad address).
   */
  static int sf_parse_len_arg(char *arg, ulong *len)
  {
  	char *ep;
  	char round_up_len; /* indicates if the "+length" form used */
  	ulong len_arg;
  
  	round_up_len = 0;
  	if (*arg == '+') {
  		round_up_len = 1;
  		++arg;
  	}
  
  	len_arg = simple_strtoul(arg, &ep, 16);
  	if (ep == arg || *ep != '\0')
  		return -1;
  
  	if (round_up_len && flash->sector_size > 0)
155cfb5ef   Anton Staaf   common: fix behav...
50
  		*len = ROUND(len_arg, flash->sector_size);
334eb4b02   Richard Retanubun   cmd_sf: add handl...
51
52
53
54
55
  	else
  		*len = len_arg;
  
  	return 1;
  }
a683c288d   James Miller   spi: Add progress...
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
  /**
   * This function takes a byte length and a delta unit of time to compute the
   * approximate bytes per second
   *
   * @param len		amount of bytes currently processed
   * @param start_ms	start time of processing in ms
   * @return bytes per second if OK, 0 on error
   */
  static ulong bytes_per_second(unsigned int len, ulong start_ms)
  {
  	/* less accurate but avoids overflow */
  	if (len >= ((unsigned int) -1) / 1024)
  		return len / (max(get_timer(start_ms) / 1024, 1));
  	else
  		return 1024 * len / max(get_timer(start_ms), 1);
  }
54841ab50   Wolfgang Denk   Make sure that ar...
72
  static int do_spi_flash_probe(int argc, char * const argv[])
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
73
  {
c1173bd07   Eric Nelson   sf command: allow...
74
75
  	unsigned int bus = CONFIG_SF_DEFAULT_BUS;
  	unsigned int cs = CONFIG_SF_DEFAULT_CS;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
76
77
78
79
  	unsigned int speed = CONFIG_SF_DEFAULT_SPEED;
  	unsigned int mode = CONFIG_SF_DEFAULT_MODE;
  	char *endp;
  	struct spi_flash *new;
c1173bd07   Eric Nelson   sf command: allow...
80
81
82
  	if (argc >= 2) {
  		cs = simple_strtoul(argv[1], &endp, 0);
  		if (*argv[1] == 0 || (*endp != 0 && *endp != ':'))
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
83
  			return -1;
c1173bd07   Eric Nelson   sf command: allow...
84
85
86
87
88
89
90
91
92
  		if (*endp == ':') {
  			if (endp[1] == 0)
  				return -1;
  
  			bus = cs;
  			cs = simple_strtoul(endp + 1, &endp, 0);
  			if (*endp != 0)
  				return -1;
  		}
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
93
94
95
96
97
  	}
  
  	if (argc >= 3) {
  		speed = simple_strtoul(argv[2], &endp, 0);
  		if (*argv[2] == 0 || *endp != 0)
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
98
  			return -1;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
99
100
  	}
  	if (argc >= 4) {
6e8d58d36   TsiChung Liew   Command for acces...
101
  		mode = simple_strtoul(argv[3], &endp, 16);
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
102
  		if (*argv[3] == 0 || *endp != 0)
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
103
  			return -1;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
104
105
106
107
108
109
110
111
112
113
114
115
  	}
  
  	new = spi_flash_probe(bus, cs, speed, mode);
  	if (!new) {
  		printf("Failed to initialize SPI flash at %u:%u
  ", bus, cs);
  		return 1;
  	}
  
  	if (flash)
  		spi_flash_free(flash);
  	flash = new;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
116
  	return 0;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
117
  }
8d1af9422   Simon Glass   cmd_sf: add "upda...
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
  /**
   * Write a block of data to SPI flash, first checking if it is different from
   * what is already there.
   *
   * If the data being written is the same, then *skipped is incremented by len.
   *
   * @param flash		flash context pointer
   * @param offset	flash offset to write
   * @param len		number of bytes to write
   * @param buf		buffer to write from
   * @param cmp_buf	read buffer to use to compare data
   * @param skipped	Count of skipped data (incremented by this function)
   * @return NULL if OK, else a string containing the stage which failed
   */
  static const char *spi_flash_update_block(struct spi_flash *flash, u32 offset,
  		size_t len, const char *buf, char *cmp_buf, size_t *skipped)
  {
a97f6efdb   Andreas Bießmann   cmd_sf.c: fix pri...
135
136
  	debug("offset=%#x, sector_size=%#x, len=%#zx
  ",
402ba1e3a   Jagannadha Sutradharudu Teki   cmd_sf|env_sf: Fi...
137
  	      offset, flash->sector_size, len);
b95f958d7   Gerlando Falauto   cmd_sf: let "sf u...
138
139
  	/* Read the entire sector so to allow for rewriting */
  	if (spi_flash_read(flash, offset, flash->sector_size, cmp_buf))
8d1af9422   Simon Glass   cmd_sf: add "upda...
140
  		return "read";
b95f958d7   Gerlando Falauto   cmd_sf: let "sf u...
141
  	/* Compare only what is meaningful (len) */
8d1af9422   Simon Glass   cmd_sf: add "upda...
142
  	if (memcmp(cmp_buf, buf, len) == 0) {
a97f6efdb   Andreas Bießmann   cmd_sf.c: fix pri...
143
144
  		debug("Skip region %x size %zx: no change
  ",
402ba1e3a   Jagannadha Sutradharudu Teki   cmd_sf|env_sf: Fi...
145
  		      offset, len);
8d1af9422   Simon Glass   cmd_sf: add "upda...
146
147
148
  		*skipped += len;
  		return NULL;
  	}
348885062   Gerlando Falauto   cmd_sf: let "sf u...
149
150
  	/* Erase the entire sector */
  	if (spi_flash_erase(flash, offset, flash->sector_size))
8d1af9422   Simon Glass   cmd_sf: add "upda...
151
  		return "erase";
b95f958d7   Gerlando Falauto   cmd_sf: let "sf u...
152
  	/* Write the initial part of the block from the source */
8d1af9422   Simon Glass   cmd_sf: add "upda...
153
154
  	if (spi_flash_write(flash, offset, len, buf))
  		return "write";
b95f958d7   Gerlando Falauto   cmd_sf: let "sf u...
155
156
157
158
159
160
161
  	/* If it's a partial sector, rewrite the existing part */
  	if (len != flash->sector_size) {
  		/* Rewrite the original data to the end of the sector */
  		if (spi_flash_write(flash, offset + len,
  				    flash->sector_size - len, &cmp_buf[len]))
  			return "write";
  	}
8d1af9422   Simon Glass   cmd_sf: add "upda...
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
  	return NULL;
  }
  
  /**
   * Update an area of SPI flash by erasing and writing any blocks which need
   * to change. Existing blocks with the correct data are left unchanged.
   *
   * @param flash		flash context pointer
   * @param offset	flash offset to write
   * @param len		number of bytes to write
   * @param buf		buffer to write from
   * @return 0 if ok, 1 on error
   */
  static int spi_flash_update(struct spi_flash *flash, u32 offset,
  		size_t len, const char *buf)
  {
  	const char *err_oper = NULL;
  	char *cmp_buf;
  	const char *end = buf + len;
  	size_t todo;		/* number of bytes to do in this pass */
8e8a4bc22   Kumar Gala   cmd_sf: Fix compi...
182
  	size_t skipped = 0;	/* statistics */
a683c288d   James Miller   spi: Add progress...
183
184
185
186
  	const ulong start_time = get_timer(0);
  	size_t scale = 1;
  	const char *start_buf = buf;
  	ulong delta;
8d1af9422   Simon Glass   cmd_sf: add "upda...
187

a683c288d   James Miller   spi: Add progress...
188
189
  	if (end - buf >= 200)
  		scale = (end - buf) / 100;
8d1af9422   Simon Glass   cmd_sf: add "upda...
190
191
  	cmp_buf = malloc(flash->sector_size);
  	if (cmp_buf) {
a683c288d   James Miller   spi: Add progress...
192
  		ulong last_update = get_timer(0);
8e8a4bc22   Kumar Gala   cmd_sf: Fix compi...
193
  		for (; buf < end && !err_oper; buf += todo, offset += todo) {
8d1af9422   Simon Glass   cmd_sf: add "upda...
194
  			todo = min(end - buf, flash->sector_size);
a683c288d   James Miller   spi: Add progress...
195
196
  			if (get_timer(last_update) > 100) {
  				printf("   \rUpdating, %zu%% %lu B/s",
402ba1e3a   Jagannadha Sutradharudu Teki   cmd_sf|env_sf: Fi...
197
  				       100 - (end - buf) / scale,
a683c288d   James Miller   spi: Add progress...
198
199
200
201
  					bytes_per_second(buf - start_buf,
  							 start_time));
  				last_update = get_timer(0);
  			}
8d1af9422   Simon Glass   cmd_sf: add "upda...
202
203
204
205
206
207
208
  			err_oper = spi_flash_update_block(flash, offset, todo,
  					buf, cmp_buf, &skipped);
  		}
  	} else {
  		err_oper = "malloc";
  	}
  	free(cmp_buf);
a683c288d   James Miller   spi: Add progress...
209
  	putc('\r');
8d1af9422   Simon Glass   cmd_sf: add "upda...
210
211
212
213
214
  	if (err_oper) {
  		printf("SPI flash failed in %s step
  ", err_oper);
  		return 1;
  	}
a683c288d   James Miller   spi: Add progress...
215
216
217
  
  	delta = get_timer(start_time);
  	printf("%zu bytes written, %zu bytes skipped", len - skipped,
402ba1e3a   Jagannadha Sutradharudu Teki   cmd_sf|env_sf: Fi...
218
  	       skipped);
a683c288d   James Miller   spi: Add progress...
219
220
  	printf(" in %ld.%lds, speed %ld B/s
  ",
402ba1e3a   Jagannadha Sutradharudu Teki   cmd_sf|env_sf: Fi...
221
  	       delta / 1000, delta % 1000, bytes_per_second(len, start_time));
8e8a4bc22   Kumar Gala   cmd_sf: Fix compi...
222

8d1af9422   Simon Glass   cmd_sf: add "upda...
223
224
  	return 0;
  }
54841ab50   Wolfgang Denk   Make sure that ar...
225
  static int do_spi_flash_read_write(int argc, char * const argv[])
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
226
227
228
229
230
231
  {
  	unsigned long addr;
  	unsigned long offset;
  	unsigned long len;
  	void *buf;
  	char *endp;
60b6614ac   Jagannadha Sutradharudu Teki   cmd_sf: Add print...
232
  	int ret = 1;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
233
234
  
  	if (argc < 4)
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
235
  		return -1;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
236
237
238
  
  	addr = simple_strtoul(argv[1], &endp, 16);
  	if (*argv[1] == 0 || *endp != 0)
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
239
  		return -1;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
240
241
  	offset = simple_strtoul(argv[2], &endp, 16);
  	if (*argv[2] == 0 || *endp != 0)
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
242
  		return -1;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
243
244
  	len = simple_strtoul(argv[3], &endp, 16);
  	if (*argv[3] == 0 || *endp != 0)
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
245
  		return -1;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
246

864939949   Gerlando Falauto   cmd_sf: add size ...
247
248
249
250
  	/* Consistency checking */
  	if (offset + len > flash->size) {
  		printf("ERROR: attempting %s past flash size (%#x)
  ",
402ba1e3a   Jagannadha Sutradharudu Teki   cmd_sf|env_sf: Fi...
251
  		       argv[0], flash->size);
864939949   Gerlando Falauto   cmd_sf: add size ...
252
253
  		return 1;
  	}
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
254
255
256
257
258
259
  	buf = map_physmem(addr, len, MAP_WRBACK);
  	if (!buf) {
  		puts("Failed to map physical memory
  ");
  		return 1;
  	}
402ba1e3a   Jagannadha Sutradharudu Teki   cmd_sf|env_sf: Fi...
260
  	if (strcmp(argv[0], "update") == 0) {
8d1af9422   Simon Glass   cmd_sf: add "upda...
261
  		ret = spi_flash_update(flash, offset, len, buf);
402ba1e3a   Jagannadha Sutradharudu Teki   cmd_sf|env_sf: Fi...
262
  	} else if (strncmp(argv[0], "read", 4) == 0 ||
60b6614ac   Jagannadha Sutradharudu Teki   cmd_sf: Add print...
263
264
265
266
267
268
269
270
271
272
273
  			strncmp(argv[0], "write", 5) == 0) {
  		int read;
  
  		read = strncmp(argv[0], "read", 4) == 0;
  		if (read)
  			ret = spi_flash_read(flash, offset, len, buf);
  		else
  			ret = spi_flash_write(flash, offset, len, buf);
  
  		printf("SF: %zu bytes @ %#x %s: %s
  ", (size_t)len, (u32)offset,
402ba1e3a   Jagannadha Sutradharudu Teki   cmd_sf|env_sf: Fi...
274
  		       read ? "Read" : "Written", ret ? "ERROR" : "OK");
60b6614ac   Jagannadha Sutradharudu Teki   cmd_sf: Add print...
275
  	}
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
276
277
  
  	unmap_physmem(buf, len);
60b6614ac   Jagannadha Sutradharudu Teki   cmd_sf: Add print...
278
  	return ret == 0 ? 0 : 1;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
279
  }
54841ab50   Wolfgang Denk   Make sure that ar...
280
  static int do_spi_flash_erase(int argc, char * const argv[])
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
281
282
283
284
285
286
287
  {
  	unsigned long offset;
  	unsigned long len;
  	char *endp;
  	int ret;
  
  	if (argc < 3)
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
288
  		return -1;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
289
290
291
  
  	offset = simple_strtoul(argv[1], &endp, 16);
  	if (*argv[1] == 0 || *endp != 0)
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
292
  		return -1;
334eb4b02   Richard Retanubun   cmd_sf: add handl...
293
294
295
  
  	ret = sf_parse_len_arg(argv[2], &len);
  	if (ret != 1)
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
296
  		return -1;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
297

864939949   Gerlando Falauto   cmd_sf: add size ...
298
299
300
301
  	/* Consistency checking */
  	if (offset + len > flash->size) {
  		printf("ERROR: attempting %s past flash size (%#x)
  ",
402ba1e3a   Jagannadha Sutradharudu Teki   cmd_sf|env_sf: Fi...
302
  		       argv[0], flash->size);
864939949   Gerlando Falauto   cmd_sf: add size ...
303
304
  		return 1;
  	}
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
305
  	ret = spi_flash_erase(flash, offset, len);
96bbf5565   Jagannadha Sutradharudu Teki   cmd_sf: Add print...
306
307
  	printf("SF: %zu bytes @ %#x Erased: %s
  ", (size_t)len, (u32)offset,
402ba1e3a   Jagannadha Sutradharudu Teki   cmd_sf|env_sf: Fi...
308
  	       ret ? "ERROR" : "OK");
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
309

96bbf5565   Jagannadha Sutradharudu Teki   cmd_sf: Add print...
310
  	return ret == 0 ? 0 : 1;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
311
  }
240072731   Simon Glass   spi: Add SPI flas...
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
  #ifdef CONFIG_CMD_SF_TEST
  enum {
  	STAGE_ERASE,
  	STAGE_CHECK,
  	STAGE_WRITE,
  	STAGE_READ,
  
  	STAGE_COUNT,
  };
  
  static char *stage_name[STAGE_COUNT] = {
  	"erase",
  	"check",
  	"write",
  	"read",
  };
  
  struct test_info {
  	int stage;
  	int bytes;
  	unsigned base_ms;
  	unsigned time_ms[STAGE_COUNT];
  };
  
  static void show_time(struct test_info *test, int stage)
  {
  	uint64_t speed;	/* KiB/s */
  	int bps;	/* Bits per second */
  
  	speed = (long long)test->bytes * 1000;
d1f22d4bd   Simon Glass   sandbox: spi: Adj...
342
343
  	if (test->time_ms[stage])
  		do_div(speed, test->time_ms[stage] * 1024);
240072731   Simon Glass   spi: Add SPI flas...
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
  	bps = speed * 8;
  
  	printf("%d %s: %d ticks, %d KiB/s %d.%03d Mbps
  ", stage,
  	       stage_name[stage], test->time_ms[stage],
  	       (int)speed, bps / 1000, bps % 1000);
  }
  
  static void spi_test_next_stage(struct test_info *test)
  {
  	test->time_ms[test->stage] = get_timer(test->base_ms);
  	show_time(test, test->stage);
  	test->base_ms = get_timer(0);
  	test->stage++;
  }
  
  /**
   * Run a test on the SPI flash
   *
   * @param flash		SPI flash to use
   * @param buf		Source buffer for data to write
   * @param len		Size of data to read/write
   * @param offset	Offset within flash to check
   * @param vbuf		Verification buffer
   * @return 0 if ok, -1 on error
   */
1e7133e99   Simon Glass   sf: Use unsigned ...
370
371
  static int spi_flash_test(struct spi_flash *flash, uint8_t *buf, ulong len,
  			   ulong offset, uint8_t *vbuf)
240072731   Simon Glass   spi: Add SPI flas...
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
  {
  	struct test_info test;
  	int i;
  
  	printf("SPI flash test:
  ");
  	memset(&test, '\0', sizeof(test));
  	test.base_ms = get_timer(0);
  	test.bytes = len;
  	if (spi_flash_erase(flash, offset, len)) {
  		printf("Erase failed
  ");
  		return -1;
  	}
  	spi_test_next_stage(&test);
  
  	if (spi_flash_read(flash, offset, len, vbuf)) {
  		printf("Check read failed
  ");
  		return -1;
  	}
  	for (i = 0; i < len; i++) {
  		if (vbuf[i] != 0xff) {
  			printf("Check failed at %d
  ", i);
  			print_buffer(i, vbuf + i, 1, min(len - i, 0x40), 0);
  			return -1;
  		}
  	}
  	spi_test_next_stage(&test);
  
  	if (spi_flash_write(flash, offset, len, buf)) {
  		printf("Write failed
  ");
  		return -1;
  	}
  	memset(vbuf, '\0', len);
  	spi_test_next_stage(&test);
  
  	if (spi_flash_read(flash, offset, len, vbuf)) {
  		printf("Read failed
  ");
  		return -1;
  	}
  	spi_test_next_stage(&test);
  
  	for (i = 0; i < len; i++) {
  		if (buf[i] != vbuf[i]) {
  			printf("Verify failed at %d, good data:
  ", i);
  			print_buffer(i, buf + i, 1, min(len - i, 0x40), 0);
  			printf("Bad data:
  ");
  			print_buffer(i, vbuf + i, 1, min(len - i, 0x40), 0);
  			return -1;
  		}
  	}
  	printf("Test passed
  ");
  	for (i = 0; i < STAGE_COUNT; i++)
  		show_time(&test, i);
  
  	return 0;
  }
  
  static int do_spi_flash_test(int argc, char * const argv[])
  {
  	unsigned long offset;
  	unsigned long len;
d1f22d4bd   Simon Glass   sandbox: spi: Adj...
441
  	uint8_t *buf, *from;
240072731   Simon Glass   spi: Add SPI flas...
442
  	char *endp;
1e7133e99   Simon Glass   sf: Use unsigned ...
443
  	uint8_t *vbuf;
240072731   Simon Glass   spi: Add SPI flas...
444
  	int ret;
d1f22d4bd   Simon Glass   sandbox: spi: Adj...
445
446
  	if (argc < 3)
  		return -1;
240072731   Simon Glass   spi: Add SPI flas...
447
448
449
450
451
452
453
454
455
  	offset = simple_strtoul(argv[1], &endp, 16);
  	if (*argv[1] == 0 || *endp != 0)
  		return -1;
  	len = simple_strtoul(argv[2], &endp, 16);
  	if (*argv[2] == 0 || *endp != 0)
  		return -1;
  
  	vbuf = malloc(len);
  	if (!vbuf) {
d1f22d4bd   Simon Glass   sandbox: spi: Adj...
456
457
  		printf("Cannot allocate memory (%lu bytes)
  ", len);
240072731   Simon Glass   spi: Add SPI flas...
458
459
460
461
462
  		return 1;
  	}
  	buf = malloc(len);
  	if (!buf) {
  		free(vbuf);
d1f22d4bd   Simon Glass   sandbox: spi: Adj...
463
464
  		printf("Cannot allocate memory (%lu bytes)
  ", len);
240072731   Simon Glass   spi: Add SPI flas...
465
466
  		return 1;
  	}
d1f22d4bd   Simon Glass   sandbox: spi: Adj...
467
468
  	from = map_sysmem(CONFIG_SYS_TEXT_BASE, 0);
  	memcpy(buf, from, len);
240072731   Simon Glass   spi: Add SPI flas...
469
470
471
472
473
474
475
476
477
478
479
480
  	ret = spi_flash_test(flash, buf, len, offset, vbuf);
  	free(vbuf);
  	free(buf);
  	if (ret) {
  		printf("Test failed
  ");
  		return 1;
  	}
  
  	return 0;
  }
  #endif /* CONFIG_CMD_SF_TEST */
402ba1e3a   Jagannadha Sutradharudu Teki   cmd_sf|env_sf: Fi...
481
482
  static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc,
  			char * const argv[])
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
483
484
  {
  	const char *cmd;
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
485
  	int ret;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
486
487
488
489
490
491
  
  	/* need at least two arguments */
  	if (argc < 2)
  		goto usage;
  
  	cmd = argv[1];
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
492
493
  	--argc;
  	++argv;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
494

8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
495
496
497
498
  	if (strcmp(cmd, "probe") == 0) {
  		ret = do_spi_flash_probe(argc, argv);
  		goto done;
  	}
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
499
500
501
502
503
504
505
  
  	/* The remaining commands require a selected device */
  	if (!flash) {
  		puts("No SPI flash selected. Please run `sf probe'
  ");
  		return 1;
  	}
8d1af9422   Simon Glass   cmd_sf: add "upda...
506
507
  	if (strcmp(cmd, "read") == 0 || strcmp(cmd, "write") == 0 ||
  	    strcmp(cmd, "update") == 0)
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
508
509
510
  		ret = do_spi_flash_read_write(argc, argv);
  	else if (strcmp(cmd, "erase") == 0)
  		ret = do_spi_flash_erase(argc, argv);
240072731   Simon Glass   spi: Add SPI flas...
511
512
513
514
  #ifdef CONFIG_CMD_SF_TEST
  	else if (!strcmp(cmd, "test"))
  		ret = do_spi_flash_test(argc, argv);
  #endif
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
515
516
517
518
519
520
  	else
  		ret = -1;
  
  done:
  	if (ret != -1)
  		return ret;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
521
522
  
  usage:
4c12eeb8b   Simon Glass   Convert cmd_usage...
523
  	return CMD_RET_USAGE;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
524
  }
240072731   Simon Glass   spi: Add SPI flas...
525
526
527
528
529
530
531
  #ifdef CONFIG_CMD_SF_TEST
  #define SF_TEST_HELP "
  sf test offset len		" \
  		"- run a very basic destructive test"
  #else
  #define SF_TEST_HELP
  #endif
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
532
533
  U_BOOT_CMD(
  	sf,	5,	1,	do_spi_flash,
2fb2604d5   Peter Tyser   Command usage cle...
534
  	"SPI flash sub-system",
c1173bd07   Eric Nelson   sf command: allow...
535
536
  	"probe [[bus:]cs] [hz] [mode]	- init flash device on given SPI bus
  "
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
537
538
  	"				  and chip select
  "
402ba1e3a   Jagannadha Sutradharudu Teki   cmd_sf|env_sf: Fi...
539
540
  	"sf read addr offset len	- read `len' bytes starting at
  "
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
541
542
543
544
545
546
  	"				  `offset' to memory at `addr'
  "
  	"sf write addr offset len	- write `len' bytes from memory
  "
  	"				  at `addr' to flash at `offset'
  "
334eb4b02   Richard Retanubun   cmd_sf: add handl...
547
548
  	"sf erase offset [+]len		- erase `len' bytes from `offset'
  "
8d1af9422   Simon Glass   cmd_sf: add "upda...
549
550
551
552
553
  	"				  `+len' round up `len' to block size
  "
  	"sf update addr offset len	- erase and write `len' bytes from memory
  "
  	"				  at `addr' to flash at `offset'"
240072731   Simon Glass   spi: Add SPI flas...
554
  	SF_TEST_HELP
a89c33db9   Wolfgang Denk   General help mess...
555
  );