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

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)