lpc2000.c 23.1 KB
Newer Older
oharboe's avatar
oharboe committed
1
2
3
4
/***************************************************************************
 *   Copyright (C) 2005 by Dominic Rath                                    *
 *   Dominic.Rath@gmx.de                                                   *
 *                                                                         *
5
6
7
 *   LPC1700 support Copyright (C) 2009 by Audrius Urmanavicius            *
 *   didele.deze@gmail.com                                                 *
 *                                                                         *
oharboe's avatar
oharboe committed
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 *   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.             *
 ***************************************************************************/
oharboe's avatar
oharboe committed
23

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

#include "lpc2000.h"
#include "armv4_5.h"
30
#include "armv7m.h"
oharboe's avatar
oharboe committed
31
32
33
#include "binarybuffer.h"


34
/* flash programming support for NXP LPC17xx and LPC2xxx devices
oharboe's avatar
oharboe committed
35
36
 * currently supported devices:
 * variant 1 (lpc2000_v1):
37
 * - 2104 | 5 | 6
zwelch's avatar
zwelch committed
38
39
 * - 2114 | 9
 * - 2124 | 9
oharboe's avatar
oharboe committed
40
 * - 2194
zwelch's avatar
zwelch committed
41
42
 * - 2212 | 4
 * - 2292 | 4
oharboe's avatar
oharboe committed
43
44
45
46
 *
 * variant 2 (lpc2000_v2):
 * - 213x
 * - 214x
47
48
 * - 2101 | 2 | 3
 * - 2364 | 6 | 8
oharboe's avatar
oharboe committed
49
 * - 2378
50
51
52
53
 *
 * lpc1700:
 * - 175x
 * - 176x (tested with LPC1768)
oharboe's avatar
oharboe committed
54
55
 */

