flash.c 31.2 KB
Newer Older
oharboe's avatar
oharboe committed
1
2
3
4
/***************************************************************************
 *   Copyright (C) 2005 by Dominic Rath                                    *
 *   Dominic.Rath@gmx.de                                                   *
 *                                                                         *
5
 *   Copyright (C) 2007,2008 yvind Harboe                                 *
6
7
 *   oyvind.harboe@zylin.com                                               *
 *                                                                         *
8
9
10
 *   Copyright (C) 2008 by Spencer Oliver                                  *
 *   spen@spen-soft.co.uk                                                  *
 *                                                                         *
oharboe's avatar
oharboe committed
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 *   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 "image.h"
32
#include "time_support.h"
oharboe's avatar
oharboe committed
33
34

/* command handlers */
mifi's avatar
mifi committed
35
36
37
38
39
40
41
42
43
44
45
static int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
static int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
static int handle_flash_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
static int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
static int handle_flash_erase_address_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
static int handle_flash_protect_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
static int handle_flash_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
static int handle_flash_write_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
static int handle_flash_write_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
static int handle_flash_fill_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
static int handle_flash_protect_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
oharboe's avatar
oharboe committed
46
47
48
49
50
51
52
53

/* 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;
54
extern flash_driver_t aduc702x_flash;
oharboe's avatar
oharboe committed
55
56
57
58
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
59
extern flash_driver_t ecosflash_flash;
60
extern flash_driver_t lpc288x_flash;
oharboe's avatar
oharboe committed
61
extern flash_driver_t ocl_flash;
62
extern flash_driver_t pic32mx_flash;
63
extern flash_driver_t avr_flash;
oharboe's avatar
oharboe committed
64

65
flash_driver_t *flash_drivers[] = {
66
67
68
69
70
71
72
73
74
75
76
77
78
	&lpc2000_flash,
	&cfi_flash,
	&at91sam7_flash,
	&str7x_flash,
	&str9x_flash,
	&aduc702x_flash,
	&stellaris_flash,
	&str9xpec_flash,
	&stm32x_flash,
	&tms470_flash,
	&ecosflash_flash,
	&lpc288x_flash,
	&ocl_flash,
79
	&pic32mx_flash,
80
	&avr_flash,
81
	NULL,
oharboe's avatar
oharboe committed
82
83
84
85
};

flash_bank_t *flash_banks;
static 	command_t *flash_cmd;
86

oharboe's avatar
oharboe committed
87
/* wafer thin wrapper for invoking the flash driver */
88
static int flash_driver_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
oharboe's avatar
oharboe committed
89
{
90
91
	int retval;

zwelch's avatar
zwelch committed
92
	retval = bank->driver->write(bank, buffer, offset, count);
zwelch's avatar
zwelch committed
93
	if (retval != ERROR_OK)
oharboe's avatar
oharboe committed
94
	{
duane's avatar
duane committed
95
96
		LOG_ERROR("error writing to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32 " (%d)", 
			  bank->base, offset, retval);
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
	int retval;

zwelch's avatar
zwelch committed
106
	retval = bank->driver->erase(bank, first, last);
zwelch's avatar
zwelch committed
107
	if (retval != ERROR_OK)
oharboe's avatar
oharboe committed
108
	{
109
		LOG_ERROR("failed erasing sectors %d to %d (%d)", first, last, retval);
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

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

oharboe's avatar
oharboe committed
125
126
127
128
129
130
	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
131

ntfreak's avatar
ntfreak committed
132
	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 ...]");
oharboe's avatar
oharboe committed
133
134
135
	return ERROR_OK;
}

136
static int jim_flash_banks(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
oharboe's avatar
oharboe committed
137
{
138
	flash_bank_t *p;
oharboe's avatar
oharboe committed
139

oharboe's avatar
oharboe committed
140
141
142
143
144
	if (argc != 1) {
		Jim_WrongNumArgs(interp, 1, argv, "no arguments to flash_banks command");
		return JIM_ERR;
	}

zwelch's avatar
zwelch committed
145
	Jim_Obj *list = Jim_NewListObj(interp, NULL, 0);
oharboe's avatar
oharboe committed
146
147
	for (p = flash_banks; p; p = p->next)
	{
zwelch's avatar
zwelch committed
148
		Jim_Obj *elem = Jim_NewListObj(interp, NULL, 0);
oharboe's avatar
oharboe committed
149

150
		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "name", -1));
oharboe's avatar
oharboe committed
151
		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, p->driver->name, -1));
