Blame view

common/cmd_sf.c 13.1 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
15
16
17
18
19
20
21
  #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
c1173bd07   Eric Nelson   sf command: allow...
22
23
24
25
26
27
  #ifndef CONFIG_SF_DEFAULT_CS
  # define CONFIG_SF_DEFAULT_CS		0
  #endif
  #ifndef CONFIG_SF_DEFAULT_BUS
  # define CONFIG_SF_DEFAULT_BUS		0
  #endif
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
28
29
  
  static struct spi_flash *flash;
334eb4b02   Richard Retanubun   cmd_sf: add handl...
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
  
  /*
   * 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...
64
  		*len = ROUND(len_arg, flash->sector_size);
334eb4b02   Richard Retanubun   cmd_sf: add handl...
65
66
67
68
69
  	else
  		*len = len_arg;
  
  	return 1;
  }
a683c288d   James Miller   spi: Add progress...
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
  /**
   * 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...
86
  static int do_spi_flash_probe(int argc, char * const argv[])
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
87
  {
c1173bd07   Eric Nelson   sf command: allow...
88
89
  	unsigned int bus = CONFIG_SF_DEFAULT_BUS;
  	unsigned int cs = CONFIG_SF_DEFAULT_CS;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
90
91
92
93
  	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...
94
95
96
  	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...
97
  			return -1;
c1173bd07   Eric Nelson   sf command: allow...
98
99
100
101
102
103
104
105
106
  		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...
107
108
109
110
111
  	}
  
  	if (argc >= 3) {
  		speed = simple_strtoul(argv[2], &endp, 0);
  		if (*argv[2] == 0 || *endp != 0)
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
112
  			return -1;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
113
114
  	}
  	if (argc >= 4) {
6e8d58d36   TsiChung Liew   Command for acces...
115
  		mode = simple_strtoul(argv[3], &endp, 16);
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
116
  		if (*argv[3] == 0 || *endp != 0)
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
117
  			return -1;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
118
119
120
121
122
123
124
125
126
127
128
129
  	}
  
  	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...
130
  	return 0;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
131
  }
8d1af9422   Simon Glass   cmd_sf: add "upda...
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
  /**
   * 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...
149
150
  	debug("offset=%#x, sector_size=%#x, len=%#zx
  ",
402ba1e3a   Jagannadha Sutradharudu Teki   cmd_sf|env_sf: Fi...
151
  	      offset, flash->sector_size, len);
b95f958d7   Gerlando Falauto   cmd_sf: let "sf u...
152
153
  	/* 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...
154
  		return "read";
b95f958d7   Gerlando Falauto   cmd_sf: let "sf u...
155
  	/* Compare only what is meaningful (len) */
8d1af9422   Simon Glass   cmd_sf: add "upda...
156
  	if (memcmp(cmp_buf, buf, len) == 0) {
a97f6efdb   Andreas Bießmann   cmd_sf.c: fix pri...
157
158
  		debug("Skip region %x size %zx: no change
  ",
402ba1e3a   Jagannadha Sutradharudu Teki   cmd_sf|env_sf: Fi...
159
  		      offset, len);
8d1af9422   Simon Glass   cmd_sf: add "upda...
160
161
162
  		*skipped += len;
  		return NULL;
  	}
348885062   Gerlando Falauto   cmd_sf: let "sf u...
163
164
  	/* Erase the entire sector */
  	if (spi_flash_erase(flash, offset, flash->sector_size))
8d1af9422   Simon Glass   cmd_sf: add "upda...
165
  		return "erase";
b95f958d7   Gerlando Falauto   cmd_sf: let "sf u...
166
  	/* Write the initial part of the block from the source */
8d1af9422   Simon Glass   cmd_sf: add "upda...
167
168
  	if (spi_flash_write(flash, offset, len, buf))
  		return "write";
b95f958d7   Gerlando Falauto   cmd_sf: let "sf u...
169
170
171
172
173
174
175
  	/* 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...
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
  	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...
196
  	size_t skipped = 0;	/* statistics */
a683c288d   James Miller   spi: Add progress...
197
198
199
200
  	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...
201

a683c288d   James Miller   spi: Add progress...
202
203
  	if (end - buf >= 200)
  		scale = (end - buf) / 100;