mifi's avatar
mifi committed
56
static int lpc2000_build_sector_list(struct flash_bank_s *bank)
oharboe's avatar
oharboe committed
57
{
58
	struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
59
60
	int i;
	uint32_t offset = 0;
oharboe's avatar
oharboe committed
61

oharboe's avatar
oharboe committed
62
63
	/* default to a 4096 write buffer */
	lpc2000_info->cmd51_max_buffer = 4096;
oharboe's avatar
oharboe committed
64

65
	if (lpc2000_info->variant == lpc2000_v1)
oharboe's avatar
oharboe committed
66
67
68
69
70
	{
		/* variant 1 has different layout for 128kb and 256kb flashes */
		if (bank->size == 128 * 1024)
		{
			bank->num_sectors = 16;
71
			bank->sectors = malloc(sizeof(struct flash_sector) * 16);
oharboe's avatar
oharboe committed
72
73
74
75
76
77
78
79
80
81
82
83
			for (i = 0; i < 16; i++)
			{
				bank->sectors[i].offset = offset;
				bank->sectors[i].size = 8 * 1024;
				offset += bank->sectors[i].size;
				bank->sectors[i].is_erased = -1;
				bank->sectors[i].is_protected = 1;
			}
		}
		else if (bank->size == 256 * 1024)
		{
			bank->num_sectors = 18;
84
			bank->sectors = malloc(sizeof(struct flash_sector) * 18);
oharboe's avatar
oharboe committed
85

oharboe's avatar
oharboe committed
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
			for (i = 0; i < 8; i++)
			{
				bank->sectors[i].offset = offset;
				bank->sectors[i].size = 8 * 1024;
				offset += bank->sectors[i].size;
				bank->sectors[i].is_erased = -1;
				bank->sectors[i].is_protected = 1;
			}
			for (i = 8; i < 10; i++)
			{
				bank->sectors[i].offset = offset;
				bank->sectors[i].size = 64 * 1024;
				offset += bank->sectors[i].size;
				bank->sectors[i].is_erased = -1;
				bank->sectors[i].is_protected = 1;
			}
			for (i = 10; i < 18; i++)
			{
				bank->sectors[i].offset = offset;
				bank->sectors[i].size = 8 * 1024;
				offset += bank->sectors[i].size;
				bank->sectors[i].is_erased = -1;
				bank->sectors[i].is_protected = 1;
			}
		}
		else
		{
113
			LOG_ERROR("BUG: unknown bank->size encountered");
oharboe's avatar
oharboe committed
114
115
116
			exit(-1);
		}
	}
117
	else if (lpc2000_info->variant == lpc2000_v2)
oharboe's avatar
oharboe committed
118
119
120
121
122
123
	{
		/* variant 2 has a uniform layout, only number of sectors differs */
		switch (bank->size)
		{
			case 4 * 1024:
				lpc2000_info->cmd51_max_buffer = 1024;
124
				bank->num_sectors = 1;
oharboe's avatar
oharboe committed
125
126
127
				break;
			case 8 * 1024:
				lpc2000_info->cmd51_max_buffer = 1024;
128
				bank->num_sectors = 2;
oharboe's avatar
oharboe committed
129
130
				break;
			case 16 * 1024:
131
				bank->num_sectors = 4;
oharboe's avatar
oharboe committed
132
133
				break;
			case 32 * 1024:
134
				bank->num_sectors = 8;
oharboe's avatar
oharboe committed
135
136
				break;
			case 64 * 1024:
137
				bank->num_sectors = 9;
oharboe's avatar
oharboe committed
138
139
				break;
			case 128 * 1024:
140
				bank->num_sectors = 11;
oharboe's avatar
oharboe committed
141
142
				break;
			case 256 * 1024:
143
				bank->num_sectors = 15;
oharboe's avatar
oharboe committed
144
145
146
				break;
			case 512 * 1024:
			case 500 * 1024:
147
				bank->num_sectors = 27;
oharboe's avatar
oharboe committed
148
149
				break;
			default:
150
				LOG_ERROR("BUG: unknown bank->size encountered");
oharboe's avatar
oharboe committed
151
152
153
				exit(-1);
				break;
		}
oharboe's avatar
oharboe committed
154

155
		bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
oharboe's avatar
oharboe committed
156

157
		for (i = 0; i < bank->num_sectors; i++)
oharboe's avatar
oharboe committed
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
		{
			if ((i >= 0) && (i < 8))
			{
				bank->sectors[i].offset = offset;
				bank->sectors[i].size = 4 * 1024;
				offset += bank->sectors[i].size;
				bank->sectors[i].is_erased = -1;
				bank->sectors[i].is_protected = 1;
			}
			if ((i >= 8) && (i < 22))
			{
				bank->sectors[i].offset = offset;
				bank->sectors[i].size = 32 * 1024;
				offset += bank->sectors[i].size;
				bank->sectors[i].is_erased = -1;
				bank->sectors[i].is_protected = 1;
			}
			if ((i >= 22) && (i < 27))
			{
				bank->sectors[i].offset = offset;
				bank->sectors[i].size = 4 * 1024;
				offset += bank->sectors[i].size;
				bank->sectors[i].is_erased = -1;
				bank->sectors[i].is_protected = 1;
			}
		}
	}
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
	else if (lpc2000_info->variant == lpc1700)
	{
		switch(bank->size)
		{
			case 32 * 1024:
				bank->num_sectors = 8;
				break;
			case 64 * 1024:
				bank->num_sectors = 16;
				break;
			case 128 * 1024:
				bank->num_sectors = 18;
				break;
			case 256 * 1024:
				bank->num_sectors = 22;
				break;
			case 512 * 1024:
				bank->num_sectors = 30;
				break;
			default:
				LOG_ERROR("BUG: unknown bank->size encountered");
				exit(-1);
		}

209
		bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
210
211
212
213
214
215
216
217
218
219
220

		for(i = 0; i < bank->num_sectors; i++)
		{
			bank->sectors[i].offset = offset;
			/* sectors 0-15 are 4kB-sized, 16 and above are 32kB-sized for LPC17xx devices */
			bank->sectors[i].size = (i < 16)? 4 * 1024 : 32 * 1024;
			offset += bank->sectors[i].size;
			bank->sectors[i].is_erased = -1;
			bank->sectors[i].is_protected = 1;
		}
	}
oharboe's avatar
oharboe committed
221
222
	else
	{
223
		LOG_ERROR("BUG: unknown lpc2000_info->variant encountered");
oharboe's avatar
oharboe committed
224
225
		exit(-1);
	}
oharboe's avatar
oharboe committed
226

oharboe's avatar
oharboe committed
227
228
229
	return ERROR_OK;
}

230
231
/* call LPC1700/LPC2000 IAP function
 * uses 180 bytes working area
oharboe's avatar
oharboe committed
232
 * 0x0 to 0x7: jump gate (BX to thumb state, b -2 to wait)
233
234
235
 * 0x8 to 0x1f: command parameter table (1+5 words)
 * 0x20 to 0x33: command result table (1+4 words)
 * 0x34 to 0xb3: stack (only 128b needed)
oharboe's avatar
oharboe committed
236
 */
