pic32mx.c 25.8 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
			num_pages = 0xffff;		/* All pages protected */
278
279
280
281
282
283
284
	} else {
		/* pgm flash */
		if (pic32mx_info->dev_type == MX_1_2)
			num_pages = (~devcfg0 >> 10) & 0x3f;
		else
			num_pages = (~devcfg0 >> 12) & 0xff;
	}
285

oharboe's avatar
oharboe committed
286
287
288
289
290
291
292
293
	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;
}

294
static int pic32mx_erase(struct flash_bank *bank, int first, int last)
oharboe's avatar
oharboe committed
295
{
Zachary T Welch's avatar
Zachary T Welch committed
296
	struct target *target = bank->target;
oharboe's avatar
oharboe committed
297
	int i;
298
	uint32_t status;
oharboe's avatar
oharboe committed
299

300
	if (bank->target->state != TARGET_HALTED) {
oharboe's avatar
oharboe committed
301
302
303
304
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

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

318
	for (i = first; i <= last; i++) {
319
		target_write_u32(target, PIC32MX_NVMADDR, Virt2Phys(bank->base + bank->sectors[i].offset));
oharboe's avatar
oharboe committed
320
321
322

		status = pic32mx_nvm_exec(bank, NVMCON_OP_PAGE_ERASE, 10);

323
		if (status & NVMCON_NVMERR)
oharboe's avatar
oharboe committed
324
			return ERROR_FLASH_OPERATION_FAILED;
325
		if (status & NVMCON_LVDERR)
oharboe's avatar
oharboe committed
326
327
328
329
330
331
332
			return ERROR_FLASH_OPERATION_FAILED;
		bank->sectors[i].is_erased = 1;
	}

	return ERROR_OK;
}

333
static int pic32mx_protect(struct flash_bank *bank, int set, int first, int last)
oharboe's avatar
oharboe committed
334
{
Zachary T Welch's avatar
Zachary T Welch committed
335
	struct target *target = bank->target;
oharboe's avatar
oharboe committed
336

337
	if (target->state != TARGET_HALTED) {
oharboe's avatar
oharboe committed
338
339
340
341
342
343
344
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	return ERROR_OK;
}

345
346
/* see contib/loaders/flash/pic32mx.s for src */

347
static uint32_t pic32mx_flash_write_code[] = {
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
398
399
400
401
402
					/* 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 */
403
	0x00000000,		/* nop */
404
405
406
407
408
409
410
411
412
413
414
415
	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
416
{
Zachary T Welch's avatar
Zachary T Welch committed
417
	struct target *target = bank->target;
418
	uint32_t buffer_size = 16384;
419
	struct working_area *source;
420
	uint32_t address = bank->base + offset;
421
	struct reg_param reg_params[3];
422
	int retval = ERROR_OK;
423

424
	struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv;
425
	struct mips32_algorithm mips32_info;
oharboe's avatar
oharboe committed
426
427

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

434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
	/* 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;
	}

449
450
451
	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
452
453
454
		return retval;

	/* memory buffer */
455
	while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
456
		buffer_size /= 2;
457
		if (buffer_size <= 256) {
458
459
460
461
			/* 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
462

463
464
465
466
467
468
469
			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
470

471
472
473
474
	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);

475
	while (count > 0) {
476
		uint32_t status;
477
478
		uint32_t thisrun_count = (count > (buffer_size / 4)) ?
				(buffer_size / 4) : count;
oharboe's avatar
oharboe committed
479

480
481
482
		retval = target_write_buffer(target, source->address,
				thisrun_count * 4, buffer);
		if (retval != ERROR_OK)
oharboe's avatar
oharboe committed
483
484
			break;

485
486
487
		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
488

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

498
499
		status = buf_get_u32(reg_params[0].value, 0, 32);

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

506
		if (status & NVMCON_LVDERR) {
zwelch's avatar
zwelch committed
507
			LOG_ERROR("Flash write error LVDERR (status = 0x%08" PRIx32 ")", status);
508
509
510
			retval = ERROR_FLASH_OPERATION_FAILED;
			break;
		}
oharboe's avatar
oharboe committed
511

512
513
514
		buffer += thisrun_count * 4;
		address += thisrun_count * 4;
		count -= thisrun_count;
oharboe's avatar
oharboe committed
515
516
517
	}

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

520
521
522
	destroy_reg_param(&reg_params[0]);
	destroy_reg_param(&reg_params[1]);
	destroy_reg_param(&reg_params[2]);
oharboe's avatar
oharboe committed
523
524
525
526

	return retval;
}

527
static int pic32mx_write_word(struct flash_bank *bank, uint32_t address, uint32_t word)
oharboe's avatar
oharboe committed
528
{
Zachary T Welch's avatar
Zachary T Welch committed
529
	struct target *target = bank->target;
oharboe's avatar
oharboe committed
530

531
	target_write_u32(target, PIC32MX_NVMADDR, Virt2Phys(address));
oharboe's avatar
oharboe committed
532
533
534
535
536
	target_write_u32(target, PIC32MX_NVMDATA, word);

	return pic32mx_nvm_exec(bank, NVMCON_OP_WORD_PROG, 5);
}

537
static int pic32mx_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
538
{
539
540
541
542
543
	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;
544
	int retval;
oharboe's avatar
oharboe committed
545

546
	if (bank->target->state != TARGET_HALTED) {
oharboe's avatar
oharboe committed
547
548
549
550
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

551
552
553
	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);

554
	if (offset & 0x3) {
duane's avatar
duane committed
555
		LOG_WARNING("offset 0x%" PRIx32 "breaks required 4-byte alignment", offset);
oharboe's avatar
oharboe committed
556
557
558
559
		return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
	}

	/* multiple words (4-byte) to be programmed? */
560
	if (words_remaining > 0) {
oharboe's avatar
oharboe committed
561
		/* try using a block write */
562
563
564
		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
565
566
567
				/* 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");
568
			} else if (retval == ERROR_FLASH_OPERATION_FAILED) {
569
570
				LOG_ERROR("flash writing failed");
				return retval;
oharboe's avatar
oharboe committed
571
			}
572
		} else {
oharboe's avatar
oharboe committed
573
574
575
576
577
578
			buffer += words_remaining * 4;
			address += words_remaining * 4;
			words_remaining = 0;
		}
	}

579
	while (words_remaining > 0) {
580
581
		uint32_t value;
		memcpy(&value, buffer + bytes_written, sizeof(uint32_t));
oharboe's avatar
oharboe committed
582

583
		status = pic32mx_write_word(bank, address, value);
584

585
		if (status & NVMCON_NVMERR) {
586
			LOG_ERROR("Flash write error NVMERR (status = 0x%08" PRIx32 ")", status);
oharboe's avatar
oharboe committed
587
			return ERROR_FLASH_OPERATION_FAILED;
588
589
		}

590
		if (status & NVMCON_LVDERR) {
591
			LOG_ERROR("Flash write error LVDERR (status = 0x%08" PRIx32 ")", status);
oharboe's avatar
oharboe committed
592
			return ERROR_FLASH_OPERATION_FAILED;
593
		}
oharboe's avatar
oharboe committed
594
595
596
597
598
599

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

600
	if (bytes_remaining) {
601
		uint32_t value = 0xffffffff;
602
		memcpy(&value, buffer + bytes_written, bytes_remaining);
oharboe's avatar
oharboe committed
603

604
		status = pic32mx_write_word(bank, address, value);
605

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

611
		if (status & NVMCON_LVDERR) {
612
			LOG_ERROR("Flash write error LVDERR (status = 0x%08" PRIx32 ")", status);
oharboe's avatar
oharboe committed
613
			return ERROR_FLASH_OPERATION_FAILED;
614
		}
oharboe's avatar
oharboe committed
615
616
617
618
619
	}

	return ERROR_OK;
}

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

	pic32mx_info->probed = 0;

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

640
	if (((device_id >> 1) & 0x7ff) != PIC32MX_MANUF_ID) {
641
		LOG_WARNING("Cannot identify target as a PIC32MX family.");
oharboe's avatar
oharboe committed
642
643
644
		return ERROR_FLASH_OPERATION_FAILED;
	}

645
646
647
648
649
650
651
652
653
654
655
656
657
658
	/* 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
659

660
	if (Virt2Phys(bank->base) == PIC32MX_PHYS_BOOT_FLASH) {
661
662
663
664
665
666
667
668
669
670
671
		/* 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 */
672
673
674
675
		if (pic32mx_info->dev_type == MX_1_2)
			num_pages = (3 * 1024);
		else
			num_pages = (12 * 1024);
676
#endif
677
	} else {
678
679
		/* read the flash size from the device */
		if (target_read_u32(target, PIC32MX_BMXPFMSZ, &num_pages) != ERROR_OK) {
680
681
682
683
684
685
686
			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);
			}
687
		}
oharboe's avatar
oharboe committed
688
689
	}

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

692
	if (bank->sectors) {
693
694
695
696
		free(bank->sectors);
		bank->sectors = NULL;
	}

oharboe's avatar
oharboe committed
697
	/* calculate numbers of pages */
698
	num_pages /= page_size;
oharboe's avatar
oharboe committed
699
700
	bank->size = (num_pages * page_size);
	bank->num_sectors = num_pages;
701
	bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
oharboe's avatar
oharboe committed
702

703
	for (i = 0; i < (int)num_pages; i++) {
oharboe's avatar
oharboe committed
704
705
706
707
708
709
710
711
712
713
714
		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;
}

715
static int pic32mx_auto_probe(struct flash_bank *bank)
oharboe's avatar
oharboe committed
716
{
717
	struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv;
oharboe's avatar
oharboe committed
718
719
720
721
722
	if (pic32mx_info->probed)
		return ERROR_OK;
	return pic32mx_probe(bank);
}

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

	device_id = ejtag_info->idcode;

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

741
	for (i = 0; pic32mx_devs[i].name != NULL; i++) {
742
		if (pic32mx_devs[i].devid == (device_id & 0x0fffffff)) {
oharboe's avatar
oharboe committed
743
744
745
746
747
			printed = snprintf(buf, buf_size, "PIC32MX%s", pic32mx_devs[i].name);
			break;
		}
	}

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

751
752
	buf += printed;
	buf_size -= printed;
753
	snprintf(buf, buf_size, " Ver: 0x%02x",
754
			(unsigned)((device_id >> 28) & 0xf));
oharboe's avatar
oharboe committed
755
756
757
758

	return ERROR_OK;
}

759
COMMAND_HANDLER(pic32mx_handle_pgm_word_command)
oharboe's avatar
oharboe committed
760
{
761
	uint32_t address, value;
oharboe's avatar
oharboe committed
762
763
	int status, res;

764
	if (CMD_ARGC != 3)
Mathias K's avatar
Mathias K committed
765
		return ERROR_COMMAND_SYNTAX_ERROR;
oharboe's avatar
oharboe committed
766

767
768
	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
769

770
	struct flash_bank *bank;
771
	int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 2, &bank);
772
773
	if (ERROR_OK != retval)
		return retval;
oharboe's avatar
oharboe committed
774

775
	if (address < bank->base || address >= (bank->base + bank->size)) {
776
		command_print(CMD_CTX, "flash address '%s' is out of bounds", CMD_ARGV[0]);
oharboe's avatar
oharboe committed
777
778
779
780
781
		return ERROR_OK;
	}

	res = ERROR_OK;
	status = pic32mx_write_word(bank, address, value);
782
	if (status & NVMCON_NVMERR)
oharboe's avatar
oharboe committed
783
		res = ERROR_FLASH_OPERATION_FAILED;
784
	if (status & NVMCON_LVDERR)
oharboe's avatar
oharboe committed
785
786
787
		res = ERROR_FLASH_OPERATION_FAILED;

	if (res == ERROR_OK)
788
		command_print(CMD_CTX, "pic32mx pgm word complete");
oharboe's avatar
oharboe committed
789
	else
790
		command_print(CMD_CTX, "pic32mx pgm word failed (status = 0x%x)", status);
oharboe's avatar
oharboe committed
791
792
793

	return ERROR_OK;
}
794

Spencer Oliver's avatar
Spencer Oliver committed
795
796
797
798
799
800
801
802
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;

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

	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);
824
	if (mchip_cmd & (1 << 7)) {
Spencer Oliver's avatar
Spencer Oliver committed
825
826
827
828
829
		/* device is not locked */
		command_print(CMD_CTX, "pic32mx is already unlocked, erasing anyway");
	}

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

832
	mips_ejtag_drscan_8_out(ejtag_info, MCHP_ERASE);
Spencer Oliver's avatar
Spencer Oliver committed
833
834
835
836

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

844
	mips_ejtag_drscan_8_out(ejtag_info, MCHP_DE_ASSERT_RST);
Spencer Oliver's avatar
Spencer Oliver committed
845
846
847
848
849
850
851
852
853
854
855

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

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

874
875
876
877
878
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
879
		.usage = "",
880
881
882
883
		.chain = pic32mx_exec_command_handlers,
	},
	COMMAND_REGISTRATION_DONE
};
884

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