152
		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "base", -1));
oharboe's avatar
oharboe committed
153
		Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->base));
154
		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "size", -1));
oharboe's avatar
oharboe committed
155
		Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->size));
156
		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "bus_width", -1));
oharboe's avatar
oharboe committed
157
		Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->bus_width));
158
		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "chip_width", -1));
oharboe's avatar
oharboe committed
159
		Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->chip_width));
oharboe's avatar
oharboe committed
160

161
		Jim_ListAppendElement(interp, list, elem);
oharboe's avatar
oharboe committed
162
163
164
165
166
167
168
	}

	Jim_SetResult(interp, list);

	return JIM_OK;
}

oharboe's avatar
oharboe committed
169
170
int flash_init_drivers(struct command_context_s *cmd_ctx)
{
171
172
	register_jim(cmd_ctx, "ocd_flash_banks", jim_flash_banks, "return information about the flash banks");

oharboe's avatar
oharboe committed
173
174
175
176
177
178
179
180
181
182
183
184
185
186
	if (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>");
oharboe's avatar
   
oharboe committed
187
188

		register_command(cmd_ctx, flash_cmd, "fillw", handle_flash_fill_command, COMMAND_EXEC,
oharboe's avatar
oharboe committed
189
						 "fill with pattern (no autoerase) <address> <word_pattern> <count>");
oharboe's avatar
   
oharboe committed
190
191
192
193
194
		register_command(cmd_ctx, flash_cmd, "fillh", handle_flash_fill_command, COMMAND_EXEC,
						 "fill with pattern <address> <halfword_pattern> <count>");
		register_command(cmd_ctx, flash_cmd, "fillb", handle_flash_fill_command, COMMAND_EXEC,
						 "fill with pattern <address> <byte_pattern> <count>");

oharboe's avatar
oharboe committed
195
196
197
		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,
198
						 "write_image [erase] <file> [offset] [type]");
oharboe's avatar
oharboe committed
199
		register_command(cmd_ctx, flash_cmd, "protect", handle_flash_protect_command, COMMAND_EXEC,
zwelch's avatar
zwelch committed
200
						 "set protection of sectors at <bank> <first> <last> <on | off>");
oharboe's avatar
oharboe committed
201
	}
ntfreak's avatar
ntfreak committed
202

oharboe's avatar
oharboe committed
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
	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;
		}
	}
218
	LOG_ERROR("flash bank %d does not exist", num);
oharboe's avatar
oharboe committed
219
220
221
	return NULL;
}

oharboe's avatar
oharboe committed
222
int flash_get_bank_count(void)
oharboe's avatar
oharboe committed
223
224
225
226
227
228
229
230
231
232
{
	flash_bank_t *p;
	int i = 0;
	for (p = flash_banks; p; p = p->next)
	{
		i++;
	}
	return i;
}

oharboe's avatar
oharboe committed
233
234
235
236
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
237

oharboe's avatar
oharboe committed
238
239
	if (p == NULL)
		return NULL;
ntfreak's avatar
ntfreak committed
240

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

oharboe's avatar
oharboe committed
243
244
	if (retval != ERROR_OK)
	{
245
		LOG_ERROR("auto_probe failed %d\n", retval);
oharboe's avatar
oharboe committed
246
247
248
249
250
		return NULL;
	}
	return p;
}

