flash.c 29.6 KB
Newer Older
oharboe's avatar
oharboe committed
1
2
3
4
/***************************************************************************
 *   Copyright (C) 2005 by Dominic Rath                                    *
 *   Dominic.Rath@gmx.de                                                   *
 *                                                                         *
5
6
7
 *   Copyright (C) 2007,2008 yvind Harboe                                      *
 *   oyvind.harboe@zylin.com                                               *
 *                                                                         *
oharboe's avatar
oharboe committed
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
 *   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"
oharboe's avatar
   
oharboe committed
34
35
36
37
#include "armv4_5.h"
#include "algorithm.h"
#include "binarybuffer.h"
#include "armv7m.h"
oharboe's avatar
oharboe committed
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

#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_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);
oharboe's avatar
   
oharboe committed
58
int handle_flash_fill_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
oharboe's avatar
oharboe committed
59
60
61
62
63
64
65
66
67
68
69
70
71
72
int handle_flash_protect_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
73
extern flash_driver_t ecosflash_flash;
74
extern flash_driver_t lpc288x_flash;
oharboe's avatar
oharboe committed
75
extern flash_driver_t ocl_flash;
oharboe's avatar
oharboe committed
76
77
78
79
80
81
82
83
84
85
86
87

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
88
	&ecosflash_flash,
89
	&lpc288x_flash,
oharboe's avatar
oharboe committed
90
	&ocl_flash,
oharboe's avatar
oharboe committed
91
92
93
94
95
	NULL,
};

flash_bank_t *flash_banks;
static 	command_t *flash_cmd;
96

oharboe's avatar
oharboe committed
97
98
99
/* wafer thin wrapper for invoking the flash driver */
static int flash_driver_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
{
100
101
102
	int retval;

	retval=bank->driver->write(bank, buffer, offset, count);
oharboe's avatar
oharboe committed
103
104
	if (retval!=ERROR_OK)
	{
105
		LOG_ERROR("error writing to flash at address 0x%08x at offset 0x%8.8x (%d)", bank->base, offset, retval);
oharboe's avatar
oharboe committed
106
	}
107

oharboe's avatar
oharboe committed
108
109
110
111
112
	return retval;
}

static int flash_driver_erase(struct flash_bank_s *bank, int first, int last)
{
113
114
115
	int retval;

	retval=bank->driver->erase(bank, first, last);
oharboe's avatar
oharboe committed
116
117
	if (retval!=ERROR_OK)
	{
118
		LOG_ERROR("failed erasing sectors %d to %d (%d)", first, last, retval);
oharboe's avatar
oharboe committed
119
	}
120

oharboe's avatar
oharboe committed
121
122
123
124
125
126
	return retval;
}

int flash_driver_protect(struct flash_bank_s *bank, int set, int first, int last)
{
	int retval;
127
128

	retval=bank->driver->protect(bank, set, first, last);
oharboe's avatar
oharboe committed
129
130
	if (retval!=ERROR_OK)
	{
131
		LOG_ERROR("failed setting protection for areas %d to %d (%d)", first, last, retval);
oharboe's avatar
oharboe committed
132
	}
133

oharboe's avatar
oharboe committed
134
135
136
137
138
139
	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
140

oharboe's avatar
oharboe committed
141
142
143
144
	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 ...]");
	return ERROR_OK;
}

145
static int jim_flash_banks(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
oharboe's avatar
oharboe committed
146
{
147
148
	flash_bank_t *p;
	
oharboe's avatar
oharboe committed
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
	if (argc != 1) {
		Jim_WrongNumArgs(interp, 1, argv, "no arguments to flash_banks command");
		return JIM_ERR;
	}

	if (!flash_banks)
	{
		return JIM_ERR;
	}

	Jim_Obj *list=Jim_NewListObj(interp, NULL, 0);
	for (p = flash_banks; p; p = p->next)
	{
		Jim_Obj *elem=Jim_NewListObj(interp, NULL, 0);
		
164
		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "name", -1));
oharboe's avatar
oharboe committed
165
		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, p->driver->name, -1));