237
static int lpc2000_iap_call(flash_bank_t *bank, int code, uint32_t param_table[5], uint32_t result_table[4])
oharboe's avatar
oharboe committed
238
{
239
	int retval;
240
	struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
oharboe's avatar
oharboe committed
241
	target_t *target = bank->target;
242
	struct mem_param mem_params[2];
243
	struct reg_param reg_params[5];
244
245
246
247
	armv4_5_algorithm_t armv4_5_info; /* for LPC2000 */
	armv7m_algorithm_t armv7m_info;   /* for LPC1700 */
 	uint32_t status_code;
	uint32_t iap_entry_point = 0; /* to make compiler happier */
oharboe's avatar
oharboe committed
248

oharboe's avatar
oharboe committed
249
250
251
	/* regrab previously allocated working_area, or allocate a new one */
	if (!lpc2000_info->iap_working_area)
	{
252
		uint8_t jump_gate[8];
oharboe's avatar
oharboe committed
253

oharboe's avatar
oharboe committed
254
		/* make sure we have a working area */
255
		if (target_alloc_working_area(target, 180, &lpc2000_info->iap_working_area) != ERROR_OK)
oharboe's avatar
oharboe committed
256
		{
257
			LOG_ERROR("no working area specified, can't write LPC2000 internal flash");
oharboe's avatar
oharboe committed
258
259
			return ERROR_FLASH_OPERATION_FAILED;
		}
oharboe's avatar
oharboe committed
260

oharboe's avatar
oharboe committed
261
		/* write IAP code to working area */
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
		switch(lpc2000_info->variant)
		{
			case lpc1700:
				target_buffer_set_u32(target, jump_gate, ARMV7M_T_BX(12));
				target_buffer_set_u32(target, jump_gate + 4, ARMV7M_T_B(0xfffffe));
				break;
			case lpc2000_v1:
			case lpc2000_v2:
				target_buffer_set_u32(target, jump_gate, ARMV4_5_BX(12));
				target_buffer_set_u32(target, jump_gate + 4, ARMV4_5_B(0xfffffe, 0));
				break;
			default:
				LOG_ERROR("BUG: unknown bank->size encountered");
				exit(-1);
		}

zwelch's avatar
zwelch committed
278
		if ((retval = target_write_memory(target, lpc2000_info->iap_working_area->address, 4, 2, jump_gate)) != ERROR_OK)
279
		{
280
			LOG_ERROR("Write memory at address 0x%8.8" PRIx32 " failed (check work_area definition)", lpc2000_info->iap_working_area->address);
281
282
			return retval;
		}
oharboe's avatar
oharboe committed
283
	}
oharboe's avatar
oharboe committed
284

285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
	switch(lpc2000_info->variant)
	{
		case lpc1700:
			armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
			armv7m_info.core_mode = ARMV7M_MODE_ANY;
			iap_entry_point = 0x1fff1ff1;
			break;
		case lpc2000_v1:
		case lpc2000_v2:
			armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
			armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
			armv4_5_info.core_state = ARMV4_5_STATE_ARM;
			iap_entry_point = 0x7ffffff1;
			break;
		default:
			LOG_ERROR("BUG: unknown lpc2000->variant encountered");
			exit(-1);
	}
oharboe's avatar
oharboe committed
303

oharboe's avatar
oharboe committed
304
	/* command parameter table */
305
	init_mem_param(&mem_params[0], lpc2000_info->iap_working_area->address + 8, 6 * 4, PARAM_OUT);
oharboe's avatar
oharboe committed
306
	target_buffer_set_u32(target, mem_params[0].value, code);
307
308
309
	target_buffer_set_u32(target, mem_params[0].value + 0x04, param_table[0]);
	target_buffer_set_u32(target, mem_params[0].value + 0x08, param_table[1]);
	target_buffer_set_u32(target, mem_params[0].value + 0x0c, param_table[2]);
oharboe's avatar
oharboe committed
310
311
	target_buffer_set_u32(target, mem_params[0].value + 0x10, param_table[3]);
	target_buffer_set_u32(target, mem_params[0].value + 0x14, param_table[4]);
oharboe's avatar
oharboe committed
312

oharboe's avatar
oharboe committed
313
	init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
314
	buf_set_u32(reg_params[0].value, 0, 32, lpc2000_info->iap_working_area->address + 0x08);
oharboe's avatar
oharboe committed
315

oharboe's avatar
oharboe committed
316
	/* command result table */
317
	init_mem_param(&mem_params[1], lpc2000_info->iap_working_area->address + 0x20, 5 * 4, PARAM_IN);
oharboe's avatar
oharboe committed
318

oharboe's avatar
oharboe committed
319
320
	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
	buf_set_u32(reg_params[1].value, 0, 32, lpc2000_info->iap_working_area->address + 0x20);
oharboe's avatar
oharboe committed
321

oharboe's avatar
oharboe committed
322
323
	/* IAP entry point */
	init_reg_param(&reg_params[2], "r12", 32, PARAM_OUT);
324
	buf_set_u32(reg_params[2].value, 0, 32, iap_entry_point);
oharboe's avatar
oharboe committed
325

326
327
328
329
330
331
	switch(lpc2000_info->variant)
	{
		case lpc1700:
			/* IAP stack */
			init_reg_param(&reg_params[3], "sp", 32, PARAM_OUT);
			buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xb4);
oharboe's avatar
oharboe committed
332

333
334
335
			/* return address */
			init_reg_param(&reg_params[4], "lr", 32, PARAM_OUT);
			buf_set_u32(reg_params[4].value, 0, 32, (lpc2000_info->iap_working_area->address + 0x04) | 1); /* bit0 of LR = 1 to return in Thumb mode */
oharboe's avatar
oharboe committed
336

337
338
339
340
341
342
343
			target_run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, lpc2000_info->iap_working_area->address + 0x4, 10000, &armv7m_info);
			break;
		case lpc2000_v1:
		case lpc2000_v2:
			/* IAP stack */
			init_reg_param(&reg_params[3], "r13_svc", 32, PARAM_OUT);
			buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xb4);
