flash.c 31.5 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
static int flash_write_unlock(target_t *target, image_t *image, uint32_t *written, int erase, bool unlock);
oharboe's avatar
oharboe committed
35
36
37
38

/* flash drivers
 */
extern flash_driver_t lpc2000_flash;
39
40
extern flash_driver_t lpc288x_flash;
extern flash_driver_t lpc2900_flash;
oharboe's avatar
oharboe committed
41
extern flash_driver_t cfi_flash;
42
extern flash_driver_t at91sam3_flash;
oharboe's avatar
oharboe committed
43
44
45
extern flash_driver_t at91sam7_flash;
extern flash_driver_t str7x_flash;
extern flash_driver_t str9x_flash;
46
extern flash_driver_t aduc702x_flash;
oharboe's avatar
oharboe committed
47
48
49
50
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
51
extern flash_driver_t ecosflash_flash;
oharboe's avatar
oharboe committed
52
extern flash_driver_t ocl_flash;
53
extern flash_driver_t pic32mx_flash;
54
extern flash_driver_t avr_flash;
55
extern flash_driver_t faux_flash;
oharboe's avatar
oharboe committed
56

57
flash_driver_t *flash_drivers[] = {
58
	&lpc2000_flash,
59
60
	&lpc288x_flash,
	&lpc2900_flash,
61
62
	&cfi_flash,
	&at91sam7_flash,
63
	&at91sam3_flash,
64
65
66
67
68
69
70
71
72
	&str7x_flash,
	&str9x_flash,
	&aduc702x_flash,
	&stellaris_flash,
	&str9xpec_flash,
	&stm32x_flash,
	&tms470_flash,
	&ecosflash_flash,
	&ocl_flash,
73
	&pic32mx_flash,
74
	&avr_flash,
75
	&faux_flash,
76
	NULL,
oharboe's avatar
oharboe committed
77
78
79
80
};

flash_bank_t *flash_banks;
static 	command_t *flash_cmd;
81

oharboe's avatar
oharboe committed
82
/* wafer thin wrapper for invoking the flash driver */
83
static int flash_driver_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
oharboe's avatar
oharboe committed
84
{
85
86
	int retval;

zwelch's avatar
zwelch committed
87
	retval = bank->driver->write(bank, buffer, offset, count);
zwelch's avatar
zwelch committed
88
	if (retval != ERROR_OK)
oharboe's avatar
oharboe committed
89
	{
90
		LOG_ERROR("error writing to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32 " (%d)",
duane's avatar
duane committed
91
			  bank->base, offset, retval);
oharboe's avatar
oharboe committed
92
	}
93

oharboe's avatar
oharboe committed
94
95
96
97
98
	return retval;
}

static int flash_driver_erase(struct flash_bank_s *bank, int first, int last)
{
99
100
	int retval;

zwelch's avatar
zwelch committed
101
	retval = bank->driver->erase(bank, first, last);
zwelch's avatar
zwelch committed
102
	if (retval != ERROR_OK)
oharboe's avatar
oharboe committed
103
	{
104
		LOG_ERROR("failed erasing sectors %d to %d (%d)", first, last, retval);
oharboe's avatar
oharboe committed
105
	}
106

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

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

zwelch's avatar
zwelch committed
114
	retval = bank->driver->protect(bank, set, first, last);
zwelch's avatar
zwelch committed
115
	if (retval != ERROR_OK)
oharboe's avatar
oharboe committed
116
	{
117
		LOG_ERROR("failed setting protection for areas %d to %d (%d)", first, last, retval);
oharboe's avatar
oharboe committed
118
	}
119

oharboe's avatar
oharboe committed
120
121
122
	return retval;
}

123
static int jim_flash_banks(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
oharboe's avatar
oharboe committed
124
{
125
	flash_bank_t *p;
oharboe's avatar
oharboe committed
126

oharboe's avatar
oharboe committed
127
128
129
130
131
	if (argc != 1) {
		Jim_WrongNumArgs(interp, 1, argv, "no arguments to flash_banks command");
		return JIM_ERR;
	}

zwelch's avatar
zwelch committed
132
	Jim_Obj *list = Jim_NewListObj(interp, NULL, 0);
oharboe's avatar
oharboe committed
133
134
	for (p = flash_banks; p; p = p->next)
	{
zwelch's avatar
zwelch committed
135
		Jim_Obj *elem = Jim_NewListObj(interp, NULL, 0);
oharboe's avatar
oharboe committed
136

137
		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "name", -1));
oharboe's avatar
oharboe committed
138
		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, p->driver->name, -1));
139
		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "base", -1));
oharboe's avatar
oharboe committed
140
		Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->base));
141
		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "size", -1));
oharboe's avatar
oharboe committed
142
		Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->size));
143
		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "bus_width", -1));
