flash.c 23.3 KB
Newer Older
oharboe's avatar
oharboe committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/***************************************************************************
 *   Copyright (C) 2005 by Dominic Rath                                    *
 *   Dominic.Rath@gmx.de                                                   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "flash.h"
#include "command.h"
#include "target.h"
#include "time_support.h"
#include "fileio.h"
#include "image.h"
#include "log.h"

#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <inttypes.h>

/* command handlers */
int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_flash_banks_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_flash_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_flash_erase_address_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_flash_protect_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_flash_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_flash_write_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_flash_write_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_flash_protect_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_flash_auto_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
flash_bank_t *get_flash_bank_by_addr(target_t *target, u32 addr);

/* flash drivers
 */
extern flash_driver_t lpc2000_flash;
extern flash_driver_t cfi_flash;
extern flash_driver_t at91sam7_flash;
extern flash_driver_t str7x_flash;
extern flash_driver_t str9x_flash;
extern flash_driver_t stellaris_flash;
extern flash_driver_t str9xpec_flash;
extern flash_driver_t stm32x_flash;
extern flash_driver_t tms470_flash;
ntfreak's avatar
ntfreak committed
67
extern flash_driver_t ecosflash_flash;
oharboe's avatar
oharboe committed
68
69
70
71
72
73
74
75
76
77
78
79

flash_driver_t *flash_drivers[] =
{
	&lpc2000_flash,
	&cfi_flash,
	&at91sam7_flash,
	&str7x_flash,
	&str9x_flash,
	&stellaris_flash,
	&str9xpec_flash,
	&stm32x_flash,
	&tms470_flash,
ntfreak's avatar
ntfreak committed
80
	&ecosflash_flash,
oharboe's avatar
oharboe committed
81
82
83
84
85
86
87
88
89
90
	NULL,
};

flash_bank_t *flash_banks;
static 	command_t *flash_cmd;
static int auto_erase = 0;

/* wafer thin wrapper for invoking the flash driver */
static int flash_driver_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
{
91
92
93
	int retval;

	retval=bank->driver->write(bank, buffer, offset, count);
oharboe's avatar
oharboe committed
94
95
	if (retval!=ERROR_OK)
	{
96
		ERROR("error writing to flash at address 0x%08x at offset 0x%8.8x", bank->base, offset);
oharboe's avatar
oharboe committed
97
	}
98

oharboe's avatar
oharboe committed
99
100
101
102
103
	return retval;
}

static int flash_driver_erase(struct flash_bank_s *bank, int first, int last)
{
104
105
106
	int retval;

	retval=bank->driver->erase(bank, first, last);
oharboe's avatar
oharboe committed
107
108
	if (retval!=ERROR_OK)
	{
oharboe's avatar
oharboe committed
109
		ERROR("failed erasing sectors %d to %d", first, last);
oharboe's avatar
oharboe committed
110
	}
111

oharboe's avatar
oharboe committed
112
113
114
115
116
117
	return retval;
}

int flash_driver_protect(struct flash_bank_s *bank, int set, int first, int last)
{
	int retval;
118
119

	retval=bank->driver->protect(bank, set, first, last);
oharboe's avatar
oharboe committed
120
121
	if (retval!=ERROR_OK)
	{
oharboe's avatar
oharboe committed
122
		ERROR("failed setting protection for areas %d to %d", first, last);
oharboe's avatar
oharboe committed
123
	}
124

oharboe's avatar
oharboe committed
125
126
127
128
129
130
131
	return retval;
}


int flash_register_commands(struct command_context_s *cmd_ctx)
{
	flash_cmd = register_command(cmd_ctx, NULL, "flash", NULL, COMMAND_ANY, NULL);
ntfreak's avatar
ntfreak committed
132

oharboe's avatar
oharboe committed
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
	register_command(cmd_ctx, flash_cmd, "bank", handle_flash_bank_command, COMMAND_CONFIG, "flash_bank <driver> <base> <size> <chip_width> <bus_width> <target> [driver_options ...]");
	register_command(cmd_ctx, flash_cmd, "auto_erase", handle_flash_auto_erase_command, COMMAND_ANY,
						 "auto erase flash sectors <on|off>");
	return ERROR_OK;
}

