Add get and set accessors for jtag_speed:
[openocd.git] / src / jtag / zy1000 / 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_get_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 __inline void scanFields(int num_fields, scan_field_t *fields, tap_state_t shiftState, tap_state_t end_state)
431 {
432 int i;
433 int j;
434 int k;
435
436 for (i = 0; i < num_fields; i++)
437 {
438 cyg_uint32 value;
439
440 static u8 *in_buff=NULL; /* pointer to buffer for scanned data */
441 static int in_buff_size=0;
442 u8 *inBuffer=NULL;
443
444
445 // figure out where to store the input data
446 int num_bits=fields[i].num_bits;
447 if (fields[i].in_value!=NULL)
448 {
449 inBuffer=fields[i].in_value;
450 }
451
452 // here we shuffle N bits out/in
453 j=0;
454 while (j<num_bits)
455 {
456 tap_state_t pause_state;
457 int l;
458 k=num_bits-j;
459 pause_state=(shiftState==TAP_DRSHIFT)?TAP_DRSHIFT:TAP_IRSHIFT;
460 if (k>32)
461 {
462 k=32;
463 /* we have more to shift out */
464 } else if (i == num_fields-1)
465 {
466 /* this was the last to shift out this time */
467 pause_state=end_state;
468 }
469
470 // we have (num_bits+7)/8 bytes of bits to toggle out.
471 // bits are pushed out LSB to MSB
472 value=0;
473 if (fields[i].out_value!=NULL)
474 {
475 for (l=0; l<k; l+=8)
476 {
477 value|=fields[i].out_value[(j+l)/8]<<l;
478 }
479 }
480 /* mask away unused bits for easier debugging */
481 value&=~(((u32)0xffffffff)<<k);
482
483 shiftValueInner(shiftState, pause_state, k, value);
484
485 if (inBuffer!=NULL)
486 {
487 // data in, LSB to MSB
488 value=getShiftValue();
489 // we're shifting in data to MSB, shift data to be aligned for returning the value
490 value >>= 32-k;
491
492 for (l=0; l<k; l+=8)
493 {
494 inBuffer[(j+l)/8]=(value>>l)&0xff;
495 }
496 }
497 j+=k;
498 }
499 }
500 }
501
502 int interface_jtag_set_end_state(tap_state_t state)
503 {
504 return ERROR_OK;
505 }
506
507
508 int interface_jtag_add_ir_scan(int num_fields, const scan_field_t *fields, tap_state_t state)
509 {
510
511 int j;
512 int scan_size = 0;
513 jtag_tap_t *tap, *nextTap;
514 for(tap = jtag_tap_next_enabled(NULL); tap!= NULL; tap=nextTap)
515 {
516 nextTap=jtag_tap_next_enabled(tap);
517 tap_state_t end_state;
518 if (nextTap==NULL)
519 {
520 end_state = state;
521 } else
522 {
523 end_state = TAP_IRSHIFT;
524 }
525
526 int found = 0;
527
528 scan_size = tap->ir_length;
529
530 /* search the list */
531 for (j=0; j < num_fields; j++)
532 {
533 if (tap == fields[j].tap)
534 {
535 found = 1;
536
537 scanFields(1, fields+j, TAP_IRSHIFT, end_state);
538 /* update device information */
539 buf_cpy(fields[j].out_value, tap->cur_instr, scan_size);
540
541 tap->bypass = 0;
542 break;
543 }
544 }
545
546 if (!found)
547 {
548 /* if a device isn't listed, set it to BYPASS */
549 u8 ones[]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
550
551 scan_field_t tmp;
552 memset(&tmp, 0, sizeof(tmp));
553 tmp.out_value = ones;
554 tmp.num_bits = scan_size;
555 scanFields(1, &tmp, TAP_IRSHIFT, end_state);
556 /* update device information */
557 buf_cpy(tmp.out_value, tap->cur_instr, scan_size);
558 tap->bypass = 1;
559 }
560 }
561
562 return ERROR_OK;
563 }
564
565
566
567
568
569 int interface_jtag_add_plain_ir_scan(int num_fields, const scan_field_t *fields, tap_state_t state)
570 {
571 scanFields(num_fields, fields, TAP_IRSHIFT, state);
572
573 return ERROR_OK;
574 }
575
576 /*extern jtag_command_t **jtag_get_last_command_p(void);*/
577
578 int interface_jtag_add_dr_scan(int num_fields, const scan_field_t *fields, tap_state_t state)
579 {
580
581 int j;
582 jtag_tap_t *tap, *nextTap;
583 for(tap = jtag_tap_next_enabled(NULL); tap!= NULL; tap=nextTap)
584 {
585 nextTap=jtag_tap_next_enabled(tap);
586 int found=0;
587 tap_state_t end_state;
588 if (nextTap==NULL)
589 {
590 end_state = state;
591 } else
592 {
593 end_state = TAP_DRSHIFT;
594 }
595
596 for (j=0; j < num_fields; j++)
597 {
598 if (tap == fields[j].tap)
599 {
600 found = 1;
601
602 scanFields(1, fields+j, TAP_DRSHIFT, end_state);
603 }
604 }
605 if (!found)
606 {
607 scan_field_t tmp;
608 /* program the scan field to 1 bit length, and ignore it's value */
609 tmp.num_bits = 1;
610 tmp.out_value = NULL;
611 tmp.in_value = NULL;
612
613 scanFields(1, &tmp, TAP_DRSHIFT, end_state);
614 }
615 else
616 {
617 }
618 }
619 return ERROR_OK;
620 }
621
622 int interface_jtag_add_plain_dr_scan(int num_fields, const scan_field_t *fields, tap_state_t state)
623 {
624 scanFields(num_fields, fields, TAP_DRSHIFT, state);
625 return ERROR_OK;
626 }
627
628
629 int interface_jtag_add_tlr()
630 {
631 setCurrentState(TAP_RESET);
632 return ERROR_OK;
633 }
634
635
636
637
638 extern int jtag_nsrst_delay;
639 extern int jtag_ntrst_delay;
640
641 int interface_jtag_add_reset(int req_trst, int req_srst)
642 {
643 zy1000_reset(req_trst, req_srst);
644 return ERROR_OK;
645 }
646
647 static int zy1000_jtag_add_clocks(int num_cycles, tap_state_t state, tap_state_t clockstate)
648 {
649 /* num_cycles can be 0 */
650 setCurrentState(clockstate);
651
652 /* execute num_cycles, 32 at the time. */
653 int i;
654 for (i=0; i<num_cycles; i+=32)
655 {
656 int num;
657 num=32;
658 if (num_cycles-i<num)
659 {
660 num=num_cycles-i;
661 }
662 shiftValueInner(clockstate, clockstate, num, 0);
663 }
664
665 #if !TEST_MANUAL()
666 /* finish in end_state */
667 setCurrentState(state);
668 #else
669 tap_state_t t=TAP_IDLE;
670 /* test manual drive code on any target */
671 int tms;
672 u8 tms_scan = tap_get_tms_path(t, state);
673 int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state());
674
675 for (i = 0; i < tms_count; i++)
676 {
677 tms = (tms_scan >> i) & 1;
678 waitIdle();
679 ZY1000_POKE(ZY1000_JTAG_BASE+0x28, tms);
680 }
681 waitIdle();
682 ZY1000_POKE(ZY1000_JTAG_BASE+0x20, state);
683 #endif
684
685
686 return ERROR_OK;
687 }
688
689 int interface_jtag_add_runtest(int num_cycles, tap_state_t state)
690 {
691 return zy1000_jtag_add_clocks(num_cycles, state, TAP_IDLE);
692 }
693
694 int interface_jtag_add_clocks(int num_cycles)
695 {
696 return zy1000_jtag_add_clocks(num_cycles, cmd_queue_cur_state, cmd_queue_cur_state);
697 }
698
699 int interface_jtag_add_sleep(u32 us)
700 {
701 jtag_sleep(us);
702 return ERROR_OK;
703 }
704
705 int interface_jtag_add_pathmove(int num_states, const tap_state_t *path)
706 {
707 int state_count;
708 int tms = 0;
709
710 /*wait for the fifo to be empty*/
711 waitIdle();
712
713 state_count = 0;
714
715 tap_state_t cur_state=cmd_queue_cur_state;
716
717 while (num_states)
718 {
719 if (tap_state_transition(cur_state, false) == path[state_count])
720 {
721 tms = 0;
722 }
723 else if (tap_state_transition(cur_state, true) == path[state_count])
724 {
725 tms = 1;
726 }
727 else
728 {
729 LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(cur_state), tap_state_name(path[state_count]));
730 exit(-1);
731 }
732
733 waitIdle();
734 ZY1000_POKE(ZY1000_JTAG_BASE+0x28, tms);
735
736 cur_state = path[state_count];
737 state_count++;
738 num_states--;
739 }
740
741 waitIdle();
742 ZY1000_POKE(ZY1000_JTAG_BASE+0x20, cur_state);
743 return ERROR_OK;
744 }
745
746
747
748 void embeddedice_write_dcc(jtag_tap_t *tap, int reg_addr, u8 *buffer, int little, int count)
749 {
750 // static int const reg_addr=0x5;
751 tap_state_t end_state=jtag_get_end_state();
752 if (jtag_tap_next_enabled(jtag_tap_next_enabled(NULL))==NULL)
753 {
754 /* better performance via code duplication */
755 if (little)
756 {
757 int i;
758 for (i = 0; i < count; i++)
759 {
760 shiftValueInner(TAP_DRSHIFT, TAP_DRSHIFT, 32, fast_target_buffer_get_u32(buffer, 1));
761 shiftValueInner(TAP_DRSHIFT, end_state, 6, reg_addr|(1<<5));
762 buffer+=4;
763 }
764 } else
765 {
766 int i;
767 for (i = 0; i < count; i++)
768 {
769 shiftValueInner(TAP_DRSHIFT, TAP_DRSHIFT, 32, fast_target_buffer_get_u32(buffer, 0));
770 shiftValueInner(TAP_DRSHIFT, end_state, 6, reg_addr|(1<<5));
771 buffer+=4;
772 }
773 }
774 }
775 else
776 {
777 int i;
778 for (i = 0; i < count; i++)
779 {
780 embeddedice_write_reg_inner(tap, reg_addr, fast_target_buffer_get_u32(buffer, little));
781 buffer += 4;
782 }
783 }
784 }
785
786 int loadFile(const char *fileName, void **data, int *len);
787
788 /* boolean parameter stored on config */
789 int boolParam(char *var)
790 {
791 bool result = false;
792 char *name = alloc_printf("%s/%s", zylin_config_dir, var);
793 if (name == NULL)
794 return result;
795
796 void *data;
797 int len;
798 if (loadFile(name, &data, &len) == ERROR_OK)
799 {
800 if (len > 1)
801 len = 1;
802 result = strncmp((char *) data, "1", len) == 0;
803 free(data);
804 }
805 free(name);
806 return result;
807 }
808
809

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)