oharboe's avatar
oharboe committed
144
		Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->bus_width));
145
		Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "chip_width", -1));
oharboe's avatar
oharboe committed
146
		Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->chip_width));
oharboe's avatar
oharboe committed
147

148
		Jim_ListAppendElement(interp, list, elem);
oharboe's avatar
oharboe committed
149
150
151
152
153
154
155
	}

	Jim_SetResult(interp, list);

	return JIM_OK;
}

oharboe's avatar
oharboe committed
156
157
158
159
160
161
162
163
164
165
166
167
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;
		}
	}
168
	LOG_ERROR("flash bank %d does not exist", num);
oharboe's avatar
oharboe committed
169
170
171
	return NULL;
}

oharboe's avatar
oharboe committed
172
int flash_get_bank_count(void)
oharboe's avatar
oharboe committed
173
174
175
176
177
178
179
180
181
182
{
	flash_bank_t *p;
	int i = 0;
	for (p = flash_banks; p; p = p->next)
	{
		i++;
	}
	return i;
}

oharboe's avatar
oharboe committed
183
184
185
186
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
187

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

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

oharboe's avatar
oharboe committed
193
194
	if (retval != ERROR_OK)
	{
195
		LOG_ERROR("auto_probe failed %d\n", retval);
oharboe's avatar
oharboe committed
196
197
198
199
200
		return NULL;
	}
	return p;
}

201
int flash_command_get_bank_by_num(
202
	struct command_context_s *cmd_ctx, const char *str, flash_bank_t **bank)
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
{
	unsigned bank_num;
	COMMAND_PARSE_NUMBER(uint, str, bank_num);

	*bank = get_flash_bank_by_num(bank_num);
	if (!*bank)
	{
		command_print(cmd_ctx,
			"flash bank '#%u' not found", bank_num);
		return ERROR_INVALID_ARGUMENTS;
	}
	return ERROR_OK;
}


mifi's avatar
mifi committed
218
static int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
oharboe's avatar
oharboe committed
219
{
oharboe's avatar
oharboe committed
220
	int retval;
oharboe's avatar
oharboe committed
221
222
223
	int i;
	int found = 0;
	target_t *target;
ntfreak's avatar
ntfreak committed
224

oharboe's avatar
oharboe committed
225
226
227
228
	if (argc < 6)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
ntfreak's avatar
ntfreak committed
229

230
	if ((target = get_target(args[5])) == NULL)
oharboe's avatar
oharboe committed
231
	{
232
		LOG_ERROR("target '%s' not defined", args[5]);
oharboe's avatar
oharboe committed
233
		return ERROR_FAIL;
oharboe's avatar
oharboe committed
234
	}
ntfreak's avatar
ntfreak committed
235

oharboe's avatar
oharboe committed
236
237
	for (i = 0; flash_drivers[i]; i++)
	{
Zachary T Welch's avatar
Zachary T Welch committed
238
239
240
241
242
243
244
		if (strcmp(args[0], flash_drivers[i]->name) != 0)
			continue;

		flash_bank_t *p, *c;

		/* register flash specific commands */
		if (flash_drivers[i]->register_commands(cmd_ctx) != ERROR_OK)
oharboe's avatar
oharboe committed
245
		{
Zachary T Welch's avatar
Zachary T Welch committed
246
247
248
			LOG_ERROR("couldn't register '%s' commands", args[0]);
			return ERROR_FAIL;
		}
ntfreak's avatar
ntfreak committed
249

Zachary T Welch's avatar
Zachary T Welch committed
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
		c = malloc(sizeof(flash_bank_t));
		c->target = target;
		c->driver = flash_drivers[i];
		c->driver_priv = NULL;
		COMMAND_PARSE_NUMBER(u32, args[1], c->base);
		COMMAND_PARSE_NUMBER(u32, args[2], c->size);
		COMMAND_PARSE_NUMBER(int, args[3], c->chip_width);
		COMMAND_PARSE_NUMBER(int, args[4], c->bus_width);
		c->num_sectors = 0;
		c->sectors = NULL;
		c->next = NULL;

		if ((retval = flash_drivers[i]->flash_bank_command(cmd_ctx, cmd, args, argc, c)) != ERROR_OK)
		{
			LOG_ERROR("'%s' driver rejected flash bank at 0x%8.8" PRIx32 , args[0], c->base);
			free(c);
			return retval;
		}

		/* put flash bank in linked list */
		if (flash_banks)
		{
			int	bank_num = 0;
			/* find last flash bank */
			for (p = flash_banks; p && p->next; p = p->next) bank_num++;
			if (p)
				p->next = c;
			c->bank_number = bank_num + 1;
oharboe's avatar
oharboe committed
278
		}
Zachary T Welch's avatar
Zachary T Welch committed
279
280
281
282
283
284
285
		else
		{
			flash_banks = c;
			c->bank_number = 0;
		}

		found = 1;
oharboe's avatar
oharboe committed
286
	}
ntfreak's avatar
ntfreak committed
287

oharboe's avatar
oharboe committed
288
289
290
	/* no matching flash driver found */
	if (!found)
	{
291
		LOG_ERROR("flash driver '%s' not found", args[0]);
oharboe's avatar
oharboe committed
292
		return ERROR_FAIL;
oharboe's avatar
oharboe committed
293
	}
ntfreak's avatar
ntfreak committed
294

oharboe's avatar
oharboe committed
295
296
297
	return ERROR_OK;
}