166
		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "base", -1));
oharboe's avatar
oharboe committed
167
		Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->base));
168
		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "size", -1));
oharboe's avatar
oharboe committed
169
		Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->size));
170
		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "bus_width", -1));
oharboe's avatar
oharboe committed
171
		Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->bus_width));
172
		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "chip_width", -1));
oharboe's avatar
oharboe committed
173
174
		Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->chip_width));
		
175
		Jim_ListAppendElement(interp, list, elem);
oharboe's avatar
oharboe committed
176
177
178
179
180
181
182
	}

	Jim_SetResult(interp, list);

	return JIM_OK;
}

oharboe's avatar
oharboe committed
183
184
185
186
int flash_init_drivers(struct command_context_s *cmd_ctx)
{
	if (flash_banks)
	{
187
		register_jim(cmd_ctx, "ocd_flash_banks", jim_flash_banks, "return information about the flash banks");
oharboe's avatar
oharboe committed
188
		
oharboe's avatar
oharboe committed
189
190
191
192
193
194
195
196
197
198
199
200
		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
201
202
203
204
205
206
207
208

		register_command(cmd_ctx, flash_cmd, "fillw", handle_flash_fill_command, COMMAND_EXEC,
						 "fill with pattern <address> <word_pattern> <count>");
		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
209
210
211
		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,
212
						 "write_image [erase] <file> [offset] [type]");
oharboe's avatar
oharboe committed
213
214
215
		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
216

oharboe's avatar
oharboe committed
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
	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;
		}
	}
232
	LOG_ERROR("flash bank %d does not exist", num);
oharboe's avatar
oharboe committed
233
234
235
	return NULL;
}

oharboe's avatar
oharboe committed
236
237
238
239
240
241
242
243
244
245
246
int flash_get_bank_count()
{
	flash_bank_t *p;
	int i = 0;
	for (p = flash_banks; p; p = p->next)
	{
		i++;
	}
	return i;
}

oharboe's avatar
oharboe committed
247
248
249
250
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
251

oharboe's avatar
oharboe committed
252
253
	if (p == NULL)
		return NULL;
ntfreak's avatar
ntfreak committed
254

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

