pic32mx.c 24.5 KB
Newer Older
oharboe's avatar
oharboe committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/***************************************************************************
 *   Copyright (C) 2005 by Dominic Rath                                    *
 *   Dominic.Rath@gmx.de                                                   *
 *                                                                         *
 *   Copyright (C) 2008 by Spencer Oliver                                  *
 *   spen@spen-soft.co.uk                                                  *
 *                                                                         *
 *   Copyright (C) 2008 by John McCarthy                                   *
 *   jgmcc@magma.ca                                                        *
 *                                                                         *
 *   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 "pic32mx.h"
#include "mips32.h"


static
struct pic32mx_devs_s {
36
	uint8_t	devid;
oharboe's avatar
oharboe committed
37
	char	*name;
38
	uint32_t	pfm_size;
oharboe's avatar
oharboe committed
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
} pic32mx_devs[] = {
	{ 0x78, "460F512L USB", 512 },
	{ 0x74, "460F256L USB", 256 },
	{ 0x6D, "440F128L USB", 128 },
	{ 0x56, "440F512H USB", 512 },
	{ 0x52, "440F256H USB", 256 },
	{ 0x4D, "440F128H USB", 128 },
	{ 0x42, "420F032H USB",  32 },
	{ 0x38, "360F512L",     512 },
	{ 0x34, "360F256L",     256 },
	{ 0x2D, "340F128L",     128 },
	{ 0x2A, "320F128L",     128 },
	{ 0x16, "340F512H",     512 },
	{ 0x12, "340F256H",     256 },
	{ 0x0D, "340F128H",     128 },
	{ 0x0A, "320F128H",     128 },
	{ 0x06, "320F064H",      64 },
	{ 0x02, "320F032H",      32 },
	{ 0x00, NULL, 0 }
};

60
61
static int pic32mx_write_row(struct flash_bank *bank, uint32_t address, uint32_t srcaddr);
static int pic32mx_write_word(struct flash_bank *bank, uint32_t address, uint32_t word);
oharboe's avatar
oharboe committed
62
63
64

/* flash bank pic32mx <base> <size> 0 0 <target#>
 */
65
FLASH_BANK_COMMAND_HANDLER(pic32mx_flash_bank_command)
oharboe's avatar
oharboe committed
66
{
67
	struct pic32mx_flash_bank *pic32mx_info;
oharboe's avatar
oharboe committed
68

69
	if (CMD_ARGC < 6)
oharboe's avatar
oharboe committed
70
71
72
73
74
	{
		LOG_WARNING("incomplete flash_bank pic32mx configuration");
		return ERROR_FLASH_BANK_INVALID;
	}

75
	pic32mx_info = malloc(sizeof(struct pic32mx_flash_bank));
oharboe's avatar
oharboe committed
76
77
78
79
80
81
82
83
	bank->driver_priv = pic32mx_info;

	pic32mx_info->write_algorithm = NULL;
	pic32mx_info->probed = 0;

	return ERROR_OK;
}

84
static uint32_t pic32mx_get_flash_status(struct flash_bank *bank)
oharboe's avatar
oharboe committed
85
{
Zachary T Welch's avatar
Zachary T Welch committed
86
	struct target *target = bank->target;
87
	uint32_t status;
oharboe's avatar
oharboe committed
88
89
90
91
92
93

	target_read_u32(target, PIC32MX_NVMCON, &status);

	return status;
}

94
static uint32_t pic32mx_wait_status_busy(struct flash_bank *bank, int timeout)
oharboe's avatar
oharboe committed
95
{
96
	uint32_t status;
oharboe's avatar
oharboe committed
97
98
99
100

	/* wait for busy to clear */
	while (((status = pic32mx_get_flash_status(bank)) & NVMCON_NVMWR) && (timeout-- > 0))
	{
101
		LOG_DEBUG("status: 0x%" PRIx32, status);
oharboe's avatar
oharboe committed
102
103
		alive_sleep(1);
	}
zwelch's avatar
zwelch committed
104
	if (timeout <= 0)
105
		LOG_DEBUG("timeout: status: 0x%" PRIx32, status);
oharboe's avatar
oharboe committed
106
107
108
109

	return status;
}

110
static int pic32mx_nvm_exec(struct flash_bank *bank, uint32_t op, uint32_t timeout)
oharboe's avatar
oharboe committed
111
{
Zachary T Welch's avatar
Zachary T Welch committed
112
	struct target *target = bank->target;
113
	uint32_t status;
oharboe's avatar
oharboe committed
114

zwelch's avatar
zwelch committed
115
	target_write_u32(target, PIC32MX_NVMCON, NVMCON_NVMWREN | op);
oharboe's avatar
oharboe committed
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131

	/* unlock flash registers */
	target_write_u32(target, PIC32MX_NVMKEY, NVMKEY1);
	target_write_u32(target, PIC32MX_NVMKEY, NVMKEY2);

	/* start operation */
	target_write_u32(target, PIC32MX_NVMCONSET, NVMCON_NVMWR);

	status = pic32mx_wait_status_busy(bank, timeout);

	/* lock flash registers */
	target_write_u32(target, PIC32MX_NVMCONCLR, NVMCON_NVMWREN);

	return status;
}