mifi's avatar
mifi committed
298
static int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
oharboe's avatar
oharboe committed
299
300
{
	flash_bank_t *p;
301
	uint32_t i = 0;
oharboe's avatar
oharboe committed
302
	int j = 0;
303
	int retval;
ntfreak's avatar
ntfreak committed
304

oharboe's avatar
oharboe committed
305
306
	if (argc != 1)
		return ERROR_COMMAND_SYNTAX_ERROR;
307
308
309

	unsigned bank_nr;
	COMMAND_PARSE_NUMBER(uint, args[0], bank_nr);
ntfreak's avatar
ntfreak committed
310

oharboe's avatar
oharboe committed
311
312
	for (p = flash_banks; p; p = p->next, i++)
	{
Zachary T Welch's avatar
Zachary T Welch committed
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
		if (i != bank_nr)
			continue;

		char buf[1024];

		/* attempt auto probe */
		if ((retval = p->driver->auto_probe(p)) != ERROR_OK)
			return retval;

		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);
		for (j = 0; j < p->num_sectors; j++)
oharboe's avatar
oharboe committed
331
		{
Zachary T Welch's avatar
Zachary T Welch committed
332
			char *protect_state;
ntfreak's avatar
ntfreak committed
333

Zachary T Welch's avatar
Zachary T Welch committed
334
335
336
337
338
339
			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";
ntfreak's avatar
ntfreak committed
340

341
			command_print(cmd_ctx,
Zachary T Welch's avatar
Zachary T Welch committed
342
343
344
345
346
347
				      "\t#%3i: 0x%8.8" PRIx32 " (0x%" PRIx32 " %" PRIi32 "kB) %s",
				      j,
				      p->sectors[j].offset,
				      p->sectors[j].size,
				      p->sectors[j].size >> 10,
				      protect_state);
oharboe's avatar
oharboe committed
348
		}
Zachary T Welch's avatar
Zachary T Welch committed
349
350
351
352
353
354

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

oharboe's avatar
oharboe committed
357
358
359
	return ERROR_OK;
}

