09d6fc8a158366896c13cfcac4729de28e0c278b
[openocd.git] / src / target / embeddedice.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * Copyright (C) 2007-2010 Øyvind Harboe *
6 * oyvind.harboe@zylin.com *
7 * *
8 * Copyright (C) 2008 by Spencer Oliver *
9 * spen@spen-soft.co.uk *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * GNU General Public License for more details. *
20 * *
21 * You should have received a copy of the GNU General Public License *
22 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
23 ***************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include "embeddedice.h"
30 #include "register.h"
31
32 /**
33 * @file
34 *
35 * This provides lowlevel glue to the EmbeddedICE (or EmbeddedICE-RT)
36 * module found on scan chain 2 in ARM7, ARM9, and some other families
37 * of ARM cores. The module is called "EmbeddedICE-RT" if it has
38 * monitor mode support.
39 *
40 * EmbeddedICE provides basic watchpoint/breakpoint hardware and a Debug
41 * Communications Channel (DCC) used to read or write 32-bit words to
42 * OpenOCD-aware code running on the target CPU.
43 * Newer modules also include vector catch hardware. Some versions
44 * support hardware single-stepping, "monitor mode" debug (which is not
45 * currently supported by OpenOCD), or extended reporting on why the
46 * core entered debug mode.
47 */
48
49 static int embeddedice_set_reg_w_exec(struct reg *reg, uint8_t *buf);
50
51 /*
52 * From: ARM9E-S TRM, DDI 0165, table C-4 (and similar, for other cores)
53 */
54 static const struct {
55 const char *name;
56 unsigned short addr;
57 unsigned short width;
58 } eice_regs[] = {
59 [EICE_DBG_CTRL] = {
60 .name = "debug_ctrl",
61 .addr = 0,
62 /* width is assigned based on EICE version */
63 },
64 [EICE_DBG_STAT] = {
65 .name = "debug_status",
66 .addr = 1,
67 /* width is assigned based on EICE version */
68 },
69 [EICE_COMMS_CTRL] = {
70 .name = "comms_ctrl",
71 .addr = 4,
72 .width = 6,
73 },
74 [EICE_COMMS_DATA] = {
75 .name = "comms_data",
76 .addr = 5,
77 .width = 32,
78 },
79 [EICE_W0_ADDR_VALUE] = {
80 .name = "watch_0_addr_value",
81 .addr = 8,
82 .width = 32,
83 },
84 [EICE_W0_ADDR_MASK] = {
85 .name = "watch_0_addr_mask",
86 .addr = 9,
87 .width = 32,
88 },
89 [EICE_W0_DATA_VALUE] = {
90 .name = "watch_0_data_value",
91 .addr = 10,
92 .width = 32,
93 },
94 [EICE_W0_DATA_MASK] = {
95 .name = "watch_0_data_mask",
96 .addr = 11,
97 .width = 32,
98 },
99 [EICE_W0_CONTROL_VALUE] = {
100 .name = "watch_0_control_value",
101 .addr = 12,
102 .width = 9,
103 },
104 [EICE_W0_CONTROL_MASK] = {
105 .name = "watch_0_control_mask",
106 .addr = 13,
107 .width = 8,
108 },
109 [EICE_W1_ADDR_VALUE] = {
110 .name = "watch_1_addr_value",
111 .addr = 16,
112 .width = 32,
113 },
114 [EICE_W1_ADDR_MASK] = {
115 .name = "watch_1_addr_mask",
116 .addr = 17,
117 .width = 32,
118 },
119 [EICE_W1_DATA_VALUE] = {
120 .name = "watch_1_data_value",
121 .addr = 18,
122 .width = 32,
123 },
124 [EICE_W1_DATA_MASK] = {
125 .name = "watch_1_data_mask",
126 .addr = 19,
127 .width = 32,
128 },
129 [EICE_W1_CONTROL_VALUE] = {
130 .name = "watch_1_control_value",
131 .addr = 20,
132 .width = 9,
133 },
134 [EICE_W1_CONTROL_MASK] = {
135 .name = "watch_1_control_mask",
136 .addr = 21,
137 .width = 8,
138 },
139 /* vector_catch isn't always present */
140 [EICE_VEC_CATCH] = {
141 .name = "vector_catch",
142 .addr = 2,
143 .width = 8,
144 },
145 };
146
147 static int embeddedice_get_reg(struct reg *reg)
148 {
149 int retval = embeddedice_read_reg(reg);
150 if (retval != ERROR_OK) {
151 LOG_ERROR("error queueing EmbeddedICE register read");
152 return retval;
153 }
154
155 retval = jtag_execute_queue();
156 if (retval != ERROR_OK)
157 LOG_ERROR("EmbeddedICE register read failed");
158
159 return retval;
160 }
161
162 static const struct reg_arch_type eice_reg_type = {
163 .get = embeddedice_get_reg,
164 .set = embeddedice_set_reg_w_exec,
165 };
166
167 /**
168 * Probe EmbeddedICE module and set up local records of its registers.
169 * Different versions of the modules have different capabilities, such as
170 * hardware support for vector_catch, single stepping, and monitor mode.
171 */
172 struct reg_cache *embeddedice_build_reg_cache(struct target *target,
173 struct arm7_9_common *arm7_9)
174 {
175 int retval;
176 struct reg_cache *reg_cache = malloc(sizeof(struct reg_cache));
177 struct reg *reg_list = NULL;
178 struct embeddedice_reg *arch_info = NULL;
179 struct arm_jtag *jtag_info = &arm7_9->jtag_info;
180 int num_regs = ARRAY_SIZE(eice_regs);
181 int i;
182 int eice_version = 0;
183
184 /* vector_catch isn't always present */
185 if (!arm7_9->has_vector_catch)
186 num_regs--;
187
188 /* the actual registers are kept in two arrays */
189 reg_list = calloc(num_regs, sizeof(struct reg));
190 arch_info = calloc(num_regs, sizeof(struct embeddedice_reg));
191
192 /* fill in values for the reg cache */
193 reg_cache->name = "EmbeddedICE registers";
194 reg_cache->next = NULL;
195 reg_cache->reg_list = reg_list;
196 reg_cache->num_regs = num_regs;
197
198 /* FIXME the second watchpoint unit on Feroceon and Dragonite
199 * seems not to work ... we should have a way to not set up
200 * its four registers here!
201 */
202
203 /* set up registers */
204 for (i = 0; i < num_regs; i++) {
205 reg_list[i].name = eice_regs[i].name;
206 reg_list[i].size = eice_regs[i].width;
207 reg_list[i].dirty = 0;
208 reg_list[i].valid = 0;
209 reg_list[i].value = calloc(1, 4);
210 reg_list[i].arch_info = &arch_info[i];
211 reg_list[i].type = &eice_reg_type;
212 arch_info[i].addr = eice_regs[i].addr;
213 arch_info[i].jtag_info = jtag_info;
214 }
215
216 /* identify EmbeddedICE version by reading DCC control register */
217 embeddedice_read_reg(&reg_list[EICE_COMMS_CTRL]);
218 retval = jtag_execute_queue();
219 if (retval != ERROR_OK) {
220 for (i = 0; i < num_regs; i++)
221 free(reg_list[i].value);
222 free(reg_list);
223 free(reg_cache);
224 free(arch_info);
225 return NULL;
226 }
227
228 eice_version = buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 28, 4);
229 LOG_INFO("Embedded ICE version %d", eice_version);
230
231 switch (eice_version) {
232 case 1:
233 /* ARM7TDMI r3, ARM7TDMI-S r3
234 *
235 * REVISIT docs say ARM7TDMI-S r4 uses version 1 but
236 * that it has 6-bit CTRL and 5-bit STAT... doc bug?
237 * ARM7TDMI r4 docs say EICE v4.
238 */
239 reg_list[EICE_DBG_CTRL].size = 3;
240 reg_list[EICE_DBG_STAT].size = 5;
241 break;
242 case 2:
243 /* ARM9TDMI */
244 reg_list[EICE_DBG_CTRL].size = 4;
245 reg_list[EICE_DBG_STAT].size = 5;
246 arm7_9->has_single_step = 1;
247 break;
248 case 3:
249 LOG_ERROR("EmbeddedICE v%d handling might be broken",
250 eice_version);
251 reg_list[EICE_DBG_CTRL].size = 6;
252 reg_list[EICE_DBG_STAT].size = 5;
253 arm7_9->has_single_step = 1;
254 arm7_9->has_monitor_mode = 1;
255 break;
256 case 4:
257 /* ARM7TDMI r4 */
258 reg_list[EICE_DBG_CTRL].size = 6;
259 reg_list[EICE_DBG_STAT].size = 5;
260 arm7_9->has_monitor_mode = 1;
261 break;
262 case 5:
263 /* ARM9E-S rev 1 */
264 reg_list[EICE_DBG_CTRL].size = 6;
265 reg_list[EICE_DBG_STAT].size = 5;
266 arm7_9->has_single_step = 1;
267 arm7_9->has_monitor_mode = 1;
268 break;
269 case 6:
270 /* ARM7EJ-S, ARM9E-S rev 2, ARM9EJ-S */
271 reg_list[EICE_DBG_CTRL].size = 6;
272 reg_list[EICE_DBG_STAT].size = 10;
273 /* DBG_STAT has MOE bits */
274 arm7_9->has_monitor_mode = 1;
275 break;
276 case 7:
277 LOG_ERROR("EmbeddedICE v%d handling might be broken",
278 eice_version);
279 reg_list[EICE_DBG_CTRL].size = 6;
280 reg_list[EICE_DBG_STAT].size = 5;
281 arm7_9->has_monitor_mode = 1;
282 break;
283 default:
284 /*
285 * The Feroceon implementation has the version number
286 * in some unusual bits. Let feroceon.c validate it
287 * and do the appropriate setup itself.
288 */
289 if (strcmp(target_type_name(target), "feroceon") == 0 ||
290 strcmp(target_type_name(target), "dragonite") == 0)
291 break;
292 LOG_ERROR("unknown EmbeddedICE version "
293 "(comms ctrl: 0x%8.8" PRIx32 ")",
294 buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 0, 32));
295 }
296
297 /* On Feroceon and Dragonite the second unit is seemingly missing. */
298 LOG_INFO("%s: hardware has %d breakpoint/watchpoint unit%s",
299 target_name(target), arm7_9->wp_available_max,
300 (arm7_9->wp_available_max != 1) ? "s" : "");
301
302 return reg_cache;
303 }
304
305 /**
306 * Initialize EmbeddedICE module, if needed.
307 */
308 int embeddedice_setup(struct target *target)
309 {
310 int retval;
311 struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
312
313 /* Explicitly disable monitor mode. For now we only support halting
314 * debug ... we don't know how to talk with a resident debug monitor
315 * that manages break requests. ARM's "Angel Debug Monitor" is one
316 * common example of such code.
317 */
318 if (arm7_9->has_monitor_mode) {
319 struct reg *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL];
320
321 embeddedice_read_reg(dbg_ctrl);
322 retval = jtag_execute_queue();
323 if (retval != ERROR_OK)
324 return retval;
325 buf_set_u32(dbg_ctrl->value, 4, 1, 0);
326 embeddedice_set_reg_w_exec(dbg_ctrl, dbg_ctrl->value);
327 }
328 return jtag_execute_queue();
329 }
330
331 /**
332 * Queue a read for an EmbeddedICE register into the register cache,
333 * optionally checking the value read.
334 * Note that at this level, all registers are 32 bits wide.
335 */
336 int embeddedice_read_reg_w_check(struct reg *reg,
337 uint8_t *check_value, uint8_t *check_mask)
338 {
339 struct embeddedice_reg *ice_reg = reg->arch_info;
340 uint8_t reg_addr = ice_reg->addr & 0x1f;
341 struct scan_field fields[3];
342 uint8_t field1_out[1];
343 uint8_t field2_out[1];
344 int retval;
345
346 retval = arm_jtag_scann(ice_reg->jtag_info, 0x2, TAP_IDLE);
347 if (retval != ERROR_OK)
348 return retval;
349
350 retval = arm_jtag_set_instr(ice_reg->jtag_info->tap,
351 ice_reg->jtag_info->intest_instr, NULL, TAP_IDLE);
352 if (retval != ERROR_OK)
353 return retval;
354
355 /* bits 31:0 -- data (ignored here) */
356 fields[0].num_bits = 32;
357 fields[0].out_value = reg->value;
358 fields[0].in_value = NULL;
359 fields[0].check_value = NULL;
360 fields[0].check_mask = NULL;
361
362 /* bits 36:32 -- register */
363 fields[1].num_bits = 5;
364 fields[1].out_value = field1_out;
365 field1_out[0] = reg_addr;
366 fields[1].in_value = NULL;
367 fields[1].check_value = NULL;
368 fields[1].check_mask = NULL;
369
370 /* bit 37 -- 0/read */
371 fields[2].num_bits = 1;
372 fields[2].out_value = field2_out;
373 field2_out[0] = 0;
374 fields[2].in_value = NULL;
375 fields[2].check_value = NULL;
376 fields[2].check_mask = NULL;
377
378 /* traverse Update-DR, setting address for the next read */
379 jtag_add_dr_scan(ice_reg->jtag_info->tap, 3, fields, TAP_IDLE);
380
381 /* bits 31:0 -- the data we're reading (and maybe checking) */
382 fields[0].in_value = reg->value;
383 fields[0].check_value = check_value;
384 fields[0].check_mask = check_mask;
385
386 /* when reading the DCC data register, leaving the address field set to
387 * EICE_COMMS_DATA would read the register twice
388 * reading the control register is safe
389 */
390 field1_out[0] = eice_regs[EICE_COMMS_CTRL].addr;
391
392 /* traverse Update-DR, reading but with no other side effects */
393 jtag_add_dr_scan_check(ice_reg->jtag_info->tap, 3, fields, TAP_IDLE);
394
395 return ERROR_OK;
396 }
397
398 /**
399 * Receive a block of size 32-bit words from the DCC.
400 * We assume the target is always going to be fast enough (relative to
401 * the JTAG clock) that the debugger won't need to poll the handshake
402 * bit. The JTAG clock is usually at least six times slower than the
403 * functional clock, so the 50+ JTAG clocks needed to receive the word
404 * allow hundreds of instruction cycles (per word) in the target.
405 */
406 int embeddedice_receive(struct arm_jtag *jtag_info, uint32_t *data, uint32_t size)
407 {
408 struct scan_field fields[3];
409 uint8_t field1_out[1];
410 uint8_t field2_out[1];
411 int retval;
412
413 retval = arm_jtag_scann(jtag_info, 0x2, TAP_IDLE);
414 if (retval != ERROR_OK)
415 return retval;
416 retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_IDLE);
417 if (retval != ERROR_OK)
418 return retval;
419
420 fields[0].num_bits = 32;
421 fields[0].out_value = NULL;
422 fields[0].in_value = NULL;
423
424 fields[1].num_bits = 5;
425 fields[1].out_value = field1_out;
426 field1_out[0] = eice_regs[EICE_COMMS_DATA].addr;
427 fields[1].in_value = NULL;
428
429 fields[2].num_bits = 1;
430 fields[2].out_value = field2_out;
431 field2_out[0] = 0;
432 fields[2].in_value = NULL;
433
434 jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
435
436 while (size > 0) {
437 /* when reading the last item, set the register address to the DCC control reg,
438 * to avoid reading additional data from the DCC data reg
439 */
440 if (size == 1)
441 field1_out[0] = eice_regs[EICE_COMMS_CTRL].addr;
442
443 fields[0].in_value = (uint8_t *)data;
444 jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
445 jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)data);
446
447 data++;
448 size--;
449 }
450
451 return jtag_execute_queue();
452 }
453
454 /**
455 * Queue a read for an EmbeddedICE register into the register cache,
456 * not checking the value read.
457 */
458 int embeddedice_read_reg(struct reg *reg)
459 {
460 return embeddedice_read_reg_w_check(reg, NULL, NULL);
461 }
462
463 /**
464 * Queue a write for an EmbeddedICE register, updating the register cache.
465 * Uses embeddedice_write_reg().
466 */
467 void embeddedice_set_reg(struct reg *reg, uint32_t value)
468 {
469 embeddedice_write_reg(reg, value);
470
471 buf_set_u32(reg->value, 0, reg->size, value);
472 reg->valid = 1;
473 reg->dirty = 0;
474
475 }
476
477 /**
478 * Write an EmbeddedICE register, updating the register cache.
479 * Uses embeddedice_set_reg(); not queued.
480 */
481 static int embeddedice_set_reg_w_exec(struct reg *reg, uint8_t *buf)
482 {
483 int retval;
484
485 embeddedice_set_reg(reg, buf_get_u32(buf, 0, reg->size));
486 retval = jtag_execute_queue();
487 if (retval != ERROR_OK)
488 LOG_ERROR("register write failed");
489 return retval;
490 }
491
492 /**
493 * Queue a write for an EmbeddedICE register, bypassing the register cache.
494 */
495 void embeddedice_write_reg(struct reg *reg, uint32_t value)
496 {
497 struct embeddedice_reg *ice_reg = reg->arch_info;
498
499 LOG_DEBUG("%i: 0x%8.8" PRIx32 "", ice_reg->addr, value);
500
501 arm_jtag_scann(ice_reg->jtag_info, 0x2, TAP_IDLE);
502
503 arm_jtag_set_instr(ice_reg->jtag_info->tap, ice_reg->jtag_info->intest_instr, NULL, TAP_IDLE);
504
505 uint8_t reg_addr = ice_reg->addr & 0x1f;
506 embeddedice_write_reg_inner(ice_reg->jtag_info->tap, reg_addr, value);
507 }
508
509 /**
510 * Queue a write for an EmbeddedICE register, using cached value.
511 * Uses embeddedice_write_reg().
512 */
513 void embeddedice_store_reg(struct reg *reg)
514 {
515 embeddedice_write_reg(reg, buf_get_u32(reg->value, 0, reg->size));
516 }
517
518 /**
519 * Send a block of size 32-bit words to the DCC.
520 * We assume the target is always going to be fast enough (relative to
521 * the JTAG clock) that the debugger won't need to poll the handshake
522 * bit. The JTAG clock is usually at least six times slower than the
523 * functional clock, so the 50+ JTAG clocks needed to receive the word
524 * allow hundreds of instruction cycles (per word) in the target.
525 */
526 int embeddedice_send(struct arm_jtag *jtag_info, uint32_t *data, uint32_t size)
527 {
528 struct scan_field fields[3];
529 uint8_t field0_out[4];
530 uint8_t field1_out[1];
531 uint8_t field2_out[1];
532 int retval;
533
534 retval = arm_jtag_scann(jtag_info, 0x2, TAP_IDLE);
535 if (retval != ERROR_OK)
536 return retval;
537 retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_IDLE);
538 if (retval != ERROR_OK)
539 return retval;
540
541 fields[0].num_bits = 32;
542 fields[0].out_value = field0_out;
543 fields[0].in_value = NULL;
544
545 fields[1].num_bits = 5;
546 fields[1].out_value = field1_out;
547 field1_out[0] = eice_regs[EICE_COMMS_DATA].addr;
548 fields[1].in_value = NULL;
549
550 fields[2].num_bits = 1;
551 fields[2].out_value = field2_out;
552 field2_out[0] = 1;
553
554 fields[2].in_value = NULL;
555
556 while (size > 0) {
557 buf_set_u32(field0_out, 0, 32, *data);
558 jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
559
560 data++;
561 size--;
562 }
563
564 /* call to jtag_execute_queue() intentionally omitted */
565 return ERROR_OK;
566 }
567
568 /**
569 * Poll DCC control register until read or write handshake completes.
570 */
571 int embeddedice_handshake(struct arm_jtag *jtag_info, int hsbit, uint32_t timeout)
572 {
573 struct scan_field fields[3];
574 uint8_t field0_in[4];
575 uint8_t field1_out[1];
576 uint8_t field2_out[1];
577 int retval;
578 uint32_t hsact;
579 struct timeval lap;
580 struct timeval now;
581
582 if (hsbit == EICE_COMM_CTRL_WBIT)
583 hsact = 1;
584 else if (hsbit == EICE_COMM_CTRL_RBIT)
585 hsact = 0;
586 else {
587 LOG_ERROR("Invalid arguments");
588 return ERROR_COMMAND_SYNTAX_ERROR;
589 }
590
591 retval = arm_jtag_scann(jtag_info, 0x2, TAP_IDLE);
592 if (retval != ERROR_OK)
593 return retval;
594 retval = arm_jtag_set_instr(jtag_info->tap, jtag_info->intest_instr, NULL, TAP_IDLE);
595 if (retval != ERROR_OK)
596 return retval;
597
598 fields[0].num_bits = 32;
599 fields[0].out_value = NULL;
600 fields[0].in_value = field0_in;
601
602 fields[1].num_bits = 5;
603 fields[1].out_value = field1_out;
604 field1_out[0] = eice_regs[EICE_COMMS_DATA].addr;
605 fields[1].in_value = NULL;
606
607 fields[2].num_bits = 1;
608 fields[2].out_value = field2_out;
609 field2_out[0] = 0;
610 fields[2].in_value = NULL;
611
612 jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
613 gettimeofday(&lap, NULL);
614 do {
615 jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE);
616 retval = jtag_execute_queue();
617 if (retval != ERROR_OK)
618 return retval;
619
620 if (buf_get_u32(field0_in, hsbit, 1) == hsact)
621 return ERROR_OK;
622
623 gettimeofday(&now, NULL);
624 } while ((uint32_t)((now.tv_sec - lap.tv_sec) * 1000
625 + (now.tv_usec - lap.tv_usec) / 1000) <= timeout);
626
627 LOG_ERROR("embeddedice handshake timeout");
628 return ERROR_TARGET_TIMEOUT;
629 }
630
631 #ifndef HAVE_JTAG_MINIDRIVER_H
632 /**
633 * This is an inner loop of the open loop DCC write of data to target
634 */
635 void embeddedice_write_dcc(struct jtag_tap *tap,
636 int reg_addr, const uint8_t *buffer, int little, int count)
637 {
638 int i;
639
640 for (i = 0; i < count; i++) {
641 embeddedice_write_reg_inner(tap, reg_addr,
642 fast_target_buffer_get_u32(buffer, little));
643 buffer += 4;
644 }
645 }
646 #else
647 /* provided by minidriver */
648 #endif

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)