oharboe's avatar
oharboe committed
257
258
	if (retval != ERROR_OK)
	{
259
		LOG_ERROR("auto_probe failed %d\n", retval);
oharboe's avatar
oharboe committed
260
261
262
263
264
265
266
267
268
269
		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
270

oharboe's avatar
oharboe committed
271
272
273
274
	if (argc < 6)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
ntfreak's avatar
ntfreak committed
275

oharboe's avatar
oharboe committed
276
277
	if ((target = get_target_by_num(strtoul(args[5], NULL, 0))) == NULL)
	{
278
		LOG_ERROR("target %lu not defined", strtoul(args[5], NULL, 0));
oharboe's avatar
oharboe committed
279
280
		return ERROR_OK;
	}
ntfreak's avatar
ntfreak committed
281

oharboe's avatar
oharboe committed
282
283
284
285
286
	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
287

oharboe's avatar
oharboe committed
288
289
290
			/* register flash specific commands */
			if (flash_drivers[i]->register_commands(cmd_ctx) != ERROR_OK)
			{
291
				LOG_ERROR("couldn't register '%s' commands", args[0]);
oharboe's avatar
oharboe committed
292
293
				exit(-1);
			}
ntfreak's avatar
ntfreak committed
294

oharboe's avatar
oharboe committed
295
296
297
298
299
300
301
302
303
304
305
			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
306

oharboe's avatar
oharboe committed
307
308
			if (flash_drivers[i]->flash_bank_command(cmd_ctx, cmd, args, argc, c) != ERROR_OK)
			{
309
				LOG_ERROR("'%s' driver rejected flash bank at 0x%8.8x", args[0], c->base);
oharboe's avatar
oharboe committed
310
311
312
				free(c);
				return ERROR_OK;
			}
ntfreak's avatar
ntfreak committed
313

oharboe's avatar
oharboe committed
314
315
316
317
318
319
320
321
322
323
324
325
			/* 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
326

oharboe's avatar
oharboe committed
327
328
329
			found = 1;
		}
	}
ntfreak's avatar
ntfreak committed
330

oharboe's avatar
oharboe committed
331
332
333
	/* no matching flash driver found */
	if (!found)
	{
334
		LOG_ERROR("flash driver '%s' not found", args[0]);
oharboe's avatar
oharboe committed
335
336
		exit(-1);
	}
ntfreak's avatar
ntfreak committed
337

oharboe's avatar
oharboe committed
338
339
340
341
342
343
344
345
	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;
346
	int retval;
ntfreak's avatar
ntfreak committed
347

oharboe's avatar
oharboe committed
348
349
350
351
	if (argc != 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
ntfreak's avatar
ntfreak committed
352

oharboe's avatar
oharboe committed
353
354
355
356
357
	for (p = flash_banks; p; p = p->next, i++)
	{
		if (i == strtoul(args[0], NULL, 0))
		{
			char buf[1024];
ntfreak's avatar
ntfreak committed
358

oharboe's avatar
oharboe committed
359
			/* attempt auto probe */
360
361
			if ((retval = p->driver->auto_probe(p)) != ERROR_OK)
				return retval;
ntfreak's avatar
ntfreak committed
362

oharboe's avatar
oharboe committed
363
364
365
366
			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++)
			{
oharboe's avatar
   
oharboe committed
367
				char *protect_state;
ntfreak's avatar
ntfreak committed
368

oharboe's avatar
oharboe committed
369
370
371
372
373
374
375
				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";

oharboe's avatar
   
oharboe committed
376
				command_print(cmd_ctx, "\t#%i: 0x%8.8x (0x%x %ikB) %s",
oharboe's avatar
oharboe committed
377
							j, p->sectors[j].offset, p->sectors[j].size, p->sectors[j].size>>10,
oharboe's avatar
   
oharboe 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
392
393
394
395
	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
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
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
	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
424

oharboe's avatar
oharboe committed
425
426
427
428
429
430
431
	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
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
444
445
446
447
448
449
450
		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);
		}
oharboe's avatar
   
oharboe committed
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
		
		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";

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

oharboe's avatar
oharboe committed
470
471
472
473
474
475
476
477
478
479
480
	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
481

oharboe's avatar
oharboe committed
482
483
484
485
486
487
	target_t *target = get_current_target(cmd_ctx);

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

oharboe's avatar
oharboe committed
489
490
491
492
493
494
495
496
497
498
499
	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
500
		return ERROR_FAIL;
oharboe's avatar
oharboe committed
501
	}
ntfreak's avatar
ntfreak committed
502

oharboe's avatar
oharboe committed
503
504
	/* 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
505

oharboe's avatar
oharboe committed
506
	duration_start_measure(&duration);
ntfreak's avatar
ntfreak committed
507

oharboe's avatar
oharboe committed
508
509
	if ((retval = flash_erase_address_range(target, address, length)) == ERROR_OK)
	{
ntfreak's avatar
ntfreak committed
510
		duration_stop_measure(&duration, &duration_text);
oharboe's avatar
oharboe committed
511
512
513
		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
514

oharboe's avatar
oharboe committed
515
516
517
518
519
520
521
	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
522

oharboe's avatar
oharboe committed
523
524
525
526
	if (argc != 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
ntfreak's avatar
ntfreak committed
527

oharboe's avatar
oharboe committed
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
	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
548

oharboe's avatar
oharboe committed
549
550
551
552
553
554
555
556
557
558
559
560
561
	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
562

oharboe's avatar
oharboe committed
563
		duration_start_measure(&duration);
ntfreak's avatar
ntfreak committed
564

oharboe's avatar
oharboe committed
565
566
567
568
		if (!p)
		{
			return ERROR_COMMAND_SYNTAX_ERROR;
		}
ntfreak's avatar
ntfreak committed
569

oharboe's avatar
oharboe committed
570
571
		if ((retval = flash_driver_erase(p, first, last)) == ERROR_OK)
		{
ntfreak's avatar
ntfreak committed
572
573
			duration_stop_measure(&duration, &duration_text);

oharboe's avatar
oharboe committed
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
			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
600

oharboe's avatar
oharboe committed
601
602
603
604
605
606
607
608
		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
609

oharboe's avatar
oharboe committed
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
		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
628

oharboe's avatar
oharboe committed
629
630
	image_t image;
	u32 written;
ntfreak's avatar
ntfreak committed
631

oharboe's avatar
oharboe committed
632
633
	duration_t duration;
	char *duration_text;
ntfreak's avatar
ntfreak committed
634

oharboe's avatar
oharboe committed
635
636
637
638
639
640
	int retval;

	if (argc < 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
641
642
643
644
	
	/* flash auto-erase is disabled by default*/
	int auto_erase = 0;
	
ntfreak's avatar
ntfreak committed
645
	if (strcmp(args[0], "erase")==0)
646
647
648
649
650
651
652
	{
		auto_erase = 1;
		args++;
		argc--;
		command_print(cmd_ctx, "auto erase enabled");
	}
	
ntfreak's avatar
ntfreak committed
653

654
655
656
657
658
	if (argc < 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
	
oharboe's avatar
oharboe committed
659
660
	if (!target)
	{
661
		LOG_ERROR("no target selected");
662
		return ERROR_FAIL;
oharboe's avatar
oharboe committed
663
	}
ntfreak's avatar
ntfreak committed
664

oharboe's avatar
oharboe committed
665
	duration_start_measure(&duration);
ntfreak's avatar
ntfreak committed
666

oharboe's avatar
oharboe committed
667
668
669
670
671
672
673
674
675
676
	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
677

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

oharboe's avatar
oharboe committed
686
687
688
689
690
691
	retval = flash_write(target, &image, &written, auto_erase);
	if (retval != ERROR_OK)
	{
		image_close(&image);
		return retval;
	}
ntfreak's avatar
ntfreak committed
692

oharboe's avatar
oharboe committed
693
694
695
	duration_stop_measure(&duration, &duration_text);
	if (retval == ERROR_OK)
	{
696
697
698
		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)));
oharboe's avatar
oharboe committed
699
700
701
702
	}
	free(duration_text);

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