int flash_init_drivers(struct command_context_s *cmd_ctx)
{
	if (flash_banks)
	{
		register_command(cmd_ctx, flash_cmd, "banks", handle_flash_banks_command, COMMAND_EXEC,
						 "list configured flash banks ");
		register_command(cmd_ctx, flash_cmd, "info", handle_flash_info_command, COMMAND_EXEC,
						 "print info about flash bank <num>");
		register_command(cmd_ctx, flash_cmd, "probe", handle_flash_probe_command, COMMAND_EXEC,
						 "identify flash bank <num>");
		register_command(cmd_ctx, flash_cmd, "erase_check", handle_flash_erase_check_command, COMMAND_EXEC,
						 "check erase state of sectors in flash bank <num>");
		register_command(cmd_ctx, flash_cmd, "protect_check", handle_flash_protect_check_command, COMMAND_EXEC,
						 "check protection state of sectors in flash bank <num>");
		register_command(cmd_ctx, flash_cmd, "erase_sector", handle_flash_erase_command, COMMAND_EXEC,
						 "erase sectors at <bank> <first> <last>");
		register_command(cmd_ctx, flash_cmd, "erase_address", handle_flash_erase_address_command, COMMAND_EXEC,
						 "erase address range <address> <length>");
		register_command(cmd_ctx, flash_cmd, "write_bank", handle_flash_write_bank_command, COMMAND_EXEC,
						 "write binary data to <bank> <file> <offset>");
		register_command(cmd_ctx, flash_cmd, "write_image", handle_flash_write_image_command, COMMAND_EXEC,
						 "write_image <file> [offset] [type]");
		register_command(cmd_ctx, flash_cmd, "protect", handle_flash_protect_command, COMMAND_EXEC,
						 "set protection of sectors at <bank> <first> <last> <on|off>");
	}
ntfreak's avatar
ntfreak committed
164

oharboe's avatar
oharboe committed
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
	return ERROR_OK;
}

flash_bank_t *get_flash_bank_by_num_noprobe(int num)
{
	flash_bank_t *p;
	int i = 0;

	for (p = flash_banks; p; p = p->next)
	{
		if (i++ == num)
		{
			return p;
		}
	}
180
	ERROR("flash bank %d does not exist", num);
oharboe's avatar
oharboe committed
181
182
183
184
185
186
187
	return NULL;
}

flash_bank_t *get_flash_bank_by_num(int num)
{
	flash_bank_t *p = get_flash_bank_by_num_noprobe(num);
	int retval;
ntfreak's avatar
ntfreak committed
188

oharboe's avatar
oharboe committed
189
190
	if (p == NULL)
		return NULL;
ntfreak's avatar
ntfreak committed
191

oharboe's avatar
oharboe committed
192
	retval = p->driver->auto_probe(p);
ntfreak's avatar
ntfreak committed
193

oharboe's avatar
oharboe committed
194
195
196
197
198
199
200
201
202
203
204
205
206
	if (retval != ERROR_OK)
	{
		ERROR("auto_probe failed %d\n", retval);
		return NULL;
	}
	return p;
}

int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	int i;
	int found = 0;
	target_t *target;
ntfreak's avatar
ntfreak committed
207

oharboe's avatar
oharboe committed
208
209
210
211
	if (argc < 6)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
ntfreak's avatar
ntfreak committed
212

oharboe's avatar
oharboe committed
213
214
215
216
217
	if ((target = get_target_by_num(strtoul(args[5], NULL, 0))) == NULL)
	{
		ERROR("target %lu not defined", strtoul(args[5], NULL, 0));
		return ERROR_OK;
	}
ntfreak's avatar
ntfreak committed
218