oharboe's avatar
oharboe committed
344

345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
			/* return address */
			init_reg_param(&reg_params[4], "lr_svc", 32, PARAM_OUT);
			buf_set_u32(reg_params[4].value, 0, 32, lpc2000_info->iap_working_area->address + 0x04);

			target_run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, lpc2000_info->iap_working_area->address + 0x4, 10000, &armv4_5_info);
			break;
		default:
			LOG_ERROR("BUG: unknown lpc2000->variant encountered");
			exit(-1);
	}


	status_code     = target_buffer_get_u32(target, mem_params[1].value);
	result_table[0] = target_buffer_get_u32(target, mem_params[1].value + 0x04);
	result_table[1] = target_buffer_get_u32(target, mem_params[1].value + 0x08);
	result_table[2] = target_buffer_get_u32(target, mem_params[1].value + 0x0c);
	result_table[3] = target_buffer_get_u32(target, mem_params[1].value + 0x10);

	LOG_DEBUG("IAP command = %i (0x%8.8" PRIx32", 0x%8.8" PRIx32", 0x%8.8" PRIx32", 0x%8.8" PRIx32", 0x%8.8" PRIx32") completed with result = %8.8" PRIx32,
			  code, param_table[0], param_table[1], param_table[2], param_table[3], param_table[4], status_code);
oharboe's avatar
oharboe committed
365

oharboe's avatar
oharboe committed
366
367
	destroy_mem_param(&mem_params[0]);
	destroy_mem_param(&mem_params[1]);
oharboe's avatar
oharboe committed
368

oharboe's avatar
oharboe committed
369
370
371
372
373
	destroy_reg_param(&reg_params[0]);
	destroy_reg_param(&reg_params[1]);
	destroy_reg_param(&reg_params[2]);
	destroy_reg_param(&reg_params[3]);
	destroy_reg_param(&reg_params[4]);
oharboe's avatar
oharboe committed
374

oharboe's avatar
oharboe committed
375
376
377
	return status_code;
}

mifi's avatar
mifi committed
378
static int lpc2000_iap_blank_check(struct flash_bank_s *bank, int first, int last)
oharboe's avatar
oharboe committed
379
{
380
	uint32_t param_table[5];
381
	uint32_t result_table[4];
oharboe's avatar
oharboe committed
382
383
	int status_code;
	int i;
oharboe's avatar
oharboe committed
384

mifi's avatar
mifi committed
385
	if ((first < 0) || (last >= bank->num_sectors))
oharboe's avatar
oharboe committed
386
		return ERROR_FLASH_SECTOR_INVALID;
oharboe's avatar
oharboe committed
387

oharboe's avatar
oharboe committed
388
389
390
391
392
	for (i = first; i <= last; i++)
	{
		/* check single sector */
		param_table[0] = param_table[1] = i;
		status_code = lpc2000_iap_call(bank, 53, param_table, result_table);
oharboe's avatar
oharboe committed
393

oharboe's avatar
oharboe committed
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
		switch (status_code)
		{
			case ERROR_FLASH_OPERATION_FAILED:
				return ERROR_FLASH_OPERATION_FAILED;
			case LPC2000_CMD_SUCCESS:
				bank->sectors[i].is_erased = 1;
				break;
			case LPC2000_SECTOR_NOT_BLANK:
				bank->sectors[i].is_erased = 0;
				break;
			case LPC2000_INVALID_SECTOR:
				bank->sectors[i].is_erased = 0;
				break;
			case LPC2000_BUSY:
				return ERROR_FLASH_BUSY;
				break;
			default:
411
				LOG_ERROR("BUG: unknown LPC2000 status code %i", status_code);
oharboe's avatar
oharboe committed
412
413
414
				exit(-1);
		}
	}
oharboe's avatar
oharboe committed
415

oharboe's avatar
oharboe committed
416
417
418
	return ERROR_OK;
}

419
420
/*
 * flash bank lpc2000 <base> <size> 0 0 <target#> <lpc_variant> <cclk> [calc_checksum]
oharboe's avatar
oharboe committed
421
 */