oharboe's avatar
oharboe committed
704
705
706
	return retval;
}

oharboe's avatar
   
oharboe committed
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
int handle_flash_fill_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
	int err = ERROR_OK;
	u32 address;
	u32 pattern;
	u32 count;
	u8 chunk[1024];
	u32 wrote = 0;
	int chunk_count;
	char *duration_text;
	duration_t duration;
	target_t *target = get_current_target(cmd_ctx);
	u32 i;
	int wordsize;
	
	if (argc != 3)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
	
	address	= strtoul(args[0], NULL, 0);
	pattern	= strtoul(args[1], NULL, 0);
	count 	= strtoul(args[2], NULL, 0);
	
	if(count == 0)
		return ERROR_OK;


	switch(cmd[4])
	{
	case 'w':
		wordsize=4;
		break;
	case 'h':
		wordsize=2;
		break;
	case 'b':
		wordsize=1;
		break;
	default:
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
	
	chunk_count = MIN(count, (1024 / wordsize));
	switch(wordsize)
	{
	case 4:
		for(i = 0; i < chunk_count; i++)
		{
			target_buffer_set_u32(target, chunk + i * wordsize, pattern);
		}
		break;
	case 2:
		for(i = 0; i < chunk_count; i++)
		{
			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);
	}
	
	duration_start_measure(&duration);

	flash_set_dirty();
	err = flash_erase_address_range( target, address, count*wordsize );
	if (err == ERROR_OK)
	{
		for (wrote=0; wrote<(count*wordsize); wrote+=sizeof(chunk))
		{ 
			int cur_size = MIN( (count*wordsize - wrote) , 1024 );
			if (err == ERROR_OK)
			{
				flash_bank_t *bank;
				bank = get_flash_bank_by_addr(target, address);
				if(bank == NULL)
				{
					err = ERROR_FAIL;
					break;
				}
				err = flash_driver_write(bank, chunk, address - bank->base + wrote, cur_size);
				wrote += cur_size;
			}
			if (err!=ERROR_OK)
				break;
		}
	}
	
	duration_stop_measure(&duration, &duration_text);

	if(err == ERROR_OK)
	{
		float speed;
		speed=wrote / 1024.0;
		speed/=((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0));
		command_print(cmd_ctx, "wrote %d bytes to 0x%8.8x in %s (%f kb/s)",
			count*wordsize, address, duration_text,
			speed);
	}
	free(duration_text);
	return ERROR_OK;
}