mifi's avatar
mifi committed
251
static int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
oharboe's avatar
oharboe committed
252
{
oharboe's avatar
oharboe committed
253
	int retval;
oharboe's avatar
oharboe committed
254
255
256
	int i;
	int found = 0;
	target_t *target;
ntfreak's avatar
ntfreak committed
257

oharboe's avatar
oharboe committed
258
259
260
261
	if (argc < 6)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
ntfreak's avatar
ntfreak committed
262

263
	if ((target = get_target(args[5])) == NULL)
oharboe's avatar
oharboe committed
264
	{
265
		LOG_ERROR("target '%s' not defined", args[5]);
oharboe's avatar
oharboe committed
266
		return ERROR_FAIL;
oharboe's avatar
oharboe committed
267
	}
ntfreak's avatar
ntfreak committed
268

oharboe's avatar
oharboe committed
269
270
271
272
273
	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
274

oharboe's avatar
oharboe committed
275
276
277
			/* register flash specific commands */
			if (flash_drivers[i]->register_commands(cmd_ctx) != ERROR_OK)
			{
278
				LOG_ERROR("couldn't register '%s' commands", args[0]);
oharboe's avatar
oharboe committed
279
				return ERROR_FAIL;
oharboe's avatar
oharboe committed
280
			}
ntfreak's avatar
ntfreak committed
281

oharboe's avatar
oharboe committed
282
283
284
285
286
287
288
289
290
291
292
			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
293

zwelch's avatar
zwelch committed
294
			if ((retval = flash_drivers[i]->flash_bank_command(cmd_ctx, cmd, args, argc, c)) != ERROR_OK)
oharboe's avatar
oharboe committed
295
			{
duane's avatar
duane committed
296
				LOG_ERROR("'%s' driver rejected flash bank at 0x%8.8" PRIx32 , args[0], c->base);
oharboe's avatar
oharboe committed
297
				free(c);
oharboe's avatar
oharboe committed
298
				return retval;
oharboe's avatar
oharboe committed
299
			}
ntfreak's avatar
ntfreak committed
300

oharboe's avatar
oharboe committed
301
302
303
			/* put flash bank in linked list */
			if (flash_banks)
			{
304
				int	bank_num = 0;
oharboe's avatar
oharboe committed
305
				/* find last flash bank */
306
				for (p = flash_banks; p && p->next; p = p->next) bank_num++;
oharboe's avatar
oharboe committed
307
308
				if (p)
					p->next = c;
309
				c->bank_number = bank_num + 1;
oharboe's avatar
oharboe committed
310
311
312
313
			}
			else
			{
				flash_banks = c;
314
				c->bank_number = 0;
oharboe's avatar
oharboe committed
315
			}
ntfreak's avatar
ntfreak committed
316

oharboe's avatar
oharboe committed
317
318
319
			found = 1;
		}
	}
ntfreak's avatar
ntfreak committed
320

oharboe's avatar
oharboe committed
321
322
323
	/* no matching flash driver found */
	if (!found)
	{
324
		LOG_ERROR("flash driver '%s' not found", args[0]);
oharboe's avatar
oharboe committed
325
		return ERROR_FAIL;
oharboe's avatar
oharboe committed
326
	}
ntfreak's avatar
ntfreak committed
327

oharboe's avatar
oharboe committed
328
329
330
	return ERROR_OK;
}