132
static int pic32mx_protect_check(struct flash_bank *bank)
oharboe's avatar
oharboe committed
133
{
Zachary T Welch's avatar
Zachary T Welch committed
134
	struct target *target = bank->target;
oharboe's avatar
oharboe committed
135

136
	uint32_t devcfg0;
oharboe's avatar
oharboe committed
137
138
139
140
141
142
143
144
145
146
	int s;
	int num_pages;

	if (target->state != TARGET_HALTED)
	{
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	target_read_u32(target, PIC32MX_DEVCFG0, &devcfg0);
zwelch's avatar
zwelch committed
147
	if ((devcfg0 & (1 << 28)) == 0) /* code protect bit */
oharboe's avatar
oharboe committed
148
		num_pages = 0xffff;  /* All pages protected */
zwelch's avatar
zwelch committed
149
	else if (bank->base == PIC32MX_KSEG1_BOOT_FLASH)
oharboe's avatar
oharboe committed
150
	{
zwelch's avatar
zwelch committed
151
		if (devcfg0 & (1 << 24))
oharboe's avatar
oharboe committed
152
153
154
155
156
157
158
159
160
161
162
163
164
165
			num_pages = 0;       /* All pages unprotected */
		else
			num_pages = 0xffff;  /* All pages protected */
	}
	else /* pgm flash */
		num_pages = (~devcfg0 >> 12) & 0xff;
	for (s = 0; s < bank->num_sectors && s < num_pages; s++)
		bank->sectors[s].is_protected = 1;
	for (; s < bank->num_sectors; s++)
		bank->sectors[s].is_protected = 0;

	return ERROR_OK;
}

166
static int pic32mx_erase(struct flash_bank *bank, int first, int last)
oharboe's avatar
oharboe committed
167
{
Zachary T Welch's avatar
Zachary T Welch committed
168
	struct target *target = bank->target;
oharboe's avatar
oharboe committed
169
	int i;
170
	uint32_t status;
oharboe's avatar
oharboe committed
171
172
173
174
175
176
177
178
179

	if (bank->target->state != TARGET_HALTED)
	{
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	if ((first == 0) && (last == (bank->num_sectors - 1)) && (bank->base == PIC32MX_KSEG0_PGM_FLASH || bank->base == PIC32MX_KSEG1_PGM_FLASH))
	{
180
		LOG_DEBUG("Erasing entire program flash");
oharboe's avatar
oharboe committed
181
		status = pic32mx_nvm_exec(bank, NVMCON_OP_PFM_ERASE, 50);
182
		if (status & NVMCON_NVMERR)
oharboe's avatar
oharboe committed
183
			return ERROR_FLASH_OPERATION_FAILED;
184
		if (status & NVMCON_LVDERR)
oharboe's avatar
oharboe committed
185
186
187
188
189
190
			return ERROR_FLASH_OPERATION_FAILED;
		return ERROR_OK;
	}

	for (i = first; i <= last; i++)
	{
zwelch's avatar
zwelch committed
191
		if (bank->base >= PIC32MX_KSEG1_PGM_FLASH)
192
193
194
			target_write_u32(target, PIC32MX_NVMADDR, KS1Virt2Phys(bank->base + bank->sectors[i].offset));
		else
			target_write_u32(target, PIC32MX_NVMADDR, KS0Virt2Phys(bank->base + bank->sectors[i].offset));
oharboe's avatar
oharboe committed
195
196
197

		status = pic32mx_nvm_exec(bank, NVMCON_OP_PAGE_ERASE, 10);

198
		if (status & NVMCON_NVMERR)
oharboe's avatar
oharboe committed
199
			return ERROR_FLASH_OPERATION_FAILED;
200
		if (status & NVMCON_LVDERR)
oharboe's avatar
oharboe committed
201
202
203
204
205
206
207
			return ERROR_FLASH_OPERATION_FAILED;
		bank->sectors[i].is_erased = 1;
	}

	return ERROR_OK;
}

208
static int pic32mx_protect(struct flash_bank *bank, int set, int first, int last)
oharboe's avatar
oharboe committed
209
{
210
	struct pic32mx_flash_bank *pic32mx_info = NULL;
Zachary T Welch's avatar
Zachary T Welch committed
211
	struct target *target = bank->target;
212
#if 0
zwelch's avatar
zwelch committed
213
	uint16_t prot_reg[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
oharboe's avatar
oharboe committed
214
215
	int i, reg, bit;
	int status;
216
	uint32_t protection;
217
#endif
oharboe's avatar
oharboe committed
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237

	pic32mx_info = bank->driver_priv;

	if (target->state != TARGET_HALTED)
	{
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

#if 0
	if ((first && (first % pic32mx_info->ppage_size)) || ((last + 1) && (last + 1) % pic32mx_info->ppage_size))
	{
		LOG_WARNING("sector start/end incorrect - stm32 has %dK sector protection", pic32mx_info->ppage_size);
		return ERROR_FLASH_SECTOR_INVALID;
	}

	/* medium density - each bit refers to a 4bank protection
	 * high density - each bit refers to a 2bank protection */
	target_read_u32(target, PIC32MX_FLASH_WRPR, &protection);

zwelch's avatar
zwelch committed
238
239
240
241
	prot_reg[0] = (uint16_t)protection;
	prot_reg[1] = (uint16_t)(protection >> 8);
	prot_reg[2] = (uint16_t)(protection >> 16);
	prot_reg[3] = (uint16_t)(protection >> 24);
oharboe's avatar
oharboe committed
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265

	if (pic32mx_info->ppage_size == 2)
	{
		/* high density flash */

		/* bit 7 controls sector 62 - 255 protection */
		if (last > 61)
		{
			if (set)
				prot_reg[3] &= ~(1 << 7);
			else
				prot_reg[3] |= (1 << 7);
		}

		if (first > 61)
			first = 62;
		if (last > 61)
			last = 61;

		for (i = first; i <= last; i++)
		{
			reg = (i / pic32mx_info->ppage_size) / 8;
			bit = (i / pic32mx_info->ppage_size) - (reg * 8);

266
			if (set)
oharboe's avatar
oharboe committed
267
268
269
270
271
272
273
274
275
276
277
278
279
				prot_reg[reg] &= ~(1 << bit);
			else
				prot_reg[reg] |= (1 << bit);
		}
	}
	else
	{
		/* medium density flash */
		for (i = first; i <= last; i++)
		{
			reg = (i / pic32mx_info->ppage_size) / 8;
			bit = (i / pic32mx_info->ppage_size) - (reg * 8);

280
			if (set)
oharboe's avatar
oharboe committed
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
				prot_reg[reg] &= ~(1 << bit);
			else
				prot_reg[reg] |= (1 << bit);
		}
	}

	if ((status = pic32mx_erase_options(bank)) != ERROR_OK)
		return status;

	pic32mx_info->option_bytes.protection[0] = prot_reg[0];
	pic32mx_info->option_bytes.protection[1] = prot_reg[1];
	pic32mx_info->option_bytes.protection[2] = prot_reg[2];
	pic32mx_info->option_bytes.protection[3] = prot_reg[3];

	return pic32mx_write_options(bank);
#else
	return ERROR_OK;
#endif
}

301
static int pic32mx_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
oharboe's avatar
oharboe committed
302
{
Zachary T Welch's avatar
Zachary T Welch committed
303
	struct target *target = bank->target;
304
	uint32_t buffer_size = 512;
305
	struct working_area *source;
306
	uint32_t address = bank->base + offset;
307
	int retval = ERROR_OK;
oharboe's avatar
oharboe committed
308
#if 0
309
	struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv;
310
	struct armv7m_algorithm armv7m_info;
oharboe's avatar
oharboe committed
311

312
	uint8_t pic32mx_flash_write_code[] = {
oharboe's avatar
oharboe committed
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
									/* write: */
		0xDF, 0xF8, 0x24, 0x40,		/* ldr	r4, PIC32MX_FLASH_CR */
		0x09, 0x4D,					/* ldr	r5, PIC32MX_FLASH_SR */
		0x4F, 0xF0, 0x01, 0x03,		/* mov	r3, #1 */
		0x23, 0x60,					/* str	r3, [r4, #0] */
		0x30, 0xF8, 0x02, 0x3B,		/* ldrh r3, [r0], #2 */
		0x21, 0xF8, 0x02, 0x3B,		/* strh r3, [r1], #2 */
									/* busy: */
		0x2B, 0x68,					/* ldr 	r3, [r5, #0] */
		0x13, 0xF0, 0x01, 0x0F,		/* tst 	r3, #0x01 */
		0xFB, 0xD0,					/* beq 	busy */
		0x13, 0xF0, 0x14, 0x0F,		/* tst	r3, #0x14 */
		0x01, 0xD1,					/* bne	exit */
		0x01, 0x3A,					/* subs	r2, r2, #1 */
		0xED, 0xD1,					/* bne	write */
									/* exit: */
		0xFE, 0xE7,					/* b exit */
		0x10, 0x20, 0x02, 0x40,		/* PIC32MX_FLASH_CR:	.word 0x40022010 */
		0x0C, 0x20, 0x02, 0x40		/* PIC32MX_FLASH_SR:	.word 0x4002200C */
	};

	/* flash write code */
	if (target_alloc_working_area(target, sizeof(pic32mx_flash_write_code), &pic32mx_info->write_algorithm) != ERROR_OK)
	{
		LOG_WARNING("no working area available, can't do block memory writes");
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	};

zwelch's avatar
zwelch committed
341
	if ((retval = target_write_buffer(target, pic32mx_info->write_algorithm->address, sizeof(pic32mx_flash_write_code), pic32mx_flash_write_code)) != ERROR_OK)
oharboe's avatar
oharboe committed
342
		return retval;
343
#endif
oharboe's avatar
oharboe committed
344
345

	/* memory buffer */
346
	if (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
oharboe's avatar
oharboe committed
347
	{
348
349
350
351
352
#if 0
		/* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
		if (pic32mx_info->write_algorithm)
			target_free_working_area(target, pic32mx_info->write_algorithm);
#endif
oharboe's avatar
oharboe committed
353

354
355
356
		LOG_WARNING("no large enough working area available, can't do block memory writes");
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	}
oharboe's avatar
oharboe committed
357

358
	while (count >= buffer_size/4)
oharboe's avatar
oharboe committed
359
	{
360
		uint32_t status;
oharboe's avatar
oharboe committed
361

zwelch's avatar
zwelch committed
362
		if ((retval = target_write_buffer(target, source->address, buffer_size, buffer)) != ERROR_OK) {
duane's avatar
duane committed
363
			LOG_ERROR("Failed to write row buffer (%d words) to RAM", (int)(buffer_size/4));
oharboe's avatar
oharboe committed
364
			break;
365
		}
oharboe's avatar
oharboe committed
366

367
#if 0
oharboe's avatar
oharboe committed
368
369
		buf_set_u32(reg_params[0].value, 0, 32, source->address);
		buf_set_u32(reg_params[1].value, 0, 32, address);
370
		buf_set_u32(reg_params[2].value, 0, 32, buffer_size/4);
oharboe's avatar
oharboe committed
371

zwelch's avatar
zwelch committed
372
		if ((retval = target_run_algorithm(target, 0, NULL, 4, reg_params, pic32mx_info->write_algorithm->address, \
oharboe's avatar
oharboe committed
373
374
375
376
377
378
379
380
381
382
383
384
				pic32mx_info->write_algorithm->address + (sizeof(pic32mx_flash_write_code) - 10), 10000, &armv7m_info)) != ERROR_OK)
		{
			LOG_ERROR("error executing pic32mx flash write algorithm");
			retval = ERROR_FLASH_OPERATION_FAILED;
			break;
		}

		if (buf_get_u32(reg_params[3].value, 0, 32) & 0x14)
		{
			retval = ERROR_FLASH_OPERATION_FAILED;
			break;
		}
385
386
#endif
		status = pic32mx_write_row(bank, address, source->address);
387
		if (status & NVMCON_NVMERR) {
zwelch's avatar
zwelch committed
388
			LOG_ERROR("Flash write error NVMERR (status = 0x%08" PRIx32 ")", status);
389
390
391
			retval = ERROR_FLASH_OPERATION_FAILED;
			break;
		}
392
		if (status & NVMCON_LVDERR) {
zwelch's avatar
zwelch committed
393
			LOG_ERROR("Flash write error LVDERR (status = 0x%08" PRIx32 ")", status);
394
395
396
			retval = ERROR_FLASH_OPERATION_FAILED;
			break;
		}
oharboe's avatar
oharboe committed
397

398
399
400
		buffer  += buffer_size;
		address += buffer_size;
		count   -= buffer_size/4;
oharboe's avatar
oharboe committed
401
402
403
404
	}

	target_free_working_area(target, source);

zwelch's avatar
zwelch committed
405
	while (count > 0)
406
	{
407
408
		uint32_t value;
		memcpy(&value, buffer, sizeof(uint32_t));
409

410
		uint32_t status = pic32mx_write_word(bank, address, value);
411
		if (status & NVMCON_NVMERR) {
zwelch's avatar
zwelch committed
412
			LOG_ERROR("Flash write error NVMERR (status = 0x%08" PRIx32 ")", status);
413
414
415
			retval = ERROR_FLASH_OPERATION_FAILED;
			break;
		}
416
		if (status & NVMCON_LVDERR) {
zwelch's avatar
zwelch committed
417
			LOG_ERROR("Flash write error LVDERR (status = 0x%08" PRIx32 ")", status);
418
419
420
421
422
423
424
425
			retval = ERROR_FLASH_OPERATION_FAILED;
			break;
		}

		buffer  += 4;
		address += 4;
		count--;
	}
oharboe's avatar
oharboe committed
426
427
428
429

	return retval;
}

430
static int pic32mx_write_word(struct flash_bank *bank, uint32_t address, uint32_t word)
oharboe's avatar
oharboe committed
431
{
Zachary T Welch's avatar
Zachary T Welch committed
432
	struct target *target = bank->target;
oharboe's avatar
oharboe committed
433

zwelch's avatar
zwelch committed
434
	if (bank->base >= PIC32MX_KSEG1_PGM_FLASH)
435
436
437
		target_write_u32(target, PIC32MX_NVMADDR, KS1Virt2Phys(address));
	else
		target_write_u32(target, PIC32MX_NVMADDR, KS0Virt2Phys(address));
oharboe's avatar
oharboe committed
438
439
440
441
442
	target_write_u32(target, PIC32MX_NVMDATA, word);

	return pic32mx_nvm_exec(bank, NVMCON_OP_WORD_PROG, 5);
}

443
444
445
/*
 * Write a 128 word (512 byte) row to flash address from RAM srcaddr.
 */
446
static int pic32mx_write_row(struct flash_bank *bank, uint32_t address, uint32_t srcaddr)
oharboe's avatar
oharboe committed
447
{
Zachary T Welch's avatar
Zachary T Welch committed
448
	struct target *target = bank->target;
449

duane's avatar
duane committed
450
	LOG_DEBUG("addr: 0x%08" PRIx32 " srcaddr: 0x%08" PRIx32 "", address, srcaddr);
451

zwelch's avatar
zwelch committed
452
	if (address >= PIC32MX_KSEG1_PGM_FLASH)
453
454
455
		target_write_u32(target, PIC32MX_NVMADDR,    KS1Virt2Phys(address));
	else
		target_write_u32(target, PIC32MX_NVMADDR,    KS0Virt2Phys(address));
zwelch's avatar
zwelch committed
456
	if (srcaddr >= PIC32MX_KSEG1_RAM)
457
458
459
460
461
462
463
		target_write_u32(target, PIC32MX_NVMSRCADDR, KS1Virt2Phys(srcaddr));
	else
		target_write_u32(target, PIC32MX_NVMSRCADDR, KS0Virt2Phys(srcaddr));

	return pic32mx_nvm_exec(bank, NVMCON_OP_ROW_PROG, 100);
}

464
static int pic32mx_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
465
{
466
467
468
469
470
	uint32_t words_remaining = (count / 4);
	uint32_t bytes_remaining = (count & 0x00000003);
	uint32_t address = bank->base + offset;
	uint32_t bytes_written = 0;
	uint32_t status;
471
	int retval;
oharboe's avatar
oharboe committed
472
473
474
475
476
477
478
479
480

	if (bank->target->state != TARGET_HALTED)
	{
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	if (offset & 0x3)
	{
duane's avatar
duane committed
481
		LOG_WARNING("offset 0x%" PRIx32 "breaks required 4-byte alignment", offset);
oharboe's avatar
oharboe committed
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
		return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
	}

	/* multiple words (4-byte) to be programmed? */
	if (words_remaining > 0)
	{
		/* try using a block write */
		if ((retval = pic32mx_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)
		{
			if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
			{
				/* if block write failed (no sufficient working area),
				 * we use normal (slow) single dword accesses */
				LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
			}
			else if (retval == ERROR_FLASH_OPERATION_FAILED)
			{
				LOG_ERROR("flash writing failed with error code: 0x%x", retval);
				return ERROR_FLASH_OPERATION_FAILED;
			}
		}
		else
		{
			buffer += words_remaining * 4;
			address += words_remaining * 4;
			words_remaining = 0;
		}
	}

	while (words_remaining > 0)
	{
513
514
		uint32_t value;
		memcpy(&value, buffer + bytes_written, sizeof(uint32_t));
oharboe's avatar
oharboe committed
515

516
		status = pic32mx_write_word(bank, address, value);
517
		if (status & NVMCON_NVMERR)
oharboe's avatar
oharboe committed
518
			return ERROR_FLASH_OPERATION_FAILED;
519
		if (status & NVMCON_LVDERR)
oharboe's avatar
oharboe committed
520
521
522
523
524
525
526
527
528
			return ERROR_FLASH_OPERATION_FAILED;

		bytes_written += 4;
		words_remaining--;
		address += 4;
	}

	if (bytes_remaining)
	{
529
		uint32_t value = 0xffffffff;
530
		memcpy(&value, buffer + bytes_written, bytes_remaining);
oharboe's avatar
oharboe committed
531

532
		status = pic32mx_write_word(bank, address, value);
533
		if (status & NVMCON_NVMERR)
oharboe's avatar
oharboe committed
534
			return ERROR_FLASH_OPERATION_FAILED;
535
		if (status & NVMCON_LVDERR)
oharboe's avatar
oharboe committed
536
537
538
539
540
541
			return ERROR_FLASH_OPERATION_FAILED;
	}

	return ERROR_OK;
}

542
static int pic32mx_probe(struct flash_bank *bank)
oharboe's avatar
oharboe committed
543
{
Zachary T Welch's avatar
Zachary T Welch committed
544
	struct target *target = bank->target;
545
	struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv;
546
	struct mips32_common *mips32 = target->arch_info;
547
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
oharboe's avatar
oharboe committed
548
	int i;
zwelch's avatar
zwelch committed
549
	uint16_t num_pages = 0;
550
	uint32_t device_id;
oharboe's avatar
oharboe committed
551
552
553
554
555
	int page_size;

	pic32mx_info->probed = 0;

	device_id = ejtag_info->idcode;
556
	LOG_INFO("device id = 0x%08" PRIx32 " (manuf 0x%03x dev 0x%02x, ver 0x%03x)",
duane's avatar
duane committed
557
			  device_id,
558
559
			  (unsigned)((device_id >> 1)&0x7ff),
			  (unsigned)((device_id >> 12)&0xff),
560
			  (unsigned)((device_id >> 20)&0xfff));
oharboe's avatar
oharboe committed
561

zwelch's avatar
zwelch committed
562
	if (((device_id >> 1)&0x7ff) != PIC32MX_MANUF_ID) {
563
		LOG_WARNING("Cannot identify target as a PIC32MX family.");
oharboe's avatar
oharboe committed
564
565
566
567
		return ERROR_FLASH_OPERATION_FAILED;
	}

	page_size = 4096;
zwelch's avatar
zwelch committed
568
	if (bank->base == PIC32MX_KSEG1_BOOT_FLASH || bank->base == 1) {
oharboe's avatar
oharboe committed
569
570
571
572
		/* 0xBFC00000: Boot flash size fixed at 12k */
		num_pages = 12;
	} else {
		/* 0xBD000000: Program flash size varies with device */
zwelch's avatar
zwelch committed
573
		for (i = 0; pic32mx_devs[i].name != NULL; i++)
zwelch's avatar
zwelch committed
574
			if (pic32mx_devs[i].devid == ((device_id >> 12) & 0xff)) {
oharboe's avatar
oharboe committed
575
576
577
				num_pages = pic32mx_devs[i].pfm_size;
				break;
			}
zwelch's avatar
zwelch committed
578
		if (pic32mx_devs[i].name == NULL) {
579
			LOG_WARNING("Cannot identify target as a PIC32MX family.");
oharboe's avatar
oharboe committed
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
			return ERROR_FLASH_OPERATION_FAILED;
		}
	}

#if 0
	if (bank->target->state != TARGET_HALTED)
	{
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	/* get flash size from target */
	if (target_read_u16(target, 0x1FFFF7E0, &num_pages) != ERROR_OK)
	{
		/* failed reading flash size, default to max target family */
		num_pages = 0xffff;
	}
#endif

599
	LOG_INFO("flash size = %dkbytes", num_pages);
oharboe's avatar
oharboe committed
600
601
602
603

	/* calculate numbers of pages */
	num_pages /= (page_size / 1024);

zwelch's avatar
zwelch committed
604
605
	if (bank->base == 0) bank->base = PIC32MX_KSEG1_PGM_FLASH;
	if (bank->base == 1) bank->base = PIC32MX_KSEG1_BOOT_FLASH;
oharboe's avatar
oharboe committed
606
607
608
609
	bank->size = (num_pages * page_size);
	bank->num_sectors = num_pages;
	bank->chip_width = 4;
	bank->bus_width  = 4;
610
	bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
oharboe's avatar
oharboe committed
611
612
613
614
615
616
617
618
619
620
621
622
623
624

	for (i = 0; i < num_pages; i++)
	{
		bank->sectors[i].offset = i * page_size;
		bank->sectors[i].size = page_size;
		bank->sectors[i].is_erased = -1;
		bank->sectors[i].is_protected = 1;
	}

	pic32mx_info->probed = 1;

	return ERROR_OK;
}

625
static int pic32mx_auto_probe(struct flash_bank *bank)
oharboe's avatar
oharboe committed
626
{
627
	struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv;
oharboe's avatar
oharboe committed
628
629
630
631
632
	if (pic32mx_info->probed)
		return ERROR_OK;
	return pic32mx_probe(bank);
}

mifi's avatar
mifi committed
633
#if 0
634
COMMAND_HANDLER(pic32mx_handle_part_id_command)
oharboe's avatar
oharboe committed
635
636
637
{
	return ERROR_OK;
}
mifi's avatar
mifi committed
638
#endif
oharboe's avatar
oharboe committed
639

640
static int pic32mx_info(struct flash_bank *bank, char *buf, int buf_size)
oharboe's avatar
oharboe committed
641
{
Zachary T Welch's avatar
Zachary T Welch committed
642
	struct target *target = bank->target;
643
	struct mips32_common *mips32 = target->arch_info;
644
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
645
	uint32_t device_id;
646
	int printed = 0, i;
oharboe's avatar
oharboe committed
647
648
649

	device_id = ejtag_info->idcode;

zwelch's avatar
zwelch committed
650
	if (((device_id >> 1)&0x7ff) != PIC32MX_MANUF_ID) {
651
652
653
		snprintf(buf, buf_size,
				 "Cannot identify target as a PIC32MX family (manufacturer 0x%03d != 0x%03d)\n",
				 (unsigned)((device_id >> 1)&0x7ff),
duane's avatar
duane committed
654
				 PIC32MX_MANUF_ID);
oharboe's avatar
oharboe committed
655
656
		return ERROR_FLASH_OPERATION_FAILED;
	}
zwelch's avatar
zwelch committed
657
	for (i = 0; pic32mx_devs[i].name != NULL; i++)
zwelch's avatar
zwelch committed
658
		if (pic32mx_devs[i].devid == ((device_id >> 12) & 0xff)) {
oharboe's avatar
oharboe committed
659
660
661
			printed = snprintf(buf, buf_size, "PIC32MX%s", pic32mx_devs[i].name);
			break;
		}
zwelch's avatar
zwelch committed
662
	if (pic32mx_devs[i].name == NULL) {
oharboe's avatar
oharboe committed
663
664
665
666
667
		snprintf(buf, buf_size, "Cannot identify target as a PIC32MX family\n");
		return ERROR_FLASH_OPERATION_FAILED;
	}
	buf += printed;
	buf_size -= printed;
668
	printed = snprintf(buf, buf_size, "  Ver: 0x%03x",
zwelch's avatar
zwelch committed
669
					   (unsigned)((device_id >> 20)&0xfff));
oharboe's avatar
oharboe committed
670
671
672
673
674

	return ERROR_OK;
}

#if 0
675
COMMAND_HANDLER(pic32mx_handle_lock_command)
oharboe's avatar
oharboe committed
676
{
Zachary T Welch's avatar
Zachary T Welch committed
677
	struct target *target = NULL;
678
	struct pic32mx_flash_bank *pic32mx_info = NULL;
oharboe's avatar
oharboe committed
679

680
	if (CMD_ARGC < 1)
oharboe's avatar
oharboe committed
681
	{
682
		command_print(CMD_CTX, "pic32mx lock <bank>");
oharboe's avatar
oharboe committed
683
684
685
		return ERROR_OK;
	}

686
	struct flash_bank *bank;
687
	int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
688
689
	if (ERROR_OK != retval)
		return retval;
oharboe's avatar
oharboe committed
690
691
692
693
694
695
696
697
698
699
700
701
702

	pic32mx_info = bank->driver_priv;

	target = bank->target;

	if (target->state != TARGET_HALTED)
	{
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	if (pic32mx_erase_options(bank) != ERROR_OK)
	{
703
		command_print(CMD_CTX, "pic32mx failed to erase options");
oharboe's avatar
oharboe committed
704
705
706
707
708
709
710
711
		return ERROR_OK;
	}

	/* set readout protection */
	pic32mx_info->option_bytes.RDP = 0;

	if (pic32mx_write_options(bank) != ERROR_OK)
	{
712
		command_print(CMD_CTX, "pic32mx failed to lock device");
oharboe's avatar
oharboe committed
713
714
715
		return ERROR_OK;
	}

716
	command_print(CMD_CTX, "pic32mx locked");
oharboe's avatar
oharboe committed
717
718
719
720

	return ERROR_OK;
}

721
COMMAND_HANDLER(pic32mx_handle_unlock_command)
oharboe's avatar
oharboe committed
722
{
Zachary T Welch's avatar
Zachary T Welch committed
723
	struct target *target = NULL;
724
	struct pic32mx_flash_bank *pic32mx_info = NULL;
oharboe's avatar
oharboe committed
725

726
	if (CMD_ARGC < 1)
oharboe's avatar
oharboe committed
727
	{
728
		command_print(CMD_CTX, "pic32mx unlock <bank>");
oharboe's avatar
oharboe committed
729
730
731
		return ERROR_OK;
	}

732
	struct flash_bank *bank;
733
	int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
734
735
	if (ERROR_OK != retval)
		return retval;
oharboe's avatar
oharboe committed
736
737
738
739
740
741
742
743
744
745
746
747
748

	pic32mx_info = bank->driver_priv;

	target = bank->target;

	if (target->state != TARGET_HALTED)
	{
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	if (pic32mx_erase_options(bank) != ERROR_OK)
	{
749
		command_print(CMD_CTX, "pic32mx failed to unlock device");
oharboe's avatar
oharboe committed
750
751
752
753
754
		return ERROR_OK;
	}

	if (pic32mx_write_options(bank) != ERROR_OK)
	{
755
		command_print(CMD_CTX, "pic32mx failed to lock device");
oharboe's avatar
oharboe committed
756
757
758
		return ERROR_OK;
	}

759
	command_print(CMD_CTX, "pic32mx unlocked");
oharboe's avatar
oharboe committed
760
761
762
763
764

	return ERROR_OK;
}
#endif

mifi's avatar
mifi committed
765
#if 0
766
static int pic32mx_chip_erase(struct flash_bank *bank)
oharboe's avatar
oharboe committed
767
{
Zachary T Welch's avatar
Zachary T Welch committed
768
	struct target *target = bank->target;
769
#if 0
770
	uint32_t status;
771
#endif
oharboe's avatar
oharboe committed
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787

	if (target->state != TARGET_HALTED)
	{
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	LOG_INFO("PIC32MX chip erase called");

#if 0
	/* unlock option flash registers */
	target_write_u32(target, PIC32MX_FLASH_KEYR, KEY1);
	target_write_u32(target, PIC32MX_FLASH_KEYR, KEY2);

	/* chip erase flash memory */
	target_write_u32(target, PIC32MX_FLASH_CR, FLASH_MER);
zwelch's avatar
zwelch committed
788
	target_write_u32(target, PIC32MX_FLASH_CR, FLASH_MER | FLASH_STRT);
oharboe's avatar
oharboe committed
789
790
791
792
793

	status = pic32mx_wait_status_busy(bank, 10);

	target_write_u32(target, PIC32MX_FLASH_CR, FLASH_LOCK);

794
	if (status & FLASH_WRPRTERR)
oharboe's avatar
oharboe committed
795
796
797
798
799
	{
		LOG_ERROR("pic32mx device protected");
		return ERROR_OK;
	}

800
	if (status & FLASH_PGERR)
oharboe's avatar
oharboe committed
801
802
803
804
805
806
807
808
	{
		LOG_ERROR("pic32mx device programming failed");
		return ERROR_OK;
	}
#endif

	return ERROR_OK;
}
mifi's avatar
mifi committed
809
#endif
oharboe's avatar
oharboe committed
810

811
COMMAND_HANDLER(pic32mx_handle_chip_erase_command)
oharboe's avatar
oharboe committed
812
{
813
#if 0
oharboe's avatar
oharboe committed
814
815
	int i;

816
	if (CMD_ARGC != 0)
oharboe's avatar
oharboe committed
817
	{
818
		command_print(CMD_CTX, "pic32mx chip_erase");
oharboe's avatar
oharboe committed
819
820
821
		return ERROR_OK;
	}

822
	struct flash_bank *bank;
823
	int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
824
825
	if (ERROR_OK != retval)
		return retval;
oharboe's avatar
oharboe committed
826
827
828
829
830
831
832
833
834

	if (pic32mx_chip_erase(bank) == ERROR_OK)
	{
		/* set all sectors as erased */
		for (i = 0; i < bank->num_sectors; i++)
		{
			bank->sectors[i].is_erased = 1;
		}

835
		command_print(CMD_CTX, "pic32mx chip erase complete");
oharboe's avatar
oharboe committed
836
837
838
	}
	else
	{
839
		command_print(CMD_CTX, "pic32mx chip erase failed");
oharboe's avatar
oharboe committed
840
841
842
843
844
845
	}
#endif

	return ERROR_OK;
}

846
COMMAND_HANDLER(pic32mx_handle_pgm_word_command)
oharboe's avatar
oharboe committed
847
{
848
	uint32_t address, value;
oharboe's avatar
oharboe committed
849
850
	int status, res;

851
	if (CMD_ARGC != 3)
oharboe's avatar
oharboe committed
852
	{
853
		command_print(CMD_CTX, "pic32mx pgm_word <addr> <value> <bank>");
oharboe's avatar
oharboe committed
854
855
856
		return ERROR_OK;
	}

857
858
	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
859

860
	struct flash_bank *bank;
861
	int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 2, &bank);
862
863
	if (ERROR_OK != retval)
		return retval;
oharboe's avatar
oharboe committed
864

zwelch's avatar
zwelch committed
865
	if (address < bank->base || address >= (bank->base + bank->size))
oharboe's avatar
oharboe committed
866
	{
867
		command_print(CMD_CTX, "flash address '%s' is out of bounds", CMD_ARGV[0]);
oharboe's avatar
oharboe committed
868
869
870
871
872
		return ERROR_OK;
	}

	res = ERROR_OK;
	status = pic32mx_write_word(bank, address, value);
873
	if (status & NVMCON_NVMERR)
oharboe's avatar
oharboe committed
874
		res = ERROR_FLASH_OPERATION_FAILED;
875
	if (status & NVMCON_LVDERR)
oharboe's avatar
oharboe committed
876
877
878
		res = ERROR_FLASH_OPERATION_FAILED;

	if (res == ERROR_OK)
879
		command_print(CMD_CTX, "pic32mx pgm word complete");
oharboe's avatar
oharboe committed
880
	else
881
		command_print(CMD_CTX, "pic32mx pgm word failed (status = 0x%x)", status);
oharboe's avatar
oharboe committed
882
883
884

	return ERROR_OK;
}
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
static const struct command_registration pic32mx_exec_command_handlers[] = {
	{
		.name = "chip_erase",
		.handler = &pic32mx_handle_chip_erase_command,
		.mode = COMMAND_EXEC,
		.help = "erase device",
	},
	{
		.name = "pgm_word",
		.handler = &pic32mx_handle_pgm_word_command,
		.mode = COMMAND_EXEC,
		.help = "program a word",
	},
	COMMAND_REGISTRATION_DONE
};
static const struct command_registration pic32mx_command_handlers[] = {
	{
		.name = "pic32mx",
		.mode = COMMAND_ANY,
		.help = "pic32mx flash command group",
		.chain = pic32mx_exec_command_handlers,
	},
	COMMAND_REGISTRATION_DONE
};
909

910
struct flash_driver pic32mx_flash = {
911
		.name = "pic32mx",
912
		.commands = pic32mx_command_handlers,
913
914
915
916
917
918
919
920
921
922
		.flash_bank_command = &pic32mx_flash_bank_command,
		.erase = &pic32mx_erase,
		.protect = &pic32mx_protect,
		.write = &pic32mx_write,
		.probe = &pic32mx_probe,
		.auto_probe = &pic32mx_auto_probe,
		.erase_check = &default_flash_mem_blank_check,
		.protect_check = &pic32mx_protect_check,
		.info = &pic32mx_info,
	};