mifi's avatar
mifi committed
360
static int handle_flash_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
oharboe's avatar
oharboe committed
361
362
{
	int retval;
ntfreak's avatar
ntfreak committed
363

oharboe's avatar
oharboe committed
364
365
366
367
	if (argc != 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
ntfreak's avatar
ntfreak committed
368

369
370
371
	unsigned bank_nr;
	COMMAND_PARSE_NUMBER(uint, args[0], bank_nr);
	flash_bank_t *p = get_flash_bank_by_num_noprobe(bank_nr);
oharboe's avatar
oharboe committed
372
373
374
375
	if (p)
	{
		if ((retval = p->driver->probe(p)) == ERROR_OK)
		{
duane's avatar
duane committed
376
			command_print(cmd_ctx, "flash '%s' found at 0x%8.8" PRIx32, p->driver->name, p->base);
oharboe's avatar
oharboe committed
377
378
379
		}
		else if (retval == ERROR_FLASH_BANK_INVALID)
		{
duane's avatar
duane committed
380
			command_print(cmd_ctx, "probing failed for flash bank '#%s' at 0x%8.8" PRIx32,
oharboe's avatar
oharboe committed
381
382
383
384
						  args[0], p->base);
		}
		else
		{
duane's avatar
duane committed
385
			command_print(cmd_ctx, "unknown error when probing flash bank '#%s' at 0x%8.8" PRIx32,
oharboe's avatar
oharboe committed
386
387
388
389
390
391
392
						  args[0], p->base);
		}
	}
	else
	{
		command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
	}
ntfreak's avatar
ntfreak committed
393

oharboe's avatar
oharboe committed
394
395
396
	return ERROR_OK;
}

mifi's avatar
mifi committed
397
static int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
oharboe's avatar
oharboe committed
398
399
400
401
402
{
	if (argc != 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
ntfreak's avatar
ntfreak committed
403

404
405
406
407
408
	flash_bank_t *p;
	int retval = flash_command_get_bank_by_num(cmd_ctx, args[0], &p);
	if (ERROR_OK != retval)
		return retval;

Zachary T Welch's avatar
Zachary T Welch committed
409
410
	int j;
	if ((retval = p->driver->erase_check(p)) == ERROR_OK)
oharboe's avatar
oharboe committed
411
	{
Zachary T Welch's avatar
Zachary T Welch committed
412
413
414
415
416
417
418
		command_print(cmd_ctx, "successfully checked erase state");
	}
	else
	{
		command_print(cmd_ctx, "unknown error when checking erase state of flash bank #%s at 0x%8.8" PRIx32,
			args[0], p->base);
	}
oharboe's avatar
oharboe committed
419

Zachary T Welch's avatar
Zachary T Welch committed
420
421
422
	for (j = 0; j < p->num_sectors; j++)
	{
		char *erase_state;
oharboe's avatar
   
oharboe committed
423

Zachary T Welch's avatar
Zachary T Welch committed
424
425
426
427
428
429
		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";
oharboe's avatar
   
oharboe committed
430

Zachary T Welch's avatar
Zachary T Welch committed
431
432
433
434
435
436
437
		command_print(cmd_ctx,
			      "\t#%3i: 0x%8.8" PRIx32 " (0x%" PRIx32 " %" PRIi32 "kB) %s",
			      j,
			      p->sectors[j].offset,
			      p->sectors[j].size,
			      p->sectors[j].size >> 10,
			      erase_state);
oharboe's avatar
oharboe committed
438
	}
ntfreak's avatar
ntfreak committed
439

oharboe's avatar
oharboe committed
440
441
442
	return ERROR_OK;
}

mifi's avatar
mifi committed
443
static int handle_flash_erase_address_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
oharboe's avatar
oharboe committed
444
445
446
447
448
{
	flash_bank_t *p;
	int retval;
	int address;
	int length;
ntfreak's avatar
ntfreak committed
449

oharboe's avatar
oharboe committed
450
451
452
453
	target_t *target = get_current_target(cmd_ctx);

	if (argc != 2)
		return ERROR_COMMAND_SYNTAX_ERROR;
ntfreak's avatar
ntfreak committed
454

455
456
	COMMAND_PARSE_NUMBER(int, args[0], address);
	COMMAND_PARSE_NUMBER(int, args[1], length);
oharboe's avatar
oharboe committed
457
458
459
460
461
462
463
464
465
	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
466
		return ERROR_FAIL;
oharboe's avatar
oharboe committed
467
	}
ntfreak's avatar
ntfreak committed
468

oharboe's avatar
oharboe committed
469
470
	/* 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
471

Zachary T Welch's avatar
Zachary T Welch committed
472
473
	struct duration bench;
	duration_start(&bench);
ntfreak's avatar
ntfreak committed
474

Zachary T Welch's avatar
Zachary T Welch committed
475
476
477
	retval = flash_erase_address_range(target, address, length);

	if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK))
oharboe's avatar
oharboe committed
478
	{
Zachary T Welch's avatar
Zachary T Welch committed
479
480
481
		command_print(cmd_ctx, "erased address 0x%8.8x (length %i)"
				" in %fs (%0.3f kb/s)", address, length,
				duration_elapsed(&bench), duration_kbps(&bench, length));
oharboe's avatar
oharboe committed
482
	}
ntfreak's avatar
ntfreak committed
483

oharboe's avatar
oharboe committed
484
485
486
	return retval;
}

mifi's avatar
mifi committed
487
static int handle_flash_protect_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
oharboe's avatar
oharboe committed
488
489
490
{
	if (argc != 1)
		return ERROR_COMMAND_SYNTAX_ERROR;
ntfreak's avatar
ntfreak committed
491

492
493
494
495
496
	flash_bank_t *p;
	int retval = flash_command_get_bank_by_num(cmd_ctx, args[0], &p);
	if (ERROR_OK != retval)
		return retval;

Zachary T Welch's avatar
Zachary T Welch committed
497
	if ((retval = p->driver->protect_check(p)) == ERROR_OK)
oharboe's avatar
oharboe committed
498
	{
Zachary T Welch's avatar
Zachary T Welch committed
499
500
501
502
503
504
505
506
507
		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.8" PRIx32, args[0], p->base);
	}
	else
	{
		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
508
	}
ntfreak's avatar
ntfreak committed
509

oharboe's avatar
oharboe committed
510
511
512
	return ERROR_OK;
}

513
static int flash_check_sector_parameters(struct command_context_s *cmd_ctx,
514
		uint32_t first, uint32_t last, uint32_t num_sectors)
515
516
517
518
519
520
521
522
{
	if (!(first <= last)) {
		command_print(cmd_ctx, "ERROR: "
				"first sector must be <= last sector");
		return ERROR_FAIL;
	}

	if (!(last <= (num_sectors - 1))) {
David Brownell's avatar
David Brownell committed
523
524
		command_print(cmd_ctx, "ERROR: last sector must be <= %d",
				(int) num_sectors - 1);
525
526
527
528
529
530
531
532
		return ERROR_FAIL;
	}

	return ERROR_OK;
}

static int handle_flash_erase_command(struct command_context_s *cmd_ctx,
		char *cmd, char **args, int argc)
oharboe's avatar
oharboe committed
533
{
Zachary T Welch's avatar
Zachary T Welch committed
534
535
	if (argc != 2)
		return ERROR_COMMAND_SYNTAX_ERROR;
ntfreak's avatar
ntfreak committed
536

Zachary T Welch's avatar
Zachary T Welch committed
537
538
539
	uint32_t bank_nr;
	uint32_t first;
	uint32_t last;
540

Zachary T Welch's avatar
Zachary T Welch committed
541
542
543
544
545
546
547
548
	COMMAND_PARSE_NUMBER(u32, args[0], bank_nr);
	flash_bank_t *p = get_flash_bank_by_num(bank_nr);
	if (!p)
		return ERROR_OK;

	COMMAND_PARSE_NUMBER(u32, args[1], first);
	if (strcmp(args[2], "last") == 0)
		last = p->num_sectors - 1;
oharboe's avatar
oharboe committed
549
	else
Zachary T Welch's avatar
Zachary T Welch committed
550
551
552
553
554
555
556
		COMMAND_PARSE_NUMBER(u32, args[2], last);

	int retval;
	if ((retval = flash_check_sector_parameters(cmd_ctx,
			first, last, p->num_sectors)) != ERROR_OK)
		return retval;

Zachary T Welch's avatar
Zachary T Welch committed
557
558
	struct duration bench;
	duration_start(&bench);
Zachary T Welch's avatar
Zachary T Welch committed
559

Zachary T Welch's avatar
Zachary T Welch committed
560
561
562
563
564
565
566
	retval = flash_driver_erase(p, first, last);

	if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK))
	{
		command_print(cmd_ctx, "erased sectors %" PRIu32 " "
				"through %" PRIu32" on flash bank %" PRIu32 " "
				"in %fs", first, last, bank_nr, duration_elapsed(&bench));
Zachary T Welch's avatar
Zachary T Welch committed
567
	}
oharboe's avatar
oharboe committed
568
569
570
571

	return ERROR_OK;
}

572
573
static int handle_flash_protect_command(struct command_context_s *cmd_ctx,
		char *cmd, char **args, int argc)
oharboe's avatar
oharboe committed
574
{
Zachary T Welch's avatar
Zachary T Welch committed
575
576
	if (argc != 3)
		return ERROR_COMMAND_SYNTAX_ERROR;
ntfreak's avatar
ntfreak committed
577

Zachary T Welch's avatar
Zachary T Welch committed
578
579
580
581
	uint32_t bank_nr;
	uint32_t first;
	uint32_t last;
	int set;
582

Zachary T Welch's avatar
Zachary T Welch committed
583
584
585
586
	COMMAND_PARSE_NUMBER(u32, args[0], bank_nr);
	flash_bank_t *p = get_flash_bank_by_num(bank_nr);
	if (!p)
		return ERROR_OK;
ntfreak's avatar
ntfreak committed
587

Zachary T Welch's avatar
Zachary T Welch committed
588
589
590
591
592
593
594
595
596
597
	COMMAND_PARSE_NUMBER(u32, args[1], first);
	if (strcmp(args[2], "last") == 0)
		last = p->num_sectors - 1;
	else
		COMMAND_PARSE_NUMBER(u32, args[2], last);

	if (strcmp(args[3], "on") == 0)
		set = 1;
	else if (strcmp(args[3], "off") == 0)
		set = 0;
oharboe's avatar
oharboe committed
598
599
600
	else
		return ERROR_COMMAND_SYNTAX_ERROR;

Zachary T Welch's avatar
Zachary T Welch committed
601
602
603
604
605
606
607
608
609
610
611
612
613
	int retval;
	if ((retval = flash_check_sector_parameters(cmd_ctx,
			first, last, p->num_sectors)) != ERROR_OK)
		return retval;

	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", (int) first,
			(int) last, (int) bank_nr);
	}

oharboe's avatar
oharboe committed
614
615
616
	return ERROR_OK;
}

mifi's avatar
mifi committed
617
static int handle_flash_write_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
oharboe's avatar
oharboe committed
618
619
{
	target_t *target = get_current_target(cmd_ctx);
ntfreak's avatar
ntfreak committed
620

oharboe's avatar
oharboe committed
621
	image_t image;
622
	uint32_t written;
ntfreak's avatar
ntfreak committed
623

Zachary T Welch's avatar
Zachary T Welch committed
624
	int retval;
oharboe's avatar
oharboe committed
625
626
627
628
629

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

631
632
	/* flash auto-erase is disabled by default*/
	int auto_erase = 0;
633
	bool auto_unlock = false;
oharboe's avatar
oharboe committed
634

635
	for (;;)
636
	{
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
		if (strcmp(args[0], "erase") == 0)
		{
			auto_erase = 1;
			args++;
			argc--;
			command_print(cmd_ctx, "auto erase enabled");
		} else if (strcmp(args[0], "unlock") == 0)
		{
			auto_unlock = true;
			args++;
			argc--;
			command_print(cmd_ctx, "auto unlock enabled");
		} else
		{
			break;
		}
653
	}
oharboe's avatar
oharboe committed
654

655
656
657
658
	if (argc < 1)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
oharboe's avatar
oharboe committed
659

oharboe's avatar
oharboe committed
660
661
	if (!target)
	{
662
		LOG_ERROR("no target selected");
663
		return ERROR_FAIL;
oharboe's avatar
oharboe committed
664
	}
ntfreak's avatar
ntfreak committed
665

Zachary T Welch's avatar
Zachary T Welch committed
666
667
	struct duration bench;
	duration_start(&bench);
ntfreak's avatar
ntfreak committed
668

oharboe's avatar
oharboe committed
669
670
671
	if (argc >= 2)
	{
		image.base_address_set = 1;
672
		COMMAND_PARSE_NUMBER(int, args[1], image.base_address);
oharboe's avatar
oharboe committed
673
674
675
676
677
678
	}
	else
	{
		image.base_address_set = 0;
		image.base_address = 0x0;
	}
ntfreak's avatar
ntfreak committed
679

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

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

Zachary T Welch's avatar
Zachary T Welch committed
695
	if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK))
