1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
5 * Copyright (C) 2010 by David Brownell
6 ***************************************************************************/
10 * Utilities to support ARM "Serial Wire Debug" (SWD), a low pin-count debug
11 * link protocol used in cases where JTAG is not wanted. This is coupled to
12 * recent versions of ARM's "CoreSight" debug framework. This specific code
13 * is a transport level interface, with "target/arm_adi_v5.[hc]" code
14 * understanding operation semantics, shared with the JTAG transport.
16 * Single DAP and multidrop-SWD support.
18 * for details, see "ARM IHI 0031A"
19 * ARM Debug Interface v5 Architecture Specification
20 * especially section 5.3 for SWD protocol
21 * and "ARM IHI 0074C" ARM Debug Interface Architecture Specification ADIv6.0
23 * On many chips (most current Cortex-M3 parts) SWD is a run-time alternative
24 * to JTAG. Boards may support one or both. There are also SWD-only chips,
25 * (using SW-DP not SWJ-DP).
27 * Even boards that also support JTAG can benefit from SWD support, because
28 * usually there's no way to access the SWO trace view mechanism in JTAG mode.
29 * That is, trace access may require SWD support.
38 #include "arm_adi_v5.h"
39 #include <helper/time_support.h>
41 #include <transport/transport.h>
42 #include <jtag/interface.h>
46 /* for debug, set do_sync to true to force synchronous transfers */
49 static struct adiv5_dap
*swd_multidrop_selected_dap
;
51 static bool swd_multidrop_in_swd_state
;
54 static int swd_queue_dp_write_inner(struct adiv5_dap
*dap
, unsigned int reg
,
58 static int swd_send_sequence(struct adiv5_dap
*dap
, enum swd_special_seq seq
)
60 const struct swd_driver
*swd
= adiv5_dap_swd_driver(dap
);
63 return swd
->switch_seq(seq
);
66 static void swd_finish_read(struct adiv5_dap
*dap
)
68 const struct swd_driver
*swd
= adiv5_dap_swd_driver(dap
);
70 swd
->read_reg(swd_cmd(true, false, DP_RDBUFF
), dap
->last_read
, 0);
71 dap
->last_read
= NULL
;
75 static void swd_clear_sticky_errors(struct adiv5_dap
*dap
)
77 const struct swd_driver
*swd
= adiv5_dap_swd_driver(dap
);
80 swd
->write_reg(swd_cmd(false, false, DP_ABORT
),
81 STKCMPCLR
| STKERRCLR
| WDERRCLR
| ORUNERRCLR
, 0);
84 static int swd_run_inner(struct adiv5_dap
*dap
)
86 const struct swd_driver
*swd
= adiv5_dap_swd_driver(dap
);
91 static inline int check_sync(struct adiv5_dap
*dap
)
93 return do_sync
? swd_run_inner(dap
) : ERROR_OK
;
96 /** Select the DP register bank */
97 static int swd_queue_dp_bankselect(struct adiv5_dap
*dap
, unsigned int reg
)
99 /* Only register address 0 (ADIv6 only) and 4 are banked. */
100 if (is_adiv6(dap
) ? (reg
& 0xf) > 4 : (reg
& 0xf) != 4)
103 uint32_t sel
= (reg
>> 4) & DP_SELECT_DPBANK
;
105 /* ADIv6 ensures DPBANKSEL = 0 after line reset */
106 if ((dap
->select_valid
|| (is_adiv6(dap
) && dap
->select_dpbanksel_valid
))
107 && (sel
== (dap
->select
& DP_SELECT_DPBANK
)))
110 /* Use the AP part of dap->select regardless of dap->select_valid:
111 * if !dap->select_valid
112 * dap->select contains a speculative value likely going to be used
113 * in the following swd_queue_ap_bankselect() */
114 sel
|= (uint32_t)(dap
->select
& SELECT_AP_MASK
);
116 LOG_DEBUG_IO("DP BANK SELECT: %" PRIx32
, sel
);
118 /* dap->select cache gets updated in the following call */
119 return swd_queue_dp_write_inner(dap
, DP_SELECT
, sel
);
122 static int swd_queue_dp_read_inner(struct adiv5_dap
*dap
, unsigned int reg
,
125 const struct swd_driver
*swd
= adiv5_dap_swd_driver(dap
);
128 int retval
= swd_queue_dp_bankselect(dap
, reg
);
129 if (retval
!= ERROR_OK
)
132 swd
->read_reg(swd_cmd(true, false, reg
), data
, 0);
134 return check_sync(dap
);
137 static int swd_queue_dp_write_inner(struct adiv5_dap
*dap
, unsigned int reg
,
140 int retval
= ERROR_OK
;
141 const struct swd_driver
*swd
= adiv5_dap_swd_driver(dap
);
144 swd_finish_read(dap
);
146 if (reg
== DP_SELECT
) {
147 dap
->select
= data
| (dap
->select
& (0xffffffffull
<< 32));
149 swd
->write_reg(swd_cmd(false, false, reg
), data
, 0);
151 retval
= check_sync(dap
);
152 dap
->select_valid
= (retval
== ERROR_OK
);
153 dap
->select_dpbanksel_valid
= dap
->select_valid
;
158 if (reg
== DP_SELECT1
)
159 dap
->select
= ((uint64_t)data
<< 32) | (dap
->select
& 0xffffffffull
);
161 /* DP_ABORT write is not banked.
162 * Prevent writing DP_SELECT before as it would fail on locked up DP */
164 retval
= swd_queue_dp_bankselect(dap
, reg
);
166 if (retval
== ERROR_OK
) {
167 swd
->write_reg(swd_cmd(false, false, reg
), data
, 0);
169 retval
= check_sync(dap
);
172 if (reg
== DP_SELECT1
)
173 dap
->select1_valid
= (retval
== ERROR_OK
);
179 static int swd_multidrop_select_inner(struct adiv5_dap
*dap
, uint32_t *dpidr_ptr
,
180 uint32_t *dlpidr_ptr
, bool clear_sticky
)
183 uint32_t dpidr
, dlpidr
;
185 assert(dap_is_multidrop(dap
));
187 /* Send JTAG_TO_DORMANT and DORMANT_TO_SWD just once
188 * and then use shorter LINE_RESET until communication fails */
189 if (!swd_multidrop_in_swd_state
) {
190 swd_send_sequence(dap
, JTAG_TO_DORMANT
);
191 swd_send_sequence(dap
, DORMANT_TO_SWD
);
193 swd_send_sequence(dap
, LINE_RESET
);
197 * Zero dap->select and set dap->select_dpbanksel_valid
198 * to skip the write to DP_SELECT before DPIDR read, avoiding
199 * the protocol error.
200 * Clear the other validity flags because the rest of the DP
201 * SELECT and SELECT1 registers is unknown after line reset.
204 dap
->select_dpbanksel_valid
= true;
205 dap
->select_valid
= false;
206 dap
->select1_valid
= false;
208 retval
= swd_queue_dp_write_inner(dap
, DP_TARGETSEL
, dap
->multidrop_targetsel
);
209 if (retval
!= ERROR_OK
)
212 retval
= swd_queue_dp_read_inner(dap
, DP_DPIDR
, &dpidr
);
213 if (retval
!= ERROR_OK
)
217 /* Clear all sticky errors (including ORUN) */
218 swd_clear_sticky_errors(dap
);
220 /* Ideally just clear ORUN flag which is set by reset */
221 retval
= swd_queue_dp_write_inner(dap
, DP_ABORT
, ORUNERRCLR
);
222 if (retval
!= ERROR_OK
)
226 retval
= swd_queue_dp_read_inner(dap
, DP_DLPIDR
, &dlpidr
);
227 if (retval
!= ERROR_OK
)
230 retval
= swd_run_inner(dap
);
231 if (retval
!= ERROR_OK
)
234 if ((dpidr
& DP_DPIDR_VERSION_MASK
) < (2UL << DP_DPIDR_VERSION_SHIFT
)) {
235 LOG_INFO("Read DPIDR 0x%08" PRIx32
236 " has version < 2. A non multidrop capable device connected?",
241 /* TODO: check TARGETID if DLIPDR is same for more than one DP */
242 uint32_t expected_dlpidr
= DP_DLPIDR_PROTVSN
|
243 (dap
->multidrop_targetsel
& DP_TARGETSEL_INSTANCEID_MASK
);
244 if (dlpidr
!= expected_dlpidr
) {
245 LOG_INFO("Read incorrect DLPIDR 0x%08" PRIx32
246 " (possibly CTRL/STAT value)",
251 LOG_DEBUG_IO("Selected DP_TARGETSEL 0x%08" PRIx32
, dap
->multidrop_targetsel
);
252 swd_multidrop_selected_dap
= dap
;
253 swd_multidrop_in_swd_state
= true;
259 *dlpidr_ptr
= dlpidr
;
264 static int swd_multidrop_select(struct adiv5_dap
*dap
)
266 if (!dap_is_multidrop(dap
))
269 if (swd_multidrop_selected_dap
== dap
)
272 int retval
= ERROR_OK
;
273 for (unsigned int retry
= 0; ; retry
++) {
274 bool clear_sticky
= retry
> 0;
276 retval
= swd_multidrop_select_inner(dap
, NULL
, NULL
, clear_sticky
);
277 if (retval
== ERROR_OK
)
280 swd_multidrop_selected_dap
= NULL
;
282 LOG_ERROR("Failed to select multidrop %s", adiv5_dap_name(dap
));
283 dap
->do_reconnect
= true;
287 LOG_DEBUG("Failed to select multidrop %s, retrying...",
288 adiv5_dap_name(dap
));
291 dap
->do_reconnect
= false;
295 static int swd_connect_multidrop(struct adiv5_dap
*dap
)
298 uint32_t dpidr
= 0xdeadbeef;
299 uint32_t dlpidr
= 0xdeadbeef;
300 int64_t timeout
= timeval_ms() + 500;
303 /* Do not make any assumptions about SWD state in case of reconnect */
304 if (dap
->do_reconnect
)
305 swd_multidrop_in_swd_state
= false;
307 /* Clear link state, including the SELECT cache. */
308 dap
->do_reconnect
= false;
309 dap_invalidate_cache(dap
);
310 swd_multidrop_selected_dap
= NULL
;
312 retval
= swd_multidrop_select_inner(dap
, &dpidr
, &dlpidr
, true);
313 if (retval
== ERROR_OK
)
316 swd_multidrop_in_swd_state
= false;
319 } while (timeval_ms() < timeout
);
321 if (retval
!= ERROR_OK
) {
322 swd_multidrop_selected_dap
= NULL
;
323 LOG_ERROR("Failed to connect multidrop %s", adiv5_dap_name(dap
));
327 swd_multidrop_in_swd_state
= true;
328 LOG_INFO("SWD DPIDR 0x%08" PRIx32
", DLPIDR 0x%08" PRIx32
,
334 static int swd_connect_single(struct adiv5_dap
*dap
)
337 uint32_t dpidr
= 0xdeadbeef;
338 int64_t timeout
= timeval_ms() + 500;
341 if (dap
->switch_through_dormant
) {
342 swd_send_sequence(dap
, JTAG_TO_DORMANT
);
343 swd_send_sequence(dap
, DORMANT_TO_SWD
);
345 swd_send_sequence(dap
, JTAG_TO_SWD
);
348 /* Clear link state, including the SELECT cache. */
349 dap
->do_reconnect
= false;
350 dap_invalidate_cache(dap
);
352 /* The sequences to enter in SWD (JTAG_TO_SWD and DORMANT_TO_SWD) end
353 * with a SWD line reset sequence (50 clk with SWDIO high).
354 * From ARM IHI 0031F ADIv5.2 and ARM IHI 0074C ADIv6.0,
355 * chapter B4.3.3 "Connection and line reset sequence":
356 * - DPv3 (ADIv6) only: line reset sets DP_SELECT_DPBANK to zero;
357 * - read of DP_DPIDR takes the connection out of reset;
358 * - write of DP_TARGETSEL keeps the connection in reset;
359 * - other accesses return protocol error (SWDIO not driven by target).
361 * dap_invalidate_cache() sets dap->select to zero and all validity
362 * flags to invalid. Set dap->select_dpbanksel_valid only
363 * to skip the write to DP_SELECT, avoiding the protocol error.
364 * Read DP_DPIDR to get out of reset.
366 dap
->select_dpbanksel_valid
= true;
368 retval
= swd_queue_dp_read_inner(dap
, DP_DPIDR
, &dpidr
);
369 if (retval
== ERROR_OK
) {
370 retval
= swd_run_inner(dap
);
371 if (retval
== ERROR_OK
)
377 dap
->switch_through_dormant
= !dap
->switch_through_dormant
;
378 } while (timeval_ms() < timeout
);
380 if (retval
!= ERROR_OK
) {
381 LOG_ERROR("Error connecting DP: cannot read IDR");
385 LOG_INFO("SWD DPIDR 0x%08" PRIx32
, dpidr
);
388 dap
->do_reconnect
= false;
390 /* force clear all sticky faults */
391 swd_clear_sticky_errors(dap
);
393 retval
= swd_run_inner(dap
);
394 if (retval
!= ERROR_WAIT
)
399 } while (timeval_ms() < timeout
);
404 static int swd_pre_connect(struct adiv5_dap
*dap
)
406 swd_multidrop_in_swd_state
= false;
411 static int swd_connect(struct adiv5_dap
*dap
)
415 /* FIXME validate transport config ... is the
416 * configured DAP present (check IDCODE)?
419 /* Check if we should reset srst already when connecting, but not if reconnecting. */
420 if (!dap
->do_reconnect
) {
421 enum reset_types jtag_reset_config
= jtag_get_reset_config();
423 if (jtag_reset_config
& RESET_CNCT_UNDER_SRST
) {
424 if (jtag_reset_config
& RESET_SRST_NO_GATING
)
425 adapter_assert_reset();
427 LOG_WARNING("\'srst_nogate\' reset_config option is required");
431 if (dap_is_multidrop(dap
))
432 status
= swd_connect_multidrop(dap
);
434 status
= swd_connect_single(dap
);
437 * "A WAIT response must not be issued to the ...
438 * ... writes to the ABORT register"
439 * swd_clear_sticky_errors() writes to the ABORT register only.
441 * Unfortunately at least Microchip SAMD51/E53/E54 returns WAIT
442 * in a corner case. Just try if ABORT resolves the problem.
444 if (status
== ERROR_WAIT
) {
445 LOG_WARNING("Connecting DP: stalled AP operation, issuing ABORT");
447 dap
->do_reconnect
= false;
449 status
= swd_queue_dp_write_inner(dap
, DP_ABORT
,
450 DAPABORT
| STKCMPCLR
| STKERRCLR
| WDERRCLR
| ORUNERRCLR
);
452 if (status
== ERROR_OK
)
453 status
= swd_run_inner(dap
);
456 if (status
== ERROR_OK
)
457 status
= dap_dp_init(dap
);
462 static int swd_check_reconnect(struct adiv5_dap
*dap
)
464 if (dap
->do_reconnect
)
465 return swd_connect(dap
);
470 static int swd_queue_ap_abort(struct adiv5_dap
*dap
, uint8_t *ack
)
472 const struct swd_driver
*swd
= adiv5_dap_swd_driver(dap
);
475 /* TODO: Send DAPABORT in swd_multidrop_select_inner()
476 * in the case the multidrop dap is not selected?
477 * swd_queue_ap_abort() is not currently used anyway...
479 int retval
= swd_multidrop_select(dap
);
480 if (retval
!= ERROR_OK
)
483 swd
->write_reg(swd_cmd(false, false, DP_ABORT
),
484 DAPABORT
| STKCMPCLR
| STKERRCLR
| WDERRCLR
| ORUNERRCLR
, 0);
485 return check_sync(dap
);
488 static int swd_queue_dp_read(struct adiv5_dap
*dap
, unsigned reg
,
491 int retval
= swd_check_reconnect(dap
);
492 if (retval
!= ERROR_OK
)
495 retval
= swd_multidrop_select(dap
);
496 if (retval
!= ERROR_OK
)
499 return swd_queue_dp_read_inner(dap
, reg
, data
);
502 static int swd_queue_dp_write(struct adiv5_dap
*dap
, unsigned reg
,
505 const struct swd_driver
*swd
= adiv5_dap_swd_driver(dap
);
508 int retval
= swd_check_reconnect(dap
);
509 if (retval
!= ERROR_OK
)
512 retval
= swd_multidrop_select(dap
);
513 if (retval
!= ERROR_OK
)
516 return swd_queue_dp_write_inner(dap
, reg
, data
);
519 /** Select the AP register bank */
520 static int swd_queue_ap_bankselect(struct adiv5_ap
*ap
, unsigned reg
)
523 struct adiv5_dap
*dap
= ap
->dap
;
527 sel
= ap
->ap_num
| (reg
& 0x00000FF0);
529 sel
= (ap
->ap_num
<< 24) | (reg
& ADIV5_DP_SELECT_APBANK
);
531 uint64_t sel_diff
= (sel
^ dap
->select
) & SELECT_AP_MASK
;
533 bool set_select
= !dap
->select_valid
|| (sel_diff
& 0xffffffffull
);
534 bool set_select1
= is_adiv6(dap
) && dap
->asize
> 32
535 && (!dap
->select1_valid
536 || sel_diff
& (0xffffffffull
<< 32));
538 if (set_select
&& set_select1
) {
539 /* Prepare DP bank for DP_SELECT1 now to save one write */
540 sel
|= (DP_SELECT1
& 0x000000f0) >> 4;
542 /* Use the DP part of dap->select regardless of dap->select_valid:
543 * if !dap->select_valid
544 * dap->select contains a speculative value likely going to be used
545 * in the following swd_queue_dp_bankselect().
546 * Moreover dap->select_valid should never be false here as a DP bank
547 * is always selected before selecting an AP bank */
548 sel
|= dap
->select
& DP_SELECT_DPBANK
;
552 LOG_DEBUG_IO("AP BANK SELECT: %" PRIx32
, (uint32_t)sel
);
554 retval
= swd_queue_dp_write(dap
, DP_SELECT
, (uint32_t)sel
);
555 if (retval
!= ERROR_OK
)
560 LOG_DEBUG_IO("AP BANK SELECT1: %" PRIx32
, (uint32_t)(sel
>> 32));
562 retval
= swd_queue_dp_write(dap
, DP_SELECT1
, (uint32_t)(sel
>> 32));
563 if (retval
!= ERROR_OK
)
570 static int swd_queue_ap_read(struct adiv5_ap
*ap
, unsigned reg
,
573 struct adiv5_dap
*dap
= ap
->dap
;
574 const struct swd_driver
*swd
= adiv5_dap_swd_driver(dap
);
577 int retval
= swd_check_reconnect(dap
);
578 if (retval
!= ERROR_OK
)
581 retval
= swd_multidrop_select(dap
);
582 if (retval
!= ERROR_OK
)
585 retval
= swd_queue_ap_bankselect(ap
, reg
);
586 if (retval
!= ERROR_OK
)
589 swd
->read_reg(swd_cmd(true, true, reg
), dap
->last_read
, ap
->memaccess_tck
);
590 dap
->last_read
= data
;
592 return check_sync(dap
);
595 static int swd_queue_ap_write(struct adiv5_ap
*ap
, unsigned reg
,
598 struct adiv5_dap
*dap
= ap
->dap
;
599 const struct swd_driver
*swd
= adiv5_dap_swd_driver(dap
);
602 int retval
= swd_check_reconnect(dap
);
603 if (retval
!= ERROR_OK
)
606 retval
= swd_multidrop_select(dap
);
607 if (retval
!= ERROR_OK
)
610 swd_finish_read(dap
);
612 retval
= swd_queue_ap_bankselect(ap
, reg
);
613 if (retval
!= ERROR_OK
)
616 swd
->write_reg(swd_cmd(false, true, reg
), data
, ap
->memaccess_tck
);
618 return check_sync(dap
);
621 /** Executes all queued DAP operations. */
622 static int swd_run(struct adiv5_dap
*dap
)
624 int retval
= swd_multidrop_select(dap
);
625 if (retval
!= ERROR_OK
)
628 swd_finish_read(dap
);
630 retval
= swd_run_inner(dap
);
631 if (retval
!= ERROR_OK
) {
633 dap
->do_reconnect
= true;
639 /** Put the SWJ-DP back to JTAG mode */
640 static void swd_quit(struct adiv5_dap
*dap
)
642 const struct swd_driver
*swd
= adiv5_dap_swd_driver(dap
);
645 /* There is no difference if the sequence is sent at the last
646 * or the first swd_quit() call, send it just once */
651 if (dap_is_multidrop(dap
)) {
652 /* Emit the switch seq to dormant state regardless the state mirrored
653 * in swd_multidrop_in_swd_state. Doing so ensures robust operation
654 * in the case the variable is out of sync.
655 * Sending SWD_TO_DORMANT makes no change if the DP is already dormant. */
656 swd
->switch_seq(SWD_TO_DORMANT
);
657 swd_multidrop_in_swd_state
= false;
659 * Leaving DPs in dormant state was tested and offers some safety
660 * against DPs mismatch in case of unintentional use of non-multidrop SWD.
661 * To put SWJ-DPs to power-on state issue
662 * swd->switch_seq(DORMANT_TO_JTAG);
665 if (dap
->switch_through_dormant
) {
666 swd
->switch_seq(SWD_TO_DORMANT
);
667 swd
->switch_seq(DORMANT_TO_JTAG
);
669 swd
->switch_seq(SWD_TO_JTAG
);
673 /* flush the queue to shift out the sequence before exit */
677 const struct dap_ops swd_dap_ops
= {
678 .pre_connect_init
= swd_pre_connect
,
679 .connect
= swd_connect
,
680 .send_sequence
= swd_send_sequence
,
681 .queue_dp_read
= swd_queue_dp_read
,
682 .queue_dp_write
= swd_queue_dp_write
,
683 .queue_ap_read
= swd_queue_ap_read
,
684 .queue_ap_write
= swd_queue_ap_write
,
685 .queue_ap_abort
= swd_queue_ap_abort
,
690 static const struct command_registration swd_commands
[] = {
693 * Set up SWD and JTAG targets identically, unless/until
694 * infrastructure improves ... meanwhile, ignore all
695 * JTAG-specific stuff like IR length for SWD.
697 * REVISIT can we verify "just one SWD DAP" here/early?
700 .handler
= handle_jtag_newtap
,
701 .mode
= COMMAND_CONFIG
,
702 .help
= "declare a new SWD DAP",
703 .usage
= "basename dap_type ['-irlen' count] "
704 "['-enable'|'-disable'] "
705 "['-expected_id' number] "
706 "['-ignore-version'] "
707 "['-ignore-bypass'] "
708 "['-ircapture' number] "
709 "['-ir-bypass' number] "
712 COMMAND_REGISTRATION_DONE
715 static const struct command_registration swd_handlers
[] = {
719 .help
= "SWD command group",
720 .chain
= swd_commands
,
723 COMMAND_REGISTRATION_DONE
726 static int swd_select(struct command_context
*ctx
)
728 /* FIXME: only place where global 'adapter_driver' is still needed */
729 extern struct adapter_driver
*adapter_driver
;
730 const struct swd_driver
*swd
= adapter_driver
->swd_ops
;
733 retval
= register_commands(ctx
, NULL
, swd_handlers
);
734 if (retval
!= ERROR_OK
)
737 /* be sure driver is in SWD mode; start
738 * with hardware default TRN (1), it can be changed later
740 if (!swd
|| !swd
->read_reg
|| !swd
->write_reg
|| !swd
->init
) {
741 LOG_DEBUG("no SWD driver?");
745 retval
= swd
->init();
746 if (retval
!= ERROR_OK
) {
747 LOG_DEBUG("can't init SWD driver");
754 static int swd_init(struct command_context
*ctx
)
756 /* nothing done here, SWD is initialized
757 * together with the DAP */
761 static struct transport swd_transport
= {
763 .select
= swd_select
,
767 static void swd_constructor(void) __attribute__((constructor
));
768 static void swd_constructor(void)
770 transport_register(&swd_transport
);
773 /** Returns true if the current debug session
774 * is using SWD as its transport.
776 bool transport_is_swd(void)
778 return get_current_transport() == &swd_transport
;
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)