pic32mx.c 25.7 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
/***************************************************************************
 *   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.             *
 ***************************************************************************/
26

oharboe's avatar
oharboe committed
27
28
29
30
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

Zachary T Welch's avatar
Zachary T Welch committed
31
#include "imp.h"
32
#include <target/algorithm.h>
33
#include <target/mips32.h>
Spencer Oliver's avatar
Spencer Oliver committed
34
#include <target/mips_m4k.h>
oharboe's avatar
oharboe committed
35

36
37
38
39
40
41
42
43
44
45
46
47
48
49
#define PIC32MX_MANUF_ID	0x029

/* pic32mx memory locations */

#define PIC32MX_PHYS_RAM			0x00000000
#define PIC32MX_PHYS_PGM_FLASH		0x1D000000
#define PIC32MX_PHYS_PERIPHERALS	0x1F800000
#define PIC32MX_PHYS_BOOT_FLASH		0x1FC00000

/*
 * Translate Virtual and Physical addresses.
 * Note: These macros only work for KSEG0/KSEG1 addresses.
 */

50
#define Virt2Phys(v)	((v) & 0x1FFFFFFF)
51
52
53

/* pic32mx configuration register locations */

54
#define PIC32MX_DEVCFG0_1_2	0xBFC00BFC
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#define PIC32MX_DEVCFG0		0xBFC02FFC
#define PIC32MX_DEVCFG1		0xBFC02FF8
#define PIC32MX_DEVCFG2		0xBFC02FF4
#define PIC32MX_DEVCFG3		0xBFC02FF0
#define PIC32MX_DEVID		0xBF80F220

#define PIC32MX_BMXPFMSZ	0xBF882060
#define PIC32MX_BMXBOOTSZ	0xBF882070
#define PIC32MX_BMXDRMSZ	0xBF882040

/* pic32mx flash controller register locations */

#define PIC32MX_NVMCON		0xBF80F400
#define PIC32MX_NVMCONCLR	0xBF80F404
#define PIC32MX_NVMCONSET	0xBF80F408
#define PIC32MX_NVMCONINV	0xBF80F40C
#define NVMCON_NVMWR		(1 << 15)
#define NVMCON_NVMWREN		(1 << 14)
#define NVMCON_NVMERR		(1 << 13)
#define NVMCON_LVDERR		(1 << 12)
#define NVMCON_LVDSTAT		(1 << 11)
#define NVMCON_OP_PFM_ERASE		0x5
#define NVMCON_OP_PAGE_ERASE	0x4
#define NVMCON_OP_ROW_PROG		0x3
#define NVMCON_OP_WORD_PROG		0x1
#define NVMCON_OP_NOP			0x0

#define PIC32MX_NVMKEY		0xBF80F410
#define PIC32MX_NVMADDR		0xBF80F420
#define PIC32MX_NVMADDRCLR	0xBF80F424
#define PIC32MX_NVMADDRSET	0xBF80F428
#define PIC32MX_NVMADDRINV	0xBF80F42C
#define PIC32MX_NVMDATA		0xBF80F430
#define PIC32MX_NVMSRCADDR	0xBF80F440

/* flash unlock keys */

#define NVMKEY1			0xAA996655
#define NVMKEY2			0x556699AA

95
96
#define MX_1_2			1	/* PIC32mx1xx/2xx */

97
struct pic32mx_flash_bank {
98
99
	struct working_area *write_algorithm;
	int probed;
100
	int dev_type;		/* Default 0. 1 for Pic32MX1XX/2XX variant */
101
102
};

103
/*
104
 * DEVID values as per PIC32MX Flash Programming Specification Rev J
105
106
 */