696
	{
Zachary T Welch's avatar
Zachary T Welch committed
697
698
699
		command_print(cmd_ctx, "wrote %" PRIu32 " byte from file %s "
				"in %fs (%0.3f kb/s)", written, args[0],
				duration_elapsed(&bench), duration_kbps(&bench, written));
700
	}
701

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

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

mifi's avatar
mifi committed
707
static int handle_flash_fill_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
oharboe's avatar
   
oharboe committed
708
{
Zachary T Welch's avatar
Zachary T Welch committed
709
	int err = ERROR_OK;
710
711
712
	uint32_t address;
	uint32_t pattern;
	uint32_t count;
713
714
	uint8_t chunk[1024];
	uint8_t readback[1024];
715
716
717
	uint32_t wrote = 0;
	uint32_t cur_size = 0;
	uint32_t chunk_count;
oharboe's avatar
   
oharboe committed
718
	target_t *target = get_current_target(cmd_ctx);
719
720
	uint32_t i;
	uint32_t wordsize;
oharboe's avatar
oharboe committed
721

oharboe's avatar
   
oharboe committed
722
723
	if (argc != 3)
		return ERROR_COMMAND_SYNTAX_ERROR;
oharboe's avatar
oharboe committed
724

725
726
727
	COMMAND_PARSE_NUMBER(u32, args[0], address);
	COMMAND_PARSE_NUMBER(u32, args[1], pattern);
	COMMAND_PARSE_NUMBER(u32, args[2], count);
oharboe's avatar
oharboe committed
728

zwelch's avatar
zwelch committed
729
	if (count == 0)
oharboe's avatar
   
oharboe committed
730
731
		return ERROR_OK;

zwelch's avatar
zwelch committed
732
	switch (cmd[4])
oharboe's avatar
   
oharboe committed
733
734
	{
	case 'w':
zwelch's avatar
zwelch committed
735
		wordsize = 4;
oharboe's avatar
   
oharboe committed
736
737
		break;
	case 'h':
zwelch's avatar
zwelch committed
738
		wordsize = 2;
oharboe's avatar
   
oharboe committed
739
740
		break;
	case 'b':
zwelch's avatar
zwelch committed
741
		wordsize = 1;
oharboe's avatar
   
oharboe committed
742
743
744
745
		break;
	default:
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
oharboe's avatar
oharboe committed
746

oharboe's avatar
   
oharboe committed
747
	chunk_count = MIN(count, (1024 / wordsize));
zwelch's avatar
zwelch committed
748
	switch (wordsize)
oharboe's avatar
   
oharboe committed
749
750
	{
	case 4:
zwelch's avatar
zwelch committed
751
		for (i = 0; i < chunk_count; i++)
oharboe's avatar
   
oharboe committed
752
753
754
755
756
		{
			target_buffer_set_u32(target, chunk + i * wordsize, pattern);
		}
		break;
	case 2:
zwelch's avatar
zwelch committed
757
		for (i = 0; i < chunk_count; i++)
oharboe's avatar
   
oharboe committed
758
759
760
761
762
763
764
765
766
767
768
		{
			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
769

Zachary T Welch's avatar
Zachary T Welch committed
770
771
	struct duration bench;
	duration_start(&bench);
oharboe's avatar
   
oharboe committed
772

zwelch's avatar
zwelch committed
773
	for (wrote = 0; wrote < (count*wordsize); wrote += cur_size)
oharboe's avatar
   
oharboe committed
774
	{
775
		cur_size = MIN((count*wordsize - wrote), sizeof(chunk));
oharboe's avatar
oharboe committed
776
777
		flash_bank_t *bank;
		bank = get_flash_bank_by_addr(target, address);
zwelch's avatar
zwelch committed
778
		if (bank == NULL)
oharboe's avatar
oharboe committed
779
		{
oharboe's avatar
oharboe committed
780
			return ERROR_FAIL;
oharboe's avatar
   
oharboe committed
781
		}
oharboe's avatar
oharboe committed
782
		err = flash_driver_write(bank, chunk, address - bank->base + wrote, cur_size);
zwelch's avatar
zwelch committed
783
		if (err != ERROR_OK)
oharboe's avatar
oharboe committed
784
			return err;
oharboe's avatar
oharboe committed
785
786

		err = target_read_buffer(target, address + wrote, cur_size, readback);
zwelch's avatar
zwelch committed
787
		if (err != ERROR_OK)
oharboe's avatar
oharboe committed
788
789
			return err;

zwelch's avatar
zwelch committed
790
		unsigned i;
zwelch's avatar
zwelch committed
791
		for (i = 0; i < cur_size; i++)
oharboe's avatar
oharboe committed
792
793
794
		{
			if (readback[i]!=chunk[i])
			{
795
				LOG_ERROR("Verfication error address 0x%08" PRIx32 ", read back 0x%02x, expected 0x%02x",
duane's avatar
duane committed
796
						  address + wrote + i, readback[i], chunk[i]);
oharboe's avatar
oharboe committed
797
798
799
				return ERROR_FAIL;
			}
		}
oharboe's avatar
   
oharboe committed
800
	}
oharboe's avatar
oharboe committed
801

Zachary T Welch's avatar
Zachary T Welch committed
802
	if (duration_measure(&bench) == ERROR_OK)
803
	{
Zachary T Welch's avatar
Zachary T Welch committed
804
805
806
		command_print(cmd_ctx, "wrote %" PRIu32 " bytes to 0x%8.8" PRIx32 
				" in %fs (%0.3f kb/s)", wrote, address,
				duration_elapsed(&bench), duration_kbps(&bench, wrote));
807
	}
oharboe's avatar
   
oharboe committed
808
809
810
	return ERROR_OK;
}

mifi's avatar
mifi committed
811
static int handle_flash_write_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
oharboe's avatar
oharboe committed
812
{
813
	uint32_t offset;
814
	uint8_t *buffer;
815
	uint32_t buf_cnt;
oharboe's avatar
oharboe committed
816
	fileio_t fileio;
ntfreak's avatar
ntfreak committed
817

oharboe's avatar
oharboe committed
818
819
	if (argc != 3)
		return ERROR_COMMAND_SYNTAX_ERROR;
ntfreak's avatar
ntfreak committed
820

Zachary T Welch's avatar
Zachary T Welch committed
821
822
	struct duration bench;
	duration_start(&bench);
ntfreak's avatar
ntfreak committed
823

824
825
826
827
828
829
	flash_bank_t *p;
	int retval = flash_command_get_bank_by_num(cmd_ctx, args[0], &p);
	if (ERROR_OK != retval)
		return retval;

	COMMAND_PARSE_NUMBER(u32, args[2], offset);
ntfreak's avatar
ntfreak committed
830

oharboe's avatar
oharboe committed
831
832
833
834
	if (fileio_open(&fileio, args[1], FILEIO_READ, FILEIO_BINARY) != ERROR_OK)
	{
		return ERROR_OK;
	}
ntfreak's avatar
ntfreak committed
835

oharboe's avatar
oharboe committed
836
837
838
	buffer = malloc(fileio.size);
	if (fileio_read(&fileio, fileio.size, buffer, &buf_cnt) != ERROR_OK)
	{
839
840
		free(buffer);
		fileio_close(&fileio);
oharboe's avatar
oharboe committed
841
842
		return ERROR_OK;
	}
ntfreak's avatar
ntfreak committed
843

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

oharboe's avatar
oharboe committed
846
	free(buffer);
847
	buffer = NULL;
ntfreak's avatar
ntfreak committed
848

Zachary T Welch's avatar
Zachary T Welch committed
849
	if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK))
oharboe's avatar
oharboe committed
850
	{
Zachary T Welch's avatar
Zachary T Welch committed
851
852
		command_print(cmd_ctx, "wrote %lld byte from file %s to flash bank %u"
				" at offset 0x%8.8" PRIx32 " in %fs (%0.3f kb/s)",
853
				fileio.size, args[1], p->bank_number, offset,
Zachary T Welch's avatar
Zachary T Welch committed
854
				duration_elapsed(&bench), duration_kbps(&bench, fileio.size));
oharboe's avatar
oharboe committed
855
856
857
	}

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

oharboe's avatar
oharboe committed
859
860
861
862
863
864
865
	return retval;
}

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

oharboe's avatar
oharboe committed
867
868
869
870
871
	/* 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
872
			c->sectors[i].is_erased = 0;
oharboe's avatar
oharboe committed
873
874
875
876
877
		}
	}
}

/* lookup flash bank by address */
878
flash_bank_t *get_flash_bank_by_addr(target_t *target, uint32_t addr)
oharboe's avatar
oharboe committed
879
880
881
882
883
884
885
886
{
	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
887

oharboe's avatar
oharboe committed
888
889
		if (retval != ERROR_OK)
		{
890
			LOG_ERROR("auto_probe failed %d\n", retval);
oharboe's avatar
oharboe committed
891
892
893
			return NULL;
		}
		/* check whether address belongs to this flash bank */
894
		if ((addr >= c->base) && (addr <= c->base + (c->size - 1)) && target == c->target)
oharboe's avatar
oharboe committed
895
896
			return c;
	}
duane's avatar
duane committed
897
	LOG_ERROR("No flash at address 0x%08" PRIx32 "\n", addr);
oharboe's avatar
oharboe committed
898
899
900
901
	return NULL;
}