oharboe's avatar
oharboe committed
814
815
816
817
818
819
820
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
821

oharboe's avatar
oharboe committed
822
823
	duration_t duration;
	char *duration_text;
ntfreak's avatar
ntfreak committed
824

oharboe's avatar
oharboe committed
825
826
827
828
829
830
831
	int retval;
	flash_bank_t *p;

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

oharboe's avatar
oharboe committed
833
	duration_start_measure(&duration);
ntfreak's avatar
ntfreak committed
834

oharboe's avatar
oharboe committed
835
836
837
838
839
840
841
	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
842

oharboe's avatar
oharboe committed
843
844
845
846
	if (fileio_open(&fileio, args[1], FILEIO_READ, FILEIO_BINARY) != ERROR_OK)
	{
		return ERROR_OK;
	}
ntfreak's avatar
ntfreak committed
847

oharboe's avatar
oharboe committed
848
849
850
	buffer = malloc(fileio.size);
	if (fileio_read(&fileio, fileio.size, buffer, &buf_cnt) != ERROR_OK)
	{
851
852
		free(buffer);
		fileio_close(&fileio);
oharboe's avatar
oharboe committed
853
854
		return ERROR_OK;
	}
ntfreak's avatar
ntfreak committed
855

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

oharboe's avatar
oharboe committed
858
	free(buffer);
859
	buffer = NULL;
ntfreak's avatar
ntfreak committed
860

oharboe's avatar
oharboe committed
861
862
863
864
865
866
867
868
869
870
	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
871

oharboe's avatar
oharboe committed
872
873
874
875
876
877
878
	return retval;
}

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

oharboe's avatar
oharboe committed
880
881
882
883
884
	/* 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
885
			c->sectors[i].is_erased = 0;
oharboe's avatar
oharboe committed
886
887
888
889
890
891
892
893
894
895
896
897
898
899
		}
	}
}

/* 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
900

oharboe's avatar
oharboe committed
901
902
		if (retval != ERROR_OK)
		{
903
			LOG_ERROR("auto_probe failed %d\n", retval);
oharboe's avatar
oharboe committed
904
905
906
907
908
909
			return NULL;
		}
		/* check whether address belongs to this flash bank */
		if ((addr >= c->base) && (addr < c->base + c->size) && target == c->target)
			return c;
	}
910
	LOG_ERROR("No flash at address 0x%08x\n", addr);
oharboe's avatar
oharboe committed
911
912
913
914
915
916
917
918
919
920
	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
921

oharboe's avatar
oharboe committed
922
923
924
925
	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)
926
927
	{
		LOG_ERROR("Bank is invalid");
oharboe's avatar
oharboe committed
928
		return ERROR_FLASH_BANK_INVALID;
929
	}
ntfreak's avatar
ntfreak committed
930

oharboe's avatar
oharboe committed
931
932
933
934
935
	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