107
static const struct pic32mx_devs_s {
108
	uint32_t devid;
109
	const char *name;
oharboe's avatar
oharboe committed
110
} pic32mx_devs[] = {
111
112
113
114
115
116
	{0x04A07053, "110F016B"},
	{0x04A09053, "110F016C"},
	{0x04A0B053, "110F016D"},
	{0x04A06053, "120F032B"},
	{0x04A08053, "120F032C"},
	{0x04A0A053, "120F032D"},
117
118
119
120
121
122
	{0x04D07053, "130F064B"},
	{0x04D09053, "130F064C"},
	{0x04D0B053, "130F064D"},
	{0x04D06053, "150F128B"},
	{0x04D08053, "150F128C"},
	{0x04D0A053, "150F128D"},
123
124
125
126
127
128
	{0x04A01053, "210F016B"},
	{0x04A03053, "210F016C"},
	{0x04A05053, "210F016D"},
	{0x04A00053, "220F032B"},
	{0x04A02053, "220F032C"},
	{0x04A04053, "220F032D"},
129
130
131
132
133
134
	{0x04D01053, "230F064B"},
	{0x04D03053, "230F064C"},
	{0x04D05053, "230F064D"},
	{0x04D00053, "250F128B"},
	{0x04D02053, "250F128C"},
	{0x04D04053, "250F128D"},
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
	{0x00938053, "360F512L"},
	{0x00934053, "360F256L"},
	{0x0092D053, "340F128L"},
	{0x0092A053, "320F128L"},
	{0x00916053, "340F512H"},
	{0x00912053, "340F256H"},
	{0x0090D053, "340F128H"},
	{0x0090A053, "320F128H"},
	{0x00906053, "320F064H"},
	{0x00902053, "320F032H"},
	{0x00978053, "460F512L"},
	{0x00974053, "460F256L"},
	{0x0096D053, "440F128L"},
	{0x00952053, "440F256H"},
	{0x00956053, "440F512H"},
	{0x0094D053, "440F128H"},
	{0x00942053, "420F032H"},
	{0x04307053, "795F512L"},
	{0x0430E053, "795F512H"},
	{0x04306053, "775F512L"},
	{0x0430D053, "775F512H"},
	{0x04312053, "775F256L"},
	{0x04303053, "775F256H"},
	{0x04417053, "764F128L"},
	{0x0440B053, "764F128H"},
	{0x04341053, "695F512L"},
	{0x04325053, "695F512H"},
	{0x04311053, "675F512L"},
	{0x0430C053, "675F512H"},
	{0x04305053, "675F256L"},
	{0x0430B053, "675F256H"},
	{0x04413053, "664F128L"},
	{0x04407053, "664F128H"},
	{0x04411053, "664F064L"},
	{0x04405053, "664F064H"},
	{0x0430F053, "575F512L"},
	{0x04309053, "575F512H"},
	{0x04333053, "575F256L"},
	{0x04317053, "575F256H"},
	{0x0440F053, "564F128L"},
	{0x04403053, "564F128H"},
	{0x0440D053, "564F064L"},
	{0x04401053, "564F064H"},
	{0x04400053, "534F064H"},
	{0x0440C053, "534F064L"},
	{0x00000000, NULL}
oharboe's avatar
oharboe committed
181
182
183
184
};

/* flash bank pic32mx <base> <size> 0 0 <target#>
 */
185
FLASH_BANK_COMMAND_HANDLER(pic32mx_flash_bank_command)
oharboe's avatar
oharboe committed
186
{
187
	struct pic32mx_flash_bank *pic32mx_info;
oharboe's avatar
oharboe committed
188

189
	if (CMD_ARGC < 6)
Mathias K's avatar
Mathias K committed
190
		return ERROR_COMMAND_SYNTAX_ERROR;
oharboe's avatar
oharboe committed
191

192
	pic32mx_info = malloc(sizeof(struct pic32mx_flash_bank));
oharboe's avatar
oharboe committed
193
194
195
196
	bank->driver_priv = pic32mx_info;

	pic32mx_info->write_algorithm = NULL;
	pic32mx_info->probed = 0;
197
	pic32mx_info->dev_type = 0;
oharboe's avatar
oharboe committed
198
199
200
201

	return ERROR_OK;
}

202
static uint32_t pic32mx_get_flash_status(struct flash_bank *bank)
oharboe's avatar
oharboe committed
203
{
Zachary T Welch's avatar
Zachary T Welch committed
204
	struct target *target = bank->target;
205
	uint32_t status;
oharboe's avatar
oharboe committed
206
207
208
209
210
211

	target_read_u32(target, PIC32MX_NVMCON, &status);

	return status;
}

212
static uint32_t pic32mx_wait_status_busy(struct flash_bank *bank, int timeout)
oharboe's avatar
oharboe committed
213
{
214
	uint32_t status;
oharboe's avatar
oharboe committed
215
216

	/* wait for busy to clear */
217
	while (((status = pic32mx_get_flash_status(bank)) & NVMCON_NVMWR) && (timeout-- > 0)) {
218
		LOG_DEBUG("status: 0x%" PRIx32, status);
oharboe's avatar
oharboe committed
219
220
		alive_sleep(1);
	}
zwelch's avatar
zwelch committed
221
	if (timeout <= 0)
222
		LOG_DEBUG("timeout: status: 0x%" PRIx32, status);
oharboe's avatar
oharboe committed
223
224
225
226

	return status;
}