422
FLASH_BANK_COMMAND_HANDLER(lpc2000_flash_bank_command)
oharboe's avatar
oharboe committed
423
{
424
	struct lpc2000_flash_bank *lpc2000_info;
oharboe's avatar
oharboe committed
425

oharboe's avatar
oharboe committed
426
427
	if (argc < 8)
	{
428
		LOG_WARNING("incomplete flash_bank lpc2000 configuration");
oharboe's avatar
oharboe committed
429
430
		return ERROR_FLASH_BANK_INVALID;
	}
oharboe's avatar
oharboe committed
431

432
	lpc2000_info = malloc(sizeof(struct lpc2000_flash_bank));
oharboe's avatar
oharboe committed
433
	bank->driver_priv = lpc2000_info;
oharboe's avatar
oharboe committed
434

oharboe's avatar
oharboe committed
435
436
	if (strcmp(args[6], "lpc2000_v1") == 0)
	{
437
		lpc2000_info->variant = lpc2000_v1;
oharboe's avatar
oharboe committed
438
439
440
		lpc2000_info->cmd51_dst_boundary = 512;
		lpc2000_info->cmd51_can_256b = 0;
		lpc2000_info->cmd51_can_8192b = 1;
441
		lpc2000_info->checksum_vector = 5;
oharboe's avatar
oharboe committed
442
443
444
	}
	else if (strcmp(args[6], "lpc2000_v2") == 0)
	{
445
		lpc2000_info->variant = lpc2000_v2;
oharboe's avatar
oharboe committed
446
447
448
		lpc2000_info->cmd51_dst_boundary = 256;
		lpc2000_info->cmd51_can_256b = 1;
		lpc2000_info->cmd51_can_8192b = 0;
449
450
451
452
453
454
455
456
457
		lpc2000_info->checksum_vector = 5;
	}
	else if (strcmp(args[6], "lpc1700") == 0)
	{
		lpc2000_info->variant = lpc1700;
		lpc2000_info->cmd51_dst_boundary = 256;
		lpc2000_info->cmd51_can_256b = 1;
		lpc2000_info->cmd51_can_8192b = 0;
		lpc2000_info->checksum_vector = 7;
oharboe's avatar
oharboe committed
458
459
460
	}
	else
	{
461
		LOG_ERROR("unknown LPC2000 variant: %s", args[6]);
oharboe's avatar
oharboe committed
462
463
464
		free(lpc2000_info);
		return ERROR_FLASH_BANK_INVALID;
	}
oharboe's avatar
oharboe committed
465

oharboe's avatar
oharboe committed
466
	lpc2000_info->iap_working_area = NULL;
467
	COMMAND_PARSE_NUMBER(u32, args[7], lpc2000_info->cclk);
oharboe's avatar
oharboe committed
468
469
	lpc2000_info->calc_checksum = 0;
	lpc2000_build_sector_list(bank);
oharboe's avatar
oharboe committed
470

oharboe's avatar
oharboe committed
471
472
473
474
475
	if (argc >= 9)
	{
		if (strcmp(args[8], "calc_checksum") == 0)
			lpc2000_info->calc_checksum = 1;
	}
oharboe's avatar
oharboe committed
476

oharboe's avatar
oharboe committed
477
478
479
	return ERROR_OK;
}

mifi's avatar
mifi committed
480
static int lpc2000_erase(struct flash_bank_s *bank, int first, int last)
oharboe's avatar
oharboe committed
481
{
482
	struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
483
	uint32_t param_table[5];
484
	uint32_t result_table[4];
oharboe's avatar
oharboe committed
485
	int status_code;
oharboe's avatar
oharboe committed
486

487
488
	if (bank->target->state != TARGET_HALTED)
	{
oharboe's avatar
oharboe committed
489
		LOG_ERROR("Target not halted");
490
491
492
		return ERROR_TARGET_NOT_HALTED;
	}

oharboe's avatar
oharboe committed
493
494
495
	param_table[0] = first;
	param_table[1] = last;
	param_table[2] = lpc2000_info->cclk;
oharboe's avatar
oharboe committed
496

oharboe's avatar
oharboe committed
497
498
499
500
501
502
503
504
505
506
507
508
	/* Prepare sectors */
	status_code = lpc2000_iap_call(bank, 50, param_table, result_table);
	switch (status_code)
	{
		case ERROR_FLASH_OPERATION_FAILED:
			return ERROR_FLASH_OPERATION_FAILED;
		case LPC2000_CMD_SUCCESS:
			break;
		case LPC2000_INVALID_SECTOR:
			return ERROR_FLASH_SECTOR_INVALID;
			break;
		default:
509
			LOG_WARNING("lpc2000 prepare sectors returned %i", status_code);
oharboe's avatar
oharboe committed
510
511
			return ERROR_FLASH_OPERATION_FAILED;
	}
oharboe's avatar
oharboe committed
512

oharboe's avatar
oharboe committed
513
514
515
516
517
518
519
520
521
522
523
524
	/* Erase sectors */
	status_code = lpc2000_iap_call(bank, 52, param_table, result_table);
	switch (status_code)
	{
		case ERROR_FLASH_OPERATION_FAILED:
			return ERROR_FLASH_OPERATION_FAILED;
		case LPC2000_CMD_SUCCESS:
			break;
		case LPC2000_INVALID_SECTOR:
			return ERROR_FLASH_SECTOR_INVALID;
			break;
		default:
525
			LOG_WARNING("lpc2000 erase sectors returned %i", status_code);
oharboe's avatar
oharboe committed
526
527
			return ERROR_FLASH_OPERATION_FAILED;
	}
oharboe's avatar
oharboe committed
528

oharboe's avatar
oharboe committed
529
530
531
	return ERROR_OK;
}