936

oharboe's avatar
oharboe committed
937
938
939
940
941
942
		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
943

oharboe's avatar
oharboe committed
944
	addr -= c->base;
ntfreak's avatar
ntfreak committed
945

oharboe's avatar
oharboe committed
946
	for (i = 0; i < c->num_sectors; i++)
ntfreak's avatar
ntfreak committed
947
	{
oharboe's avatar
oharboe committed
948
949
950
951
952
953
954
955
		/* 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
956

oharboe's avatar
oharboe committed
957
958
	if( first == -1 || last == -1 )
		return ERROR_OK;
ntfreak's avatar
ntfreak committed
959

oharboe's avatar
oharboe committed
960
961
962
963
964
965
	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)
{
966
	int retval=ERROR_OK;
oharboe's avatar
oharboe committed
967
968
969
970

	int section;
	u32 section_offset;
	flash_bank_t *c;
971
972
	int *padding;
	
oharboe's avatar
oharboe committed
973
974
975
976
977
	section = 0;
	section_offset = 0;

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

oharboe's avatar
oharboe committed
979
980
981
982
	if (erase)
	{
		/* assume all sectors need erasing - stops any problems
		 * when flash_write is called multiple times */
ntfreak's avatar
ntfreak committed
983

oharboe's avatar
oharboe committed
984
985
		flash_set_dirty();
	}
986
987
988
989
	
	/* allocate padding array */
	padding = malloc(image->num_sections * sizeof(padding));
	
oharboe's avatar
oharboe committed
990
991
992
993
994
995
996
997
998
	/* 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;
999
1000
		int pad_bytes = 0;
		
oharboe's avatar
oharboe committed
1001
1002
		if (image->sections[section].size ==  0)
		{
1003
			LOG_WARNING("empty section %d", section);
oharboe's avatar
oharboe committed
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
			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;
1020
		padding[section] = 0;
oharboe's avatar
oharboe committed
1021
1022
1023
1024
1025
		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))
			{
1026
				LOG_DEBUG("section %d out of order(very slightly surprising, but supported)", section_last + 1);
oharboe's avatar
oharboe committed
1027
1028
				break;
			}
1029
1030
1031
1032
			/* if we have multiple sections within our image, flash programming could fail due to alignment issues
			 * attempt to rebuild a consecutive buffer for the flash loader */
			pad_bytes = (image->sections[section_last + 1].base_address) - (run_address + run_size);
			if ((run_address + run_size + pad_bytes) > (c->base + c->size))
oharboe's avatar
oharboe committed
1033
				break;
1034
			padding[section_last] = pad_bytes;
oharboe's avatar
oharboe committed
1035
			run_size += image->sections[++section_last].size;
1036
1037
1038
1039
			run_size += pad_bytes;
			padding[section_last] = 0;
			
			LOG_INFO("Padding image section %d with %d bytes", section_last-1, pad_bytes );
oharboe's avatar
oharboe committed
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
		}

		/* 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
1054

oharboe's avatar
oharboe committed
1055
1056
1057
1058
			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
1059

oharboe's avatar
oharboe committed
1060
1061
1062
1063
			if ((retval = image_read_section(image, section, section_offset,
					size_read, buffer + buffer_size, &size_read)) != ERROR_OK || size_read == 0)
			{
				free(buffer);
1064
				free(padding);
oharboe's avatar
oharboe committed
1065
1066
				return retval;
			}
1067
1068
1069
1070
1071
			
			/* see if we need to pad the section */
			while (padding[section]--)
				buffer[size_read++] = 0xff;
			
oharboe's avatar
oharboe committed
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
			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
1083

oharboe's avatar
oharboe committed
1084
1085
1086
1087
1088
		if (erase)
		{
			/* calculate and erase sectors */
			retval = flash_erase_address_range( target, run_address, run_size );
		}
ntfreak's avatar
ntfreak committed
1089

