catchup with jtag refactoring.
[openocd.git] / src / jtag / zy1000.c
1 /***************************************************************************
2 * Copyright (C) 2007-2008 by Øyvind Harboe *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
18 ***************************************************************************/
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include "embeddedice.h"
24 #include "minidriver.h"
25 #include "interface.h"
26
27 #include <cyg/hal/hal_io.h> // low level i/o
28 #include <cyg/hal/hal_diag.h>
29
30
31 #define ZYLIN_VERSION "1.52"
32 #define ZYLIN_DATE __DATE__
33 #define ZYLIN_TIME __TIME__
34 #define ZYLIN_OPENOCD "$Revision$"
35 #define ZYLIN_OPENOCD_VERSION "Zylin JTAG ZY1000 " ZYLIN_VERSION " " ZYLIN_DATE " " ZYLIN_TIME
36 const char *zylin_config_dir="/config/settings";
37
38 /* low level command set
39 */
40 int zy1000_read(void);
41 static void zy1000_write(int tck, int tms, int tdi);
42 void zy1000_reset(int trst, int srst);
43
44
45 int zy1000_speed(int speed);
46 int zy1000_register_commands(struct command_context_s *cmd_ctx);
47 int zy1000_init(void);
48 int zy1000_quit(void);
49
50 /* interface commands */
51 int zy1000_handle_zy1000_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
52
53 static int zy1000_khz(int khz, int *jtag_speed)
54 {
55 if (khz==0)
56 {
57 *jtag_speed=0;
58 }
59 else
60 {
61 *jtag_speed=64000/khz;
62 }
63 return ERROR_OK;
64 }
65
66 static int zy1000_speed_div(int speed, int *khz)
67 {
68 if (speed==0)
69 {
70 *khz = 0;
71 }
72 else
73 {
74 *khz=64000/speed;
75 }
76
77 return ERROR_OK;
78 }
79
80 static bool readPowerDropout(void)
81 {
82 cyg_uint32 state;
83 // sample and clear power dropout
84 HAL_WRITE_UINT32(ZY1000_JTAG_BASE+0x10, 0x80);
85 HAL_READ_UINT32(ZY1000_JTAG_BASE+0x10, state);
86 bool powerDropout;
87 powerDropout = (state & 0x80) != 0;
88 return powerDropout;
89 }
90
91
92 static bool readSRST(void)
93 {
94 cyg_uint32 state;
95 // sample and clear SRST sensing
96 HAL_WRITE_UINT32(ZY1000_JTAG_BASE+0x10, 0x00000040);
97 HAL_READ_UINT32(ZY1000_JTAG_BASE+0x10, state);
98 bool srstAsserted;
99 srstAsserted = (state & 0x40) != 0;
100 return srstAsserted;
101 }
102
103 static int zy1000_srst_asserted(int *srst_asserted)
104 {
105 *srst_asserted=readSRST();
106 return ERROR_OK;
107 }
108
109 static int zy1000_power_dropout(int *dropout)
110 {
111 *dropout=readPowerDropout();
112 return ERROR_OK;
113 }
114
115
116 jtag_interface_t zy1000_interface =
117 {
118 .name = "ZY1000",
119 .execute_queue = NULL,
120 .speed = zy1000_speed,
121 .register_commands = zy1000_register_commands,
122 .init = zy1000_init,
123 .quit = zy1000_quit,
124 .khz = zy1000_khz,
125 .speed_div = zy1000_speed_div,
126 .power_dropout = zy1000_power_dropout,
127 .srst_asserted = zy1000_srst_asserted,
128 };
129
130 static void zy1000_write(int tck, int tms, int tdi)
131 {
132
133 }
134
135 int zy1000_read(void)
136 {
137 return -1;
138 }
139
140 extern bool readSRST(void);
141
142 void zy1000_reset(int trst, int srst)
143 {
144 LOG_DEBUG("zy1000 trst=%d, srst=%d", trst, srst);
145 if(!srst)
146 {
147 ZY1000_POKE(ZY1000_JTAG_BASE+0x14, 0x00000001);
148 }
149 else
150 {
151 /* Danger!!! if clk!=0 when in
152 * idle in TAP_IDLE, reset halt on str912 will fail.
153 */
154 ZY1000_POKE(ZY1000_JTAG_BASE+0x10, 0x00000001);
155 }
156
157 if(!trst)
158 {
159 ZY1000_POKE(ZY1000_JTAG_BASE+0x14, 0x00000002);
160 }
161 else
162 {
163 /* assert reset */
164 ZY1000_POKE(ZY1000_JTAG_BASE+0x10, 0x00000002);
165 }
166
167 if (trst||(srst&&(jtag_reset_config & RESET_SRST_PULLS_TRST)))
168 {
169 waitIdle();
170 /* we're now in the RESET state until trst is deasserted */
171 ZY1000_POKE(ZY1000_JTAG_BASE+0x20, TAP_RESET);
172 } else
173 {
174 /* We'll get RCLK failure when we assert TRST, so clear any false positives here */
175 ZY1000_POKE(ZY1000_JTAG_BASE+0x14, 0x400);
176 }
177
178 /* wait for srst to float back up */
179 if (!srst)
180 {
181 int i;
182 for (i=0; i<1000; i++)
183 {
184 // We don't want to sense our own reset, so we clear here.
185 // There is of course a timing hole where we could loose
186 // a "real" reset.
187 if (!readSRST())
188 break;
189
190 /* wait 1ms */
191 alive_sleep(1);
192 }
193
194 if (i==1000)
195 {
196 LOG_USER("SRST didn't deassert after %dms", i);
197 } else if (i>1)
198 {
199 LOG_USER("SRST took %dms to deassert", i);
200 }
201 }
202 }
203
204 int zy1000_speed(int speed)
205 {
206 if(speed == 0)
207 {
208 /*0 means RCLK*/
209 speed = 0;
210 ZY1000_POKE(ZY1000_JTAG_BASE+0x10, 0x100);
211 LOG_DEBUG("jtag_speed using RCLK");
212 }
213 else
214 {
215 if(speed > 8190 || speed < 2)
216 {
217 LOG_USER("valid ZY1000 jtag_speed=[8190,2]. Divisor is 64MHz / even values between 8190-2, i.e. min 7814Hz, max 32MHz");
218 return ERROR_INVALID_ARGUMENTS;
219 }
220
221 LOG_USER("jtag_speed %d => JTAG clk=%f", speed, 64.0/(float)speed);
222 ZY1000_POKE(ZY1000_JTAG_BASE+0x14, 0x100);
223 ZY1000_POKE(ZY1000_JTAG_BASE+0x1c, speed&~1);
224 }
225 return ERROR_OK;
226 }
227
228 static bool savePower;
229
230
231 static void setPower(bool power)
232 {
233 savePower = power;
234 if (power)
235 {
236 HAL_WRITE_UINT32(ZY1000_JTAG_BASE+0x14, 0x8);
237 } else
238 {
239 HAL_WRITE_UINT32(ZY1000_JTAG_BASE+0x10, 0x8);
240 }
241 }
242
243 int handle_power_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
244 {
245 if (argc > 1)
246 {
247 return ERROR_INVALID_ARGUMENTS;
248 }
249
250 if (argc == 1)
251 {
252 if (strcmp(args[0], "on") == 0)
253 {
254 setPower(1);
255 }
256 else if (strcmp(args[0], "off") == 0)
257 {
258 setPower(0);
259 } else
260 {
261 command_print(cmd_ctx, "arg is \"on\" or \"off\"");
262 return ERROR_INVALID_ARGUMENTS;
263 }
264 }
265
266 command_print(cmd_ctx, "Target power %s", savePower ? "on" : "off");
267
268 return ERROR_OK;
269 }
270
271
272 /* Give TELNET a way to find out what version this is */
273 static int jim_zy1000_version(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
274 {
275 if ((argc < 1) || (argc > 2))
276 return JIM_ERR;
277 char buff[128];
278 const char *version_str=NULL;
279
280 if (argc == 1)
281 {
282 version_str=ZYLIN_OPENOCD_VERSION;
283 } else
284 {
285 const char *str = Jim_GetString(argv[1], NULL);
286 if (strcmp("openocd", str) == 0)
287 {
288 int revision;
289 revision = atol(ZYLIN_OPENOCD+strlen("XRevision: "));
290 sprintf(buff, "%d", revision);
291 version_str=buff;
292 }
293 else if (strcmp("zy1000", str) == 0)
294 {
295 version_str=ZYLIN_VERSION;
296 }
297 else if (strcmp("date", str) == 0)
298 {
299 version_str=ZYLIN_DATE;
300 }
301 else
302 {
303 return JIM_ERR;
304 }
305 }
306
307 Jim_SetResult(interp, Jim_NewStringObj(interp, version_str, -1));
308
309 return JIM_OK;
310 }
311
312
313 static int
314 zylinjtag_Jim_Command_powerstatus(Jim_Interp *interp,
315 int argc,
316 Jim_Obj * const *argv)
317 {
318 if (argc != 1)
319 {
320 Jim_WrongNumArgs(interp, 1, argv, "powerstatus");
321 return JIM_ERR;
322 }
323
324 cyg_uint32 status;
325 ZY1000_PEEK(ZY1000_JTAG_BASE+0x10, status);
326
327 Jim_SetResult(interp, Jim_NewIntObj(interp, (status&0x80)!=0));
328
329 return JIM_OK;
330 }
331
332 int zy1000_register_commands(struct command_context_s *cmd_ctx)
333 {
334 register_command(cmd_ctx, NULL, "power", handle_power_command, COMMAND_ANY,
335 "power <on/off> - turn power switch to target on/off. No arguments - print status.");
336
337 Jim_CreateCommand(interp, "zy1000_version", jim_zy1000_version, NULL, NULL);
338
339
340 Jim_CreateCommand(interp, "powerstatus", zylinjtag_Jim_Command_powerstatus, NULL, NULL);
341
342 return ERROR_OK;
343 }
344
345
346
347
348 int zy1000_init(void)
349 {
350 LOG_USER("%s", ZYLIN_OPENOCD_VERSION);
351
352 ZY1000_POKE(ZY1000_JTAG_BASE+0x10, 0x30); // Turn on LED1 & LED2
353
354 setPower(true); // on by default
355
356
357 /* deassert resets. Important to avoid infinite loop waiting for SRST to deassert */
358 zy1000_reset(0, 0);
359 zy1000_speed(jtag_speed);
360
361 return ERROR_OK;
362 }
363
364 int zy1000_quit(void)
365 {
366
367 return ERROR_OK;
368 }
369
370
371
372 int interface_jtag_execute_queue(void)
373 {
374 cyg_uint32 empty;
375
376 waitIdle();
377 ZY1000_PEEK(ZY1000_JTAG_BASE+0x10, empty);
378 /* clear JTAG error register */
379 ZY1000_POKE(ZY1000_JTAG_BASE+0x14, 0x400);
380
381 if ((empty&0x400)!=0)
382 {
383 LOG_WARNING("RCLK timeout");
384 /* the error is informative only as we don't want to break the firmware if there
385 * is a false positive.
386 */
387 // return ERROR_FAIL;
388 }
389 return ERROR_OK;
390 }
391
392
393
394
395
396 static cyg_uint32 getShiftValue(void)
397 {
398 cyg_uint32 value;
399 waitIdle();
400 ZY1000_PEEK(ZY1000_JTAG_BASE+0xc, value);
401 VERBOSE(LOG_INFO("getShiftValue %08x", value));
402 return value;
403 }
404 #if 0
405 static cyg_uint32 getShiftValueFlip(void)
406 {
407 cyg_uint32 value;
408 waitIdle();
409 ZY1000_PEEK(ZY1000_JTAG_BASE+0x18, value);
410 VERBOSE(LOG_INFO("getShiftValue %08x (flipped)", value));
411 return value;
412 }
413 #endif
414
415 #if 0
416 static void shiftValueInnerFlip(const tap_state_t state, const tap_state_t endState, int repeat, cyg_uint32 value)
417 {
418 VERBOSE(LOG_INFO("shiftValueInner %s %s %d %08x (flipped)", tap_state_name(state), tap_state_name(endState), repeat, value));
419 cyg_uint32 a,b;
420 a=state;
421 b=endState;
422 ZY1000_POKE(ZY1000_JTAG_BASE+0xc, value);
423 ZY1000_POKE(ZY1000_JTAG_BASE+0x8, (1<<15)|(repeat<<8)|(a<<4)|b);
424 VERBOSE(getShiftValueFlip());
425 }
426 #endif
427
428 extern int jtag_check_value(u8 *captured, void *priv);
429
430 static void gotoEndState(void)
431 {
432 setCurrentState(cmd_queue_end_state);
433 }
434
435 static __inline void scanFields(int num_fields, scan_field_t *fields, tap_state_t shiftState, tap_state_t end_state)
436 {
437 int i;
438 int j;
439 int k;
440
441 for (i = 0; i < num_fields; i++)
442 {
443 cyg_uint32 value;
444
445 static u8 *in_buff=NULL; /* pointer to buffer for scanned data */
446 static int in_buff_size=0;
447 u8 *inBuffer=NULL;
448
449
450 // figure out where to store the input data
451 int num_bits=fields[i].num_bits;
452 if (fields[i].in_value!=NULL)
453 {
454 inBuffer=fields[i].in_value;
455 }
456
457 // here we shuffle N bits out/in
458 j=0;
459 while (j<num_bits)
460 {
461 tap_state_t pause_state;
462 int l;
463 k=num_bits-j;
464 pause_state=(shiftState==TAP_DRSHIFT)?TAP_DRSHIFT:TAP_IRSHIFT;
465 if (k>32)
466 {
467 k=32;
468 /* we have more to shift out */
469 } else if (i == num_fields-1)
470 {
471 /* this was the last to shift out this time */
472 pause_state=end_state;
473 }
474
475 // we have (num_bits+7)/8 bytes of bits to toggle out.
476 // bits are pushed out LSB to MSB
477 value=0;
478 if (fields[i].out_value!=NULL)
479 {
480 for (l=0; l<k; l+=8)
481 {
482 value|=fields[i].out_value[(j+l)/8]<<l;
483 }
484 }
485 /* mask away unused bits for easier debugging */
486 value&=~(((u32)0xffffffff)<<k);
487
488 shiftValueInner(shiftState, pause_state, k, value);
489
490 if (inBuffer!=NULL)
491 {
492 // data in, LSB to MSB
493 value=getShiftValue();
494 // we're shifting in data to MSB, shift data to be aligned for returning the value
495 value >>= 32-k;
496
497 for (l=0; l<k; l+=8)
498 {
499 inBuffer[(j+l)/8]=(value>>l)&0xff;
500 }
501 }
502 j+=k;
503 }
504 }
505 }
506
507 int interface_jtag_add_end_state(tap_state_t state)
508 {
509 return ERROR_OK;
510 }
511
512
513 int interface_jtag_add_ir_scan(int num_fields, const scan_field_t *fields, tap_state_t state)
514 {
515
516 int j;
517 int scan_size = 0;
518 jtag_tap_t *tap, *nextTap;
519 for(tap = jtag_NextEnabledTap(NULL); tap!= NULL; tap=nextTap)
520 {
521 nextTap=jtag_NextEnabledTap(tap);
522 tap_state_t end_state;
523 if (nextTap==NULL)
524 {
525 end_state = cmd_queue_end_state;
526 } else
527 {
528 end_state = TAP_IRSHIFT;
529 }
530
531 int found = 0;
532
533 scan_size = tap->ir_length;
534
535 /* search the list */
536 for (j=0; j < num_fields; j++)
537 {
538 if (tap == fields[j].tap)
539 {
540 found = 1;
541
542 scanFields(1, fields+j, TAP_IRSHIFT, end_state);
543 /* update device information */
544 buf_cpy(fields[j].out_value, tap->cur_instr, scan_size);
545
546 tap->bypass = 0;
547 break;
548 }
549 }
550
551 if (!found)
552 {
553 /* if a device isn't listed, set it to BYPASS */
554 u8 ones[]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
555
556 scan_field_t tmp;
557 memset(&tmp, 0, sizeof(tmp));
558 tmp.out_value = ones;
559 tmp.num_bits = scan_size;
560 scanFields(1, &tmp, TAP_IRSHIFT, end_state);
561 /* update device information */
562 buf_cpy(tmp.out_value, tap->cur_instr, scan_size);
563 tap->bypass = 1;
564 }
565 }
566
567 return ERROR_OK;
568 }
569
570
571
572
573
574 int interface_jtag_add_plain_ir_scan(int num_fields, const scan_field_t *fields, tap_state_t state)
575 {
576 scanFields(num_fields, fields, TAP_IRSHIFT, cmd_queue_end_state);
577
578 return ERROR_OK;
579 }
580
581 /*extern jtag_command_t **jtag_get_last_command_p(void);*/
582
583 int interface_jtag_add_dr_scan(int num_fields, const scan_field_t *fields, tap_state_t state)
584 {
585
586 int j;
587 jtag_tap_t *tap, *nextTap;
588 for(tap = jtag_NextEnabledTap(NULL); tap!= NULL; tap=nextTap)
589 {
590 nextTap=jtag_NextEnabledTap(tap);
591 int found=0;
592 tap_state_t end_state;
593 if (nextTap==NULL)
594 {
595 end_state = cmd_queue_end_state;
596 } else
597 {
598 end_state = TAP_DRSHIFT;
599 }
600
601 for (j=0; j < num_fields; j++)
602 {
603 if (tap == fields[j].tap)
604 {
605 found = 1;
606
607 scanFields(1, fields+j, TAP_DRSHIFT, end_state);
608 }
609 }
610 if (!found)
611 {
612 scan_field_t tmp;
613 /* program the scan field to 1 bit length, and ignore it's value */
614 tmp.num_bits = 1;
615 tmp.out_value = NULL;
616 tmp.in_value = NULL;
617
618 scanFields(1, &tmp, TAP_DRSHIFT, end_state);
619 }
620 else
621 {
622 }
623 }
624 return ERROR_OK;
625 }
626
627 int interface_jtag_add_plain_dr_scan(int num_fields, const scan_field_t *fields, tap_state_t state)
628 {
629 scanFields(num_fields, fields, TAP_DRSHIFT, cmd_queue_end_state);
630 return ERROR_OK;
631 }
632
633
634 int interface_jtag_add_tlr()
635 {
636 setCurrentState(TAP_RESET);
637 return ERROR_OK;
638 }
639
640
641
642
643 extern int jtag_nsrst_delay;
644 extern int jtag_ntrst_delay;
645
646 int interface_jtag_add_reset(int req_trst, int req_srst)
647 {
648 zy1000_reset(req_trst, req_srst);
649 return ERROR_OK;
650 }
651
652 static int zy1000_jtag_add_clocks(int num_cycles, tap_state_t state, tap_state_t clockstate)
653 {
654 /* num_cycles can be 0 */
655 setCurrentState(clockstate);
656
657 /* execute num_cycles, 32 at the time. */
658 int i;
659 for (i=0; i<num_cycles; i+=32)
660 {
661 int num;
662 num=32;
663 if (num_cycles-i<num)
664 {
665 num=num_cycles-i;
666 }
667 shiftValueInner(clockstate, clockstate, num, 0);
668 }
669
670 #if !TEST_MANUAL()
671 /* finish in end_state */
672 setCurrentState(state);
673 #else
674 tap_state_t t=TAP_IDLE;
675 /* test manual drive code on any target */
676 int tms;
677 u8 tms_scan = tap_get_tms_path(t, state);
678 int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state());
679
680 for (i = 0; i < tms_count; i++)
681 {
682 tms = (tms_scan >> i) & 1;
683 waitIdle();
684 ZY1000_POKE(ZY1000_JTAG_BASE+0x28, tms);
685 }
686 waitIdle();
687 ZY1000_POKE(ZY1000_JTAG_BASE+0x20, state);
688 #endif
689
690
691 return ERROR_OK;
692 }
693
694 int interface_jtag_add_runtest(int num_cycles, tap_state_t state)
695 {
696 return zy1000_jtag_add_clocks(num_cycles, state, TAP_IDLE);
697 }
698
699 int interface_jtag_add_clocks(int num_cycles)
700 {
701 return zy1000_jtag_add_clocks(num_cycles, cmd_queue_cur_state, cmd_queue_end_state);
702 }
703
704 int interface_jtag_add_sleep(u32 us)
705 {
706 jtag_sleep(us);
707 return ERROR_OK;
708 }
709
710 int interface_jtag_add_pathmove(int num_states, const tap_state_t *path)
711 {
712 int state_count;
713 int tms = 0;
714
715 /*wait for the fifo to be empty*/
716 waitIdle();
717
718 state_count = 0;
719
720 tap_state_t cur_state=cmd_queue_cur_state;
721
722 while (num_states)
723 {
724 if (tap_state_transition(cur_state, false) == path[state_count])
725 {
726 tms = 0;
727 }
728 else if (tap_state_transition(cur_state, true) == path[state_count])
729 {
730 tms = 1;
731 }
732 else
733 {
734 LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(cur_state), tap_state_name(path[state_count]));
735 exit(-1);
736 }
737
738 waitIdle();
739 ZY1000_POKE(ZY1000_JTAG_BASE+0x28, tms);
740
741 cur_state = path[state_count];
742 state_count++;
743 num_states--;
744 }
745
746 waitIdle();
747 ZY1000_POKE(ZY1000_JTAG_BASE+0x20, cur_state);
748 return ERROR_OK;
749 }
750
751
752
753 void embeddedice_write_dcc(jtag_tap_t *tap, int reg_addr, u8 *buffer, int little, int count)
754 {
755 // static int const reg_addr=0x5;
756 tap_state_t end_state=cmd_queue_end_state;
757 if (jtag_NextEnabledTap(jtag_NextEnabledTap(NULL))==NULL)
758 {
759 /* better performance via code duplication */
760 if (little)
761 {
762 int i;
763 for (i = 0; i < count; i++)
764 {
765 shiftValueInner(TAP_DRSHIFT, TAP_DRSHIFT, 32, fast_target_buffer_get_u32(buffer, 1));
766 shiftValueInner(TAP_DRSHIFT, end_state, 6, reg_addr|(1<<5));
767 buffer+=4;
768 }
769 } else
770 {
771 int i;
772 for (i = 0; i < count; i++)
773 {
774 shiftValueInner(TAP_DRSHIFT, TAP_DRSHIFT, 32, fast_target_buffer_get_u32(buffer, 0));
775 shiftValueInner(TAP_DRSHIFT, end_state, 6, reg_addr|(1<<5));
776 buffer+=4;
777 }
778 }
779 }
780 else
781 {
782 int i;
783 for (i = 0; i < count; i++)
784 {
785 embeddedice_write_reg_inner(tap, reg_addr, fast_target_buffer_get_u32(buffer, little));
786 buffer += 4;
787 }
788 }
789 }
790
791 int loadFile(const char *fileName, void **data, int *len);
792
793 /* boolean parameter stored on config */
794 int boolParam(char *var)
795 {
796 bool result = false;
797 char *name = alloc_printf("%s/%s", zylin_config_dir, var);
798 if (name == NULL)
799 return result;
800
801 void *data;
802 int len;
803 if (loadFile(name, &data, &len) == ERROR_OK)
804 {
805 if (len > 1)
806 len = 1;
807 result = strncmp((char *) data, "1", len) == 0;
808 free(data);
809 }
810 free(name);
811 return result;
812 }
813
814

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)