/* erase given flash region, selects proper bank according to target and address */
902
903
static int flash_iterate_address_range(target_t *target, uint32_t addr, uint32_t length,
		int (*callback)(struct flash_bank_s *bank, int first, int last))
oharboe's avatar
oharboe committed
904
905
906
907
908
{
	flash_bank_t *c;
	int first = -1;
	int last = -1;
	int i;
ntfreak's avatar
ntfreak committed
909

oharboe's avatar
oharboe committed
910
911
912
913
	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)
914
915
	{
		LOG_ERROR("Bank is invalid");
oharboe's avatar
oharboe committed
916
		return ERROR_FLASH_BANK_INVALID;
917
	}
ntfreak's avatar
ntfreak committed
918

oharboe's avatar
oharboe committed
919
920
921
922
923
	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
924

925
		return callback(c, 0, c->num_sectors - 1);
oharboe's avatar
oharboe committed
926
927
928
	}

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

oharboe's avatar
oharboe committed
932
	addr -= c->base;
ntfreak's avatar
ntfreak committed
933

oharboe's avatar
oharboe committed
934
	for (i = 0; i < c->num_sectors; i++)
ntfreak's avatar
ntfreak committed
935
	{
oharboe's avatar
oharboe committed
936
937
938
939
940
941
942
943
		/* 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
944

945
	if (first == -1 || last == -1)
oharboe's avatar
oharboe committed
946
		return ERROR_OK;
ntfreak's avatar
ntfreak committed
947

948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
	return callback(c, first, last);
}



int flash_erase_address_range(target_t *target, uint32_t addr, uint32_t length)
{
	return flash_iterate_address_range(target, addr, length, &flash_driver_erase);
}

static int flash_driver_unprotect(struct flash_bank_s *bank, int first, int last)
{
	return flash_driver_protect(bank, 0, first, last);
}

static int flash_unlock_address_range(target_t *target, uint32_t addr, uint32_t length)
{
	return flash_iterate_address_range(target, addr, length, &flash_driver_unprotect);
oharboe's avatar
oharboe committed
966
967
}

968

oharboe's avatar
oharboe committed
969
/* write (optional verify) an image to flash memory of the given target */
970
static int flash_write_unlock(target_t *target, image_t *image, uint32_t *written, int erase, bool unlock)
oharboe's avatar
oharboe committed
971
{
zwelch's avatar
zwelch committed
972
	int retval = ERROR_OK;
oharboe's avatar
oharboe committed
973
974

	int section;
975
	uint32_t section_offset;
oharboe's avatar
oharboe committed
976
	flash_bank_t *c;
977
	int *padding;
oharboe's avatar
oharboe committed
978

oharboe's avatar
oharboe committed
979
980
981
982
983
	section = 0;
	section_offset = 0;

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

oharboe's avatar
oharboe committed
985
986
987
988
	if (erase)
	{
		/* assume all sectors need erasing - stops any problems
		 * when flash_write is called multiple times */
ntfreak's avatar
ntfreak committed
989

oharboe's avatar
oharboe committed
990
991
		flash_set_dirty();
	}
oharboe's avatar
oharboe committed
992