coding style: remove useless break after a goto or return
[openocd.git] / src / flash / nor / fm4.c
1 /*
2 * Spansion FM4 flash
3 *
4 * Copyright (c) 2015 Andreas Färber
5 *
6 * Based on S6E2DH_MN709-00013 for S6E2DH/DF/D5/D3 series
7 * Based on S6E2CC_MN709-00007 for S6E2CC/C5/C4/C3/C2/C1 series
8 * Based on MB9B560R_MN709-00005 for MB9BFx66/x67/x68 series
9 * Based on MB9B560L_MN709-00006 for MB9BFx64/x65/x66 series
10 */
11
12 #ifdef HAVE_CONFIG_H
13 #include "config.h"
14 #endif
15
16 #include "imp.h"
17 #include <helper/binarybuffer.h>
18 #include <target/algorithm.h>
19 #include <target/armv7m.h>
20
21 #define FLASH_BASE 0x40000000
22 #define FASZR (FLASH_BASE + 0x000)
23 #define DFCTRLR (FLASH_BASE + 0x030)
24 #define DFCTRLR_DFE (1UL << 0)
25
26 #define WDG_BASE 0x40011000
27 #define WDG_CTL (WDG_BASE + 0x008)
28 #define WDG_LCK (WDG_BASE + 0xC00)
29
30 enum fm4_variant {
31 mb9bfx64,
32 mb9bfx65,
33 mb9bfx66,
34 mb9bfx67,
35 mb9bfx68,
36
37 s6e2cx8,
38 s6e2cx9,
39 s6e2cxa,
40
41 s6e2dx,
42 };
43
44 struct fm4_flash_bank {
45 enum fm4_variant variant;
46 int macro_nr;
47 bool probed;
48 };
49
50 static int fm4_disable_hw_watchdog(struct target *target)
51 {
52 int retval;
53
54 retval = target_write_u32(target, WDG_LCK, 0x1ACCE551);
55 if (retval != ERROR_OK)
56 return retval;
57
58 retval = target_write_u32(target, WDG_LCK, 0xE5331AAE);
59 if (retval != ERROR_OK)
60 return retval;
61
62 retval = target_write_u32(target, WDG_CTL, 0);
63 if (retval != ERROR_OK)
64 return retval;
65
66 return ERROR_OK;
67 }
68
69 static int fm4_enter_flash_cpu_programming_mode(struct target *target)
70 {
71 uint32_t u32_value;
72 int retval;
73
74 /* FASZR ASZ = CPU programming mode */
75 retval = target_write_u32(target, FASZR, 0x00000001);
76 if (retval != ERROR_OK)
77 return retval;
78 retval = target_read_u32(target, FASZR, &u32_value);
79 if (retval != ERROR_OK)
80 return retval;
81
82 return ERROR_OK;
83 }
84
85 static int fm4_enter_flash_cpu_rom_mode(struct target *target)
86 {
87 uint32_t u32_value;
88 int retval;
89
90 /* FASZR ASZ = CPU ROM mode */
91 retval = target_write_u32(target, FASZR, 0x00000002);
92 if (retval != ERROR_OK)
93 return retval;
94 retval = target_read_u32(target, FASZR, &u32_value);
95 if (retval != ERROR_OK)
96 return retval;
97
98 return ERROR_OK;
99 }
100
101 static int fm4_flash_erase(struct flash_bank *bank, int first, int last)
102 {
103 struct target *target = bank->target;
104 struct working_area *workarea;
105 struct reg_param reg_params[4];
106 struct armv7m_algorithm armv7m_algo;
107 unsigned i;
108 int retval, sector;
109 const uint8_t erase_sector_code[] = {
110 #include "../../../contrib/loaders/flash/fm4/erase.inc"
111 };
112
113 if (target->state != TARGET_HALTED) {
114 LOG_WARNING("Cannot communicate... target not halted.");
115 return ERROR_TARGET_NOT_HALTED;
116 }
117
118 LOG_DEBUG("Spansion FM4 erase sectors %d to %d", first, last);
119
120 retval = fm4_disable_hw_watchdog(target);
121 if (retval != ERROR_OK)
122 return retval;
123
124 retval = fm4_enter_flash_cpu_programming_mode(target);
125 if (retval != ERROR_OK)
126 return retval;
127
128 retval = target_alloc_working_area(target, sizeof(erase_sector_code),
129 &workarea);
130 if (retval != ERROR_OK) {
131 LOG_ERROR("No working area available.");
132 retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
133 goto err_alloc_code;
134 }
135 retval = target_write_buffer(target, workarea->address,
136 sizeof(erase_sector_code), erase_sector_code);
137 if (retval != ERROR_OK)
138 goto err_write_code;
139
140 armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
141 armv7m_algo.core_mode = ARM_MODE_THREAD;
142
143 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
144 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
145 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
146 init_reg_param(&reg_params[3], "r3", 32, PARAM_IN);
147
148 for (sector = first; sector <= last; sector++) {
149 uint32_t addr = bank->base + bank->sectors[sector].offset;
150 uint32_t result;
151
152 buf_set_u32(reg_params[0].value, 0, 32, (addr & ~0xffff) | 0xAA8);
153 buf_set_u32(reg_params[1].value, 0, 32, (addr & ~0xffff) | 0x554);
154 buf_set_u32(reg_params[2].value, 0, 32, addr);
155
156 retval = target_run_algorithm(target,
157 0, NULL,
158 ARRAY_SIZE(reg_params), reg_params,
159 workarea->address, 0,
160 1000, &armv7m_algo);
161 if (retval != ERROR_OK) {
162 LOG_ERROR("Error executing flash sector erase "
163 "programming algorithm");
164 retval = ERROR_FLASH_OPERATION_FAILED;
165 goto err_run;
166 }
167
168 result = buf_get_u32(reg_params[3].value, 0, 32);
169 if (result == 2) {
170 LOG_ERROR("Timeout error from flash sector erase programming algorithm");
171 retval = ERROR_FLASH_OPERATION_FAILED;
172 goto err_run_ret;
173 } else if (result != 0) {
174 LOG_ERROR("Unexpected error %d from flash sector erase programming algorithm", result);
175 retval = ERROR_FLASH_OPERATION_FAILED;
176 goto err_run_ret;
177 } else
178 retval = ERROR_OK;
179
180 bank->sectors[sector].is_erased = 1;
181 }
182
183 err_run_ret:
184 err_run:
185 for (i = 0; i < ARRAY_SIZE(reg_params); i++)
186 destroy_reg_param(&reg_params[i]);
187
188 err_write_code:
189 target_free_working_area(target, workarea);
190
191 err_alloc_code:
192 if (retval != ERROR_OK)
193 fm4_enter_flash_cpu_rom_mode(target);
194 else
195 retval = fm4_enter_flash_cpu_rom_mode(target);
196
197 return retval;
198 }
199
200 static int fm4_flash_write(struct flash_bank *bank, const uint8_t *buffer,
201 uint32_t offset, uint32_t byte_count)
202 {
203 struct target *target = bank->target;
204 struct working_area *code_workarea, *data_workarea;
205 struct reg_param reg_params[6];
206 struct armv7m_algorithm armv7m_algo;
207 uint32_t halfword_count = DIV_ROUND_UP(byte_count, 2);
208 uint32_t result;
209 unsigned i;
210 int retval, retval2 = ERROR_OK;
211 const uint8_t write_block_code[] = {
212 #include "../../../contrib/loaders/flash/fm4/write.inc"
213 };
214
215 LOG_DEBUG("Spansion FM4 write at 0x%08" PRIx32 " (%" PRId32 " bytes)",
216 offset, byte_count);
217
218 if (offset & 0x1) {
219 LOG_ERROR("offset 0x%" PRIx32 " breaks required 2-byte alignment",
220 offset);
221 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
222 }
223 if (byte_count & 0x1) {
224 LOG_WARNING("length %" PRId32 " is not 2-byte aligned, rounding up",
225 byte_count);
226 }
227
228 if (target->state != TARGET_HALTED) {
229 LOG_WARNING("Cannot communicate... target not halted.");
230 return ERROR_TARGET_NOT_HALTED;
231 }
232
233 retval = fm4_disable_hw_watchdog(target);
234 if (retval != ERROR_OK)
235 return retval;
236
237 retval = target_alloc_working_area(target, sizeof(write_block_code),
238 &code_workarea);
239 if (retval != ERROR_OK) {
240 LOG_ERROR("No working area available for write code.");
241 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
242 }
243 retval = target_write_buffer(target, code_workarea->address,
244 sizeof(write_block_code), write_block_code);
245 if (retval != ERROR_OK)
246 goto err_write_code;
247
248 retval = target_alloc_working_area(target,
249 MIN(halfword_count * 2, target_get_working_area_avail(target)),
250 &data_workarea);
251 if (retval != ERROR_OK) {
252 LOG_ERROR("No working area available for write data.");
253 retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
254 goto err_alloc_data;
255 }
256
257 armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
258 armv7m_algo.core_mode = ARM_MODE_THREAD;
259
260 init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
261 init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
262 init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
263 init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
264 init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT);
265 init_reg_param(&reg_params[5], "r5", 32, PARAM_IN);
266
267 retval = fm4_enter_flash_cpu_programming_mode(target);
268 if (retval != ERROR_OK)
269 goto err_flash_mode;
270
271 while (byte_count > 0) {
272 uint32_t halfwords = MIN(halfword_count, data_workarea->size / 2);
273 uint32_t addr = bank->base + offset;
274
275 LOG_DEBUG("copying %" PRId32 " bytes to SRAM " TARGET_ADDR_FMT,
276 MIN(halfwords * 2, byte_count), data_workarea->address);
277
278 retval = target_write_buffer(target, data_workarea->address,
279 MIN(halfwords * 2, byte_count), buffer);
280 if (retval != ERROR_OK) {
281 LOG_ERROR("Error writing data buffer");
282 retval = ERROR_FLASH_OPERATION_FAILED;
283 goto err_write_data;
284 }
285
286 LOG_DEBUG("writing 0x%08" PRIx32 "-0x%08" PRIx32 " (%" PRId32 "x)",
287 addr, addr + halfwords * 2 - 1, halfwords);
288
289 buf_set_u32(reg_params[0].value, 0, 32, (addr & ~0xffff) | 0xAA8);
290 buf_set_u32(reg_params[1].value, 0, 32, (addr & ~0xffff) | 0x554);
291 buf_set_u32(reg_params[2].value, 0, 32, addr);
292 buf_set_u32(reg_params[3].value, 0, 32, data_workarea->address);
293 buf_set_u32(reg_params[4].value, 0, 32, halfwords);
294
295 retval = target_run_algorithm(target,
296 0, NULL,
297 ARRAY_SIZE(reg_params), reg_params,
298 code_workarea->address, 0,
299 5 * 60 * 1000, &armv7m_algo);
300 if (retval != ERROR_OK) {
301 LOG_ERROR("Error executing flash sector erase "
302 "programming algorithm");
303 retval = ERROR_FLASH_OPERATION_FAILED;
304 goto err_run;
305 }
306
307 result = buf_get_u32(reg_params[5].value, 0, 32);
308 if (result == 2) {
309 LOG_ERROR("Timeout error from flash write "
310 "programming algorithm");
311 retval = ERROR_FLASH_OPERATION_FAILED;
312 goto err_run_ret;
313 } else if (result != 0) {
314 LOG_ERROR("Unexpected error %d from flash write "
315 "programming algorithm", result);
316 retval = ERROR_FLASH_OPERATION_FAILED;
317 goto err_run_ret;
318 } else
319 retval = ERROR_OK;
320
321 halfword_count -= halfwords;
322 offset += halfwords * 2;
323 buffer += halfwords * 2;
324 byte_count -= MIN(halfwords * 2, byte_count);
325 }
326
327 err_run_ret:
328 err_run:
329 err_write_data:
330 retval2 = fm4_enter_flash_cpu_rom_mode(target);
331
332 err_flash_mode:
333 for (i = 0; i < ARRAY_SIZE(reg_params); i++)
334 destroy_reg_param(&reg_params[i]);
335
336 target_free_working_area(target, data_workarea);
337 err_alloc_data:
338 err_write_code:
339 target_free_working_area(target, code_workarea);
340
341 if (retval != ERROR_OK)
342 return retval;
343 return retval2;
344 }
345
346 static int mb9bf_probe(struct flash_bank *bank)
347 {
348 struct fm4_flash_bank *fm4_bank = bank->driver_priv;
349 uint32_t flash_addr = bank->base;
350 int i;
351
352 switch (fm4_bank->variant) {
353 case mb9bfx64:
354 bank->num_sectors = 8;
355 break;
356 case mb9bfx65:
357 bank->num_sectors = 10;
358 break;
359 case mb9bfx66:
360 bank->num_sectors = 12;
361 break;
362 case mb9bfx67:
363 bank->num_sectors = 16;
364 break;
365 case mb9bfx68:
366 bank->num_sectors = 20;
367 break;
368 default:
369 return ERROR_FLASH_OPER_UNSUPPORTED;
370 }
371
372 LOG_DEBUG("%d sectors", bank->num_sectors);
373 bank->sectors = calloc(bank->num_sectors,
374 sizeof(struct flash_sector));
375 for (i = 0; i < bank->num_sectors; i++) {
376 if (i < 4)
377 bank->sectors[i].size = 8 * 1024;
378 else if (i == 4)
379 bank->sectors[i].size = 32 * 1024;
380 else
381 bank->sectors[i].size = 64 * 1024;
382 bank->sectors[i].offset = flash_addr - bank->base;
383 bank->sectors[i].is_erased = -1;
384 bank->sectors[i].is_protected = -1;
385
386 bank->size += bank->sectors[i].size;
387 flash_addr += bank->sectors[i].size;
388 }
389
390 return ERROR_OK;
391 }
392
393 static void s6e2cc_init_sector(struct flash_sector *sector, int sa)
394 {
395 if (sa < 8)
396 sector->size = 8 * 1024;
397 else if (sa == 8)
398 sector->size = 32 * 1024;
399 else
400 sector->size = 64 * 1024;
401
402 sector->is_erased = -1;
403 sector->is_protected = -1;
404 }
405
406 static int s6e2cc_probe(struct flash_bank *bank)
407 {
408 struct target *target = bank->target;
409 struct fm4_flash_bank *fm4_bank = bank->driver_priv;
410 uint32_t u32_value;
411 uint32_t flash_addr = bank->base;
412 int i, retval, num_sectors, num_extra_sectors;
413
414 retval = target_read_u32(target, DFCTRLR, &u32_value);
415 if (retval != ERROR_OK)
416 return retval;
417 if (u32_value & DFCTRLR_DFE) {
418 LOG_WARNING("Dual Flash mode is not implemented.");
419 return ERROR_FLASH_OPER_UNSUPPORTED;
420 }
421
422 switch (fm4_bank->variant) {
423 case s6e2cx8:
424 num_sectors = (fm4_bank->macro_nr == 0) ? 20 : 0;
425 break;
426 case s6e2cx9:
427 num_sectors = (fm4_bank->macro_nr == 0) ? 20 : 12;
428 break;
429 case s6e2cxa:
430 num_sectors = 20;
431 break;
432 default:
433 return ERROR_FLASH_OPER_UNSUPPORTED;
434 }
435 num_extra_sectors = (fm4_bank->macro_nr == 0) ? 1 : 4;
436 bank->num_sectors = num_sectors + num_extra_sectors;
437
438 LOG_DEBUG("%d sectors", bank->num_sectors);
439 bank->sectors = calloc(bank->num_sectors,
440 sizeof(struct flash_sector));
441 for (i = 0; i < num_sectors; i++) {
442 int sa = 4 + i;
443 bank->sectors[i].offset = flash_addr - bank->base;
444 s6e2cc_init_sector(&bank->sectors[i], sa);
445
446 bank->size += bank->sectors[i].size;
447 flash_addr += bank->sectors[i].size;
448 }
449
450 flash_addr = (fm4_bank->macro_nr == 0) ? 0x00406000 : 0x00408000;
451 for (; i < bank->num_sectors; i++) {
452 int sa = 4 - num_extra_sectors + (i - num_sectors);
453 bank->sectors[i].offset = flash_addr - bank->base;
454 s6e2cc_init_sector(&bank->sectors[i], sa);
455
456 /*
457 * Don't increase bank->size for these sectors
458 * to avoid an overlap between Flash Macros #0 and #1.
459 */
460 flash_addr += bank->sectors[i].size;
461 }
462
463 return ERROR_OK;
464 }
465
466 static int s6e2dh_probe(struct flash_bank *bank)
467 {
468 uint32_t flash_addr = bank->base;
469 int i;
470
471 bank->num_sectors = 10;
472 bank->sectors = calloc(bank->num_sectors,
473 sizeof(struct flash_sector));
474 for (i = 0; i < bank->num_sectors; i++) {
475 if (i < 4)
476 bank->sectors[i].size = 8 * 1024;
477 else if (i == 4)
478 bank->sectors[i].size = 32 * 1024;
479 else
480 bank->sectors[i].size = 64 * 1024;
481 bank->sectors[i].offset = flash_addr - bank->base;
482 bank->sectors[i].is_erased = -1;
483 bank->sectors[i].is_protected = -1;
484
485 bank->size += bank->sectors[i].size;
486 flash_addr += bank->sectors[i].size;
487 }
488
489 return ERROR_OK;
490 }
491
492 static int fm4_probe(struct flash_bank *bank)
493 {
494 struct fm4_flash_bank *fm4_bank = bank->driver_priv;
495 int retval;
496
497 if (fm4_bank->probed)
498 return ERROR_OK;
499
500 if (bank->target->state != TARGET_HALTED) {
501 LOG_WARNING("Cannot communicate... target not halted.");
502 return ERROR_TARGET_NOT_HALTED;
503 }
504
505 switch (fm4_bank->variant) {
506 case mb9bfx64:
507 case mb9bfx65:
508 case mb9bfx66:
509 case mb9bfx67:
510 case mb9bfx68:
511 retval = mb9bf_probe(bank);
512 break;
513 case s6e2cx8:
514 case s6e2cx9:
515 case s6e2cxa:
516 retval = s6e2cc_probe(bank);
517 break;
518 case s6e2dx:
519 retval = s6e2dh_probe(bank);
520 break;
521 default:
522 return ERROR_FLASH_OPER_UNSUPPORTED;
523 }
524 if (retval != ERROR_OK)
525 return retval;
526
527 fm4_bank->probed = true;
528
529 return ERROR_OK;
530 }
531
532 static int fm4_auto_probe(struct flash_bank *bank)
533 {
534 struct fm4_flash_bank *fm4_bank = bank->driver_priv;
535
536 if (fm4_bank->probed)
537 return ERROR_OK;
538
539 return fm4_probe(bank);
540 }
541
542 static int fm4_get_info_command(struct flash_bank *bank, char *buf, int buf_size)
543 {
544 struct fm4_flash_bank *fm4_bank = bank->driver_priv;
545 const char *name;
546
547 if (bank->target->state != TARGET_HALTED) {
548 LOG_WARNING("Cannot communicate... target not halted.");
549 return ERROR_TARGET_NOT_HALTED;
550 }
551
552 switch (fm4_bank->variant) {
553 case mb9bfx64:
554 name = "MB9BFx64";
555 break;
556 case mb9bfx65:
557 name = "MB9BFx65";
558 break;
559 case mb9bfx66:
560 name = "MB9BFx66";
561 break;
562 case mb9bfx67:
563 name = "MB9BFx67";
564 break;
565 case mb9bfx68:
566 name = "MB9BFx68";
567 break;
568 case s6e2cx8:
569 name = "S6E2Cx8";
570 break;
571 case s6e2cx9:
572 name = "S6E2Cx9";
573 break;
574 case s6e2cxa:
575 name = "S6E2CxA";
576 break;
577 case s6e2dx:
578 name = "S6E2Dx";
579 break;
580 default:
581 name = "unknown";
582 break;
583 }
584
585 switch (fm4_bank->variant) {
586 case s6e2cx8:
587 case s6e2cx9:
588 case s6e2cxa:
589 snprintf(buf, buf_size, "%s MainFlash Macro #%i",
590 name, fm4_bank->macro_nr);
591 break;
592 default:
593 snprintf(buf, buf_size, "%s MainFlash", name);
594 break;
595 }
596
597 return ERROR_OK;
598 }
599
600 static bool fm4_name_match(const char *s, const char *pattern)
601 {
602 int i = 0;
603
604 while (s[i]) {
605 /* If the match string is shorter, ignore excess */
606 if (!pattern[i])
607 return true;
608 /* Use x as wildcard */
609 if (pattern[i] != 'x' && tolower(s[i]) != tolower(pattern[i]))
610 return false;
611 i++;
612 }
613 return true;
614 }
615
616 static int mb9bf_bank_setup(struct flash_bank *bank, const char *variant)
617 {
618 struct fm4_flash_bank *fm4_bank = bank->driver_priv;
619
620 if (fm4_name_match(variant, "MB9BFx64")) {
621 fm4_bank->variant = mb9bfx64;
622 } else if (fm4_name_match(variant, "MB9BFx65")) {
623 fm4_bank->variant = mb9bfx65;
624 } else if (fm4_name_match(variant, "MB9BFx66")) {
625 fm4_bank->variant = mb9bfx66;
626 } else if (fm4_name_match(variant, "MB9BFx67")) {
627 fm4_bank->variant = mb9bfx67;
628 } else if (fm4_name_match(variant, "MB9BFx68")) {
629 fm4_bank->variant = mb9bfx68;
630 } else {
631 LOG_WARNING("MB9BF variant %s not recognized.", variant);
632 return ERROR_FLASH_OPER_UNSUPPORTED;
633 }
634
635 return ERROR_OK;
636 }
637
638 static int s6e2cc_bank_setup(struct flash_bank *bank, const char *variant)
639 {
640 struct fm4_flash_bank *fm4_bank = bank->driver_priv;
641
642 if (fm4_name_match(variant, "S6E2Cx8")) {
643 fm4_bank->variant = s6e2cx8;
644 } else if (fm4_name_match(variant, "S6E2Cx9")) {
645 fm4_bank->variant = s6e2cx9;
646 } else if (fm4_name_match(variant, "S6E2CxA")) {
647 fm4_bank->variant = s6e2cxa;
648 } else {
649 LOG_WARNING("S6E2CC variant %s not recognized.", variant);
650 return ERROR_FLASH_OPER_UNSUPPORTED;
651 }
652
653 return ERROR_OK;
654 }
655
656 FLASH_BANK_COMMAND_HANDLER(fm4_flash_bank_command)
657 {
658 struct fm4_flash_bank *fm4_bank;
659 const char *variant;
660 int ret;
661
662 if (CMD_ARGC < 7)
663 return ERROR_COMMAND_SYNTAX_ERROR;
664
665 variant = CMD_ARGV[6];
666
667 fm4_bank = malloc(sizeof(struct fm4_flash_bank));
668 if (!fm4_bank)
669 return ERROR_FLASH_OPERATION_FAILED;
670
671 fm4_bank->probed = false;
672 fm4_bank->macro_nr = (bank->base == 0x00000000) ? 0 : 1;
673
674 bank->driver_priv = fm4_bank;
675
676 if (fm4_name_match(variant, "MB9BF"))
677 ret = mb9bf_bank_setup(bank, variant);
678 else if (fm4_name_match(variant, "S6E2Cx"))
679 ret = s6e2cc_bank_setup(bank, variant);
680 else if (fm4_name_match(variant, "S6E2Dx")) {
681 fm4_bank->variant = s6e2dx;
682 ret = ERROR_OK;
683 } else {
684 LOG_WARNING("Family %s not recognized.", variant);
685 ret = ERROR_FLASH_OPER_UNSUPPORTED;
686 }
687 if (ret != ERROR_OK)
688 free(fm4_bank);
689 return ret;
690 }
691
692 static const struct command_registration fm4_exec_command_handlers[] = {
693 COMMAND_REGISTRATION_DONE
694 };
695
696 static const struct command_registration fm4_command_handlers[] = {
697 {
698 .name = "fm4",
699 .mode = COMMAND_ANY,
700 .help = "fm4 flash command group",
701 .usage = "",
702 .chain = fm4_exec_command_handlers,
703 },
704 COMMAND_REGISTRATION_DONE
705 };
706
707 const struct flash_driver fm4_flash = {
708 .name = "fm4",
709 .commands = fm4_command_handlers,
710 .flash_bank_command = fm4_flash_bank_command,
711 .info = fm4_get_info_command,
712 .probe = fm4_probe,
713 .auto_probe = fm4_auto_probe,
714 .read = default_flash_read,
715 .erase = fm4_flash_erase,
716 .erase_check = default_flash_blank_check,
717 .write = fm4_flash_write,
718 .free_driver_priv = default_flash_free_driver_priv,
719 };

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)