- Added support for native MinGW builds (thanks to Spencer Oliver and Michael Fischer...
[openocd.git] / src / flash / lpc2000.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "lpc2000.h"
25
26 #include "flash.h"
27 #include "target.h"
28 #include "log.h"
29 #include "armv4_5.h"
30 #include "algorithm.h"
31 #include "binarybuffer.h"
32
33 #include <stdlib.h>
34 #include <string.h>
35
36 /* flash programming support for Philips LPC2xxx devices
37 * currently supported devices:
38 * variant 1 (lpc2000_v1):
39 * - 2104|5|6
40 * - 2114|9
41 * - 2124|9
42 * - 2194
43 * - 2212|4
44 * - 2292|4
45 *
46 * variant 2 (lpc2000_v2):
47 * - 213x
48 * - 214x
49 */
50
51 int lpc2000_register_commands(struct command_context_s *cmd_ctx);
52 int lpc2000_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
53 int lpc2000_erase(struct flash_bank_s *bank, int first, int last);
54 int lpc2000_protect(struct flash_bank_s *bank, int set, int first, int last);
55 int lpc2000_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
56 int lpc2000_probe(struct flash_bank_s *bank);
57 int lpc2000_erase_check(struct flash_bank_s *bank);
58 int lpc2000_protect_check(struct flash_bank_s *bank);
59 int lpc2000_info(struct flash_bank_s *bank, char *buf, int buf_size);
60
61 int lpc2000_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
62
63 flash_driver_t lpc2000_flash =
64 {
65 .name = "lpc2000",
66 .register_commands = lpc2000_register_commands,
67 .flash_bank_command = lpc2000_flash_bank_command,
68 .erase = lpc2000_erase,
69 .protect = lpc2000_protect,
70 .write = lpc2000_write,
71 .probe = lpc2000_probe,
72 .erase_check = lpc2000_erase_check,
73 .protect_check = lpc2000_protect_check,
74 .info = lpc2000_info
75 };
76
77 int lpc2000_register_commands(struct command_context_s *cmd_ctx)
78 {
79 command_t *lpc2000_cmd = register_command(cmd_ctx, NULL, "lpc2000", NULL, COMMAND_ANY, NULL);
80
81 register_command(cmd_ctx, lpc2000_cmd, "part_id", lpc2000_handle_part_id_command, COMMAND_EXEC,
82 "print part id of lpc2000 flash bank <num>");
83
84 return ERROR_OK;
85 }
86
87 int lpc2000_build_sector_list(struct flash_bank_s *bank)
88 {
89 lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
90
91 if (lpc2000_info->variant == 1)
92 {
93 int i = 0;
94 u32 offset = 0;
95
96 /* variant 1 has different layout for 128kb and 256kb flashes */
97 if (bank->size == 128 * 1024)
98 {
99 bank->num_sectors = 16;
100 bank->sectors = malloc(sizeof(flash_sector_t) * 16);
101 for (i = 0; i < 16; i++)
102 {
103 bank->sectors[i].offset = offset;
104 bank->sectors[i].size = 8 * 1024;
105 offset += bank->sectors[i].size;
106 bank->sectors[i].is_erased = -1;
107 bank->sectors[i].is_protected = 1;
108 }
109 }
110 else if (bank->size == 256 * 1024)
111 {
112 bank->num_sectors = 18;
113 bank->sectors = malloc(sizeof(flash_sector_t) * 18);
114
115 for (i = 0; i < 8; i++)
116 {
117 bank->sectors[i].offset = offset;
118 bank->sectors[i].size = 8 * 1024;
119 offset += bank->sectors[i].size;
120 bank->sectors[i].is_erased = -1;
121 bank->sectors[i].is_protected = 1;
122 }
123 for (i = 8; i < 10; i++)
124 {
125 bank->sectors[i].offset = offset;
126 bank->sectors[i].size = 64 * 1024;
127 offset += bank->sectors[i].size;
128 bank->sectors[i].is_erased = -1;
129 bank->sectors[i].is_protected = 1;
130 }
131 for (i = 10; i < 18; i++)
132 {
133 bank->sectors[i].offset = offset;
134 bank->sectors[i].size = 8 * 1024;
135 offset += bank->sectors[i].size;
136 bank->sectors[i].is_erased = -1;
137 bank->sectors[i].is_protected = 1;
138 }
139 }
140 else
141 {
142 ERROR("BUG: unknown bank->size encountered");
143 exit(-1);
144 }
145 }
146 else if (lpc2000_info->variant == 2)
147 {
148 int num_sectors;
149 int i;
150 u32 offset = 0;
151
152 /* variant 2 has a uniform layout, only number of sectors differs */
153 switch (bank->size)
154 {
155 case 32 * 1024:
156 num_sectors = 8;
157 break;
158 case 64 * 1024:
159 num_sectors = 9;
160 break;
161 case 128 * 1024:
162 num_sectors = 11;
163 break;
164 case 256 * 1024:
165 num_sectors = 15;
166 break;
167 case 500 * 1024:
168 num_sectors = 27;
169 break;
170 default:
171 ERROR("BUG: unknown bank->size encountered");
172 exit(-1);
173 break;
174 }
175
176 bank->num_sectors = num_sectors;
177 bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
178
179 for (i = 0; i < num_sectors; i++)
180 {
181 if ((i >= 0) && (i < 8))
182 {
183 bank->sectors[i].offset = offset;
184 bank->sectors[i].size = 4 * 1024;
185 offset += bank->sectors[i].size;
186 bank->sectors[i].is_erased = -1;
187 bank->sectors[i].is_protected = 1;
188 }
189 if ((i >= 8) && (i < 22))
190 {
191 bank->sectors[i].offset = offset;
192 bank->sectors[i].size = 32 * 1024;
193 offset += bank->sectors[i].size;
194 bank->sectors[i].is_erased = -1;
195 bank->sectors[i].is_protected = 1;
196 }
197 if ((i >= 22) && (i < 27))
198 {
199 bank->sectors[i].offset = offset;
200 bank->sectors[i].size = 4 * 1024;
201 offset += bank->sectors[i].size;
202 bank->sectors[i].is_erased = -1;
203 bank->sectors[i].is_protected = 1;
204 }
205 }
206 }
207 else
208 {
209 ERROR("BUG: unknown lpc2000_info->variant encountered");
210 exit(-1);
211 }
212
213 return ERROR_OK;
214 }
215
216 /* call LPC2000 IAP function
217 * uses 172 bytes working area
218 * 0x0 to 0x7: jump gate (BX to thumb state, b -2 to wait)
219 * 0x8 to 0x1f: command parameter table
220 * 0x20 to 0x2b: command result table
221 * 0x2c to 0xac: stack (only 128b needed)
222 */
223 int lpc2000_iap_call(flash_bank_t *bank, int code, u32 param_table[5], u32 result_table[2])
224 {
225 lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
226 target_t *target = lpc2000_info->target;
227 mem_param_t mem_params[2];
228 reg_param_t reg_params[5];
229 armv4_5_algorithm_t armv4_5_info;
230 u32 status_code;
231
232 /* regrab previously allocated working_area, or allocate a new one */
233 if (!lpc2000_info->iap_working_area)
234 {
235 u8 jump_gate[8];
236
237 /* make sure we have a working area */
238 if (target_alloc_working_area(target, 172, &lpc2000_info->iap_working_area) != ERROR_OK)
239 {
240 ERROR("no working area specified, can't write LPC2000 internal flash");
241 return ERROR_FLASH_OPERATION_FAILED;
242 }
243
244 /* write IAP code to working area */
245 buf_set_u32(jump_gate, 0, 32, ARMV4_5_BX(12));
246 buf_set_u32(jump_gate, 32, 32, 0xeafffffe);
247 target->type->write_memory(target, lpc2000_info->iap_working_area->address, 4, 2, (u8*)jump_gate);
248 }
249
250 armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
251 armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
252 armv4_5_info.core_state = ARMV4_5_STATE_ARM;
253
254 /* command parameter table */
255 init_mem_param(&mem_params[0], lpc2000_info->iap_working_area->address + 8, 4 * 6, PARAM_OUT);
256 buf_set_u32(mem_params[0].value, 0, 32, code);
257 buf_set_u32(mem_params[0].value, 32, 32, param_table[0]);
258 buf_set_u32(mem_params[0].value, 64, 32, param_table[1]);
259 buf_set_u32(mem_params[0].value, 96, 32, param_table[2]);
260 buf_set_u32(mem_params[0].value, 128, 32, param_table[3]);
261 buf_set_u32(mem_params[0].value, 160, 32, param_table[4]);
262
263 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
264 buf_set_u32(reg_params[0].value, 0, 32, lpc2000_info->iap_working_area->address + 0x8);
265
266 /* command result table */
267 init_mem_param(&mem_params[1], lpc2000_info->iap_working_area->address + 0x20, 4 * 3, PARAM_IN);
268
269 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
270 buf_set_u32(reg_params[1].value, 0, 32, lpc2000_info->iap_working_area->address + 0x20);
271
272 /* IAP entry point */
273 init_reg_param(&reg_params[2], "r12", 32, PARAM_OUT);
274 buf_set_u32(reg_params[2].value, 0, 32, 0x7ffffff1);
275
276 /* IAP stack */
277 init_reg_param(&reg_params[3], "r13_svc", 32, PARAM_OUT);
278 buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xac);
279
280 /* return address */
281 init_reg_param(&reg_params[4], "lr_svc", 32, PARAM_OUT);
282 buf_set_u32(reg_params[4].value, 0, 32, lpc2000_info->iap_working_area->address + 0x4);
283
284 target->type->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);
285
286 status_code = buf_get_u32(mem_params[1].value, 0, 32);
287 result_table[0] = buf_get_u32(mem_params[1].value, 32, 32);
288 result_table[1] = buf_get_u32(mem_params[1].value, 64, 32);
289
290 destroy_mem_param(&mem_params[0]);
291 destroy_mem_param(&mem_params[1]);
292
293 destroy_reg_param(&reg_params[0]);
294 destroy_reg_param(&reg_params[1]);
295 destroy_reg_param(&reg_params[2]);
296 destroy_reg_param(&reg_params[3]);
297 destroy_reg_param(&reg_params[4]);
298
299 return status_code;
300 }
301
302 int lpc2000_iap_blank_check(struct flash_bank_s *bank, int first, int last)
303 {
304 u32 param_table[5];
305 u32 result_table[2];
306 int status_code;
307 int i;
308
309 if ((first < 0) || (last > bank->num_sectors))
310 return ERROR_FLASH_SECTOR_INVALID;
311
312 for (i = first; i <= last; i++)
313 {
314 /* check single sector */
315 param_table[0] = param_table[1] = i;
316 status_code = lpc2000_iap_call(bank, 53, param_table, result_table);
317
318 switch (status_code)
319 {
320 case ERROR_FLASH_OPERATION_FAILED:
321 return ERROR_FLASH_OPERATION_FAILED;
322 case LPC2000_CMD_SUCCESS:
323 bank->sectors[i].is_erased = 1;
324 break;
325 case LPC2000_SECTOR_NOT_BLANK:
326 bank->sectors[i].is_erased = 0;
327 break;
328 case LPC2000_INVALID_SECTOR:
329 bank->sectors[i].is_erased = 0;
330 break;
331 case LPC2000_BUSY:
332 return ERROR_FLASH_BUSY;
333 break;
334 default:
335 ERROR("BUG: unknown LPC2000 status code");
336 exit(-1);
337 }
338 }
339
340 return ERROR_OK;
341 }
342
343 /* flash_bank lpc2000 <base> <size> 0 0 <lpc_variant> <target#> <cclk> [calc_checksum]
344 */
345 int lpc2000_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
346 {
347 lpc2000_flash_bank_t *lpc2000_info;
348
349 if (argc < 8)
350 {
351 WARNING("incomplete flash_bank lpc2000 configuration");
352 return ERROR_FLASH_BANK_INVALID;
353 }
354
355 lpc2000_info = malloc(sizeof(lpc2000_flash_bank_t));
356 bank->driver_priv = lpc2000_info;
357
358 if (strcmp(args[5], "lpc2000_v1") == 0)
359 {
360 lpc2000_info->variant = 1;
361 lpc2000_info->cmd51_dst_boundary = 512;
362 lpc2000_info->cmd51_can_256b = 0;
363 lpc2000_info->cmd51_can_8192b = 1;
364 }
365 else if (strcmp(args[5], "lpc2000_v2") == 0)
366 {
367 lpc2000_info->variant = 2;
368 lpc2000_info->cmd51_dst_boundary = 256;
369 lpc2000_info->cmd51_can_256b = 1;
370 lpc2000_info->cmd51_can_8192b = 0;
371 }
372 else
373 {
374 ERROR("unknown LPC2000 variant");
375 free(lpc2000_info);
376 return ERROR_FLASH_BANK_INVALID;
377 }
378
379 lpc2000_info->target = get_target_by_num(strtoul(args[6], NULL, 0));
380 if (!lpc2000_info->target)
381 {
382 ERROR("no target '%s' configured", args[6]);
383 exit(-1);
384 }
385 lpc2000_info->iap_working_area = NULL;
386 lpc2000_info->cclk = strtoul(args[7], NULL, 0);
387 lpc2000_info->calc_checksum = 0;
388 lpc2000_build_sector_list(bank);
389
390
391 if (argc >= 9)
392 {
393 if (strcmp(args[8], "calc_checksum") == 0)
394 lpc2000_info->calc_checksum = 1;
395 }
396
397 return ERROR_OK;
398 }
399
400 int lpc2000_erase(struct flash_bank_s *bank, int first, int last)
401 {
402 lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
403 u32 param_table[5];
404 u32 result_table[2];
405 int status_code;
406
407 if (lpc2000_info->target->state != TARGET_HALTED)
408 {
409 return ERROR_TARGET_NOT_HALTED;
410 }
411
412 if ((first < 0) || (last < first) || (last >= bank->num_sectors))
413 {
414 return ERROR_FLASH_SECTOR_INVALID;
415 }
416
417 param_table[0] = first;
418 param_table[1] = last;
419 param_table[2] = lpc2000_info->cclk;
420
421 /* Prepare sectors */
422 status_code = lpc2000_iap_call(bank, 50, param_table, result_table);
423 switch (status_code)
424 {
425 case ERROR_FLASH_OPERATION_FAILED:
426 return ERROR_FLASH_OPERATION_FAILED;
427 case LPC2000_CMD_SUCCESS:
428 break;
429 case LPC2000_INVALID_SECTOR:
430 return ERROR_FLASH_SECTOR_INVALID;
431 break;
432 default:
433 WARNING("lpc2000 prepare sectors returned %i", status_code);
434 return ERROR_FLASH_OPERATION_FAILED;
435 }
436
437 /* Erase sectors */
438 status_code = lpc2000_iap_call(bank, 52, param_table, result_table);
439 switch (status_code)
440 {
441 case ERROR_FLASH_OPERATION_FAILED:
442 return ERROR_FLASH_OPERATION_FAILED;
443 case LPC2000_CMD_SUCCESS:
444 break;
445 case LPC2000_INVALID_SECTOR:
446 return ERROR_FLASH_SECTOR_INVALID;
447 break;
448 default:
449 WARNING("lpc2000 erase sectors returned %i", status_code);
450 return ERROR_FLASH_OPERATION_FAILED;
451 }
452
453 return ERROR_OK;
454 }
455
456 int lpc2000_protect(struct flash_bank_s *bank, int set, int first, int last)
457 {
458 /* can't protect/unprotect on the lpc2000 */
459 return ERROR_OK;
460 }
461
462 int lpc2000_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
463 {
464 lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
465 target_t *target = lpc2000_info->target;
466 u32 dst_min_alignment;
467 u32 bytes_remaining = count;
468 u32 bytes_written = 0;
469 int first_sector = 0;
470 int last_sector = 0;
471 u32 param_table[5];
472 u32 result_table[2];
473 int status_code;
474 int i;
475 working_area_t *download_area;
476
477 if (lpc2000_info->target->state != TARGET_HALTED)
478 {
479 return ERROR_TARGET_NOT_HALTED;
480 }
481
482 /* allocate a working area */
483 if (target_alloc_working_area(target, 4096, &download_area) != ERROR_OK)
484 {
485 ERROR("no working area specified, can't write LPC2000 internal flash");
486 return ERROR_FLASH_OPERATION_FAILED;
487 }
488
489 if (offset + count > bank->size)
490 return ERROR_FLASH_DST_OUT_OF_BANK;
491
492 if (lpc2000_info->cmd51_can_256b)
493 dst_min_alignment = 256;
494 else
495 dst_min_alignment = 512;
496
497 if (offset % dst_min_alignment)
498 {
499 WARNING("offset 0x%x breaks required alignment 0x%x", offset, dst_min_alignment);
500 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
501 }
502
503 for (i = 0; i < bank->num_sectors; i++)
504 {
505 if (offset >= bank->sectors[i].offset)
506 first_sector = i;
507 if (offset + CEIL(count, dst_min_alignment) * dst_min_alignment > bank->sectors[i].offset)
508 last_sector = i;
509 }
510
511 DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector);
512
513 /* check if exception vectors should be flashed */
514 if ((offset == 0) && (count >= 0x20) && lpc2000_info->calc_checksum)
515 {
516 u32 checksum = 0;
517 int i = 0;
518 for (i = 0; i < 8; i++)
519 {
520 DEBUG("0x%2.2x: 0x%8.8x", i * 4, buf_get_u32(buffer + (i * 4), 0, 32));
521 if (i != 5)
522 checksum += buf_get_u32(buffer + (i * 4), 0, 32);
523 }
524 checksum = 0 - checksum;
525 DEBUG("checksum: 0x%8.8x", checksum);
526 buf_set_u32(buffer + 0x14, 0, 32, checksum);
527 }
528
529 while (bytes_remaining > 0)
530 {
531 u32 thisrun_bytes;
532 if (bytes_remaining >= 4096)
533 thisrun_bytes = 4096;
534 else if (bytes_remaining >= 1024)
535 thisrun_bytes = 1024;
536 else if ((bytes_remaining >= 512) || (!lpc2000_info->cmd51_can_256b))
537 thisrun_bytes = 512;
538 else
539 thisrun_bytes = 256;
540
541 /* Prepare sectors */
542 param_table[0] = first_sector;
543 param_table[1] = last_sector;
544 status_code = lpc2000_iap_call(bank, 50, param_table, result_table);
545 switch (status_code)
546 {
547 case ERROR_FLASH_OPERATION_FAILED:
548 return ERROR_FLASH_OPERATION_FAILED;
549 case LPC2000_CMD_SUCCESS:
550 break;
551 case LPC2000_INVALID_SECTOR:
552 return ERROR_FLASH_SECTOR_INVALID;
553 break;
554 default:
555 WARNING("lpc2000 prepare sectors returned %i", status_code);
556 return ERROR_FLASH_OPERATION_FAILED;
557 }
558
559 if (bytes_remaining >= thisrun_bytes)
560 {
561 if (target_write_buffer(lpc2000_info->target, download_area->address, thisrun_bytes, buffer + bytes_written) != ERROR_OK)
562 {
563 target_free_working_area(target, download_area);
564 return ERROR_FLASH_OPERATION_FAILED;
565 }
566 }
567 else
568 {
569 u8 *last_buffer = malloc(thisrun_bytes);
570 int i;
571 memcpy(last_buffer, buffer + bytes_written, bytes_remaining);
572 for (i = bytes_remaining; i < thisrun_bytes; i++)
573 last_buffer[i] = 0xff;
574 target_write_buffer(lpc2000_info->target, download_area->address, thisrun_bytes, last_buffer);
575 free(last_buffer);
576 }
577
578 DEBUG("writing 0x%x bytes to address 0x%x", thisrun_bytes, bank->base + offset + bytes_written);
579
580 /* Write data */
581 param_table[0] = bank->base + offset + bytes_written;
582 param_table[1] = download_area->address;
583 param_table[2] = thisrun_bytes;
584 param_table[3] = lpc2000_info->cclk;
585 status_code = lpc2000_iap_call(bank, 51, param_table, result_table);
586 switch (status_code)
587 {
588 case ERROR_FLASH_OPERATION_FAILED:
589 return ERROR_FLASH_OPERATION_FAILED;
590 case LPC2000_CMD_SUCCESS:
591 break;
592 case LPC2000_INVALID_SECTOR:
593 return ERROR_FLASH_SECTOR_INVALID;
594 break;
595 default:
596 WARNING("lpc2000 returned %i", status_code);
597 return ERROR_FLASH_OPERATION_FAILED;
598 }
599
600 if (bytes_remaining > thisrun_bytes)
601 bytes_remaining -= thisrun_bytes;
602 else
603 bytes_remaining = 0;
604 bytes_written += thisrun_bytes;
605 }
606
607 target_free_working_area(target, download_area);
608
609 return ERROR_OK;
610 }
611
612 int lpc2000_probe(struct flash_bank_s *bank)
613 {
614 /* we can't probe on an lpc2000
615 * if this is an lpc2xxx, it has the configured flash
616 */
617 return ERROR_OK;
618 }
619
620 int lpc2000_erase_check(struct flash_bank_s *bank)
621 {
622 lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
623
624 if (lpc2000_info->target->state != TARGET_HALTED)
625 {
626 return ERROR_TARGET_NOT_HALTED;
627 }
628
629 return lpc2000_iap_blank_check(bank, 0, bank->num_sectors - 1);
630 }
631
632 int lpc2000_protect_check(struct flash_bank_s *bank)
633 {
634 /* sectors are always protected */
635 return ERROR_OK;
636 }
637
638 int lpc2000_info(struct flash_bank_s *bank, char *buf, int buf_size)
639 {
640 lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
641
642 snprintf(buf, buf_size, "lpc2000 flash driver variant: %i, clk: %i", lpc2000_info->variant, lpc2000_info->cclk);
643
644 return ERROR_OK;
645 }
646
647 int lpc2000_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
648 {
649 flash_bank_t *bank;
650 u32 param_table[5];
651 u32 result_table[2];
652 int status_code;
653 lpc2000_flash_bank_t *lpc2000_info;
654
655 if (argc < 1)
656 {
657 command_print(cmd_ctx, "usage: lpc2000 part_id <num>");
658 return ERROR_OK;
659 }
660
661 bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
662 if (!bank)
663 {
664 command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
665 return ERROR_OK;
666 }
667
668 lpc2000_info = bank->driver_priv;
669 if (lpc2000_info->target->state != TARGET_HALTED)
670 {
671 return ERROR_TARGET_NOT_HALTED;
672 }
673
674 if ((status_code = lpc2000_iap_call(bank, 54, param_table, result_table)) != 0x0)
675 {
676 if (status_code == ERROR_FLASH_OPERATION_FAILED)
677 {
678 command_print(cmd_ctx, "no sufficient working area specified, can't access LPC2000 IAP interface");
679 return ERROR_OK;
680 }
681 command_print(cmd_ctx, "lpc2000 IAP returned status code %i", status_code);
682 }
683 else
684 {
685 command_print(cmd_ctx, "lpc2000 part id: 0x%8.8x", result_table[0]);
686 }
687
688 return ERROR_OK;
689 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)