oharboe's avatar
oharboe committed
219
220
221
222
223
	for (i = 0; flash_drivers[i]; i++)
	{
		if (strcmp(args[0], flash_drivers[i]->name) == 0)
		{
			flash_bank_t *p, *c;
ntfreak's avatar
ntfreak committed
224

oharboe's avatar
oharboe committed
225
226
227
228
229
230
			/* register flash specific commands */
			if (flash_drivers[i]->register_commands(cmd_ctx) != ERROR_OK)
			{
				ERROR("couldn't register '%s' commands", args[0]);
				exit(-1);
			}
ntfreak's avatar
ntfreak committed
231

oharboe's avatar
oharboe committed
232
233
234
235
236
237
238
239
240
241
242
			c = malloc(sizeof(flash_bank_t));
			c->target = target;
			c->driver = flash_drivers[i];
			c->driver_priv = NULL;
			c->base = strtoul(args[1], NULL, 0);
			c->size = strtoul(args[2], NULL, 0);
			c->chip_width = strtoul(args[3], NULL, 0);
			c->bus_width = strtoul(args[4], NULL, 0);
			c->num_sectors = 0;
			c->sectors = NULL;
			c->next = NULL;
ntfreak's avatar
ntfreak committed
243

oharboe's avatar
oharboe committed
244
245
246
247
248
249
			if (flash_drivers[i]->flash_bank_command(cmd_ctx, cmd, args, argc, c) != ERROR_OK)
			{
				ERROR("'%s' driver rejected flash bank at 0x%8.8x", args[0], c->base);
				free(c);
				return ERROR_OK;
			}
ntfreak's avatar
ntfreak committed
250

oharboe's avatar
oharboe committed
251
252
253
254
255
256
257
258
259
260
261
262
			/* put flash bank in linked list */
			if (flash_banks)
			{
				/* find last flash bank */
				for (p = flash_banks; p && p->next; p = p->next);
				if (p)
					p->next = c;
			}
			else
			{
				flash_banks = c;
			}
ntfreak's avatar
ntfreak committed
263

oharboe's avatar
oharboe committed
264
265
266
			found = 1;
		}
	}
ntfreak's avatar
ntfreak committed
267

oharboe's avatar
oharboe committed
268
269
270
271
272
273
	/* no matching flash driver found */
	if (!found)
	{
		ERROR("flash driver '%s' not found", args[0]);
		exit(-1);
	}
ntfreak's avatar
ntfreak committed
274

oharboe's avatar
oharboe committed
275
276
277
278
279
280
281
	return ERROR_OK;
}

int handle_flash_banks_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	flash_bank_t *p;
	int i = 0;
ntfreak's avatar
ntfreak committed
282

oharboe's avatar
oharboe committed
283
284
285
286
287
	if (!flash_banks)
	{
		command_print(cmd_ctx, "no flash banks configured");
		return ERROR_OK;
	}
ntfreak's avatar
ntfreak committed
288

oharboe's avatar
oharboe committed
289
290
291
292
293
	for (p = flash_banks; p; p = p->next)
	{
		command_print(cmd_ctx, "#%i: %s at 0x%8.8x, size 0x%8.8x, buswidth %i, chipwidth %i",
					  i++, p->driver->name, p->base, p->size, p->bus_width, p->chip_width);
	}
ntfreak's avatar
ntfreak committed
294

oharboe's avatar
oharboe committed
295
296
297
298
299
300
301
302
	return ERROR_OK;
}

int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	flash_bank_t *p;
	int i = 0;
	int j = 0;
ntfreak's avatar
ntfreak committed
303

oharboe's avatar
oharboe committed
304
305
306
307
	if (argc != 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
ntfreak's avatar
ntfreak committed
308

oharboe's avatar
oharboe committed
309
310
311
312
313
	for (p = flash_banks; p; p = p->next, i++)
	{
		if (i == strtoul(args[0], NULL, 0))
		{
			char buf[1024];
ntfreak's avatar
ntfreak committed
314

oharboe's avatar
oharboe committed
315
316
			/* attempt auto probe */
			p->driver->auto_probe(p);
ntfreak's avatar
ntfreak committed
317

oharboe's avatar
oharboe committed
318
319
320
321
322
			command_print(cmd_ctx, "#%i: %s at 0x%8.8x, size 0x%8.8x, buswidth %i, chipwidth %i",
						i, p->driver->name, p->base, p->size, p->bus_width, p->chip_width);
			for (j = 0; j < p->num_sectors; j++)
			{
				char *erase_state, *protect_state;
ntfreak's avatar
ntfreak committed
323

oharboe's avatar
oharboe committed
324
325
326
327
328
329
				if (p->sectors[j].is_erased == 0)
					erase_state = "not erased";
				else if (p->sectors[j].is_erased == 1)
					erase_state = "erased";
				else
					erase_state = "erase state unknown";
ntfreak's avatar
ntfreak committed
330

oharboe's avatar
oharboe committed
331
332
333
334
335
336
337
338
339
340
341
				if (p->sectors[j].is_protected == 0)
					protect_state = "not protected";
				else if (p->sectors[j].is_protected == 1)
					protect_state = "protected";
				else
					protect_state = "protection state unknown";

				command_print(cmd_ctx, "\t#%i: 0x%8.8x (0x%x %ikB) %s, %s",
							j, p->sectors[j].offset, p->sectors[j].size, p->sectors[j].size>>10,
							erase_state, protect_state);
			}
ntfreak's avatar
ntfreak committed
342

oharboe's avatar
oharboe committed
343
344
345
346
			p->driver->info(p, buf, 1024);
			command_print(cmd_ctx, "%s", buf);
		}
	}
ntfreak's avatar
ntfreak committed
347

oharboe's avatar
oharboe committed
348
349
350
351
352
353
354
	return ERROR_OK;
}