oharboe's avatar
oharboe committed
1090
1091
1092
1093
1094
		if (retval == ERROR_OK)
		{
			/* write flash sectors */
			retval = flash_driver_write(c, buffer, run_address - c->base, run_size);
		}
ntfreak's avatar
ntfreak committed
1095

oharboe's avatar
oharboe committed
1096
1097
1098
1099
		free(buffer);

		if (retval != ERROR_OK)
		{
1100
			free(padding);
1101
1102
			return retval; /* abort operation */
		}
oharboe's avatar
oharboe committed
1103
1104
1105
1106

		if (written != NULL)
			*written += run_size; /* add run size to total written counter */
	}
1107
1108
1109
	
	free(padding);
	
1110
	return retval;
oharboe's avatar
oharboe committed
1111
1112
}

1113
int default_flash_mem_blank_check(struct flash_bank_s *bank)
1114
1115
1116
{
	target_t *target = bank->target;
	u8 buffer[1024];
1117
	int buffer_size = sizeof(buffer);
1118
1119
1120
1121
1122
1123
1124
1125
	int i;
	int nBytes;
	
	if (bank->target->state != TARGET_HALTED)
	{
		return ERROR_TARGET_NOT_HALTED;
	}
	
1126
	for (i = 0; i < bank->num_sectors; i++)
oharboe's avatar
   
oharboe committed
1127
	{
1128
1129
1130
1131
		int j;
		bank->sectors[i].is_erased = 1;
		
		for (j = 0; j < bank->sectors[i].size; j += buffer_size)
oharboe's avatar
   
oharboe committed
1132
		{
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
			int chunk;
			int retval;
			chunk = buffer_size;
			if (chunk > (j - bank->sectors[i].size))
			{
				chunk = (j - bank->sectors[i].size);
			}
			
			retval = target->type->read_memory(target, bank->base + bank->sectors[i].offset + j, 4, chunk/4, buffer);
			if (retval != ERROR_OK)
				return retval;
		
			for (nBytes = 0; nBytes < chunk; nBytes++)
			{
				if (buffer[nBytes] != 0xFF)
				{
					bank->sectors[i].is_erased = 0;
					break;
				}
			}
oharboe's avatar
   
oharboe committed
1153
1154
1155
		}
	}
	
1156
1157
	return ERROR_OK;
}
oharboe's avatar
   
oharboe committed
1158

1159
1160
1161
1162
1163
1164
1165
int default_flash_blank_check(struct flash_bank_s *bank)
{
	target_t *target = bank->target;
	int i;
	int retval;
	int fast_check = 0;
	int blank;
oharboe's avatar
   
oharboe committed
1166
	
1167
	if (bank->target->state != TARGET_HALTED)
oharboe's avatar
   
oharboe committed
1168
	{
1169
		return ERROR_TARGET_NOT_HALTED;
oharboe's avatar
   
oharboe committed
1170
	}
1171
		
1172
	for (i = 0; i < bank->num_sectors; i++)
oharboe's avatar
   
oharboe committed
1173
	{
1174
1175
1176
1177
		u32 address = bank->base + bank->sectors[i].offset;
		u32 size = bank->sectors[i].size;
		
		if ((retval = target_blank_check_memory(target, address, size, &blank)) != ERROR_OK)
oharboe's avatar
   
oharboe committed
1178
		{
1179
1180
			fast_check = 0;
			break;
oharboe's avatar
   
oharboe committed
1181
		}
1182
1183
1184
1185
1186
		if (blank == 0xFF)
			bank->sectors[i].is_erased = 1;
		else
			bank->sectors[i].is_erased = 0;
		fast_check = 1;
oharboe's avatar
   
oharboe committed
1187
	}
1188
		
oharboe's avatar
   
oharboe committed
1189
1190
1191
	if (!fast_check)
	{
		LOG_USER("Running slow fallback erase check - add working memory");
1192
		return default_flash_mem_blank_check(bank);
1193
1194
1195
1196
	}
	
	return ERROR_OK;
}