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

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)