int handle_flash_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	flash_bank_t *p;
	int retval;
ntfreak's avatar
ntfreak committed
355

oharboe's avatar
oharboe committed
356
357
358
359
	if (argc != 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
ntfreak's avatar
ntfreak committed
360

oharboe's avatar
oharboe committed
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
	p = get_flash_bank_by_num_noprobe(strtoul(args[0], NULL, 0));
	if (p)
	{
		if ((retval = p->driver->probe(p)) == ERROR_OK)
		{
			command_print(cmd_ctx, "flash '%s' found at 0x%8.8x", p->driver->name, p->base);
		}
		else if (retval == ERROR_FLASH_BANK_INVALID)
		{
			command_print(cmd_ctx, "probing failed for flash bank '#%s' at 0x%8.8x",
						  args[0], p->base);
		}
		else
		{
			command_print(cmd_ctx, "unknown error when probing flash bank '#%s' at 0x%8.8x",
						  args[0], p->base);
		}
	}
	else
	{
		command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
	}
ntfreak's avatar
ntfreak committed
383

oharboe's avatar
oharboe committed
384
385
386
387
388
389
390
	return ERROR_OK;
}

int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	flash_bank_t *p;
	int retval;
ntfreak's avatar
ntfreak committed
391

oharboe's avatar
oharboe committed
392
393
394
395
	if (argc != 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
ntfreak's avatar
ntfreak committed
396

oharboe's avatar
oharboe committed
397
398
399
400
401
402
403
404
405
406
407
408
409
	p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
	if (p)
	{
		if ((retval = p->driver->erase_check(p)) == ERROR_OK)
		{
			command_print(cmd_ctx, "successfully checked erase state", p->driver->name, p->base);
		}
		else
		{
			command_print(cmd_ctx, "unknown error when checking erase state of flash bank #%s at 0x%8.8x",
				args[0], p->base);
		}
	}
ntfreak's avatar
ntfreak committed
410

oharboe's avatar
oharboe committed
411
412
413
414
415
416
417
418
419
420
421
	return ERROR_OK;
}

int handle_flash_erase_address_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	flash_bank_t *p;
	int retval;
	int address;
	int length;
	duration_t duration;
	char *duration_text;
ntfreak's avatar
ntfreak committed
422

oharboe's avatar
oharboe committed
423
424
425
426
427
428
	target_t *target = get_current_target(cmd_ctx);

	if (argc != 2)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
ntfreak's avatar
ntfreak committed
429

oharboe's avatar
oharboe committed
430
431
432
433
434
435
436
437
438
439
440
441
442
	address = strtoul(args[0], NULL, 0);
	length = strtoul(args[1], NULL, 0);
	if (length <= 0)
	{
		command_print(cmd_ctx, "Length must be >0");
		return ERROR_COMMAND_SYNTAX_ERROR;
	}

	p = get_flash_bank_by_addr(target, address);
	if (p == NULL)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
ntfreak's avatar
ntfreak committed
443

oharboe's avatar
oharboe committed
444
445
	/* We can't know if we did a resume + halt, in which case we no longer know the erased state */
	flash_set_dirty();
ntfreak's avatar
ntfreak committed
446

oharboe's avatar
oharboe committed
447
	duration_start_measure(&duration);
ntfreak's avatar
ntfreak committed
448

oharboe's avatar
oharboe committed
449
450
	if ((retval = flash_erase_address_range(target, address, length)) == ERROR_OK)
	{
ntfreak's avatar
ntfreak committed
451
		duration_stop_measure(&duration, &duration_text);
oharboe's avatar
oharboe committed
452
453
454
		command_print(cmd_ctx, "erased address 0x%8.8x length %i in %s", address, length, duration_text);
		free(duration_text);
	}