227
static int pic32mx_nvm_exec(struct flash_bank *bank, uint32_t op, uint32_t timeout)
oharboe's avatar
oharboe committed
228
{
Zachary T Welch's avatar
Zachary T Welch committed
229
	struct target *target = bank->target;
230
	uint32_t status;
oharboe's avatar
oharboe committed
231

zwelch's avatar
zwelch committed
232
	target_write_u32(target, PIC32MX_NVMCON, NVMCON_NVMWREN | op);
oharboe's avatar
oharboe committed
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248

	/* 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;
}

249
static int pic32mx_protect_check(struct flash_bank *bank)
oharboe's avatar
oharboe committed
250
{
Zachary T Welch's avatar
Zachary T Welch committed
251
	struct target *target = bank->target;
252
	struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv;
oharboe's avatar
oharboe committed
253

254
	uint32_t config0_address;
255
	uint32_t devcfg0;
oharboe's avatar
oharboe committed
256
257
258
	int s;
	int num_pages;

259
	if (target->state != TARGET_HALTED) {
oharboe's avatar
oharboe committed
260
261
262
263
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

264
265
266
267
268
269
	if (pic32mx_info->dev_type == MX_1_2)
		config0_address = PIC32MX_DEVCFG0_1_2;
	else
		config0_address = PIC32MX_DEVCFG0;

	target_read_u32(target, config0_address, &devcfg0);
270

zwelch's avatar
zwelch committed
271
	if ((devcfg0 & (1 << 28)) == 0) /* code protect bit */
272
273
		num_pages = 0xffff;			/* All pages protected */
	else if (Virt2Phys(bank->base) == PIC32MX_PHYS_BOOT_FLASH) {
zwelch's avatar
zwelch committed
274
		if (devcfg0 & (1 << 24))
275
			num_pages = 0;			/* All pages unprotected */
oharboe's avatar
oharboe committed
276
		else
277
278
			num_pages = 0xffff;		/* All pages protected */
	} else /* pgm flash */
oharboe's avatar
oharboe committed
279
		num_pages = (~devcfg0 >> 12) & 0xff;
280

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

289
static int pic32mx_erase(struct flash_bank *bank, int first, int last)
oharboe's avatar
oharboe committed
290
{
Zachary T Welch's avatar
Zachary T Welch committed
291
	struct target *target = bank->target;
oharboe's avatar
oharboe committed
292
	int i;
293
	uint32_t status;
oharboe's avatar
oharboe committed
294

295
	if (bank->target->state != TARGET_HALTED) {
oharboe's avatar
oharboe committed
296
297
298
299
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

300
	if ((first == 0) && (last == (bank->num_sectors - 1))
301
		&& (Virt2Phys(bank->base) == PIC32MX_PHYS_PGM_FLASH)) {
302
303
		/* this will only erase the Program Flash (PFM), not the Boot Flash (BFM)
		 * we need to use the MTAP to perform a full erase */
304
		LOG_DEBUG("Erasing entire program flash");
oharboe's avatar
oharboe committed
305
		status = pic32mx_nvm_exec(bank, NVMCON_OP_PFM_ERASE, 50);
306
		if (status & NVMCON_NVMERR)
oharboe's avatar
oharboe committed
307
			return ERROR_FLASH_OPERATION_FAILED;
308
		if (status & NVMCON_LVDERR)
oharboe's avatar
oharboe committed
309
310
311
312
			return ERROR_FLASH_OPERATION_FAILED;
		return ERROR_OK;
	}

313
	for (i = first; i <= last; i++) {
314
		target_write_u32(target, PIC32MX_NVMADDR, Virt2Phys(bank->base + bank->sectors[i].offset));
oharboe's avatar
oharboe committed
315
316
317

		status = pic32mx_nvm_exec(bank, NVMCON_OP_PAGE_ERASE, 10);

318
		if (status & NVMCON_NVMERR)
oharboe's avatar
oharboe committed
319
			return ERROR_FLASH_OPERATION_FAILED;
320
		if (status & NVMCON_LVDERR)
oharboe's avatar
oharboe committed
321
322
323
324
325
326
327
			return ERROR_FLASH_OPERATION_FAILED;
		bank->sectors[i].is_erased = 1;
	}

	return ERROR_OK;
}

328
static int pic32mx_protect(struct flash_bank *bank, int set, int first, int last)
oharboe's avatar
oharboe committed
329
{
Zachary T Welch's avatar
Zachary T Welch committed
330
	struct target *target = bank->target;
oharboe's avatar
oharboe committed
331

332
	if (target->state != TARGET_HALTED) {
oharboe's avatar
oharboe committed
333
334
335
336
337
338
339
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	return ERROR_OK;
}

340
341
/* see contib/loaders/flash/pic32mx.s for src */

342
static uint32_t pic32mx_flash_write_code[] = {
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
					/* write: */
	0x3C08AA99,		/* lui $t0, 0xaa99 */
	0x35086655,		/* ori $t0, 0x6655 */
	0x3C095566,		/* lui $t1, 0x5566 */
	0x352999AA,		/* ori $t1, 0x99aa */
	0x3C0ABF80,		/* lui $t2, 0xbf80 */
	0x354AF400,		/* ori $t2, 0xf400 */
	0x340B4003,		/* ori $t3, $zero, 0x4003 */
	0x340C8000,		/* ori $t4, $zero, 0x8000 */
					/* write_row: */
	0x2CD30080,		/* sltiu $s3, $a2, 128 */
	0x16600008,		/* bne $s3, $zero, write_word */
	0x340D4000,		/* ori $t5, $zero, 0x4000 */
	0xAD450020,		/* sw $a1, 32($t2) */
	0xAD440040,		/* sw $a0, 64($t2) */
	0x04110016,		/* bal progflash */
	0x24840200,		/* addiu $a0, $a0, 512 */
	0x24A50200,		/* addiu $a1, $a1, 512 */
	0x1000FFF7,		/* beq $zero, $zero, write_row */
	0x24C6FF80,		/* addiu $a2, $a2, -128 */
					/* write_word: */
	0x3C15A000,		/* lui $s5, 0xa000 */
	0x36B50000,		/* ori $s5, $s5, 0x0 */
	0x00952025,		/* or $a0, $a0, $s5 */
	0x10000008,		/* beq $zero, $zero, next_word */
	0x340B4001,		/* ori $t3, $zero, 0x4001 */
					/* prog_word: */
	0x8C940000,		/* lw $s4, 0($a0) */
	0xAD540030,		/* sw $s4, 48($t2) */
	0xAD450020,		/* sw $a1, 32($t2) */
	0x04110009,		/* bal progflash */
	0x24840004,		/* addiu $a0, $a0, 4 */
	0x24A50004,		/* addiu $a1, $a1, 4 */
	0x24C6FFFF,		/* addiu $a2, $a2, -1 */
					/* next_word: */
	0x14C0FFF8,		/* bne $a2, $zero, prog_word */
	0x00000000,		/* nop */
					/* done: */
	0x10000002,		/* beq $zero, $zero, exit */
	0x24040000,		/* addiu $a0, $zero, 0 */
					/* error: */
	0x26240000,		/* addiu $a0, $s1, 0 */
					/* exit: */
	0x7000003F,		/* sdbbp */
					/* progflash: */
	0xAD4B0000,		/* sw $t3, 0($t2) */
	0xAD480010,		/* sw $t0, 16($t2) */
	0xAD490010,		/* sw $t1, 16($t2) */
	0xAD4C0008,		/* sw $t4, 8($t2) */
					/* waitflash: */
	0x8D500000,		/* lw $s0, 0($t2) */
	0x020C8024,		/* and $s0, $s0, $t4 */
	0x1600FFFD,		/* bne $s0, $zero, waitflash */
	0x00000000,		/* nop */
	0x00000000,		/* nop */
398
	0x00000000,		/* nop */
399
400
401
402
403
404
405
406
407
408
409
410
	0x00000000,		/* nop */
	0x00000000,		/* nop */
	0x8D510000,		/* lw $s1, 0($t2) */
	0x30113000,		/* andi $s1, $zero, 0x3000 */
	0x1620FFEF,		/* bne $s1, $zero, error */
	0xAD4D0004,		/* sw $t5, 4($t2) */
	0x03E00008,		/* jr $ra */
	0x00000000		/* nop */
};

static int pic32mx_write_block(struct flash_bank *bank, uint8_t *buffer,
		uint32_t offset, uint32_t count)
oharboe's avatar
oharboe committed
411
{
Zachary T Welch's avatar
Zachary T Welch committed
412
	struct target *target = bank->target;
413
	uint32_t buffer_size = 16384;
414
	struct working_area *source;
415
	uint32_t address = bank->base + offset;
416
	struct reg_param reg_params[3];
417
	int retval = ERROR_OK;
418

419
	struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv;
420
	struct mips32_algorithm mips32_info;
oharboe's avatar
oharboe committed
421
422

	/* flash write code */
423
	if (target_alloc_working_area(target, sizeof(pic32mx_flash_write_code),
424
			&pic32mx_info->write_algorithm) != ERROR_OK) {
oharboe's avatar
oharboe committed
425
426
427
428
		LOG_WARNING("no working area available, can't do block memory writes");
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	};

429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
	/* Change values for counters and row size, depending on variant */
	if (pic32mx_info->dev_type == MX_1_2) {
		/* 128 byte row */
		pic32mx_flash_write_code[8] = 0x2CD30020;
		pic32mx_flash_write_code[14] = 0x24840080;
		pic32mx_flash_write_code[15] = 0x24A50080;
		pic32mx_flash_write_code[17] = 0x24C6FFE0;
	} else {
		/* 512 byte row */
		pic32mx_flash_write_code[8] = 0x2CD30080;
		pic32mx_flash_write_code[14] = 0x24840200;
		pic32mx_flash_write_code[15] = 0x24A50200;
		pic32mx_flash_write_code[17] = 0x24C6FF80;
	}

444
445
446
	retval = target_write_buffer(target, pic32mx_info->write_algorithm->address,
			sizeof(pic32mx_flash_write_code), (uint8_t *)pic32mx_flash_write_code);
	if (retval != ERROR_OK)
oharboe's avatar
oharboe committed
447
448
449
		return retval;

	/* memory buffer */
450
	while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
451
		buffer_size /= 2;
452
		if (buffer_size <= 256) {
453
454
455
456
			/* 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);
oharboe's avatar
oharboe committed
457

458
459
460
461
462
463
464
			LOG_WARNING("no large enough working area available, can't do block memory writes");
			return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
		}
	};

	mips32_info.common_magic = MIPS32_COMMON_MAGIC;
	mips32_info.isa_mode = MIPS32_ISA_MIPS32;
oharboe's avatar
oharboe committed
465

466
467
468
469
	init_reg_param(&reg_params[0], "a0", 32, PARAM_IN_OUT);
	init_reg_param(&reg_params[1], "a1", 32, PARAM_OUT);
	init_reg_param(&reg_params[2], "a2", 32, PARAM_OUT);

470
	while (count > 0) {
471
		uint32_t status;
472
473
		uint32_t thisrun_count = (count > (buffer_size / 4)) ?
				(buffer_size / 4) : count;
oharboe's avatar
oharboe committed
474

475
476
477
		retval = target_write_buffer(target, source->address,
				thisrun_count * 4, buffer);
		if (retval != ERROR_OK)
oharboe's avatar
oharboe committed
478
479
			break;

480
481
482
		buf_set_u32(reg_params[0].value, 0, 32, Virt2Phys(source->address));
		buf_set_u32(reg_params[1].value, 0, 32, Virt2Phys(address));
		buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);
oharboe's avatar
oharboe committed
483

484
		retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
485
				pic32mx_info->write_algorithm->address,
486
487
				0, 10000, &mips32_info);
		if (retval != ERROR_OK) {
oharboe's avatar
oharboe committed
488
489
490
491
492
			LOG_ERROR("error executing pic32mx flash write algorithm");
			retval = ERROR_FLASH_OPERATION_FAILED;
			break;
		}

493
494
		status = buf_get_u32(reg_params[0].value, 0, 32);

495
		if (status & NVMCON_NVMERR) {
zwelch's avatar
zwelch committed
496
			LOG_ERROR("Flash write error NVMERR (status = 0x%08" PRIx32 ")", status);
497
498
499
			retval = ERROR_FLASH_OPERATION_FAILED;
			break;
		}
500

501
		if (status & NVMCON_LVDERR) {
zwelch's avatar
zwelch committed
502
			LOG_ERROR("Flash write error LVDERR (status = 0x%08" PRIx32 ")", status);
503
504
505
			retval = ERROR_FLASH_OPERATION_FAILED;
			break;
		}
oharboe's avatar
oharboe committed
506

507
508
509
		buffer += thisrun_count * 4;
		address += thisrun_count * 4;
		count -= thisrun_count;
oharboe's avatar
oharboe committed
510
511
512
	}

	target_free_working_area(target, source);
513
	target_free_working_area(target, pic32mx_info->write_algorithm);
oharboe's avatar
oharboe committed
514

515
516
517
	destroy_reg_param(&reg_params[0]);
	destroy_reg_param(&reg_params[1]);
	destroy_reg_param(&reg_params[2]);
oharboe's avatar
oharboe committed
518
519
520
521

	return retval;
}

522
static int pic32mx_write_word(struct flash_bank *bank, uint32_t address, uint32_t word)
oharboe's avatar
oharboe committed
523
{
Zachary T Welch's avatar
Zachary T Welch committed
524
	struct target *target = bank->target;
oharboe's avatar
oharboe committed
525

526
	target_write_u32(target, PIC32MX_NVMADDR, Virt2Phys(address));
oharboe's avatar
oharboe committed
527
528
529
530
531
	target_write_u32(target, PIC32MX_NVMDATA, word);

	return pic32mx_nvm_exec(bank, NVMCON_OP_WORD_PROG, 5);
}

532
static int pic32mx_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
533
{
534
535
536
537
538
	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;
539
	int retval;
oharboe's avatar
oharboe committed
540

541
	if (bank->target->state != TARGET_HALTED) {
oharboe's avatar
oharboe committed
542
543
544
545
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

546
547
548
	LOG_DEBUG("writing to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32
			" count: 0x%8.8" PRIx32 "", bank->base, offset, count);

549
	if (offset & 0x3) {
duane's avatar
duane committed
550
		LOG_WARNING("offset 0x%" PRIx32 "breaks required 4-byte alignment", offset);
oharboe's avatar
oharboe committed
551
552
553
554
		return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
	}

	/* multiple words (4-byte) to be programmed? */
555
	if (words_remaining > 0) {
oharboe's avatar
oharboe committed
556
		/* try using a block write */
557
558
559
		retval = pic32mx_write_block(bank, buffer, offset, words_remaining);
		if (retval != ERROR_OK) {
			if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
oharboe's avatar
oharboe committed
560
561
562
				/* 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");
563
			} else if (retval == ERROR_FLASH_OPERATION_FAILED) {
564
565
				LOG_ERROR("flash writing failed");
				return retval;
oharboe's avatar
oharboe committed
566
			}
567
		} else {
oharboe's avatar
oharboe committed
568
569
570
571
572
573
			buffer += words_remaining * 4;
			address += words_remaining * 4;
			words_remaining = 0;
		}
	}

574
	while (words_remaining > 0) {
575
576
		uint32_t value;
		memcpy(&value, buffer + bytes_written, sizeof(uint32_t));
oharboe's avatar
oharboe committed
577

578
		status = pic32mx_write_word(bank, address, value);
579

580
		if (status & NVMCON_NVMERR) {
581
			LOG_ERROR("Flash write error NVMERR (status = 0x%08" PRIx32 ")", status);
oharboe's avatar
oharboe committed
582
			return ERROR_FLASH_OPERATION_FAILED;
583
584
		}

585
		if (status & NVMCON_LVDERR) {
586
			LOG_ERROR("Flash write error LVDERR (status = 0x%08" PRIx32 ")", status);
oharboe's avatar
oharboe committed
587
			return ERROR_FLASH_OPERATION_FAILED;
588
		}
oharboe's avatar
oharboe committed
589
590
591
592
593
594

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

595
	if (bytes_remaining) {
596
		uint32_t value = 0xffffffff;
597
		memcpy(&value, buffer + bytes_written, bytes_remaining);
oharboe's avatar
oharboe committed
598

599
		status = pic32mx_write_word(bank, address, value);
600

601
		if (status & NVMCON_NVMERR) {
602
			LOG_ERROR("Flash write error NVMERR (status = 0x%08" PRIx32 ")", status);
oharboe's avatar
oharboe committed
603
			return ERROR_FLASH_OPERATION_FAILED;
604
605
		}

606
		if (status & NVMCON_LVDERR) {
607
			LOG_ERROR("Flash write error LVDERR (status = 0x%08" PRIx32 ")", status);
oharboe's avatar
oharboe committed
608
			return ERROR_FLASH_OPERATION_FAILED;
609
		}
oharboe's avatar
oharboe committed
610
611
612
613
614
	}

	return ERROR_OK;
}

615
static int pic32mx_probe(struct flash_bank *bank)
oharboe's avatar
oharboe committed
616
{
Zachary T Welch's avatar
Zachary T Welch committed
617
	struct target *target = bank->target;
618
	struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv;
619
	struct mips32_common *mips32 = target->arch_info;
620
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
oharboe's avatar
oharboe committed
621
	int i;
622
	uint32_t num_pages = 0;
623
	uint32_t device_id;
oharboe's avatar
oharboe committed
624
625
626
627
628
	int page_size;

	pic32mx_info->probed = 0;

	device_id = ejtag_info->idcode;
629
	LOG_INFO("device id = 0x%08" PRIx32 " (manuf 0x%03x dev 0x%04x, ver 0x%02x)",
duane's avatar
duane committed
630
			  device_id,
631
			  (unsigned)((device_id >> 1) & 0x7ff),
632
			  (unsigned)((device_id >> 12) & 0xffff),
633
			  (unsigned)((device_id >> 28) & 0xf));
oharboe's avatar
oharboe committed
634

635
	if (((device_id >> 1) & 0x7ff) != PIC32MX_MANUF_ID) {
636
		LOG_WARNING("Cannot identify target as a PIC32MX family.");
oharboe's avatar
oharboe committed
637
638
639
		return ERROR_FLASH_OPERATION_FAILED;
	}

640
641
642
643
644
645
646
647
648
649
650
651
652
653
	/* Check for PIC32mx1xx/2xx */
	for (i = 0; pic32mx_devs[i].name != NULL; i++) {
		if (pic32mx_devs[i].devid == (device_id & 0x0fffffff)) {
			if ((*(pic32mx_devs[i].name) == '1') || (*(pic32mx_devs[i].name) == '2'))
				pic32mx_info->dev_type = MX_1_2;
			break;
		}
	}

	if (pic32mx_info->dev_type == MX_1_2)
		page_size = 1024;
	else
		page_size = 4096;

oharboe's avatar
oharboe committed
654

655
	if (Virt2Phys(bank->base) == PIC32MX_PHYS_BOOT_FLASH) {
656
657
658
659
660
661
662
663
664
665
666
		/* 0x1FC00000: Boot flash size */
#if 0
		/* for some reason this register returns 8k for the boot bank size
		 * this does not match the docs, so for now set the boot bank at a
		 * fixed 12k */
		if (target_read_u32(target, PIC32MX_BMXBOOTSZ, &num_pages) != ERROR_OK) {
			LOG_WARNING("PIC32MX flash size failed, probe inaccurate - assuming 12k flash");
			num_pages = (12 * 1024);
		}
#else
		/* fixed 12k boot bank - see comments above */
667
668
669
670
		if (pic32mx_info->dev_type == MX_1_2)
			num_pages = (3 * 1024);
		else
			num_pages = (12 * 1024);
671
#endif
672
	} else {
673
674
		/* read the flash size from the device */
		if (target_read_u32(target, PIC32MX_BMXPFMSZ, &num_pages) != ERROR_OK) {
675
676
677
678
679
680
681
			if (pic32mx_info->dev_type == MX_1_2) {
				LOG_WARNING("PIC32MX flash size failed, probe inaccurate - assuming 32k flash");
				num_pages = (32 * 1024);
			} else {
				LOG_WARNING("PIC32MX flash size failed, probe inaccurate - assuming 512k flash");
				num_pages = (512 * 1024);
			}
682
		}
oharboe's avatar
oharboe committed
683
684
	}

685
	LOG_INFO("flash size = %" PRId32 "kbytes", num_pages / 1024);
oharboe's avatar
oharboe committed
686

687
	if (bank->sectors) {
688
689
690
691
		free(bank->sectors);
		bank->sectors = NULL;
	}

oharboe's avatar
oharboe committed
692
	/* calculate numbers of pages */
693
	num_pages /= page_size;
oharboe's avatar
oharboe committed
694
695
	bank->size = (num_pages * page_size);
	bank->num_sectors = num_pages;
696
	bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
oharboe's avatar
oharboe committed
697

698
	for (i = 0; i < (int)num_pages; i++) {
oharboe's avatar
oharboe committed
699
700
701
702
703
704
705
706
707
708
709
		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;
}

710
static int pic32mx_auto_probe(struct flash_bank *bank)
oharboe's avatar
oharboe committed
711
{
712
	struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv;
oharboe's avatar
oharboe committed
713
714
715
716
717
	if (pic32mx_info->probed)
		return ERROR_OK;
	return pic32mx_probe(bank);
}

718
static int pic32mx_info(struct flash_bank *bank, char *buf, int buf_size)
oharboe's avatar
oharboe committed
719
{
Zachary T Welch's avatar
Zachary T Welch committed
720
	struct target *target = bank->target;
721
	struct mips32_common *mips32 = target->arch_info;
722
	struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
723
	uint32_t device_id;
724
	int printed = 0, i;
oharboe's avatar
oharboe committed
725
726
727

	device_id = ejtag_info->idcode;

728
	if (((device_id >> 1) & 0x7ff) != PIC32MX_MANUF_ID) {
729
730
		snprintf(buf, buf_size,
				 "Cannot identify target as a PIC32MX family (manufacturer 0x%03d != 0x%03d)\n",
731
				 (unsigned)((device_id >> 1) & 0x7ff),
duane's avatar
duane committed
732
				 PIC32MX_MANUF_ID);
oharboe's avatar
oharboe committed
733
734
		return ERROR_FLASH_OPERATION_FAILED;
	}
735

736
	for (i = 0; pic32mx_devs[i].name != NULL; i++) {
737
		if (pic32mx_devs[i].devid == (device_id & 0x0fffffff)) {
oharboe's avatar
oharboe committed
738
739
740
741
742
			printed = snprintf(buf, buf_size, "PIC32MX%s", pic32mx_devs[i].name);
			break;
		}
	}

743
	if (pic32mx_devs[i].name == NULL)
744
		printed = snprintf(buf, buf_size, "Unknown");
oharboe's avatar
oharboe committed
745

746
747
	buf += printed;
	buf_size -= printed;
748
	snprintf(buf, buf_size, " Ver: 0x%02x",
749
			(unsigned)((device_id >> 28) & 0xf));
oharboe's avatar
oharboe committed
750
751
752
753

	return ERROR_OK;
}

754
COMMAND_HANDLER(pic32mx_handle_pgm_word_command)
oharboe's avatar
oharboe committed
755
{
756
	uint32_t address, value;
oharboe's avatar
oharboe committed
757
758
	int status, res;

759
	if (CMD_ARGC != 3)
Mathias K's avatar
Mathias K committed
760
		return ERROR_COMMAND_SYNTAX_ERROR;
oharboe's avatar
oharboe committed
761

762
763
	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
764

765
	struct flash_bank *bank;
766
	int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 2, &bank);
767
768
	if (ERROR_OK != retval)
		return retval;
oharboe's avatar
oharboe committed
769

770
	if (address < bank->base || address >= (bank->base + bank->size)) {
771
		command_print(CMD_CTX, "flash address '%s' is out of bounds", CMD_ARGV[0]);
oharboe's avatar
oharboe committed
772
773
774
775
776
		return ERROR_OK;
	}

	res = ERROR_OK;
	status = pic32mx_write_word(bank, address, value);
777
	if (status & NVMCON_NVMERR)
oharboe's avatar
oharboe committed
778
		res = ERROR_FLASH_OPERATION_FAILED;
779
	if (status & NVMCON_LVDERR)
oharboe's avatar
oharboe committed
780
781
782
		res = ERROR_FLASH_OPERATION_FAILED;

	if (res == ERROR_OK)
783
		command_print(CMD_CTX, "pic32mx pgm word complete");
oharboe's avatar
oharboe committed
784
	else
785
		command_print(CMD_CTX, "pic32mx pgm word failed (status = 0x%x)", status);
oharboe's avatar
oharboe committed
786
787
788

	return ERROR_OK;
}
789

Spencer Oliver's avatar
Spencer Oliver committed
790
791
792
793
794
795
796
797
COMMAND_HANDLER(pic32mx_handle_unlock_command)
{
	uint32_t mchip_cmd;
	struct target *target = NULL;
	struct mips_m4k_common *mips_m4k;
	struct mips_ejtag *ejtag_info;
	int timeout = 10;

798
	if (CMD_ARGC < 1) {
Spencer Oliver's avatar
Spencer Oliver committed
799
		command_print(CMD_CTX, "pic32mx unlock <bank>");
Mathias K's avatar
Mathias K committed
800
		return ERROR_COMMAND_SYNTAX_ERROR;
Spencer Oliver's avatar
Spencer Oliver committed
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
	}

	struct flash_bank *bank;
	int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
	if (ERROR_OK != retval)
		return retval;

	target = bank->target;
	mips_m4k = target_to_m4k(target);
	ejtag_info = &mips_m4k->mips32.ejtag_info;

	/* we have to use the MTAP to perform a full erase */
	mips_ejtag_set_instr(ejtag_info, MTAP_SW_MTAP);
	mips_ejtag_set_instr(ejtag_info, MTAP_COMMAND);

	/* first check status of device */
	mchip_cmd = MCHP_STATUS;
	mips_ejtag_drscan_8(ejtag_info, &mchip_cmd);
819
	if (mchip_cmd & (1 << 7)) {
Spencer Oliver's avatar
Spencer Oliver committed
820
821
822
823
824
		/* device is not locked */
		command_print(CMD_CTX, "pic32mx is already unlocked, erasing anyway");
	}

	/* unlock/erase device */
825
	mips_ejtag_drscan_8_out(ejtag_info, MCHP_ASERT_RST);
Spencer Oliver's avatar
Spencer Oliver committed
826

827
	mips_ejtag_drscan_8_out(ejtag_info, MCHP_ERASE);
Spencer Oliver's avatar
Spencer Oliver committed
828
829
830
831

	do {
		mchip_cmd = MCHP_STATUS;
		mips_ejtag_drscan_8(ejtag_info, &mchip_cmd);
832
		if (timeout-- == 0) {
Spencer Oliver's avatar
Spencer Oliver committed
833
834
835
836
837
838
			LOG_DEBUG("timeout waiting for unlock: 0x%" PRIx32 "", mchip_cmd);
			break;
		}
		alive_sleep(1);
	} while ((mchip_cmd & (1 << 2)) || (!(mchip_cmd & (1 << 3))));

839
	mips_ejtag_drscan_8_out(ejtag_info, MCHP_DE_ASSERT_RST);
Spencer Oliver's avatar
Spencer Oliver committed
840
841
842
843
844
845
846
847
848
849
850

	/* select ejtag tap */
	mips_ejtag_set_instr(ejtag_info, MTAP_SW_ETAP);

	command_print(CMD_CTX, "pic32mx unlocked.\n"
			"INFO: a reset or power cycle is required "
			"for the new settings to take effect.");

	return ERROR_OK;
}

851
852
853
static const struct command_registration pic32mx_exec_command_handlers[] = {
	{
		.name = "pgm_word",
Mathias K's avatar
Mathias K committed
854
		.usage = "<addr> <value> <bank>",
David Brownell's avatar
David Brownell committed
855
		.handler = pic32mx_handle_pgm_word_command,
856
857
858
		.mode = COMMAND_EXEC,
		.help = "program a word",
	},
Spencer Oliver's avatar
Spencer Oliver committed
859
860
861
862
863
864
865
	{
		.name = "unlock",
		.handler = pic32mx_handle_unlock_command,
		.mode = COMMAND_EXEC,
		.usage = "[bank_id]",
		.help = "Unlock/Erase entire device.",
	},
866
867
	COMMAND_REGISTRATION_DONE
};
868

869
870
871
872
873
static const struct command_registration pic32mx_command_handlers[] = {
	{
		.name = "pic32mx",
		.mode = COMMAND_ANY,
		.help = "pic32mx flash command group",
Spencer Oliver's avatar
Spencer Oliver committed
874
		.usage = "",
875
876
877
878
		.chain = pic32mx_exec_command_handlers,
	},
	COMMAND_REGISTRATION_DONE
};
879

880
struct flash_driver pic32mx_flash = {
David Brownell's avatar
David Brownell committed
881
882
883
884
885
886
	.name = "pic32mx",
	.commands = pic32mx_command_handlers,
	.flash_bank_command = pic32mx_flash_bank_command,
	.erase = pic32mx_erase,
	.protect = pic32mx_protect,
	.write = pic32mx_write,
887
	.read = default_flash_read,
David Brownell's avatar
David Brownell committed
888
889
890
891
892
893
	.probe = pic32mx_probe,
	.auto_probe = pic32mx_auto_probe,
	.erase_check = default_flash_mem_blank_check,
	.protect_check = pic32mx_protect_check,
	.info = pic32mx_info,
};