f2b514826eaafd29e28e78105a07f7e1c6cb665f
[openocd.git] / src / target / arm_tpiu_swo.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /**
4 * @file
5 * This file implements support for the ARM CoreSight components Trace Port
6 * Interface Unit (TPIU) and Serial Wire Output (SWO). It also supports the
7 * CoreSight TPIU-Lite and the special TPIU version present with Cortex-M3
8 * and Cortex-M4 (that includes SWO).
9 */
10
11 /*
12 * Relevant specifications from ARM include:
13 *
14 * CoreSight(tm) Components Technical Reference Manual ARM DDI 0314H
15 * CoreSight(tm) TPIU-Lite Technical Reference Manual ARM DDI 0317A
16 * Cortex(tm)-M3 Technical Reference Manual ARM DDI 0337G
17 * Cortex(tm)-M4 Technical Reference Manual ARM DDI 0439B
18 * CoreSight(tm) SoC-400 Technical Reference Manual ARM DDI 0480F
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <stdlib.h>
26 #include <jim.h>
27
28 #include <helper/bits.h>
29 #include <helper/command.h>
30 #include <helper/jim-nvp.h>
31 #include <helper/list.h>
32 #include <helper/log.h>
33 #include <helper/types.h>
34 #include <jtag/interface.h>
35 #include <server/server.h>
36 #include <target/arm_adi_v5.h>
37 #include <target/target.h>
38 #include <transport/transport.h>
39 #include "arm_tpiu_swo.h"
40
41 /* START_DEPRECATED_TPIU */
42 #include <target/cortex_m.h>
43 #include <target/target_type.h>
44 #define MSG "DEPRECATED \'tpiu config\' command: "
45 /* END_DEPRECATED_TPIU */
46
47 #define TCP_SERVICE_NAME "tpiu_swo_trace"
48
49 /* default for Cortex-M3 and Cortex-M4 specific TPIU */
50 #define TPIU_SWO_DEFAULT_BASE 0xE0040000
51
52 #define TPIU_SSPSR_OFFSET 0x000
53 #define TPIU_CSPSR_OFFSET 0x004
54 #define TPIU_ACPR_OFFSET 0x010
55 #define TPIU_SPPR_OFFSET 0x0F0
56 #define TPIU_FFSR_OFFSET 0x300
57 #define TPIU_FFCR_OFFSET 0x304
58 #define TPIU_FSCR_OFFSET 0x308
59 #define TPIU_DEVID_OFFSET 0xfc8
60
61 #define TPIU_ACPR_MAX_PRESCALER 0x1fff
62 #define TPIU_SPPR_PROTOCOL_SYNC (TPIU_PIN_PROTOCOL_SYNC)
63 #define TPIU_SPPR_PROTOCOL_MANCHESTER (TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER)
64 #define TPIU_SPPR_PROTOCOL_UART (TPIU_PIN_PROTOCOL_ASYNC_UART)
65 #define TPIU_DEVID_NOSUPPORT_SYNC BIT(9)
66 #define TPIU_DEVID_SUPPORT_MANCHESTER BIT(10)
67 #define TPIU_DEVID_SUPPORT_UART BIT(11)
68
69 enum arm_tpiu_swo_event {
70 TPIU_SWO_EVENT_PRE_ENABLE,
71 TPIU_SWO_EVENT_POST_ENABLE,
72 TPIU_SWO_EVENT_PRE_DISABLE,
73 TPIU_SWO_EVENT_POST_DISABLE,
74 };
75
76 static const struct jim_nvp nvp_arm_tpiu_swo_event[] = {
77 { .value = TPIU_SWO_EVENT_PRE_ENABLE, .name = "pre-enable" },
78 { .value = TPIU_SWO_EVENT_POST_ENABLE, .name = "post-enable" },
79 { .value = TPIU_SWO_EVENT_PRE_DISABLE, .name = "pre-disable" },
80 { .value = TPIU_SWO_EVENT_POST_DISABLE, .name = "post-disable" },
81 };
82
83 struct arm_tpiu_swo_event_action {
84 enum arm_tpiu_swo_event event;
85 Jim_Interp *interp;
86 Jim_Obj *body;
87 struct arm_tpiu_swo_event_action *next;
88 };
89
90 struct arm_tpiu_swo_object {
91 struct list_head lh;
92 struct adiv5_mem_ap_spot spot;
93 char *name;
94 struct arm_tpiu_swo_event_action *event_action;
95 /* record enable before init */
96 bool deferred_enable;
97 bool enabled;
98 bool en_capture;
99 /** Handle to output trace data in INTERNAL capture mode */
100 /** Synchronous output port width */
101 uint32_t port_width;
102 FILE *file;
103 /** output mode */
104 unsigned int pin_protocol;
105 /** Enable formatter */
106 bool en_formatter;
107 /** frequency of TRACECLKIN (usually matches HCLK) */
108 unsigned int traceclkin_freq;
109 /** SWO pin frequency */
110 unsigned int swo_pin_freq;
111 /** where to dump the captured output trace data */
112 char *out_filename;
113 /** track TCP connections */
114 struct list_head connections;
115 /* START_DEPRECATED_TPIU */
116 bool recheck_ap_cur_target;
117 /* END_DEPRECATED_TPIU */
118 };
119
120 struct arm_tpiu_swo_connection {
121 struct list_head lh;
122 struct connection *connection;
123 };
124
125 struct arm_tpiu_swo_priv_connection {
126 struct arm_tpiu_swo_object *obj;
127 };
128
129 static LIST_HEAD(all_tpiu_swo);
130
131 #define ARM_TPIU_SWO_TRACE_BUF_SIZE 4096
132
133 static int arm_tpiu_swo_poll_trace(void *priv)
134 {
135 struct arm_tpiu_swo_object *obj = priv;
136 uint8_t buf[ARM_TPIU_SWO_TRACE_BUF_SIZE];
137 size_t size = sizeof(buf);
138 struct arm_tpiu_swo_connection *c;
139
140 int retval = adapter_poll_trace(buf, &size);
141 if (retval != ERROR_OK || !size)
142 return retval;
143
144 target_call_trace_callbacks(/*target*/NULL, size, buf);
145
146 if (obj->file) {
147 if (fwrite(buf, 1, size, obj->file) == size) {
148 fflush(obj->file);
149 } else {
150 LOG_ERROR("Error writing to the SWO trace destination file");
151 return ERROR_FAIL;
152 }
153 }
154
155 if (obj->out_filename && obj->out_filename[0] == ':')
156 list_for_each_entry(c, &obj->connections, lh)
157 if (connection_write(c->connection, buf, size) != (int)size)
158 retval = ERROR_FAIL;
159
160 return ERROR_OK;
161 }
162
163 static void arm_tpiu_swo_handle_event(struct arm_tpiu_swo_object *obj, enum arm_tpiu_swo_event event)
164 {
165 for (struct arm_tpiu_swo_event_action *ea = obj->event_action; ea; ea = ea->next) {
166 if (ea->event != event)
167 continue;
168
169 LOG_DEBUG("TPIU/SWO: %s event: %s (%d) action : %s",
170 obj->name,
171 jim_nvp_value2name_simple(nvp_arm_tpiu_swo_event, event)->name,
172 event,
173 Jim_GetString(ea->body, NULL));
174
175 /* prevent event execution to change current target */
176 struct command_context *cmd_ctx = current_command_context(ea->interp);
177 struct target *saved_target = cmd_ctx->current_target;
178 int retval = Jim_EvalObj(ea->interp, ea->body);
179 cmd_ctx->current_target = saved_target;
180
181 if (retval == JIM_RETURN)
182 retval = ea->interp->returnCode;
183 if (retval == JIM_OK || retval == ERROR_COMMAND_CLOSE_CONNECTION)
184 return;
185
186 Jim_MakeErrorMessage(ea->interp);
187 LOG_USER("Error executing event %s on TPIU/SWO %s:\n%s",
188 jim_nvp_value2name_simple(nvp_arm_tpiu_swo_event, event)->name,
189 obj->name,
190 Jim_GetString(Jim_GetResult(ea->interp), NULL));
191 /* clean both error code and stacktrace before return */
192 Jim_Eval(ea->interp, "error \"\" \"\"");
193 return;
194 }
195 }
196
197 static void arm_tpiu_swo_close_output(struct arm_tpiu_swo_object *obj)
198 {
199 if (obj->file) {
200 fclose(obj->file);
201 obj->file = NULL;
202 }
203 if (obj->out_filename && obj->out_filename[0] == ':')
204 remove_service(TCP_SERVICE_NAME, &obj->out_filename[1]);
205 }
206
207 int arm_tpiu_swo_cleanup_all(void)
208 {
209 struct arm_tpiu_swo_object *obj, *tmp;
210
211 list_for_each_entry_safe(obj, tmp, &all_tpiu_swo, lh) {
212 if (obj->enabled)
213 arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_PRE_DISABLE);
214
215 arm_tpiu_swo_close_output(obj);
216
217 if (obj->en_capture) {
218 target_unregister_timer_callback(arm_tpiu_swo_poll_trace, obj);
219
220 int retval = adapter_config_trace(false, 0, 0, NULL, 0, NULL);
221 if (retval != ERROR_OK)
222 LOG_ERROR("Failed to stop adapter's trace");
223 }
224
225 if (obj->enabled)
226 arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_POST_DISABLE);
227
228 struct arm_tpiu_swo_event_action *ea = obj->event_action;
229 while (ea) {
230 struct arm_tpiu_swo_event_action *next = ea->next;
231 Jim_DecrRefCount(ea->interp, ea->body);
232 free(ea);
233 ea = next;
234 }
235
236 free(obj->name);
237 free(obj->out_filename);
238 free(obj);
239 }
240
241 return ERROR_OK;
242 }
243
244 static int arm_tpiu_swo_service_new_connection(struct connection *connection)
245 {
246 struct arm_tpiu_swo_priv_connection *priv = connection->service->priv;
247 struct arm_tpiu_swo_object *obj = priv->obj;
248 struct arm_tpiu_swo_connection *c = malloc(sizeof(*c));
249 if (!c) {
250 LOG_ERROR("Out of memory");
251 return ERROR_FAIL;
252 }
253 c->connection = connection;
254 list_add(&c->lh, &obj->connections);
255 return ERROR_OK;
256 }
257
258 static int arm_tpiu_swo_service_input(struct connection *connection)
259 {
260 /* read a dummy buffer to check if the connection is still active */
261 long dummy;
262 int bytes_read = connection_read(connection, &dummy, sizeof(dummy));
263
264 if (bytes_read == 0) {
265 return ERROR_SERVER_REMOTE_CLOSED;
266 } else if (bytes_read == -1) {
267 LOG_ERROR("error during read: %s", strerror(errno));
268 return ERROR_SERVER_REMOTE_CLOSED;
269 }
270
271 return ERROR_OK;
272 }
273
274 static int arm_tpiu_swo_service_connection_closed(struct connection *connection)
275 {
276 struct arm_tpiu_swo_priv_connection *priv = connection->service->priv;
277 struct arm_tpiu_swo_object *obj = priv->obj;
278 struct arm_tpiu_swo_connection *c, *tmp;
279
280 list_for_each_entry_safe(c, tmp, &obj->connections, lh)
281 if (c->connection == connection) {
282 list_del(&c->lh);
283 free(c);
284 return ERROR_OK;
285 }
286 LOG_ERROR("Failed to find connection to close!");
287 return ERROR_FAIL;
288 }
289
290 COMMAND_HANDLER(handle_arm_tpiu_swo_event_list)
291 {
292 struct arm_tpiu_swo_object *obj = CMD_DATA;
293
294 command_print(CMD, "Event actions for TPIU/SWO %s\n", obj->name);
295 command_print(CMD, "%-25s | Body", "Event");
296 command_print(CMD, "------------------------- | "
297 "----------------------------------------");
298
299 for (struct arm_tpiu_swo_event_action *ea = obj->event_action; ea; ea = ea->next) {
300 struct jim_nvp *opt = jim_nvp_value2name_simple(nvp_arm_tpiu_swo_event, ea->event);
301 command_print(CMD, "%-25s | %s",
302 opt->name, Jim_GetString(ea->body, NULL));
303 }
304 command_print(CMD, "***END***");
305 return ERROR_OK;
306 }
307
308 enum arm_tpiu_swo_cfg_param {
309 CFG_PORT_WIDTH,
310 CFG_PROTOCOL,
311 CFG_FORMATTER,
312 CFG_TRACECLKIN,
313 CFG_BITRATE,
314 CFG_OUTFILE,
315 CFG_EVENT,
316 };
317
318 static const struct jim_nvp nvp_arm_tpiu_swo_config_opts[] = {
319 { .name = "-port-width", .value = CFG_PORT_WIDTH },
320 { .name = "-protocol", .value = CFG_PROTOCOL },
321 { .name = "-formatter", .value = CFG_FORMATTER },
322 { .name = "-traceclk", .value = CFG_TRACECLKIN },
323 { .name = "-pin-freq", .value = CFG_BITRATE },
324 { .name = "-output", .value = CFG_OUTFILE },
325 { .name = "-event", .value = CFG_EVENT },
326 /* handled by mem_ap_spot, added for jim_getopt_nvp_unknown() */
327 { .name = "-dap", .value = -1 },
328 { .name = "-ap-num", .value = -1 },
329 { .name = "-baseaddr", .value = -1 },
330 { .name = NULL, .value = -1 },
331 };
332
333 static const struct jim_nvp nvp_arm_tpiu_swo_protocol_opts[] = {
334 { .name = "sync", .value = TPIU_SPPR_PROTOCOL_SYNC },
335 { .name = "uart", .value = TPIU_SPPR_PROTOCOL_UART },
336 { .name = "manchester", .value = TPIU_SPPR_PROTOCOL_MANCHESTER },
337 { .name = NULL, .value = -1 },
338 };
339
340 static const struct jim_nvp nvp_arm_tpiu_swo_bool_opts[] = {
341 { .name = "on", .value = 1 },
342 { .name = "yes", .value = 1 },
343 { .name = "1", .value = 1 },
344 { .name = "true", .value = 1 },
345 { .name = "off", .value = 0 },
346 { .name = "no", .value = 0 },
347 { .name = "0", .value = 0 },
348 { .name = "false", .value = 0 },
349 { .name = NULL, .value = -1 },
350 };
351
352 static int arm_tpiu_swo_configure(struct jim_getopt_info *goi, struct arm_tpiu_swo_object *obj)
353 {
354 assert(obj);
355
356 if (goi->isconfigure && obj->enabled) {
357 Jim_SetResultFormatted(goi->interp, "Cannot configure TPIU/SWO; %s is enabled!", obj->name);
358 return JIM_ERR;
359 }
360
361 /* parse config or cget options ... */
362 while (goi->argc > 0) {
363 Jim_SetEmptyResult(goi->interp);
364
365 int e = adiv5_jim_mem_ap_spot_configure(&obj->spot, goi);
366 if (e == JIM_OK)
367 continue;
368 if (e == JIM_ERR)
369 return e;
370
371 struct jim_nvp *n;
372 e = jim_getopt_nvp(goi, nvp_arm_tpiu_swo_config_opts, &n);
373 if (e != JIM_OK) {
374 jim_getopt_nvp_unknown(goi, nvp_arm_tpiu_swo_config_opts, 0);
375 return e;
376 }
377
378 switch (n->value) {
379 case CFG_PORT_WIDTH:
380 if (goi->isconfigure) {
381 jim_wide port_width;
382 e = jim_getopt_wide(goi, &port_width);
383 if (e != JIM_OK)
384 return e;
385 if (port_width < 1 || port_width > 32) {
386 Jim_SetResultString(goi->interp, "Invalid port width!", -1);
387 return JIM_ERR;
388 }
389 obj->port_width = (uint32_t)port_width;
390 } else {
391 if (goi->argc)
392 goto err_no_params;
393 Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, obj->port_width));
394 }
395 break;
396 case CFG_PROTOCOL:
397 if (goi->isconfigure) {
398 struct jim_nvp *p;
399 e = jim_getopt_nvp(goi, nvp_arm_tpiu_swo_protocol_opts, &p);
400 if (e != JIM_OK)
401 return e;
402 obj->pin_protocol = p->value;
403 } else {
404 if (goi->argc)
405 goto err_no_params;
406 struct jim_nvp *p;
407 e = jim_nvp_value2name(goi->interp, nvp_arm_tpiu_swo_protocol_opts, obj->pin_protocol, &p);
408 if (e != JIM_OK) {
409 Jim_SetResultString(goi->interp, "protocol error", -1);
410 return JIM_ERR;
411 }
412 Jim_SetResult(goi->interp, Jim_NewStringObj(goi->interp, p->name, -1));
413 }
414 break;
415 case CFG_FORMATTER:
416 if (goi->isconfigure) {
417 struct jim_nvp *p;
418 e = jim_getopt_nvp(goi, nvp_arm_tpiu_swo_bool_opts, &p);
419 if (e != JIM_OK)
420 return e;
421 obj->en_formatter = p->value;
422 } else {
423 if (goi->argc)
424 goto err_no_params;
425 struct jim_nvp *p;
426 e = jim_nvp_value2name(goi->interp, nvp_arm_tpiu_swo_bool_opts, obj->en_formatter, &p);
427 if (e != JIM_OK) {
428 Jim_SetResultString(goi->interp, "formatter error", -1);
429 return JIM_ERR;
430 }
431 Jim_SetResult(goi->interp, Jim_NewStringObj(goi->interp, p->name, -1));
432 }
433 break;
434 case CFG_TRACECLKIN:
435 if (goi->isconfigure) {
436 jim_wide clk;
437 e = jim_getopt_wide(goi, &clk);
438 if (e != JIM_OK)
439 return e;
440 obj->traceclkin_freq = clk;
441 } else {
442 if (goi->argc)
443 goto err_no_params;
444 Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, obj->traceclkin_freq));
445 }
446 break;
447 case CFG_BITRATE:
448 if (goi->isconfigure) {
449 jim_wide clk;
450 e = jim_getopt_wide(goi, &clk);
451 if (e != JIM_OK)
452 return e;
453 obj->swo_pin_freq = clk;
454 } else {
455 if (goi->argc)
456 goto err_no_params;
457 Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, obj->swo_pin_freq));
458 }
459 break;
460 case CFG_OUTFILE:
461 if (goi->isconfigure) {
462 const char *s;
463 e = jim_getopt_string(goi, &s, NULL);
464 if (e != JIM_OK)
465 return e;
466 if (s[0] == ':') {
467 char *end;
468 long port = strtol(s + 1, &end, 0);
469 if (port <= 0 || port > UINT16_MAX || *end != '\0') {
470 Jim_SetResultFormatted(goi->interp, "Invalid TCP port \'%s\'", s + 1);
471 return JIM_ERR;
472 }
473 }
474 free(obj->out_filename);
475 obj->out_filename = strdup(s);
476 if (!obj->out_filename) {
477 LOG_ERROR("Out of memory");
478 return JIM_ERR;
479 }
480 } else {
481 if (goi->argc)
482 goto err_no_params;
483 if (obj->out_filename)
484 Jim_SetResult(goi->interp, Jim_NewStringObj(goi->interp, obj->out_filename, -1));
485 }
486 break;
487 case CFG_EVENT:
488 if (goi->isconfigure) {
489 if (goi->argc < 2) {
490 Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name? ?EVENT-BODY?");
491 return JIM_ERR;
492 }
493 } else {
494 if (goi->argc != 1) {
495 Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name?");
496 return JIM_ERR;
497 }
498 }
499
500 {
501 struct jim_nvp *p;
502 Jim_Obj *o;
503 struct arm_tpiu_swo_event_action *ea = obj->event_action;
504
505 e = jim_getopt_nvp(goi, nvp_arm_tpiu_swo_event, &p);
506 if (e != JIM_OK) {
507 jim_getopt_nvp_unknown(goi, nvp_arm_tpiu_swo_event, 1);
508 return e;
509 }
510
511 while (ea) {
512 /* replace existing? */
513 if (ea->event == (enum arm_tpiu_swo_event)p->value)
514 break;
515 ea = ea->next;
516 }
517
518 if (goi->isconfigure) {
519 if (!ea) {
520 ea = calloc(1, sizeof(*ea));
521 if (!ea) {
522 LOG_ERROR("Out of memory");
523 return JIM_ERR;
524 }
525 ea->next = obj->event_action;
526 obj->event_action = ea;
527 }
528 if (ea->body)
529 Jim_DecrRefCount(ea->interp, ea->body);
530 ea->event = p->value;
531 ea->interp = goi->interp;
532 jim_getopt_obj(goi, &o);
533 ea->body = Jim_DuplicateObj(goi->interp, o);
534 Jim_IncrRefCount(ea->body);
535 } else {
536 if (ea)
537 Jim_SetResult(goi->interp, Jim_DuplicateObj(goi->interp, ea->body));
538 }
539 }
540 break;
541 }
542 }
543
544 return JIM_OK;
545
546 err_no_params:
547 Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS");
548 return JIM_ERR;
549 }
550
551 static int jim_arm_tpiu_swo_configure(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
552 {
553 struct command *c = jim_to_command(interp);
554 struct jim_getopt_info goi;
555
556 jim_getopt_setup(&goi, interp, argc - 1, argv + 1);
557 goi.isconfigure = !strcmp(c->name, "configure");
558 if (goi.argc < 1) {
559 Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv,
560 "missing: -option ...");
561 return JIM_ERR;
562 }
563 struct arm_tpiu_swo_object *obj = c->jim_handler_data;
564 return arm_tpiu_swo_configure(&goi, obj);
565 }
566
567 static int wrap_write_u32(struct target *target, struct adiv5_ap *tpiu_ap,
568 target_addr_t address, uint32_t value)
569 {
570 if (transport_is_hla())
571 return target_write_u32(target, address, value);
572 else
573 return mem_ap_write_atomic_u32(tpiu_ap, address, value);
574 }
575
576 static int wrap_read_u32(struct target *target, struct adiv5_ap *tpiu_ap,
577 target_addr_t address, uint32_t *value)
578 {
579 if (transport_is_hla())
580 return target_read_u32(target, address, value);
581 else
582 return mem_ap_read_atomic_u32(tpiu_ap, address, value);
583 }
584
585 static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
586 {
587 struct command *c = jim_to_command(interp);
588 struct arm_tpiu_swo_object *obj = c->jim_handler_data;
589 struct command_context *cmd_ctx = current_command_context(interp);
590 struct adiv5_ap *tpiu_ap = dap_ap(obj->spot.dap, obj->spot.ap_num);
591 uint32_t value;
592 int retval;
593
594 if (argc != 1) {
595 Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
596 return JIM_ERR;
597 }
598
599 if (cmd_ctx->mode == COMMAND_CONFIG) {
600 LOG_DEBUG("%s: enable deferred", obj->name);
601 obj->deferred_enable = true;
602 return JIM_OK;
603 }
604
605 if (obj->enabled)
606 return JIM_OK;
607
608 if (transport_is_hla() && obj->spot.ap_num > 0) {
609 LOG_ERROR("Invalid access port %d. Only AP#0 allowed with hla transport", obj->spot.ap_num);
610 return JIM_ERR;
611 }
612
613 if (!obj->traceclkin_freq) {
614 LOG_ERROR("Trace clock-in frequency not set");
615 return JIM_ERR;
616 }
617
618 if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_MANCHESTER || obj->pin_protocol == TPIU_SPPR_PROTOCOL_UART)
619 if (!obj->swo_pin_freq) {
620 LOG_ERROR("SWO pin frequency not set");
621 return JIM_ERR;
622 }
623
624 struct target *target = get_current_target(cmd_ctx);
625
626 /* START_DEPRECATED_TPIU */
627 if (obj->recheck_ap_cur_target) {
628 if (strcmp(target->type->name, "cortex_m") &&
629 strcmp(target->type->name, "hla_target")) {
630 LOG_ERROR(MSG "Current target is not a Cortex-M nor a HLA");
631 return JIM_ERR;
632 }
633 if (!target_was_examined(target)) {
634 LOG_ERROR(MSG "Current target not examined yet");
635 return JIM_ERR;
636 }
637 struct cortex_m_common *cm = target_to_cm(target);
638 obj->recheck_ap_cur_target = false;
639 obj->spot.ap_num = cm->armv7m.debug_ap->ap_num;
640 tpiu_ap = dap_ap(obj->spot.dap, obj->spot.ap_num);
641 if (obj->spot.ap_num == 0)
642 LOG_INFO(MSG "Confirmed TPIU %s is on AP 0", obj->name);
643 else
644 LOG_INFO(MSG "Target %s is on AP %d. Revised command is "
645 "\'tpiu create %s -dap %s -ap-num %d\'",
646 target_name(target), obj->spot.ap_num,
647 obj->name, adiv5_dap_name(obj->spot.dap), obj->spot.ap_num);
648 }
649 /* END_DEPRECATED_TPIU */
650
651 /* trigger the event before any attempt to R/W in the TPIU/SWO */
652 arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_PRE_ENABLE);
653
654 retval = wrap_read_u32(target, tpiu_ap, obj->spot.base + TPIU_DEVID_OFFSET, &value);
655 if (retval != ERROR_OK) {
656 LOG_ERROR("Unable to read %s", obj->name);
657 return JIM_ERR;
658 }
659 switch (obj->pin_protocol) {
660 case TPIU_SPPR_PROTOCOL_SYNC:
661 value = !(value & TPIU_DEVID_NOSUPPORT_SYNC);
662 break;
663 case TPIU_SPPR_PROTOCOL_UART:
664 value &= TPIU_DEVID_SUPPORT_UART;
665 break;
666 case TPIU_SPPR_PROTOCOL_MANCHESTER:
667 value &= TPIU_DEVID_SUPPORT_MANCHESTER;
668 break;
669 default:
670 value = 0;
671 }
672 if (!value) {
673 struct jim_nvp *p;
674 jim_nvp_value2name(interp, nvp_arm_tpiu_swo_protocol_opts, obj->pin_protocol, &p);
675 LOG_ERROR("%s does not support protocol %s", obj->name, p->name);
676 return JIM_ERR;
677 }
678
679 if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_SYNC) {
680 retval = wrap_read_u32(target, tpiu_ap, obj->spot.base + TPIU_SSPSR_OFFSET, &value);
681 if (!(value & BIT(obj->port_width - 1))) {
682 LOG_ERROR("TPIU does not support port-width of %d bits", obj->port_width);
683 return JIM_ERR;
684 }
685 }
686
687 uint16_t prescaler = 1; /* dummy value */
688 unsigned int swo_pin_freq = obj->swo_pin_freq; /* could be replaced */
689
690 if (obj->out_filename && strcmp(obj->out_filename, "external") && obj->out_filename[0]) {
691 if (obj->out_filename[0] == ':') {
692 struct arm_tpiu_swo_priv_connection *priv = malloc(sizeof(*priv));
693 if (!priv) {
694 LOG_ERROR("Out of memory");
695 return JIM_ERR;
696 }
697 priv->obj = obj;
698 LOG_INFO("starting trace server for %s on %s", obj->name, &obj->out_filename[1]);
699 retval = add_service("tpiu_swo_trace", &obj->out_filename[1],
700 CONNECTION_LIMIT_UNLIMITED, arm_tpiu_swo_service_new_connection,
701 arm_tpiu_swo_service_input, arm_tpiu_swo_service_connection_closed,
702 priv);
703 if (retval != ERROR_OK) {
704 LOG_ERROR("Can't configure trace TCP port %s", &obj->out_filename[1]);
705 return JIM_ERR;
706 }
707 } else if (strcmp(obj->out_filename, "-")) {
708 obj->file = fopen(obj->out_filename, "ab");
709 if (!obj->file) {
710 LOG_ERROR("Can't open trace destination file \"%s\"", obj->out_filename);
711 return JIM_ERR;
712 }
713 }
714
715 retval = adapter_config_trace(true, obj->pin_protocol, obj->port_width,
716 &swo_pin_freq, obj->traceclkin_freq, &prescaler);
717 if (retval != ERROR_OK) {
718 LOG_ERROR("Failed to start adapter's trace");
719 arm_tpiu_swo_close_output(obj);
720 return JIM_ERR;
721 }
722
723 if (obj->swo_pin_freq != swo_pin_freq)
724 LOG_INFO("SWO pin data rate adjusted by adapter to %d Hz", swo_pin_freq);
725 obj->swo_pin_freq = swo_pin_freq;
726
727 target_register_timer_callback(arm_tpiu_swo_poll_trace, 1,
728 TARGET_TIMER_TYPE_PERIODIC, obj);
729
730 obj->en_capture = true;
731 } else if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_MANCHESTER || obj->pin_protocol == TPIU_SPPR_PROTOCOL_UART) {
732 prescaler = (obj->traceclkin_freq + obj->swo_pin_freq / 2) / obj->swo_pin_freq;
733 if (prescaler > TPIU_ACPR_MAX_PRESCALER)
734 prescaler = TPIU_ACPR_MAX_PRESCALER;
735 swo_pin_freq = obj->traceclkin_freq / prescaler;
736
737 if (obj->swo_pin_freq != swo_pin_freq)
738 LOG_INFO("SWO pin data rate adjusted to %d Hz", swo_pin_freq);
739 obj->swo_pin_freq = swo_pin_freq;
740 }
741
742 retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_CSPSR_OFFSET, BIT(obj->port_width - 1));
743 if (retval != ERROR_OK)
744 goto error_exit;
745
746 retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_ACPR_OFFSET, prescaler - 1);
747 if (retval != ERROR_OK)
748 goto error_exit;
749
750 retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_SPPR_OFFSET, obj->pin_protocol);
751 if (retval != ERROR_OK)
752 goto error_exit;
753
754 retval = wrap_read_u32(target, tpiu_ap, obj->spot.base + TPIU_FFCR_OFFSET, &value);
755 if (retval != ERROR_OK)
756 goto error_exit;
757 if (obj->en_formatter)
758 value |= BIT(1);
759 else
760 value &= ~BIT(1);
761 retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_FFCR_OFFSET, value);
762 if (retval != ERROR_OK)
763 goto error_exit;
764
765 arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_POST_ENABLE);
766
767 /* START_DEPRECATED_TPIU */
768 target_handle_event(target, TARGET_EVENT_TRACE_CONFIG);
769 /* END_DEPRECATED_TPIU */
770
771 obj->enabled = true;
772 return JIM_OK;
773
774 error_exit:
775 LOG_ERROR("Error!");
776
777 if (obj->en_capture) {
778 obj->en_capture = false;
779
780 arm_tpiu_swo_close_output(obj);
781
782 target_unregister_timer_callback(arm_tpiu_swo_poll_trace, obj);
783
784 retval = adapter_config_trace(false, 0, 0, NULL, 0, NULL);
785 if (retval != ERROR_OK) {
786 LOG_ERROR("Failed to stop adapter's trace");
787 return JIM_ERR;
788 }
789 }
790 return JIM_ERR;
791 }
792
793 static int jim_arm_tpiu_swo_disable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
794 {
795 struct command *c = jim_to_command(interp);
796 struct arm_tpiu_swo_object *obj = c->jim_handler_data;
797
798 if (argc != 1) {
799 Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
800 return JIM_ERR;
801 }
802
803 if (!obj->enabled)
804 return JIM_OK;
805 obj->enabled = false;
806
807 arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_PRE_DISABLE);
808
809 if (obj->en_capture) {
810 obj->en_capture = false;
811
812 arm_tpiu_swo_close_output(obj);
813
814 target_unregister_timer_callback(arm_tpiu_swo_poll_trace, obj);
815
816 int retval = adapter_config_trace(false, 0, 0, NULL, 0, NULL);
817 if (retval != ERROR_OK) {
818 LOG_ERROR("Failed to stop adapter's trace");
819 return JIM_ERR;
820 }
821 }
822
823 arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_POST_DISABLE);
824
825 /* START_DEPRECATED_TPIU */
826 struct command_context *cmd_ctx = current_command_context(interp);
827 struct target *target = get_current_target(cmd_ctx);
828 target_handle_event(target, TARGET_EVENT_TRACE_CONFIG);
829 /* END_DEPRECATED_TPIU */
830
831 return JIM_OK;
832 }
833
834 static const struct command_registration arm_tpiu_swo_instance_command_handlers[] = {
835 {
836 .name = "configure",
837 .mode = COMMAND_ANY,
838 .jim_handler = jim_arm_tpiu_swo_configure,
839 .help = "configure a new TPIU/SWO for use",
840 .usage = "[attribute value ...]",
841 },
842 {
843 .name = "cget",
844 .mode = COMMAND_ANY,
845 .jim_handler = jim_arm_tpiu_swo_configure,
846 .help = "returns the specified TPIU/SWO attribute",
847 .usage = "attribute",
848 },
849 {
850 .name = "eventlist",
851 .mode = COMMAND_ANY,
852 .handler = handle_arm_tpiu_swo_event_list,
853 .help = "displays a table of events defined for this TPIU/SWO",
854 .usage = "",
855 },
856 {
857 .name = "enable",
858 .mode = COMMAND_ANY,
859 .jim_handler = jim_arm_tpiu_swo_enable,
860 .usage = "",
861 .help = "Enables the TPIU/SWO output",
862 },
863 {
864 .name = "disable",
865 .mode = COMMAND_EXEC,
866 .jim_handler = jim_arm_tpiu_swo_disable,
867 .usage = "",
868 .help = "Disables the TPIU/SWO output",
869 },
870 COMMAND_REGISTRATION_DONE
871 };
872
873 static int arm_tpiu_swo_create(Jim_Interp *interp, struct arm_tpiu_swo_object *obj)
874 {
875 struct command_context *cmd_ctx;
876 Jim_Cmd *cmd;
877 int e;
878
879 cmd_ctx = current_command_context(interp);
880 assert(cmd_ctx);
881
882 /* does this command exist? */
883 cmd = Jim_GetCommand(interp, Jim_NewStringObj(interp, obj->name, -1), JIM_NONE);
884 if (cmd) {
885 Jim_SetResultFormatted(interp, "Command: %s Exists", obj->name);
886 return JIM_ERR;
887 }
888
889 /* now - create the new tpiu/swo name command */
890 const struct command_registration obj_commands[] = {
891 {
892 .name = obj->name,
893 .mode = COMMAND_ANY,
894 .help = "tpiu/swo instance command group",
895 .usage = "",
896 .chain = arm_tpiu_swo_instance_command_handlers,
897 },
898 COMMAND_REGISTRATION_DONE
899 };
900 e = register_commands_with_data(cmd_ctx, NULL, obj_commands, obj);
901 if (e != ERROR_OK)
902 return JIM_ERR;
903
904 list_add_tail(&obj->lh, &all_tpiu_swo);
905
906 return JIM_OK;
907 }
908
909 static int jim_arm_tpiu_swo_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
910 {
911 struct jim_getopt_info goi;
912 jim_getopt_setup(&goi, interp, argc - 1, argv + 1);
913 if (goi.argc < 1) {
914 Jim_WrongNumArgs(goi.interp, 1, goi.argv, "?name? ..options...");
915 return JIM_ERR;
916 }
917
918 struct arm_tpiu_swo_object *obj = calloc(1, sizeof(struct arm_tpiu_swo_object));
919 if (!obj) {
920 LOG_ERROR("Out of memory");
921 return JIM_ERR;
922 }
923 INIT_LIST_HEAD(&obj->connections);
924 adiv5_mem_ap_spot_init(&obj->spot);
925 obj->spot.base = TPIU_SWO_DEFAULT_BASE;
926 obj->port_width = 1;
927
928 Jim_Obj *n;
929 jim_getopt_obj(&goi, &n);
930 obj->name = strdup(Jim_GetString(n, NULL));
931 if (!obj->name) {
932 LOG_ERROR("Out of memory");
933 free(obj);
934 return JIM_ERR;
935 }
936
937 /* Do the rest as "configure" options */
938 goi.isconfigure = 1;
939 int e = arm_tpiu_swo_configure(&goi, obj);
940 if (e != JIM_OK)
941 goto err_exit;
942
943 if (!obj->spot.dap || obj->spot.ap_num == DP_APSEL_INVALID) {
944 Jim_SetResultString(goi.interp, "-dap and -ap-num required when creating TPIU", -1);
945 goto err_exit;
946 }
947
948 e = arm_tpiu_swo_create(goi.interp, obj);
949 if (e != JIM_OK)
950 goto err_exit;
951
952 return JIM_OK;
953
954 err_exit:
955 free(obj->name);
956 free(obj->out_filename);
957 free(obj);
958 return JIM_ERR;
959 }
960
961 static int jim_arm_tpiu_swo_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
962 {
963 struct arm_tpiu_swo_object *obj;
964
965 if (argc != 1) {
966 Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
967 return JIM_ERR;
968 }
969 Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
970 list_for_each_entry(obj, &all_tpiu_swo, lh) {
971 Jim_ListAppendElement(interp, Jim_GetResult(interp),
972 Jim_NewStringObj(interp, obj->name, -1));
973 }
974 return JIM_OK;
975 }
976
977 static int jim_arm_tpiu_swo_init(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
978 {
979 struct command_context *cmd_ctx = current_command_context(interp);
980 struct arm_tpiu_swo_object *obj;
981 int retval = JIM_OK;
982
983 if (argc != 1) {
984 Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
985 return JIM_ERR;
986 }
987 list_for_each_entry(obj, &all_tpiu_swo, lh) {
988 if (!obj->deferred_enable)
989 continue;
990 LOG_DEBUG("%s: running enable during init", obj->name);
991 int retval2 = command_run_linef(cmd_ctx, "%s enable", obj->name);
992 if (retval2 != ERROR_OK)
993 retval = JIM_ERR;
994 }
995 return retval;
996 }
997
998 /* START_DEPRECATED_TPIU */
999 /* DEPRECATED: emulation of old command 'tpiu config' */
1000 COMMAND_HANDLER(handle_tpiu_deprecated_config_command)
1001 {
1002 struct target *target = get_current_target(CMD_CTX);
1003 struct arm_tpiu_swo_object *obj = NULL;
1004 int retval;
1005
1006 if (strcmp(target->type->name, "cortex_m") &&
1007 strcmp(target->type->name, "hla_target")) {
1008 LOG_ERROR(MSG "Current target is not a Cortex-M nor a HLA");
1009 return ERROR_FAIL;
1010 }
1011
1012 if (!list_empty(&all_tpiu_swo)) {
1013 obj = list_first_entry(&all_tpiu_swo, typeof(*obj), lh);
1014 LOG_INFO(MSG "Using %s", obj->name);
1015 } else {
1016 struct cortex_m_common *cm = target_to_cm(target);
1017 struct adiv5_private_config *pc = target->private_config;
1018 struct adiv5_dap *dap = pc->dap;
1019 int ap_num = pc->ap_num;
1020 bool set_recheck_ap_cur_target = false;
1021
1022 LOG_INFO(MSG "Adding a TPIU \'%s.tpiu\' in the configuration", target_name(target));
1023
1024 if (ap_num == DP_APSEL_INVALID && transport_is_hla())
1025 ap_num = 0; /* HLA should only support AP 0 */
1026
1027 if (ap_num == DP_APSEL_INVALID && target_was_examined(target))
1028 ap_num = cm->armv7m.debug_ap->ap_num;
1029
1030 if (ap_num == DP_APSEL_INVALID) {
1031 LOG_INFO(MSG "Target %s uses AP autodetection. Adding TPIU on AP 0; can be revised later",
1032 target_name(target));
1033 ap_num = 0;
1034 set_recheck_ap_cur_target = true;
1035 }
1036
1037 LOG_INFO(MSG "Running: \'tpiu create %s.tpiu -dap %s -ap-num %d\'",
1038 target_name(target), adiv5_dap_name(dap), ap_num);
1039
1040 retval = command_run_linef(CMD_CTX, "tpiu create %s.tpiu -dap %s -ap-num %d",
1041 target_name(target), adiv5_dap_name(dap), ap_num);
1042 if (retval != ERROR_OK)
1043 return retval;
1044
1045 obj = list_first_entry(&all_tpiu_swo, typeof(*obj), lh);
1046 if (set_recheck_ap_cur_target)
1047 obj->recheck_ap_cur_target = true;
1048 }
1049
1050 unsigned int cmd_idx = 0;
1051 if (cmd_idx == CMD_ARGC)
1052 return ERROR_COMMAND_SYNTAX_ERROR;
1053
1054 if (!strcmp(CMD_ARGV[cmd_idx], "disable")) {
1055 if (CMD_ARGC != cmd_idx + 1)
1056 return ERROR_COMMAND_SYNTAX_ERROR;
1057 LOG_INFO(MSG "Running: \'%s disable\'", obj->name);
1058 return command_run_linef(CMD_CTX, "%s disable", obj->name);
1059 }
1060
1061 const char *output = NULL;
1062 const char *protocol;
1063 const char *formatter = NULL;
1064 const char *port_width = NULL;
1065 const char *trace_clk;
1066 const char *pin_clk = NULL;
1067 if (!strcmp(CMD_ARGV[cmd_idx], "internal")) {
1068 cmd_idx++;
1069 if (cmd_idx == CMD_ARGC)
1070 return ERROR_COMMAND_SYNTAX_ERROR;
1071 output = CMD_ARGV[cmd_idx];
1072 } else if (strcmp(CMD_ARGV[cmd_idx], "external"))
1073 return ERROR_COMMAND_SYNTAX_ERROR;
1074 cmd_idx++;
1075 if (cmd_idx == CMD_ARGC)
1076 return ERROR_COMMAND_SYNTAX_ERROR;
1077 if (!strcmp(CMD_ARGV[cmd_idx], "sync")) {
1078 protocol = CMD_ARGV[cmd_idx];
1079 cmd_idx++;
1080 if (cmd_idx == CMD_ARGC)
1081 return ERROR_COMMAND_SYNTAX_ERROR;
1082 port_width = CMD_ARGV[cmd_idx];
1083 } else {
1084 if (strcmp(CMD_ARGV[cmd_idx], "manchester") && strcmp(CMD_ARGV[cmd_idx], "uart"))
1085 return ERROR_COMMAND_SYNTAX_ERROR;
1086 protocol = CMD_ARGV[cmd_idx];
1087 cmd_idx++;
1088 if (cmd_idx == CMD_ARGC)
1089 return ERROR_COMMAND_SYNTAX_ERROR;
1090 formatter = CMD_ARGV[cmd_idx];
1091 }
1092 cmd_idx++;
1093 if (cmd_idx == CMD_ARGC)
1094 return ERROR_COMMAND_SYNTAX_ERROR;
1095 trace_clk = CMD_ARGV[cmd_idx];
1096 cmd_idx++;
1097 if (cmd_idx != CMD_ARGC) {
1098 pin_clk = CMD_ARGV[cmd_idx];
1099 cmd_idx++;
1100 }
1101 if (cmd_idx != CMD_ARGC)
1102 return ERROR_COMMAND_SYNTAX_ERROR;
1103
1104 LOG_INFO(MSG "Running: \'%s configure -protocol %s -traceclk %s" "%s%s" "%s%s" "%s%s" "%s%s\'",
1105 obj->name, protocol, trace_clk,
1106 pin_clk ? " -pin-freq " : "", pin_clk ? pin_clk : "",
1107 output ? " -output " : "", output ? output : "",
1108 formatter ? " -formatter " : "", formatter ? formatter : "",
1109 port_width ? " -port-width " : "", port_width ? port_width : "");
1110
1111 retval = command_run_linef(CMD_CTX,
1112 "%s configure -protocol %s -traceclk %s" "%s%s" "%s%s" "%s%s" "%s%s",
1113 obj->name, protocol, trace_clk,
1114 pin_clk ? " -pin-freq " : "", pin_clk ? pin_clk : "",
1115 output ? " -output " : "", output ? output : "",
1116 formatter ? " -formatter " : "", formatter ? formatter : "",
1117 port_width ? " -port-width " : "", port_width ? port_width : "");
1118 if (retval != ERROR_OK)
1119 return retval;
1120
1121 LOG_INFO(MSG "Running: \'%s enable\'", obj->name);
1122 retval = command_run_linef(CMD_CTX, "%s enable", obj->name);
1123 if (retval != ERROR_OK)
1124 return retval;
1125
1126 return ERROR_OK;
1127 }
1128
1129 static const struct command_registration arm_tpiu_deprecated_subcommand_handlers[] = {
1130 {
1131 .name = "config",
1132 .handler = handle_tpiu_deprecated_config_command,
1133 .mode = COMMAND_ANY,
1134 .help = "Configure TPIU features, DEPRECATED, use \'tpiu create\'",
1135 .usage = "(disable | "
1136 "((external | internal (<filename> | <:port> | -)) "
1137 "(sync <port width> | ((manchester | uart) <formatter enable>)) "
1138 "<TRACECLKIN freq> [<trace freq>]))",
1139 },
1140 COMMAND_REGISTRATION_DONE
1141 };
1142
1143 const struct command_registration arm_tpiu_deprecated_command_handlers[] = {
1144 {
1145 .name = "tpiu",
1146 .chain = arm_tpiu_deprecated_subcommand_handlers,
1147 .usage = "",
1148 .help = "tpiu command group",
1149 },
1150 COMMAND_REGISTRATION_DONE
1151 };
1152 /* END_DEPRECATED_TPIU */
1153
1154 static const struct command_registration arm_tpiu_swo_subcommand_handlers[] = {
1155 {
1156 .name = "create",
1157 .mode = COMMAND_ANY,
1158 .jim_handler = jim_arm_tpiu_swo_create,
1159 .usage = "name [-dap dap] [-ap-num num] [-address baseaddr]",
1160 .help = "Creates a new TPIU or SWO object",
1161 },
1162 {
1163 .name = "names",
1164 .mode = COMMAND_ANY,
1165 .jim_handler = jim_arm_tpiu_swo_names,
1166 .usage = "",
1167 .help = "Lists all registered TPIU and SWO objects by name",
1168 },
1169 {
1170 .name = "init",
1171 .mode = COMMAND_EXEC,
1172 .jim_handler = jim_arm_tpiu_swo_init,
1173 .usage = "",
1174 .help = "Initialize TPIU and SWO",
1175 },
1176 COMMAND_REGISTRATION_DONE
1177 };
1178
1179 static const struct command_registration arm_tpiu_swo_command_handlers[] = {
1180 {
1181 .name = "tpiu",
1182 .chain = arm_tpiu_swo_subcommand_handlers,
1183 .usage = "",
1184 .help = "tpiu command group",
1185 },
1186 {
1187 .name = "swo",
1188 .chain = arm_tpiu_swo_subcommand_handlers,
1189 .usage = "",
1190 .help = "swo command group",
1191 },
1192 COMMAND_REGISTRATION_DONE
1193 };
1194
1195 int arm_tpiu_swo_register_commands(struct command_context *cmd_ctx)
1196 {
1197 return register_commands(cmd_ctx, NULL, arm_tpiu_swo_command_handlers);
1198 }

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)