ntfreak's avatar
ntfreak committed
455

oharboe's avatar
oharboe committed
456
457
458
459
460
461
462
	return retval;
}

int handle_flash_protect_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	flash_bank_t *p;
	int retval;
ntfreak's avatar
ntfreak committed
463

oharboe's avatar
oharboe committed
464
465
466
467
	if (argc != 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
ntfreak's avatar
ntfreak committed
468

oharboe's avatar
oharboe committed
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
	p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
	if (p)
	{
		if ((retval = p->driver->protect_check(p)) == ERROR_OK)
		{
			command_print(cmd_ctx, "successfully checked protect state");
		}
		else if (retval == ERROR_FLASH_OPERATION_FAILED)
		{
			command_print(cmd_ctx, "checking protection state failed (possibly unsupported) by flash #%s at 0x%8.8x", args[0], p->base);
		}
		else
		{
			command_print(cmd_ctx, "unknown error when checking protection state of flash bank '#%s' at 0x%8.8x", args[0], p->base);
		}
	}
	else
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
ntfreak's avatar
ntfreak committed
489

oharboe's avatar
oharboe committed
490
491
492
493
494
495
496
497
498
499
500
501
502
	return ERROR_OK;
}

int handle_flash_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	if (argc > 2)
	{
		int first = strtoul(args[1], NULL, 0);
		int last = strtoul(args[2], NULL, 0);
		int retval;
		flash_bank_t *p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
		duration_t duration;
		char *duration_text;
ntfreak's avatar
ntfreak committed
503

oharboe's avatar
oharboe committed
504
		duration_start_measure(&duration);
ntfreak's avatar
ntfreak committed
505

oharboe's avatar
oharboe committed
506
507
508
509
		if (!p)
		{
			return ERROR_COMMAND_SYNTAX_ERROR;
		}
ntfreak's avatar
ntfreak committed
510

oharboe's avatar
oharboe committed
511
512
		if ((retval = flash_driver_erase(p, first, last)) == ERROR_OK)
		{
ntfreak's avatar
ntfreak committed
513
514
			duration_stop_measure(&duration, &duration_text);

oharboe's avatar
oharboe committed
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
			command_print(cmd_ctx, "erased sectors %i through %i on flash bank %i in %s", first, last, strtoul(args[0], 0, 0), duration_text);
			free(duration_text);
		}
	}
	else
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}

	return ERROR_OK;
}

int handle_flash_protect_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	if (argc > 3)
	{
		int first = strtoul(args[1], NULL, 0);
		int last = strtoul(args[2], NULL, 0);
		int set;
		int retval;
		flash_bank_t *p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
		if (!p)
		{
			command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
			return ERROR_OK;
		}
ntfreak's avatar
ntfreak committed
541

oharboe's avatar
oharboe committed
542
543
544
545
546
547
548
549
		if (strcmp(args[3], "on") == 0)
			set = 1;
		else if (strcmp(args[3], "off") == 0)
			set = 0;
		else
		{
			return ERROR_COMMAND_SYNTAX_ERROR;
		}
ntfreak's avatar
ntfreak committed
550

oharboe's avatar
oharboe committed
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
		retval = flash_driver_protect(p, set, first, last);
		if (retval == ERROR_OK)
		{
			command_print(cmd_ctx, "%s protection for sectors %i through %i on flash bank %i", (set) ? "set" : "cleared", first, last, strtoul(args[0], 0, 0));
		}
	}
	else
	{
		return ERROR_COMMAND_SYNTAX_ERROR;

	}

	return ERROR_OK;
}

int handle_flash_write_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	target_t *target = get_current_target(cmd_ctx);
ntfreak's avatar
ntfreak committed
569

oharboe's avatar
oharboe committed
570
571
	image_t image;
	u32 written;
ntfreak's avatar
ntfreak committed
572

oharboe's avatar
oharboe committed
573
574
	duration_t duration;
	char *duration_text;
ntfreak's avatar
ntfreak committed
575

oharboe's avatar
oharboe committed
576
577
578
579
580
581
582
	int retval;

	if (argc < 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;

	}
ntfreak's avatar
ntfreak committed
583