mifi's avatar
mifi committed
331
static int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
oharboe's avatar
oharboe committed
332
333
{
	flash_bank_t *p;
334
	uint32_t i = 0;
oharboe's avatar
oharboe committed
335
	int j = 0;
336
	int retval;
ntfreak's avatar
ntfreak committed
337

oharboe's avatar
oharboe committed
338
339
340
341
	if (argc != 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
ntfreak's avatar
ntfreak committed
342

oharboe's avatar
oharboe committed
343
344
345
346
347
	for (p = flash_banks; p; p = p->next, i++)
	{
		if (i == strtoul(args[0], NULL, 0))
		{
			char buf[1024];
ntfreak's avatar
ntfreak committed
348

oharboe's avatar
oharboe committed
349
			/* attempt auto probe */
350
351
			if ((retval = p->driver->auto_probe(p)) != ERROR_OK)
				return retval;
ntfreak's avatar
ntfreak committed
352

duane's avatar
duane committed
353
354
355
356
357
358
359
360
			command_print(cmd_ctx, 
				      "#%" PRIi32 " : %s at 0x%8.8" PRIx32 ", size 0x%8.8" PRIx32 ", buswidth %i, chipwidth %i",
				      i,
				      p->driver->name, 
				      p->base, 
				      p->size, 
				      p->bus_width, 
				      p->chip_width);
oharboe's avatar
oharboe committed
361
362
			for (j = 0; j < p->num_sectors; j++)
			{
oharboe's avatar
   
oharboe committed
363
				char *protect_state;
ntfreak's avatar
ntfreak committed
364

oharboe's avatar
oharboe committed
365
366
367
368
369
370
371
				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";

duane's avatar
duane committed
372
373
374
375
376
				command_print(cmd_ctx, 
					      "\t#%3i: 0x%8.8" PRIx32 " (0x%" PRIx32 " %" PRIi32 "kB) %s",
					      j,
					      p->sectors[j].offset, 
					      p->sectors[j].size, 
zwelch's avatar
zwelch committed
377
					      p->sectors[j].size >> 10,
duane's avatar
duane committed
378
					      protect_state);
oharboe's avatar
oharboe committed
379
			}
ntfreak's avatar
ntfreak committed
380

381
382
			*buf = '\0'; /* initialize buffer, otherwise it migh contain garbage if driver function fails */
			retval = p->driver->info(p, buf, sizeof(buf));
oharboe's avatar
oharboe committed
383
			command_print(cmd_ctx, "%s", buf);
384
			if (retval != ERROR_OK)
385
				LOG_ERROR("error retrieving flash info (%d)", retval);
oharboe's avatar
oharboe committed
386
387
		}
	}
ntfreak's avatar
ntfreak committed
388

oharboe's avatar
oharboe committed
389
390
391
	return ERROR_OK;
}

mifi's avatar
mifi committed
392
static int handle_flash_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
oharboe's avatar
oharboe committed
393
394
395
{
	flash_bank_t *p;
	int retval;
ntfreak's avatar
ntfreak committed
396

oharboe's avatar
oharboe committed
397
398
399
400
	if (argc != 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
ntfreak's avatar
ntfreak committed
401

oharboe's avatar
oharboe committed
402
403
404
405
406
	p = get_flash_bank_by_num_noprobe(strtoul(args[0], NULL, 0));
	if (p)
	{
		if ((retval = p->driver->probe(p)) == ERROR_OK)
		{
duane's avatar
duane committed
407
			command_print(cmd_ctx, "flash '%s' found at 0x%8.8" PRIx32, p->driver->name, p->base);
oharboe's avatar
oharboe committed
408
409
410
		}
		else if (retval == ERROR_FLASH_BANK_INVALID)
		{
duane's avatar
duane committed
411
			command_print(cmd_ctx, "probing failed for flash bank '#%s' at 0x%8.8" PRIx32,
oharboe's avatar
oharboe committed
412
413
414
415
						  args[0], p->base);
		}
		else
		{
duane's avatar
duane committed
416
			command_print(cmd_ctx, "unknown error when probing flash bank '#%s' at 0x%8.8" PRIx32,
oharboe's avatar
oharboe committed
417
418
419
420
421
422
423
						  args[0], p->base);
		}
	}
	else
	{
		command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
	}
ntfreak's avatar
ntfreak committed
424

oharboe's avatar
oharboe committed
425
426
427
	return ERROR_OK;
}

mifi's avatar
mifi committed
428
static int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
oharboe's avatar
oharboe committed
429
430
431
{
	flash_bank_t *p;
	int retval;
ntfreak's avatar
ntfreak committed
432

oharboe's avatar
oharboe committed
433
434
435
436
	if (argc != 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
ntfreak's avatar
ntfreak committed
437

oharboe's avatar
oharboe committed
438
439
440
	p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
	if (p)
	{
oharboe's avatar
   
oharboe committed
441
		int j;
oharboe's avatar
oharboe committed
442
443
		if ((retval = p->driver->erase_check(p)) == ERROR_OK)
		{
444
			command_print(cmd_ctx, "successfully checked erase state");
oharboe's avatar
oharboe committed
445
446
447
		}
		else
		{
duane's avatar
duane committed
448
			command_print(cmd_ctx, "unknown error when checking erase state of flash bank #%s at 0x%8.8" PRIx32,
oharboe's avatar
oharboe committed
449
450
				args[0], p->base);
		}
oharboe's avatar
oharboe committed
451

oharboe's avatar
   
oharboe committed
452
453
454
455
456
457
458
459
460
461
462
		for (j = 0; j < p->num_sectors; j++)
		{
			char *erase_state;

			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";

duane's avatar
duane committed
463
464
465
466
467
			command_print(cmd_ctx,
				      "\t#%3i: 0x%8.8" PRIx32 " (0x%" PRIx32 " %" PRIi32 "kB) %s",
				      j, 
				      p->sectors[j].offset, 
				      p->sectors[j].size, 
zwelch's avatar
zwelch committed
468
				      p->sectors[j].size >> 10,
duane's avatar
duane committed
469
				      erase_state);
oharboe's avatar
   
oharboe committed
470
		}
oharboe's avatar
oharboe committed
471
	}
ntfreak's avatar
ntfreak committed
472

oharboe's avatar
oharboe committed
473
474
475
	return ERROR_OK;
}

mifi's avatar
mifi committed
476
static int handle_flash_erase_address_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
oharboe's avatar
oharboe committed
477
478
479
480
481
482
483
{
	flash_bank_t *p;
	int retval;
	int address;
	int length;
	duration_t duration;
	char *duration_text;
ntfreak's avatar
ntfreak committed
484

oharboe's avatar
oharboe committed
485
486
487
488
489
490
	target_t *target = get_current_target(cmd_ctx);

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

oharboe's avatar
oharboe committed
492
493
494
495
496
497
498
499
500
501
502
	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)
	{
oharboe's avatar
oharboe committed
503
		return ERROR_FAIL;
oharboe's avatar
oharboe committed
504
	}
ntfreak's avatar
ntfreak committed
505

oharboe's avatar
oharboe committed
506
507
	/* 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
508

oharboe's avatar
oharboe committed
509
	duration_start_measure(&duration);
ntfreak's avatar
ntfreak committed
510

oharboe's avatar
oharboe committed
511
512
	if ((retval = flash_erase_address_range(target, address, length)) == ERROR_OK)
	{
513
514
515
516
		if ((retval = duration_stop_measure(&duration, &duration_text)) != ERROR_OK)
		{
			return retval;
		}
oharboe's avatar
oharboe committed
517
518
519
		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
520

oharboe's avatar
oharboe committed
521
522
523
	return retval;
}

mifi's avatar
mifi committed
524
static int handle_flash_protect_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
oharboe's avatar
oharboe committed
525
526
527
{
	flash_bank_t *p;
	int retval;
ntfreak's avatar
ntfreak committed
528

oharboe's avatar
oharboe committed
529
530
531
532
	if (argc != 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
ntfreak's avatar
ntfreak committed
533

oharboe's avatar
oharboe committed
534
535
536
537
538
539
540
541
542
	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)
		{
duane's avatar
duane committed
543
			command_print(cmd_ctx, "checking protection state failed (possibly unsupported) by flash #%s at 0x%8.8" PRIx32, args[0], p->base);
oharboe's avatar
oharboe committed
544
545
546
		}
		else
		{
duane's avatar
duane committed
547
			command_print(cmd_ctx, "unknown error when checking protection state of flash bank '#%s' at 0x%8.8" PRIx32, args[0], p->base);
oharboe's avatar
oharboe committed
548
549
550
551
552
553
		}
	}
	else
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
ntfreak's avatar
ntfreak committed
554

oharboe's avatar
oharboe committed
555
556
557
	return ERROR_OK;
}

mifi's avatar
mifi committed
558
static int handle_flash_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
oharboe's avatar
oharboe committed
559
560
561
562
563
564
565
566
567
{
	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
568

oharboe's avatar
oharboe committed
569
		duration_start_measure(&duration);
ntfreak's avatar
ntfreak committed
570

oharboe's avatar
oharboe committed
571
572
573
574
		if (!p)
		{
			return ERROR_COMMAND_SYNTAX_ERROR;
		}
ntfreak's avatar
ntfreak committed
575

oharboe's avatar
oharboe committed
576
577
		if ((retval = flash_driver_erase(p, first, last)) == ERROR_OK)
		{
578
579
580
581
			if ((retval = duration_stop_measure(&duration, &duration_text)) != ERROR_OK)
			{
				return retval;
			}
ntfreak's avatar
ntfreak committed
582

583
584
			command_print(cmd_ctx, "erased sectors %i through %i on flash bank %li in %s",
				first, last, strtoul(args[0], 0, 0), duration_text);
oharboe's avatar
oharboe committed
585
586
587
588
589
590
591
592
593
594
595
			free(duration_text);
		}
	}
	else
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}

	return ERROR_OK;
}

mifi's avatar
mifi committed
596
static int handle_flash_protect_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
oharboe's avatar
oharboe committed
597
598
599
600
601
602
603
604
605
606
607
608
609
{
	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
610

oharboe's avatar
oharboe committed
611
612
613
614
615
616
617
618
		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
619

oharboe's avatar
oharboe committed
620
621
622
		retval = flash_driver_protect(p, set, first, last);
		if (retval == ERROR_OK)
		{
623
624
625
			command_print(cmd_ctx, "%s protection for sectors %i through %i on flash bank %li",
				(set) ? "set" : "cleared", first,
				last, strtoul(args[0], 0, 0));
oharboe's avatar
oharboe committed
626
627
628
629
630
631
632
633
634
635
636
		}
	}
	else
	{
		return ERROR_COMMAND_SYNTAX_ERROR;

	}

	return ERROR_OK;
}

mifi's avatar
mifi committed
637
static int handle_flash_write_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
oharboe's avatar
oharboe committed
638
639
{
	target_t *target = get_current_target(cmd_ctx);
ntfreak's avatar
ntfreak committed
640

oharboe's avatar
oharboe committed
641
	image_t image;
642
	uint32_t written;
ntfreak's avatar
ntfreak committed
643

oharboe's avatar
oharboe committed
644
645
	duration_t duration;
	char *duration_text;
ntfreak's avatar
ntfreak committed
646

647
	int retval, retvaltemp;
oharboe's avatar
oharboe committed
648
649
650
651
652

	if (argc < 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
oharboe's avatar
oharboe committed
653

654
655
	/* flash auto-erase is disabled by default*/
	int auto_erase = 0;
oharboe's avatar
oharboe committed
656

zwelch's avatar
zwelch committed
657
	if (strcmp(args[0], "erase") == 0)
658
659
660
661
662
663
	{
		auto_erase = 1;
		args++;
		argc--;
		command_print(cmd_ctx, "auto erase enabled");
	}
oharboe's avatar
oharboe committed
664

665
666
667
668
	if (argc < 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
oharboe's avatar
oharboe committed
669

oharboe's avatar
oharboe committed
670
671
	if (!target)
	{
672
		LOG_ERROR("no target selected");
673
		return ERROR_FAIL;
oharboe's avatar
oharboe committed
674
	}
ntfreak's avatar
ntfreak committed
675

oharboe's avatar
oharboe committed
676
	duration_start_measure(&duration);
ntfreak's avatar
ntfreak committed
677

oharboe's avatar
oharboe committed
678
679
680
681
682
683
684
685
686
687
	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
688

oharboe's avatar
oharboe committed
689
690
691
692
693
694
695
	image.start_address_set = 0;

	retval = image_open(&image, args[0], (argc == 3) ? args[2] : NULL);
	if (retval != ERROR_OK)
	{
		return retval;
	}
ntfreak's avatar
ntfreak committed
696

oharboe's avatar
oharboe committed
697
698
699
700
701
702
	retval = flash_write(target, &image, &written, auto_erase);
	if (retval != ERROR_OK)
	{
		image_close(&image);
		return retval;
	}
ntfreak's avatar
ntfreak committed
703

704
705
706
707
708
	if ((retvaltemp = duration_stop_measure(&duration, &duration_text)) != ERROR_OK)
	{
		image_close(&image);
		return retvaltemp;
	}
oharboe's avatar
oharboe committed
709
710
	if (retval == ERROR_OK)
	{
duane's avatar
duane committed
711
712
713
714
715
716
		command_print(cmd_ctx, 
					  "wrote %" PRIu32 " 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)));
oharboe's avatar
oharboe committed
717
718
719
720
	}
	free(duration_text);

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

oharboe's avatar
oharboe committed
722
723
724
	return retval;
}

mifi's avatar
mifi committed
725
static int handle_flash_fill_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
oharboe's avatar
   
oharboe committed
726
{
727
	int err = ERROR_OK, retval;
728
729
730
	uint32_t address;
	uint32_t pattern;
	uint32_t count;
731
732
	uint8_t chunk[1024];
	uint8_t readback[1024];
733
734
735
	uint32_t wrote = 0;
	uint32_t cur_size = 0;
	uint32_t chunk_count;
oharboe's avatar
   
oharboe committed
736
737
738
	char *duration_text;
	duration_t duration;
	target_t *target = get_current_target(cmd_ctx);
739
740
	uint32_t i;
	uint32_t wordsize;
oharboe's avatar
oharboe committed
741

oharboe's avatar
   
oharboe committed
742
743
744
745
	if (argc != 3)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
oharboe's avatar
oharboe committed
746

oharboe's avatar
   
oharboe committed
747
748
749
	address	= strtoul(args[0], NULL, 0);
	pattern	= strtoul(args[1], NULL, 0);
	count 	= strtoul(args[2], NULL, 0);
oharboe's avatar
oharboe committed
750

zwelch's avatar
zwelch committed
751
	if (count == 0)
oharboe's avatar
   
oharboe committed
752
753
		return ERROR_OK;

zwelch's avatar
zwelch committed
754
	switch (cmd[4])
oharboe's avatar
   
oharboe committed
755
756
	{
	case 'w':
zwelch's avatar
zwelch committed
757
		wordsize = 4;
oharboe's avatar
   
oharboe committed
758
759
		break;
	case 'h':
zwelch's avatar
zwelch committed
760
		wordsize = 2;
oharboe's avatar
   
oharboe committed
761
762
		break;
	case 'b':
zwelch's avatar
zwelch committed
763
		wordsize = 1;
oharboe's avatar
   
oharboe committed
764
765
766
767
		break;
	default:
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
oharboe's avatar
oharboe committed
768

oharboe's avatar
   
oharboe committed
769
	chunk_count = MIN(count, (1024 / wordsize));
zwelch's avatar
zwelch committed
770
	switch (wordsize)
oharboe's avatar
   
oharboe committed
771
772
	{
	case 4:
zwelch's avatar
zwelch committed
773
		for (i = 0; i < chunk_count; i++)
oharboe's avatar
   
oharboe committed
774
775
776
777
778
		{
			target_buffer_set_u32(target, chunk + i * wordsize, pattern);
		}
		break;
	case 2:
zwelch's avatar
zwelch committed
779
		for (i = 0; i < chunk_count; i++)
oharboe's avatar
   
oharboe committed
780
781
782
783
784
785
786
787
788
789
790
		{
			target_buffer_set_u16(target, chunk + i * wordsize, pattern);
		}
		break;
	case 1:
		memset(chunk, pattern, chunk_count);
		break;
	default:
		LOG_ERROR("BUG: can't happen");
		exit(-1);
	}
oharboe's avatar
oharboe committed
791

oharboe's avatar
   
oharboe committed
792
793
	duration_start_measure(&duration);

zwelch's avatar
zwelch committed
794
	for (wrote = 0; wrote<(count*wordsize); wrote += cur_size)
oharboe's avatar
   
oharboe committed
795
	{
796
		cur_size = MIN( (count*wordsize - wrote), sizeof(chunk) );
oharboe's avatar
oharboe committed
797
798
		flash_bank_t *bank;
		bank = get_flash_bank_by_addr(target, address);
zwelch's avatar
zwelch committed
799
		if (bank == NULL)
oharboe's avatar
oharboe committed
800
		{
oharboe's avatar
oharboe committed
801
			return ERROR_FAIL;
oharboe's avatar
   
oharboe committed
802
		}
oharboe's avatar
oharboe committed
803
		err = flash_driver_write(bank, chunk, address - bank->base + wrote, cur_size);
zwelch's avatar
zwelch committed
804
		if (err != ERROR_OK)
oharboe's avatar
oharboe committed
805
			return err;
oharboe's avatar
oharboe committed
806
807

		err = target_read_buffer(target, address + wrote, cur_size, readback);
zwelch's avatar
zwelch committed
808
		if (err != ERROR_OK)
oharboe's avatar
oharboe committed
809
810
			return err;

zwelch's avatar
zwelch committed
811
		unsigned i;
zwelch's avatar
zwelch committed
812
		for (i = 0; i<cur_size; i++)
oharboe's avatar
oharboe committed
813
814
815
		{
			if (readback[i]!=chunk[i])
			{
duane's avatar
duane committed
816
817
				LOG_ERROR("Verfication error address 0x%08" PRIx32 ", read back 0x%02x, expected 0x%02x", 
						  address + wrote + i, readback[i], chunk[i]);
oharboe's avatar
oharboe committed
818
819
820
821
				return ERROR_FAIL;
			}
		}

oharboe's avatar
   
oharboe committed
822
	}
oharboe's avatar
oharboe committed
823

824
825
826
827
828
	if ((retval = duration_stop_measure(&duration, &duration_text)) != ERROR_OK)
	{
		return retval;
	}

zwelch's avatar
zwelch committed
829
	if (err == ERROR_OK)
oharboe's avatar
   
oharboe committed
830
831
	{
		float speed;
zwelch's avatar
zwelch committed
832
		speed = wrote / 1024.0;
oharboe's avatar
   
oharboe committed
833
		speed/=((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0));
duane's avatar
duane committed
834
835
836
837
838
839
		command_print(cmd_ctx, 
					  "wrote %" PRId32 " bytes to 0x%8.8" PRIx32 " in %s (%f kb/s)",
					  count*wordsize, 
					  address, 
					  duration_text,
					  speed);
oharboe's avatar
   
oharboe committed
840
841
842
843
844
	}
	free(duration_text);
	return ERROR_OK;
}

mifi's avatar
mifi committed
845
static int handle_flash_write_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
oharboe's avatar
oharboe committed
846
{
847
	uint32_t offset;
848
	uint8_t *buffer;
849
	uint32_t buf_cnt;
oharboe's avatar
oharboe committed
850
851

	fileio_t fileio;
ntfreak's avatar
ntfreak committed
852

oharboe's avatar
oharboe committed
853
854
	duration_t duration;
	char *duration_text;
ntfreak's avatar
ntfreak committed
855

856
	int retval, retvaltemp;
oharboe's avatar
oharboe committed
857
858
859
860
861
862
	flash_bank_t *p;

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

oharboe's avatar
oharboe committed
864
	duration_start_measure(&duration);
ntfreak's avatar
ntfreak committed
865

oharboe's avatar
oharboe committed
866
867
868
869
870
871
872
	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
873

oharboe's avatar
oharboe committed
874
875
876
877
	if (fileio_open(&fileio, args[1], FILEIO_READ, FILEIO_BINARY) != ERROR_OK)
	{
		return ERROR_OK;
	}
ntfreak's avatar
ntfreak committed
878

oharboe's avatar
oharboe committed
879
880
881
	buffer = malloc(fileio.size);
	if (fileio_read(&fileio, fileio.size, buffer, &buf_cnt) != ERROR_OK)
	{
882
883
		free(buffer);
		fileio_close(&fileio);
oharboe's avatar
oharboe committed
884
885
		return ERROR_OK;
	}
ntfreak's avatar
ntfreak committed
886

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

oharboe's avatar
oharboe committed
889
	free(buffer);
890
	buffer = NULL;
ntfreak's avatar
ntfreak committed
891

892
893
894
895
896
	if ((retvaltemp = duration_stop_measure(&duration, &duration_text)) != ERROR_OK)
	{
		fileio_close(&fileio);
		return retvaltemp;
	}
zwelch's avatar
zwelch committed
897
	if (retval == ERROR_OK)
oharboe's avatar
oharboe committed
898
	{
duane's avatar
duane committed
899
900
901
902
903
904
905
906
	command_print(cmd_ctx, 
				  "wrote  %lld byte from file %s to flash bank %li at offset 0x%8.8" PRIx32 " 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)));
oharboe's avatar
oharboe committed
907
908
909
910
	}
	free(duration_text);

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

oharboe's avatar
oharboe committed
912
913
914
915
916
917
918
	return retval;
}

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

oharboe's avatar
oharboe committed
920
921
922
923
924
	/* 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
925
			c->sectors[i].is_erased = 0;
oharboe's avatar
oharboe committed
926
927
928
929
930
		}
	}
}

/* lookup flash bank by address */
931
flash_bank_t *get_flash_bank_by_addr(target_t *target, uint32_t addr)
oharboe's avatar
oharboe committed
932
933
934
935
936
937
938
939
{
	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
940

oharboe's avatar
oharboe committed
941
942
		if (retval != ERROR_OK)
		{
943
			LOG_ERROR("auto_probe failed %d\n", retval);
oharboe's avatar
oharboe committed
944
945
946
			return NULL;
		}
		/* check whether address belongs to this flash bank */
947
		if ((addr >= c->base) && (addr <= c->base + (c->size - 1)) && target == c->target)
oharboe's avatar
oharboe committed
948
949
			return c;
	}
duane's avatar
duane committed
950
	LOG_ERROR("No flash at address 0x%08" PRIx32 "\n", addr);
oharboe's avatar
oharboe committed
951
952
953
954
	return NULL;
}

/* erase given flash region, selects proper bank according to target and address */
955
int flash_erase_address_range(target_t *target, uint32_t addr, uint32_t length)
oharboe's avatar
oharboe committed
956
957
958
959
960
{
	flash_bank_t *c;
	int first = -1;
	int last = -1;
	int i;
ntfreak's avatar
ntfreak committed
961

oharboe's avatar
oharboe committed
962
963
964
965
	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)
966
967
	{
		LOG_ERROR("Bank is invalid");
oharboe's avatar
oharboe committed
968
		return ERROR_FLASH_BANK_INVALID;
969
	}
ntfreak's avatar
ntfreak committed
970

oharboe's avatar
oharboe committed
971
972
973
974
975
	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
976

oharboe's avatar
oharboe committed
977
978
979
980
		return flash_driver_erase(c, 0, c->num_sectors - 1);
	}

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

oharboe's avatar
oharboe committed
984
	addr -= c->base;
ntfreak's avatar
ntfreak committed
985

oharboe's avatar
oharboe committed
986
	for (i = 0; i < c->num_sectors; i++)
ntfreak's avatar
ntfreak committed
987
	{
oharboe's avatar
oharboe committed
988
989
990
991
992
993
994
995
		/* 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
996

zwelch's avatar
zwelch committed
997
	if ( first == -1 || last == -1