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 if (retval
!= ERROR_OK
) {
93 dap
->do_reconnect
= true;
99 static inline int check_sync(struct adiv5_dap
*dap
)
101 return do_sync
? swd_run_inner(dap
) : ERROR_OK
;
104 /** Select the DP register bank */
105 static int swd_queue_dp_bankselect(struct adiv5_dap
*dap
, unsigned int reg
)
107 /* Only register address 0 (ADIv6 only) and 4 are banked. */
108 if (is_adiv6(dap
) ? (reg
& 0xf) > 4 : (reg
& 0xf) != 4)
111 uint32_t sel
= (reg
>> 4) & DP_SELECT_DPBANK
;
113 /* ADIv6 ensures DPBANKSEL = 0 after line reset */
114 if ((dap
->select_valid
|| (is_adiv6(dap
) && dap
->select_dpbanksel_valid
))
115 && (sel
== (dap
->select
& DP_SELECT_DPBANK
)))
118 /* Use the AP part of dap->select regardless of dap->select_valid:
119 * if !dap->select_valid
120 * dap->select contains a speculative value likely going to be used
121 * in the following swd_queue_ap_bankselect() */
122 sel
|= (uint32_t)(dap
->select
& SELECT_AP_MASK
);
124 LOG_DEBUG_IO("DP BANK SELECT: %" PRIx32
, sel
);
126 /* dap->select cache gets updated in the following call */
127 return swd_queue_dp_write_inner(dap
, DP_SELECT
, sel
);
130 static int swd_queue_dp_read_inner(struct adiv5_dap
*dap
, unsigned int reg
,
133 const struct swd_driver
*swd
= adiv5_dap_swd_driver(dap
);
136 int retval
= swd_queue_dp_bankselect(dap
, reg
);
137 if (retval
!= ERROR_OK
)
140 swd
->read_reg(swd_cmd(true, false, reg
), data
, 0);
142 return check_sync(dap
);
145 static int swd_queue_dp_write_inner(struct adiv5_dap
*dap
, unsigned int reg
,
148 int retval
= ERROR_OK
;
149 const struct swd_driver
*swd
= adiv5_dap_swd_driver(dap
);
152 swd_finish_read(dap
);
154 if (reg
== DP_SELECT
) {
155 dap
->select
= data
| (dap
->select
& (0xffffffffull
<< 32));
157 swd
->write_reg(swd_cmd(false, false, reg
), data
, 0);
159 retval
= check_sync(dap
);
160 dap
->select_valid
= (retval
== ERROR_OK
);
161 dap
->select_dpbanksel_valid
= dap
->select_valid
;
166 if (reg
== DP_SELECT1
)
167 dap
->select
= ((uint64_t)data
<< 32) | (dap
->select
& 0xffffffffull
);
169 /* DP_ABORT write is not banked.
170 * Prevent writing DP_SELECT before as it would fail on locked up DP */
172 retval
= swd_queue_dp_bankselect(dap
, reg
);
174 if (retval
== ERROR_OK
) {
175 swd
->write_reg(swd_cmd(false, false, reg
), data
, 0);
177 retval
= check_sync(dap
);
180 if (reg
== DP_SELECT1
)
181 dap
->select1_valid
= (retval
== ERROR_OK
);
187 static int swd_multidrop_select_inner(struct adiv5_dap
*dap
, uint32_t *dpidr_ptr
,
188 uint32_t *dlpidr_ptr
, bool clear_sticky
)
191 uint32_t dpidr
, dlpidr
;
193 assert(dap_is_multidrop(dap
));
195 /* Send JTAG_TO_DORMANT and DORMANT_TO_SWD just once
196 * and then use shorter LINE_RESET until communication fails */
197 if (!swd_multidrop_in_swd_state
) {
198 swd_send_sequence(dap
, JTAG_TO_DORMANT
);
199 swd_send_sequence(dap
, DORMANT_TO_SWD
);
201 swd_send_sequence(dap
, LINE_RESET
);
205 * Zero dap->select and set dap->select_dpbanksel_valid
206 * to skip the write to DP_SELECT before DPIDR read, avoiding
207 * the protocol error.
208 * Clear the other validity flags because the rest of the DP
209 * SELECT and SELECT1 registers is unknown after line reset.
212 dap
->select_dpbanksel_valid
= true;
213 dap
->select_valid
= false;
214 dap
->select1_valid
= false;
216 retval
= swd_queue_dp_write_inner(dap
, DP_TARGETSEL
, dap
->multidrop_targetsel
);
217 if (retval
!= ERROR_OK
)
220 retval
= swd_queue_dp_read_inner(dap
, DP_DPIDR
, &dpidr
);
221 if (retval
!= ERROR_OK
)
225 /* Clear all sticky errors (including ORUN) */
226 swd_clear_sticky_errors(dap
);
228 /* Ideally just clear ORUN flag which is set by reset */
229 retval
= swd_queue_dp_write_inner(dap
, DP_ABORT
, ORUNERRCLR
);
230 if (retval
!= ERROR_OK
)
234 retval
= swd_queue_dp_read_inner(dap
, DP_DLPIDR
, &dlpidr
);
235 if (retval
!= ERROR_OK
)
238 retval
= swd_run_inner(dap
);
239 if (retval
!= ERROR_OK
)
242 if ((dpidr
& DP_DPIDR_VERSION_MASK
) < (2UL << DP_DPIDR_VERSION_SHIFT
)) {
243 LOG_INFO("Read DPIDR 0x%08" PRIx32
244 " has version < 2. A non multidrop capable device connected?",
249 /* TODO: check TARGETID if DLIPDR is same for more than one DP */
250 uint32_t expected_dlpidr
= DP_DLPIDR_PROTVSN
|
251 (dap
->multidrop_targetsel
& DP_TARGETSEL_INSTANCEID_MASK
);
252 if (dlpidr
!= expected_dlpidr
) {
253 LOG_INFO("Read incorrect DLPIDR 0x%08" PRIx32
254 " (possibly CTRL/STAT value)",
259 LOG_DEBUG_IO("Selected DP_TARGETSEL 0x%08" PRIx32
, dap
->multidrop_targetsel
);
260 swd_multidrop_selected_dap
= dap
;
261 swd_multidrop_in_swd_state
= true;
267 *dlpidr_ptr
= dlpidr
;
272 static int swd_multidrop_select(struct adiv5_dap
*dap
)
274 if (!dap_is_multidrop(dap
))
277 if (swd_multidrop_selected_dap
== dap
)
280 int retval
= ERROR_OK
;
281 for (unsigned int retry
= 0; ; retry
++) {
282 bool clear_sticky
= retry
> 0;
284 retval
= swd_multidrop_select_inner(dap
, NULL
, NULL
, clear_sticky
);
285 if (retval
== ERROR_OK
)
288 swd_multidrop_selected_dap
= NULL
;
290 LOG_ERROR("Failed to select multidrop %s", adiv5_dap_name(dap
));
294 LOG_DEBUG("Failed to select multidrop %s, retrying...",
295 adiv5_dap_name(dap
));
296 /* we going to retry localy, do not ask for full reconnect */
297 dap
->do_reconnect
= false;
303 static int swd_connect_multidrop(struct adiv5_dap
*dap
)
306 uint32_t dpidr
= 0xdeadbeef;
307 uint32_t dlpidr
= 0xdeadbeef;
308 int64_t timeout
= timeval_ms() + 500;
311 /* Do not make any assumptions about SWD state in case of reconnect */
312 if (dap
->do_reconnect
)
313 swd_multidrop_in_swd_state
= false;
315 /* Clear link state, including the SELECT cache. */
316 dap
->do_reconnect
= false;
317 dap_invalidate_cache(dap
);
318 swd_multidrop_selected_dap
= NULL
;
320 retval
= swd_multidrop_select_inner(dap
, &dpidr
, &dlpidr
, true);
321 if (retval
== ERROR_OK
)
324 swd_multidrop_in_swd_state
= false;
327 } while (timeval_ms() < timeout
);
329 if (retval
!= ERROR_OK
) {
330 swd_multidrop_selected_dap
= NULL
;
331 LOG_ERROR("Failed to connect multidrop %s", adiv5_dap_name(dap
));
335 swd_multidrop_in_swd_state
= true;
336 LOG_INFO("SWD DPIDR 0x%08" PRIx32
", DLPIDR 0x%08" PRIx32
,
342 static int swd_connect_single(struct adiv5_dap
*dap
)
345 uint32_t dpidr
= 0xdeadbeef;
346 int64_t timeout
= timeval_ms() + 500;
349 if (dap
->switch_through_dormant
) {
350 swd_send_sequence(dap
, JTAG_TO_DORMANT
);
351 swd_send_sequence(dap
, DORMANT_TO_SWD
);
353 swd_send_sequence(dap
, JTAG_TO_SWD
);
356 /* Clear link state, including the SELECT cache. */
357 dap
->do_reconnect
= false;
358 dap_invalidate_cache(dap
);
360 /* The sequences to enter in SWD (JTAG_TO_SWD and DORMANT_TO_SWD) end
361 * with a SWD line reset sequence (50 clk with SWDIO high).
362 * From ARM IHI 0031F ADIv5.2 and ARM IHI 0074C ADIv6.0,
363 * chapter B4.3.3 "Connection and line reset sequence":
364 * - DPv3 (ADIv6) only: line reset sets DP_SELECT_DPBANK to zero;
365 * - read of DP_DPIDR takes the connection out of reset;
366 * - write of DP_TARGETSEL keeps the connection in reset;
367 * - other accesses return protocol error (SWDIO not driven by target).
369 * dap_invalidate_cache() sets dap->select to zero and all validity
370 * flags to invalid. Set dap->select_dpbanksel_valid only
371 * to skip the write to DP_SELECT, avoiding the protocol error.
372 * Read DP_DPIDR to get out of reset.
374 dap
->select_dpbanksel_valid
= true;
376 retval
= swd_queue_dp_read_inner(dap
, DP_DPIDR
, &dpidr
);
377 if (retval
== ERROR_OK
) {
378 retval
= swd_run_inner(dap
);
379 if (retval
== ERROR_OK
)
385 dap
->switch_through_dormant
= !dap
->switch_through_dormant
;
386 } while (timeval_ms() < timeout
);
388 if (retval
!= ERROR_OK
) {
389 LOG_ERROR("Error connecting DP: cannot read IDR");
393 LOG_INFO("SWD DPIDR 0x%08" PRIx32
, dpidr
);
396 dap
->do_reconnect
= false;
398 /* force clear all sticky faults */
399 swd_clear_sticky_errors(dap
);
401 retval
= swd_run_inner(dap
);
402 if (retval
!= ERROR_WAIT
)
407 } while (timeval_ms() < timeout
);
412 static int swd_pre_connect(struct adiv5_dap
*dap
)
414 swd_multidrop_in_swd_state
= false;
419 static int swd_connect(struct adiv5_dap
*dap
)
423 /* FIXME validate transport config ... is the
424 * configured DAP present (check IDCODE)?
427 /* Check if we should reset srst already when connecting, but not if reconnecting. */
428 if (!dap
->do_reconnect
) {
429 enum reset_types jtag_reset_config
= jtag_get_reset_config();
431 if (jtag_reset_config
& RESET_CNCT_UNDER_SRST
) {
432 if (jtag_reset_config
& RESET_SRST_NO_GATING
)
433 adapter_assert_reset();
435 LOG_WARNING("\'srst_nogate\' reset_config option is required");
439 if (dap_is_multidrop(dap
))
440 status
= swd_connect_multidrop(dap
);
442 status
= swd_connect_single(dap
);
445 * "A WAIT response must not be issued to the ...
446 * ... writes to the ABORT register"
447 * swd_clear_sticky_errors() writes to the ABORT register only.
449 * Unfortunately at least Microchip SAMD51/E53/E54 returns WAIT
450 * in a corner case. Just try if ABORT resolves the problem.
452 if (status
== ERROR_WAIT
) {
453 LOG_WARNING("Connecting DP: stalled AP operation, issuing ABORT");
455 dap
->do_reconnect
= false;
457 status
= swd_queue_dp_write_inner(dap
, DP_ABORT
,
458 DAPABORT
| STKCMPCLR
| STKERRCLR
| WDERRCLR
| ORUNERRCLR
);
460 if (status
== ERROR_OK
)
461 status
= swd_run_inner(dap
);
464 if (status
== ERROR_OK
)
465 status
= dap_dp_init(dap
);
470 static int swd_check_reconnect(struct adiv5_dap
*dap
)
472 if (dap
->do_reconnect
)
473 return swd_connect(dap
);
478 static int swd_queue_ap_abort(struct adiv5_dap
*dap
, uint8_t *ack
)
480 const struct swd_driver
*swd
= adiv5_dap_swd_driver(dap
);
483 /* TODO: Send DAPABORT in swd_multidrop_select_inner()
484 * in the case the multidrop dap is not selected?
485 * swd_queue_ap_abort() is not currently used anyway...
487 int retval
= swd_multidrop_select(dap
);
488 if (retval
!= ERROR_OK
)
491 swd
->write_reg(swd_cmd(false, false, DP_ABORT
),
492 DAPABORT
| STKCMPCLR
| STKERRCLR
| WDERRCLR
| ORUNERRCLR
, 0);
493 return check_sync(dap
);
496 static int swd_queue_dp_read(struct adiv5_dap
*dap
, unsigned reg
,
499 int retval
= swd_check_reconnect(dap
);
500 if (retval
!= ERROR_OK
)
503 retval
= swd_multidrop_select(dap
);
504 if (retval
!= ERROR_OK
)
507 return swd_queue_dp_read_inner(dap
, reg
, data
);
510 static int swd_queue_dp_write(struct adiv5_dap
*dap
, unsigned reg
,
513 const struct swd_driver
*swd
= adiv5_dap_swd_driver(dap
);
516 int retval
= swd_check_reconnect(dap
);
517 if (retval
!= ERROR_OK
)
520 retval
= swd_multidrop_select(dap
);
521 if (retval
!= ERROR_OK
)
524 return swd_queue_dp_write_inner(dap
, reg
, data
);
527 /** Select the AP register bank */
528 static int swd_queue_ap_bankselect(struct adiv5_ap
*ap
, unsigned reg
)
531 struct adiv5_dap
*dap
= ap
->dap
;
535 sel
= ap
->ap_num
| (reg
& 0x00000FF0);
537 sel
= (ap
->ap_num
<< 24) | (reg
& ADIV5_DP_SELECT_APBANK
);
539 uint64_t sel_diff
= (sel
^ dap
->select
) & SELECT_AP_MASK
;
541 bool set_select
= !dap
->select_valid
|| (sel_diff
& 0xffffffffull
);
542 bool set_select1
= is_adiv6(dap
) && dap
->asize
> 32
543 && (!dap
->select1_valid
544 || sel_diff
& (0xffffffffull
<< 32));
546 if (set_select
&& set_select1
) {
547 /* Prepare DP bank for DP_SELECT1 now to save one write */
548 sel
|= (DP_SELECT1
& 0x000000f0) >> 4;
550 /* Use the DP part of dap->select regardless of dap->select_valid:
551 * if !dap->select_valid
552 * dap->select contains a speculative value likely going to be used
553 * in the following swd_queue_dp_bankselect().
554 * Moreover dap->select_valid should never be false here as a DP bank
555 * is always selected before selecting an AP bank */
556 sel
|= dap
->select
& DP_SELECT_DPBANK
;
560 LOG_DEBUG_IO("AP BANK SELECT: %" PRIx32
, (uint32_t)sel
);
562 retval
= swd_queue_dp_write(dap
, DP_SELECT
, (uint32_t)sel
);
563 if (retval
!= ERROR_OK
)
568 LOG_DEBUG_IO("AP BANK SELECT1: %" PRIx32
, (uint32_t)(sel
>> 32));
570 retval
= swd_queue_dp_write(dap
, DP_SELECT1
, (uint32_t)(sel
>> 32));
571 if (retval
!= ERROR_OK
)
578 static int swd_queue_ap_read(struct adiv5_ap
*ap
, unsigned reg
,
581 struct adiv5_dap
*dap
= ap
->dap
;
582 const struct swd_driver
*swd
= adiv5_dap_swd_driver(dap
);
585 int retval
= swd_check_reconnect(dap
);
586 if (retval
!= ERROR_OK
)
589 retval
= swd_multidrop_select(dap
);
590 if (retval
!= ERROR_OK
)
593 retval
= swd_queue_ap_bankselect(ap
, reg
);
594 if (retval
!= ERROR_OK
)
597 swd
->read_reg(swd_cmd(true, true, reg
), dap
->last_read
, ap
->memaccess_tck
);
598 dap
->last_read
= data
;
600 return check_sync(dap
);
603 static int swd_queue_ap_write(struct adiv5_ap
*ap
, unsigned reg
,
606 struct adiv5_dap
*dap
= ap
->dap
;
607 const struct swd_driver
*swd
= adiv5_dap_swd_driver(dap
);
610 int retval
= swd_check_reconnect(dap
);
611 if (retval
!= ERROR_OK
)
614 retval
= swd_multidrop_select(dap
);
615 if (retval
!= ERROR_OK
)
618 swd_finish_read(dap
);
620 retval
= swd_queue_ap_bankselect(ap
, reg
);
621 if (retval
!= ERROR_OK
)
624 swd
->write_reg(swd_cmd(false, true, reg
), data
, ap
->memaccess_tck
);
626 return check_sync(dap
);
629 /** Executes all queued DAP operations. */
630 static int swd_run(struct adiv5_dap
*dap
)
632 int retval
= swd_multidrop_select(dap
);
633 if (retval
!= ERROR_OK
)
636 swd_finish_read(dap
);
638 return swd_run_inner(dap
);
641 /** Put the SWJ-DP back to JTAG mode */
642 static void swd_quit(struct adiv5_dap
*dap
)
644 const struct swd_driver
*swd
= adiv5_dap_swd_driver(dap
);
647 /* There is no difference if the sequence is sent at the last
648 * or the first swd_quit() call, send it just once */
653 if (dap_is_multidrop(dap
)) {
654 /* Emit the switch seq to dormant state regardless the state mirrored
655 * in swd_multidrop_in_swd_state. Doing so ensures robust operation
656 * in the case the variable is out of sync.
657 * Sending SWD_TO_DORMANT makes no change if the DP is already dormant. */
658 swd
->switch_seq(SWD_TO_DORMANT
);
659 swd_multidrop_in_swd_state
= false;
661 * Leaving DPs in dormant state was tested and offers some safety
662 * against DPs mismatch in case of unintentional use of non-multidrop SWD.
663 * To put SWJ-DPs to power-on state issue
664 * swd->switch_seq(DORMANT_TO_JTAG);
667 if (dap
->switch_through_dormant
) {
668 swd
->switch_seq(SWD_TO_DORMANT
);
669 swd
->switch_seq(DORMANT_TO_JTAG
);
671 swd
->switch_seq(SWD_TO_JTAG
);
675 /* flush the queue to shift out the sequence before exit */
679 const struct dap_ops swd_dap_ops
= {
680 .pre_connect_init
= swd_pre_connect
,
681 .connect
= swd_connect
,
682 .send_sequence
= swd_send_sequence
,
683 .queue_dp_read
= swd_queue_dp_read
,
684 .queue_dp_write
= swd_queue_dp_write
,
685 .queue_ap_read
= swd_queue_ap_read
,
686 .queue_ap_write
= swd_queue_ap_write
,
687 .queue_ap_abort
= swd_queue_ap_abort
,
692 static const struct command_registration swd_commands
[] = {
695 * Set up SWD and JTAG targets identically, unless/until
696 * infrastructure improves ... meanwhile, ignore all
697 * JTAG-specific stuff like IR length for SWD.
699 * REVISIT can we verify "just one SWD DAP" here/early?
702 .handler
= handle_jtag_newtap
,
703 .mode
= COMMAND_CONFIG
,
704 .help
= "declare a new SWD DAP",
705 .usage
= "basename dap_type ['-irlen' count] "
706 "['-enable'|'-disable'] "
707 "['-expected_id' number] "
708 "['-ignore-version'] "
709 "['-ignore-bypass'] "
710 "['-ircapture' number] "
711 "['-ir-bypass' number] "
714 COMMAND_REGISTRATION_DONE
717 static const struct command_registration swd_handlers
[] = {
721 .help
= "SWD command group",
722 .chain
= swd_commands
,
725 COMMAND_REGISTRATION_DONE
728 static int swd_select(struct command_context
*ctx
)
730 /* FIXME: only place where global 'adapter_driver' is still needed */
731 extern struct adapter_driver
*adapter_driver
;
732 const struct swd_driver
*swd
= adapter_driver
->swd_ops
;
735 retval
= register_commands(ctx
, NULL
, swd_handlers
);
736 if (retval
!= ERROR_OK
)
739 /* be sure driver is in SWD mode; start
740 * with hardware default TRN (1), it can be changed later
742 if (!swd
|| !swd
->read_reg
|| !swd
->write_reg
|| !swd
->init
) {
743 LOG_DEBUG("no SWD driver?");
747 retval
= swd
->init();
748 if (retval
!= ERROR_OK
) {
749 LOG_DEBUG("can't init SWD driver");
756 static int swd_init(struct command_context
*ctx
)
758 /* nothing done here, SWD is initialized
759 * together with the DAP */
763 static struct transport swd_transport
= {
765 .select
= swd_select
,
769 static void swd_constructor(void) __attribute__((constructor
));
770 static void swd_constructor(void)
772 transport_register(&swd_transport
);
775 /** Returns true if the current debug session
776 * is using SWD as its transport.
778 bool transport_is_swd(void)
780 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)