oharboe's avatar
oharboe committed
584
585
586
587
588
	if (!target)
	{
		ERROR("no target selected");
		return ERROR_OK;
	}
ntfreak's avatar
ntfreak committed
589

oharboe's avatar
oharboe committed
590
	duration_start_measure(&duration);
ntfreak's avatar
ntfreak committed
591

oharboe's avatar
oharboe committed
592
593
594
595
596
597
598
599
600
601
	if (argc >= 2)
	{
		image.base_address_set = 1;
		image.base_address = strtoul(args[1], NULL, 0);
	}
	else
	{
		image.base_address_set = 0;
		image.base_address = 0x0;
	}
ntfreak's avatar
ntfreak committed
602

oharboe's avatar
oharboe committed
603
604
605
606
607
608
609
610
	image.start_address_set = 0;

	retval = image_open(&image, args[0], (argc == 3) ? args[2] : NULL);
	if (retval != ERROR_OK)
	{
		command_print(cmd_ctx, "image_open error: %s", image.error_str);
		return retval;
	}
ntfreak's avatar
ntfreak committed
611

oharboe's avatar
oharboe committed
612
613
614
615
616
617
618
	retval = flash_write(target, &image, &written, auto_erase);

	if (retval != ERROR_OK)
	{
		image_close(&image);
		return retval;
	}
ntfreak's avatar
ntfreak committed
619

oharboe's avatar
oharboe committed
620
621
622
623
624
625
626
627
628
629
	duration_stop_measure(&duration, &duration_text);
	if (retval == ERROR_OK)
	{
	command_print(cmd_ctx, "wrote %u byte from file %s in %s (%f kb/s)",
		written, args[0], duration_text,
		(float)written / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0)));
	}
	free(duration_text);

	image_close(&image);
ntfreak's avatar
ntfreak committed
630

oharboe's avatar
oharboe committed
631
632
633
634
635
636
637
638
639
640
	return retval;
}

int handle_flash_write_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	u32 offset;
	u8 *buffer;
	u32 buf_cnt;

	fileio_t fileio;
ntfreak's avatar
ntfreak committed
641

oharboe's avatar
oharboe committed
642
643
	duration_t duration;
	char *duration_text;
ntfreak's avatar
ntfreak committed
644

oharboe's avatar
oharboe committed
645
646
647
648
649
650
651
	int retval;
	flash_bank_t *p;

	if (argc != 3)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
ntfreak's avatar
ntfreak committed
652

oharboe's avatar
oharboe committed
653
	duration_start_measure(&duration);
ntfreak's avatar
ntfreak committed
654

oharboe's avatar
oharboe committed
655
656
657
658
659
660
661
	offset = strtoul(args[2], NULL, 0);
	p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
	if (!p)
	{
		command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
		return ERROR_OK;
	}
ntfreak's avatar
ntfreak committed
662

oharboe's avatar
oharboe committed
663
664
665
666
667
	if (fileio_open(&fileio, args[1], FILEIO_READ, FILEIO_BINARY) != ERROR_OK)
	{
		command_print(cmd_ctx, "flash write_binary error: %s", fileio.error_str);
		return ERROR_OK;
	}
ntfreak's avatar
ntfreak committed
668

oharboe's avatar
oharboe committed
669
670
671
672
673
674
	buffer = malloc(fileio.size);
	if (fileio_read(&fileio, fileio.size, buffer, &buf_cnt) != ERROR_OK)
	{
		command_print(cmd_ctx, "flash write_binary error: %s", fileio.error_str);
		return ERROR_OK;
	}
ntfreak's avatar
ntfreak committed
675

oharboe's avatar
oharboe committed
676
	retval = flash_driver_write(p, buffer, offset, buf_cnt);
ntfreak's avatar
ntfreak committed
677

oharboe's avatar
oharboe committed
678
	free(buffer);
ntfreak's avatar
ntfreak committed
679

oharboe's avatar
oharboe committed
680
681
682
683
684
685
686
687
688
689
	duration_stop_measure(&duration, &duration_text);
	if (retval!=ERROR_OK)
	{
	command_print(cmd_ctx, "wrote  %"PRIi64" byte from file %s to flash bank %i at offset 0x%8.8x in %s (%f kb/s)",
		fileio.size, args[1], strtoul(args[0], NULL, 0), offset, duration_text,
		(float)fileio.size / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0)));
	}
	free(duration_text);

	fileio_close(&fileio);