mifi's avatar
mifi committed
532
static int lpc2000_protect(struct flash_bank_s *bank, int set, int first, int last)
oharboe's avatar
oharboe committed
533
534
535
536
537
{
	/* can't protect/unprotect on the lpc2000 */
	return ERROR_OK;
}

538
static int lpc2000_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
oharboe's avatar
oharboe committed
539
{
540
	struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
oharboe's avatar
oharboe committed
541
	target_t *target = bank->target;
542
543
544
	uint32_t dst_min_alignment;
	uint32_t bytes_remaining = count;
	uint32_t bytes_written = 0;
oharboe's avatar
oharboe committed
545
546
	int first_sector = 0;
	int last_sector = 0;
547
	uint32_t param_table[5];
548
	uint32_t result_table[4];
oharboe's avatar
oharboe committed
549
550
551
	int status_code;
	int i;
	working_area_t *download_area;
552
	int retval = ERROR_OK;
oharboe's avatar
oharboe committed
553

554
555
	if (bank->target->state != TARGET_HALTED)
	{
oharboe's avatar
oharboe committed
556
		LOG_ERROR("Target not halted");
557
558
		return ERROR_TARGET_NOT_HALTED;
	}
oharboe's avatar
oharboe committed
559

oharboe's avatar
oharboe committed
560
	if (offset + count > bank->size)
561
		return ERROR_FLASH_DST_OUT_OF_BANK;
oharboe's avatar
oharboe committed
562

563
	dst_min_alignment = lpc2000_info->cmd51_dst_boundary;
oharboe's avatar
oharboe committed
564

oharboe's avatar
oharboe committed
565
566
	if (offset % dst_min_alignment)
	{
duane's avatar
duane committed
567
		LOG_WARNING("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32, offset, dst_min_alignment);
568
		return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
oharboe's avatar
oharboe committed
569
	}
oharboe's avatar
oharboe committed
570

oharboe's avatar
oharboe committed
571
572
573
574
575
576
577
	for (i = 0; i < bank->num_sectors; i++)
	{
		if (offset >= bank->sectors[i].offset)
			first_sector = i;
		if (offset + CEIL(count, dst_min_alignment) * dst_min_alignment > bank->sectors[i].offset)
			last_sector = i;
	}
oharboe's avatar
oharboe committed
578

579
	LOG_DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector);
oharboe's avatar
oharboe committed
580
581
582
583

	/* check if exception vectors should be flashed */
	if ((offset == 0) && (count >= 0x20) && lpc2000_info->calc_checksum)
	{
584
		uint32_t checksum = 0;
585
		int i;
oharboe's avatar
oharboe committed
586
587
		for (i = 0; i < 8; i++)
		{
588
589
			LOG_DEBUG("Vector 0x%2.2x: 0x%8.8" PRIx32, i * 4, buf_get_u32(buffer + (i * 4), 0, 32));
			if (i != lpc2000_info->checksum_vector)
oharboe's avatar
oharboe committed
590
591
592
				checksum += buf_get_u32(buffer + (i * 4), 0, 32);
		}
		checksum = 0 - checksum;
duane's avatar
duane committed
593
		LOG_DEBUG("checksum: 0x%8.8" PRIx32, checksum);
594

595
		uint32_t original_value = buf_get_u32(buffer + (lpc2000_info->checksum_vector * 4), 0, 32);
zwelch's avatar
zwelch committed
596
		if (original_value != checksum)
597
		{
598
			LOG_WARNING("Verification will fail since checksum in image (0x%8.8" PRIx32 ") to be written to flash is different from calculated vector checksum (0x%8.8" PRIx32 ").",
599
600
601
602
					original_value, checksum);
			LOG_WARNING("To remove this warning modify build tools on developer PC to inject correct LPC vector checksum.");
		}

603
		buf_set_u32(buffer + (lpc2000_info->checksum_vector * 4), 0, 32, checksum);
oharboe's avatar
oharboe committed
604
	}
oharboe's avatar
oharboe committed
605

606
607
608
609
610
611
	/* allocate a working area */
	if (target_alloc_working_area(target, lpc2000_info->cmd51_max_buffer, &download_area) != ERROR_OK)
	{
		LOG_ERROR("no working area specified, can't write LPC2000 internal flash");
		return ERROR_FLASH_OPERATION_FAILED;
	}
oharboe's avatar
oharboe committed
612

oharboe's avatar
oharboe committed
613
614
	while (bytes_remaining > 0)
	{
615
		uint32_t thisrun_bytes;
oharboe's avatar
oharboe committed
616
617
618
619
620
621
622
623
		if (bytes_remaining >= lpc2000_info->cmd51_max_buffer)
			thisrun_bytes = lpc2000_info->cmd51_max_buffer;
		else if (bytes_remaining >= 1024)
			thisrun_bytes = 1024;
		else if ((bytes_remaining >= 512) || (!lpc2000_info->cmd51_can_256b))
			thisrun_bytes = 512;
		else
			thisrun_bytes = 256;
oharboe's avatar
oharboe committed
624

oharboe's avatar
oharboe committed
625
626
627
628
629
630
631
		/* Prepare sectors */
		param_table[0] = first_sector;
		param_table[1] = last_sector;
		status_code = lpc2000_iap_call(bank, 50, param_table, result_table);
		switch (status_code)
		{
			case ERROR_FLASH_OPERATION_FAILED:
632
				retval = ERROR_FLASH_OPERATION_FAILED;
633
				break;
oharboe's avatar
oharboe committed
634
635
636
			case LPC2000_CMD_SUCCESS:
				break;
			case LPC2000_INVALID_SECTOR:
637
				retval = ERROR_FLASH_SECTOR_INVALID;
oharboe's avatar
oharboe committed
638
639
				break;
			default:
640
				LOG_WARNING("lpc2000 prepare sectors returned %i", status_code);
641
				retval = ERROR_FLASH_OPERATION_FAILED;
642
				break;
oharboe's avatar
oharboe committed
643
		}
644

645
646
647
		/* Exit if error occured */
		if (retval != ERROR_OK)
			break;
oharboe's avatar
oharboe committed
648

oharboe's avatar
oharboe committed
649
		if (bytes_remaining >= thisrun_bytes)
650
		{
651
			if ((retval = target_write_buffer(bank->target, download_area->address, thisrun_bytes, buffer + bytes_written)) != ERROR_OK)
oharboe's avatar
oharboe committed
652
			{
653
654
				retval = ERROR_FLASH_OPERATION_FAILED;
				break;
oharboe's avatar
oharboe committed
655
656
657
658
			}
		}
		else
		{
659
			uint8_t *last_buffer = malloc(thisrun_bytes);
oharboe's avatar
oharboe committed
660
			memcpy(last_buffer, buffer + bytes_written, bytes_remaining);
661
			memset(last_buffer + bytes_remaining, 0xff, thisrun_bytes - bytes_remaining);
oharboe's avatar
oharboe committed
662
663
664
			target_write_buffer(bank->target, download_area->address, thisrun_bytes, last_buffer);
			free(last_buffer);
		}
oharboe's avatar
oharboe committed
665

duane's avatar
duane committed
666
		LOG_DEBUG("writing 0x%" PRIx32 " bytes to address 0x%" PRIx32 , thisrun_bytes, bank->base + offset + bytes_written);
oharboe's avatar
oharboe committed
667

oharboe's avatar
oharboe committed
668
669
670
671
672
673
674
675
676
		/* Write data */
		param_table[0] = bank->base + offset + bytes_written;
		param_table[1] = download_area->address;
		param_table[2] = thisrun_bytes;
		param_table[3] = lpc2000_info->cclk;
		status_code = lpc2000_iap_call(bank, 51, param_table, result_table);
		switch (status_code)
		{
			case ERROR_FLASH_OPERATION_FAILED:
677
				retval = ERROR_FLASH_OPERATION_FAILED;
678
				break;
oharboe's avatar
oharboe committed
679
680
681
			case LPC2000_CMD_SUCCESS:
				break;
			case LPC2000_INVALID_SECTOR:
682
				retval = ERROR_FLASH_SECTOR_INVALID;
oharboe's avatar
oharboe committed
683
684
				break;
			default:
685
				LOG_WARNING("lpc2000 returned %i", status_code);
686
				retval = ERROR_FLASH_OPERATION_FAILED;
687
				break;
oharboe's avatar
oharboe committed
688
		}
oharboe's avatar
oharboe committed
689

690
691
692
		/* Exit if error occured */
		if (retval != ERROR_OK)
			break;
oharboe's avatar
oharboe committed
693

oharboe's avatar
oharboe committed
694
695
696
697
698
699
		if (bytes_remaining > thisrun_bytes)
			bytes_remaining -= thisrun_bytes;
		else
			bytes_remaining = 0;
		bytes_written += thisrun_bytes;
	}
oharboe's avatar
oharboe committed
700

oharboe's avatar
oharboe committed
701
	target_free_working_area(target, download_area);
oharboe's avatar
oharboe committed
702

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

mifi's avatar
mifi committed
706
static int lpc2000_probe(struct flash_bank_s *bank)
oharboe's avatar
oharboe committed
707
{
oharboe's avatar
oharboe committed
708
	/* we can't probe on an lpc2000
oharboe's avatar
oharboe committed
709
710
711
712
713
	 * if this is an lpc2xxx, it has the configured flash
	 */
	return ERROR_OK;
}

mifi's avatar
mifi committed
714
static int lpc2000_erase_check(struct flash_bank_s *bank)
oharboe's avatar
oharboe committed
715
716
717
{
	if (bank->target->state != TARGET_HALTED)
	{
oharboe's avatar
oharboe committed
718
		LOG_ERROR("Target not halted");
oharboe's avatar
oharboe committed
719
720
		return ERROR_TARGET_NOT_HALTED;
	}
oharboe's avatar
oharboe committed
721

oharboe's avatar
oharboe committed
722
723
724
	return lpc2000_iap_blank_check(bank, 0, bank->num_sectors - 1);
}

mifi's avatar
mifi committed
725
static int lpc2000_protect_check(struct flash_bank_s *bank)
oharboe's avatar
oharboe committed
726
727
728
729
730
{
	/* sectors are always protected	*/
	return ERROR_OK;
}

mifi's avatar
mifi committed
731
static int lpc2000_info(struct flash_bank_s *bank, char *buf, int buf_size)
oharboe's avatar
oharboe committed
732
{
733
	struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
oharboe's avatar
oharboe committed
734

735
	snprintf(buf, buf_size, "lpc2000 flash driver variant: %i, clk: %" PRIi32 "kHz" , lpc2000_info->variant, lpc2000_info->cclk);
oharboe's avatar
oharboe committed
736

oharboe's avatar
oharboe committed
737
738
739
	return ERROR_OK;
}

740
COMMAND_HANDLER(lpc2000_handle_part_id_command)
oharboe's avatar
oharboe committed
741
{
742
	uint32_t param_table[5];
743
	uint32_t result_table[4];
oharboe's avatar
oharboe committed
744
745
746
747
	int status_code;

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

751
752
753
754
	flash_bank_t *bank;
	int retval = flash_command_get_bank_by_num(cmd_ctx, args[0], &bank);
	if (ERROR_OK != retval)
		return retval;
oharboe's avatar
oharboe committed
755
756
757

	if (bank->target->state != TARGET_HALTED)
	{
oharboe's avatar
oharboe committed
758
		LOG_ERROR("Target not halted");
oharboe's avatar
oharboe committed
759
760
		return ERROR_TARGET_NOT_HALTED;
	}
oharboe's avatar
oharboe committed
761

oharboe's avatar
oharboe committed
762
763
764
765
766
767
768
769
770
771
772
	if ((status_code = lpc2000_iap_call(bank, 54, param_table, result_table)) != 0x0)
	{
		if (status_code == ERROR_FLASH_OPERATION_FAILED)
		{
			command_print(cmd_ctx, "no sufficient working area specified, can't access LPC2000 IAP interface");
			return ERROR_OK;
		}
		command_print(cmd_ctx, "lpc2000 IAP returned status code %i", status_code);
	}
	else
	{
duane's avatar
duane committed
773
		command_print(cmd_ctx, "lpc2000 part id: 0x%8.8" PRIx32 , result_table[0]);
oharboe's avatar
oharboe committed
774
	}
oharboe's avatar
oharboe committed
775

oharboe's avatar
oharboe committed
776
777
	return ERROR_OK;
}
778
779
780
781
782
783
784
785
786
787
788
789
790

static int lpc2000_register_commands(struct command_context_s *cmd_ctx)
{
	command_t *lpc2000_cmd = register_command(cmd_ctx, NULL, "lpc2000",
			NULL, COMMAND_ANY, NULL);

	register_command(cmd_ctx, lpc2000_cmd, "part_id",
			lpc2000_handle_part_id_command, COMMAND_EXEC,
			"print part id of lpc2000 flash bank <num>");

	return ERROR_OK;
}

791
struct flash_driver lpc2000_flash = {
792
793
794
795
796
797
798
799
800
801
802
803
804
805
		.name = "lpc2000",
		.register_commands = &lpc2000_register_commands,
		.flash_bank_command = &lpc2000_flash_bank_command,
		.erase = &lpc2000_erase,
		.protect = &lpc2000_protect,
		.write = &lpc2000_write,
		.probe = &lpc2000_probe,
		.auto_probe = &lpc2000_probe,
		.erase_check = &lpc2000_erase_check,
		.protect_check = &lpc2000_protect_check,
		.info = &lpc2000_info,
	};