8d1af9422   Simon Glass   cmd_sf: add "upda...
204
205
  	cmp_buf = malloc(flash->sector_size);
  	if (cmp_buf) {
a683c288d   James Miller   spi: Add progress...
206
  		ulong last_update = get_timer(0);
8e8a4bc22   Kumar Gala   cmd_sf: Fix compi...
207
  		for (; buf < end && !err_oper; buf += todo, offset += todo) {
8d1af9422   Simon Glass   cmd_sf: add "upda...
208
  			todo = min(end - buf, flash->sector_size);
a683c288d   James Miller   spi: Add progress...
209
210
  			if (get_timer(last_update) > 100) {
  				printf("   \rUpdating, %zu%% %lu B/s",
402ba1e3a   Jagannadha Sutradharudu Teki   cmd_sf|env_sf: Fi...
211
  				       100 - (end - buf) / scale,
a683c288d   James Miller   spi: Add progress...
212
213
214
215
  					bytes_per_second(buf - start_buf,
  							 start_time));
  				last_update = get_timer(0);
  			}
8d1af9422   Simon Glass   cmd_sf: add "upda...
216
217
218
219
220
221
222
  			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...
223
  	putc('\r');
8d1af9422   Simon Glass   cmd_sf: add "upda...
224
225
226
227
228
  	if (err_oper) {
  		printf("SPI flash failed in %s step
  ", err_oper);
  		return 1;
  	}
a683c288d   James Miller   spi: Add progress...
229
230
231
  
  	delta = get_timer(start_time);
  	printf("%zu bytes written, %zu bytes skipped", len - skipped,
402ba1e3a   Jagannadha Sutradharudu Teki   cmd_sf|env_sf: Fi...
232
  	       skipped);
a683c288d   James Miller   spi: Add progress...
233
234
  	printf(" in %ld.%lds, speed %ld B/s
  ",
402ba1e3a   Jagannadha Sutradharudu Teki   cmd_sf|env_sf: Fi...
235
  	       delta / 1000, delta % 1000, bytes_per_second(len, start_time));
8e8a4bc22   Kumar Gala   cmd_sf: Fix compi...
236

8d1af9422   Simon Glass   cmd_sf: add "upda...
237
238
  	return 0;
  }
54841ab50   Wolfgang Denk   Make sure that ar...
239
  static int do_spi_flash_read_write(int argc, char * const argv[])
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
240
241
242
243
244
245
  {
  	unsigned long addr;
  	unsigned long offset;
  	unsigned long len;
  	void *buf;
  	char *endp;
60b6614ac   Jagannadha Sutradharudu Teki   cmd_sf: Add print...
246
  	int ret = 1;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
247
248
  
  	if (argc < 4)
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
249
  		return -1;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
250
251
252
  
  	addr = simple_strtoul(argv[1], &endp, 16);
  	if (*argv[1] == 0 || *endp != 0)
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
253
  		return -1;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
254
255
  	offset = simple_strtoul(argv[2], &endp, 16);
  	if (*argv[2] == 0 || *endp != 0)
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
256
  		return -1;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
257
258
  	len = simple_strtoul(argv[3], &endp, 16);
  	if (*argv[3] == 0 || *endp != 0)
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
259
  		return -1;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
260

864939949   Gerlando Falauto   cmd_sf: add size ...
261
262
263
264
  	/* Consistency checking */
  	if (offset + len > flash->size) {
  		printf("ERROR: attempting %s past flash size (%#x)
  ",
402ba1e3a   Jagannadha Sutradharudu Teki   cmd_sf|env_sf: Fi...
265
  		       argv[0], flash->size);
864939949   Gerlando Falauto   cmd_sf: add size ...
266
267
  		return 1;
  	}
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
268
269
270
271
272
273
  	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...
274
  	if (strcmp(argv[0], "update") == 0) {
8d1af9422   Simon Glass   cmd_sf: add "upda...
275
  		ret = spi_flash_update(flash, offset, len, buf);
402ba1e3a   Jagannadha Sutradharudu Teki   cmd_sf|env_sf: Fi...
276
  	} else if (strncmp(argv[0], "read", 4) == 0 ||
60b6614ac   Jagannadha Sutradharudu Teki   cmd_sf: Add print...
277
278
279
280
281
282
283
284
285
286
287
  			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...
288
  		       read ? "Read" : "Written", ret ? "ERROR" : "OK");
60b6614ac   Jagannadha Sutradharudu Teki   cmd_sf: Add print...
289
  	}
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
290
291
  
  	unmap_physmem(buf, len);
60b6614ac   Jagannadha Sutradharudu Teki   cmd_sf: Add print...
292
  	return ret == 0 ? 0 : 1;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
293
  }
54841ab50   Wolfgang Denk   Make sure that ar...
294
  static int do_spi_flash_erase(int argc, char * const argv[])
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
295
296
297
298
299
300
301
  {
  	unsigned long offset;
  	unsigned long len;
  	char *endp;
  	int ret;
  
  	if (argc < 3)
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
302
  		return -1;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
303
304
305
  
  	offset = simple_strtoul(argv[1], &endp, 16);
  	if (*argv[1] == 0 || *endp != 0)
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
306
  		return -1;
334eb4b02   Richard Retanubun   cmd_sf: add handl...
307
308
309
  
  	ret = sf_parse_len_arg(argv[2], &len);
  	if (ret != 1)
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
310
  		return -1;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
311

864939949   Gerlando Falauto   cmd_sf: add size ...
312
313
314
315
  	/* Consistency checking */
  	if (offset + len > flash->size) {
  		printf("ERROR: attempting %s past flash size (%#x)
  ",
402ba1e3a   Jagannadha Sutradharudu Teki   cmd_sf|env_sf: Fi...
316
  		       argv[0], flash->size);
864939949   Gerlando Falauto   cmd_sf: add size ...
317
318
  		return 1;
  	}
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
319
  	ret = spi_flash_erase(flash, offset, len);
96bbf5565   Jagannadha Sutradharudu Teki   cmd_sf: Add print...
320
321
  	printf("SF: %zu bytes @ %#x Erased: %s
  ", (size_t)len, (u32)offset,
402ba1e3a   Jagannadha Sutradharudu Teki   cmd_sf|env_sf: Fi...
322
  	       ret ? "ERROR" : "OK");
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
323

96bbf5565   Jagannadha Sutradharudu Teki   cmd_sf: Add print...
324
  	return ret == 0 ? 0 : 1;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
325
  }
240072731   Simon Glass   spi: Add SPI flas...
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
  #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...
356
357
  	if (test->time_ms[stage])
  		do_div(speed, test->time_ms[stage] * 1024);
240072731   Simon Glass   spi: Add SPI flas...
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
  	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 ...
384
385
  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...
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
441
442
443
444
445
446
447
448
449
450
451
452
453
454
  {
  	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...
455
  	uint8_t *buf, *from;
240072731   Simon Glass   spi: Add SPI flas...
456
  	char *endp;
1e7133e99   Simon Glass   sf: Use unsigned ...
457
  	uint8_t *vbuf;
240072731   Simon Glass   spi: Add SPI flas...
458
  	int ret;
d1f22d4bd   Simon Glass   sandbox: spi: Adj...
459
460
  	if (argc < 3)
  		return -1;
240072731   Simon Glass   spi: Add SPI flas...
461
462
463
464
465
466
467
468
469
  	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...
470
471
  		printf("Cannot allocate memory (%lu bytes)
  ", len);
240072731   Simon Glass   spi: Add SPI flas...
472
473
474
475
476
  		return 1;
  	}
  	buf = malloc(len);
  	if (!buf) {
  		free(vbuf);
d1f22d4bd   Simon Glass   sandbox: spi: Adj...
477
478
  		printf("Cannot allocate memory (%lu bytes)
  ", len);
240072731   Simon Glass   spi: Add SPI flas...
479
480
  		return 1;
  	}
d1f22d4bd   Simon Glass   sandbox: spi: Adj...
481
482
  	from = map_sysmem(CONFIG_SYS_TEXT_BASE, 0);
  	memcpy(buf, from, len);
240072731   Simon Glass   spi: Add SPI flas...
483
484
485
486
487
488
489
490
491
492
493
494
  	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...
495
496
  static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc,
  			char * const argv[])
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
497
498
  {
  	const char *cmd;
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
499
  	int ret;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
500
501
502
503
504
505
  
  	/* need at least two arguments */
  	if (argc < 2)
  		goto usage;
  
  	cmd = argv[1];
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
506
507
  	--argc;
  	++argv;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
508

8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
509
510
511
512
  	if (strcmp(cmd, "probe") == 0) {
  		ret = do_spi_flash_probe(argc, argv);
  		goto done;
  	}
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
513
514
515
516
517
518
519
  
  	/* 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...
520
521
  	if (strcmp(cmd, "read") == 0 || strcmp(cmd, "write") == 0 ||
  	    strcmp(cmd, "update") == 0)
8a07de03f   Mike Frysinger   cmd_sf: use cmd_u...
522
523
524
  		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...
525
526
527
528
  #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...
529
530
531
532
533
534
  	else
  		ret = -1;
  
  done:
  	if (ret != -1)
  		return ret;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
535
536
  
  usage:
4c12eeb8b   Simon Glass   Convert cmd_usage...
537
  	return CMD_RET_USAGE;
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
538
  }
240072731   Simon Glass   spi: Add SPI flas...
539
540
541
542
543
544
545
  #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...
546
547
  U_BOOT_CMD(
  	sf,	5,	1,	do_spi_flash,
2fb2604d5   Peter Tyser   Command usage cle...
548
  	"SPI flash sub-system",
c1173bd07   Eric Nelson   sf command: allow...
549
550
  	"probe [[bus:]cs] [hz] [mode]	- init flash device on given SPI bus
  "
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
551
552
  	"				  and chip select
  "
402ba1e3a   Jagannadha Sutradharudu Teki   cmd_sf|env_sf: Fi...
553
554
  	"sf read addr offset len	- read `len' bytes starting at
  "
b6368467e   Haavard Skinnemoen   SPI Flash: Add "s...
555
556
557
558
559
560
  	"				  `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...
561
562
  	"sf erase offset [+]len		- erase `len' bytes from `offset'
  "
8d1af9422   Simon Glass   cmd_sf: add "upda...
563
564
565
566
567
  	"				  `+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...
568
  	SF_TEST_HELP
a89c33db9   Wolfgang Denk   General help mess...
569
  );