ntfreak's avatar
ntfreak committed
690

oharboe's avatar
oharboe committed
691
692
693
694
695
696
697
	return retval;
}

void flash_set_dirty(void)
{
	flash_bank_t *c;
	int i;
ntfreak's avatar
ntfreak committed
698

oharboe's avatar
oharboe committed
699
700
701
702
703
	/* set all flash to require erasing */
	for (c = flash_banks; c; c = c->next)
	{
		for (i = 0; i < c->num_sectors; i++)
		{
ntfreak's avatar
ntfreak committed
704
			c->sectors[i].is_erased = 0;
oharboe's avatar
oharboe committed
705
706
707
708
709
710
711
712
713
714
715
716
717
718
		}
	}
}

/* lookup flash bank by address */
flash_bank_t *get_flash_bank_by_addr(target_t *target, u32 addr)
{
	flash_bank_t *c;

	/* cycle through bank list */
	for (c = flash_banks; c; c = c->next)
	{
		int retval;
		retval = c->driver->auto_probe(c);
ntfreak's avatar
ntfreak committed
719

oharboe's avatar
oharboe committed
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
		if (retval != ERROR_OK)
		{
			ERROR("auto_probe failed %d\n", retval);
			return NULL;
		}
		/* check whether address belongs to this flash bank */
		if ((addr >= c->base) && (addr < c->base + c->size) && target == c->target)
			return c;
	}
	ERROR("No flash at address 0x%08x\n", addr);
	return NULL;
}

/* erase given flash region, selects proper bank according to target and address */
int flash_erase_address_range(target_t *target, u32 addr, u32 length)
{
	flash_bank_t *c;
	int first = -1;
	int last = -1;
	int i;
ntfreak's avatar
ntfreak committed
740

oharboe's avatar
oharboe committed
741
742
743
744
745
	if ((c = get_flash_bank_by_addr(target, addr)) == NULL)
		return ERROR_FLASH_DST_OUT_OF_BANK; /* no corresponding bank found */

	if (c->size == 0 || c->num_sectors == 0)
		return ERROR_FLASH_BANK_INVALID;
ntfreak's avatar
ntfreak committed
746

oharboe's avatar
oharboe committed
747
748
749
750
751
	if (length == 0)
	{
		/* special case, erase whole bank when length is zero */
		if (addr != c->base)
			return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
ntfreak's avatar
ntfreak committed
752

oharboe's avatar
oharboe committed
753
754
755
756
757
758
		return flash_driver_erase(c, 0, c->num_sectors - 1);
	}

	/* check whether it fits */
	if (addr + length > c->base + c->size)
		return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
ntfreak's avatar
ntfreak committed
759

oharboe's avatar
oharboe committed
760
	addr -= c->base;
ntfreak's avatar
ntfreak committed
761

oharboe's avatar
oharboe committed
762
	for (i = 0; i < c->num_sectors; i++)
ntfreak's avatar
ntfreak committed
763
	{
oharboe's avatar
oharboe committed
764
765
766
767
768
769
770
771
		/* check whether sector overlaps with the given range and is not yet erased */
		if (addr < c->sectors[i].offset + c->sectors[i].size && addr + length > c->sectors[i].offset && c->sectors[i].is_erased != 1) {
			/* if first is not set yet then this is the first sector */
			if (first == -1)
				first = i;
			last = i; /* and it is the last one so far in any case */
		}
	}
ntfreak's avatar
ntfreak committed
772

oharboe's avatar
oharboe committed
773
774
	if( first == -1 || last == -1 )
		return ERROR_OK;
ntfreak's avatar
ntfreak committed
775

oharboe's avatar
oharboe committed
776
777
778
779
780
781
782
783
784
785
786
	return flash_driver_erase(c, first, last);
}

/* write (optional verify) an image to flash memory of the given target */
int flash_write(target_t *target, image_t *image, u32 *written, int erase)
{
	int retval;

	int section;
	u32 section_offset;
	flash_bank_t *c;
ntfreak's avatar
ntfreak committed
787

oharboe's avatar
oharboe committed
788
789
790
791
792
	section = 0;
	section_offset = 0;

	if (written)
		*written = 0;
ntfreak's avatar
ntfreak committed
793

oharboe's avatar
oharboe committed
794
795
796
797
	if (erase)
	{
		/* assume all sectors need erasing - stops any problems
		 * when flash_write is called multiple times */
ntfreak's avatar
ntfreak committed
798

oharboe's avatar
oharboe committed
799
800
		flash_set_dirty();
	}
ntfreak's avatar
ntfreak committed
801

oharboe's avatar
oharboe committed
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
	/* loop until we reach end of the image */
	while (section < image->num_sections)
	{
		u32 buffer_size;
		u8 *buffer;
		int section_first;
		int section_last;
		u32 run_address = image->sections[section].base_address + section_offset;
		u32 run_size = image->sections[section].size - section_offset;

		if (image->sections[section].size ==  0)
		{
			WARNING("empty section %d", section);
			section++;
			section_offset = 0;
			continue;
		}

		/* find the corresponding flash bank */
		if ((c = get_flash_bank_by_addr(target, run_address)) == NULL)
		{
			section++; /* and skip it */
			section_offset = 0;
			continue;
		}

		/* collect consecutive sections which fall into the same bank */
		section_first = section;
		section_last = section;
		while ((run_address + run_size < c->base + c->size)
				&& (section_last + 1 < image->num_sections))
		{
			if (image->sections[section_last + 1].base_address < (run_address + run_size))
			{
				DEBUG("section %d out of order(very slightly surprising, but supported)", section_last + 1);
				break;
			}
			if (image->sections[section_last + 1].base_address != (run_address + run_size))
				break;
			run_size += image->sections[++section_last].size;
		}

		/* fit the run into bank constraints */
		if (run_address + run_size > c->base + c->size)
			run_size = c->base + c->size - run_address;

		/* allocate buffer */
		buffer = malloc(run_size);
		buffer_size = 0;

		/* read sections to the buffer */
		while (buffer_size < run_size)
		{
			u32 size_read;
ntfreak's avatar
ntfreak committed
856

oharboe's avatar
oharboe committed
857
858
859
860
			if (buffer_size - run_size <= image->sections[section].size - section_offset)
				size_read = buffer_size - run_size;
			else
				size_read = image->sections[section].size - section_offset;
ntfreak's avatar
ntfreak committed
861

oharboe's avatar
oharboe committed
862
863
864
865
			if ((retval = image_read_section(image, section, section_offset,
					size_read, buffer + buffer_size, &size_read)) != ERROR_OK || size_read == 0)
			{
				free(buffer);
ntfreak's avatar
ntfreak committed
866

oharboe's avatar
oharboe committed
867
868
869
870
871
872
873
874
875
876
877
878
879
880
				return retval;
			}

			buffer_size += size_read;
			section_offset += size_read;

			if (section_offset >= image->sections[section].size)
			{
				section++;
				section_offset = 0;
			}
		}

		retval = ERROR_OK;
ntfreak's avatar
ntfreak committed
881

oharboe's avatar
oharboe committed
882
883
884
885
886
		if (erase)
		{
			/* calculate and erase sectors */
			retval = flash_erase_address_range( target, run_address, run_size );
		}
ntfreak's avatar
ntfreak committed
887

oharboe's avatar
oharboe committed
888
889
890
891
892
		if (retval == ERROR_OK)
		{
			/* write flash sectors */
			retval = flash_driver_write(c, buffer, run_address - c->base, run_size);
		}
ntfreak's avatar
ntfreak committed
893

oharboe's avatar
oharboe committed
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
		free(buffer);

		if (retval != ERROR_OK)
		{
				return retval; /* abort operation */
			}

		if (written != NULL)
			*written += run_size; /* add run size to total written counter */
	}

	return ERROR_OK;
}

int handle_flash_auto_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	if (argc != 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;

	}
ntfreak's avatar
ntfreak committed
915

oharboe's avatar
oharboe committed
916
917
918
919
	if (strcmp(args[0], "on") == 0)
		auto_erase = 1;
	else if (strcmp(args[0], "off") == 0)
		auto_erase = 0;
ntfreak's avatar
ntfreak committed
920
	else
oharboe's avatar
oharboe committed
921
		return ERROR_COMMAND_SYNTAX_ERROR;
ntfreak's avatar
ntfreak committed
922

oharboe's avatar
oharboe committed
923
924
	return ERROR_OK;
}