armv7m_trace: get rid of the old tpiu code
[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 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 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 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_NvpUnknown() */
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 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 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(Jim_GetOptInfo *goi, struct arm_tpiu_swo_object *obj)
353 {
354 assert(obj != NULL);
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 Jim_Nvp *n;
372 e = Jim_GetOpt_Nvp(goi, nvp_arm_tpiu_swo_config_opts, &n);
373 if (e != JIM_OK) {
374 Jim_GetOpt_NvpUnknown(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 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 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 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 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 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_NvpUnknown(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 Jim_GetOptInfo goi;
554
555 Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
556 goi.isconfigure = !strcmp(Jim_GetString(argv[0], NULL), "configure");
557 if (goi.argc < 1) {
558 Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv,
559 "missing: -option ...");
560 return JIM_ERR;
561 }
562 struct arm_tpiu_swo_object *obj = Jim_CmdPrivData(interp);
563 return arm_tpiu_swo_configure(&goi, obj);
564 }
565
566 static int wrap_write_u32(struct target *target, struct adiv5_ap *tpiu_ap,
567 target_addr_t address, uint32_t value)
568 {
569 if (transport_is_hla())
570 return target_write_u32(target, address, value);
571 else
572 return mem_ap_write_atomic_u32(tpiu_ap, address, value);
573 }
574
575 static int wrap_read_u32(struct target *target, struct adiv5_ap *tpiu_ap,
576 target_addr_t address, uint32_t *value)
577 {
578 if (transport_is_hla())
579 return target_read_u32(target, address, value);
580 else
581 return mem_ap_read_atomic_u32(tpiu_ap, address, value);
582 }
583
584 static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
585 {
586 struct arm_tpiu_swo_object *obj = Jim_CmdPrivData(interp);
587 struct command_context *cmd_ctx = current_command_context(interp);
588 struct adiv5_ap *tpiu_ap = dap_ap(obj->spot.dap, obj->spot.ap_num);
589 uint32_t value;
590 int retval;
591
592 if (argc != 1) {
593 Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
594 return JIM_ERR;
595 }
596
597 if (cmd_ctx->mode == COMMAND_CONFIG) {
598 LOG_DEBUG("%s: enable deferred", obj->name);
599 obj->deferred_enable = true;
600 return JIM_OK;
601 }
602
603 if (obj->enabled)
604 return JIM_OK;
605
606 if (transport_is_hla() && obj->spot.ap_num > 0) {
607 LOG_ERROR("Invalid access port %d. Only AP#0 allowed with hla transport", obj->spot.ap_num);
608 return JIM_ERR;
609 }
610
611 if (!obj->traceclkin_freq) {
612 LOG_ERROR("Trace clock-in frequency not set");
613 return JIM_ERR;
614 }
615
616 if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_MANCHESTER || obj->pin_protocol == TPIU_SPPR_PROTOCOL_UART)
617 if (!obj->swo_pin_freq) {
618 LOG_ERROR("SWO pin frequency not set");
619 return JIM_ERR;
620 }
621
622 struct target *target = get_current_target(cmd_ctx);
623
624 /* START_DEPRECATED_TPIU */
625 if (obj->recheck_ap_cur_target) {
626 if (strcmp(target->type->name, "cortex_m") &&
627 strcmp(target->type->name, "hla_target")) {
628 LOG_ERROR(MSG "Current target is not a Cortex-M nor a HLA");
629 return JIM_ERR;
630 }
631 if (!target_was_examined(target)) {
632 LOG_ERROR(MSG "Current target not examined yet");
633 return JIM_ERR;
634 }
635 struct cortex_m_common *cm = target_to_cm(target);
636 obj->recheck_ap_cur_target = false;
637 obj->spot.ap_num = cm->armv7m.debug_ap->ap_num;
638 tpiu_ap = dap_ap(obj->spot.dap, obj->spot.ap_num);
639 if (obj->spot.ap_num == 0)
640 LOG_INFO(MSG "Confirmed TPIU %s is on AP 0", obj->name);
641 else
642 LOG_INFO(MSG "Target %s is on AP %d. Revised command is "
643 "\'tpiu create %s -dap %s -ap-num %d\'",
644 target_name(target), obj->spot.ap_num,
645 obj->name, adiv5_dap_name(obj->spot.dap), obj->spot.ap_num);
646 }
647 /* END_DEPRECATED_TPIU */
648
649 /* trigger the event before any attempt to R/W in the TPIU/SWO */
650 arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_PRE_ENABLE);
651
652 retval = wrap_read_u32(target, tpiu_ap, obj->spot.base + TPIU_DEVID_OFFSET, &value);
653 if (retval != ERROR_OK) {
654 LOG_ERROR("Unable to read %s", obj->name);
655 return JIM_ERR;
656 }
657 switch (obj->pin_protocol) {
658 case TPIU_SPPR_PROTOCOL_SYNC:
659 value = !(value & TPIU_DEVID_NOSUPPORT_SYNC);
660 break;
661 case TPIU_SPPR_PROTOCOL_UART:
662 value &= TPIU_DEVID_SUPPORT_UART;
663 break;
664 case TPIU_SPPR_PROTOCOL_MANCHESTER:
665 value &= TPIU_DEVID_SUPPORT_MANCHESTER;
666 break;
667 default:
668 value = 0;
669 }
670 if (!value) {
671 Jim_Nvp *p;
672 Jim_Nvp_value2name(interp, nvp_arm_tpiu_swo_protocol_opts, obj->pin_protocol, &p);
673 LOG_ERROR("%s does not support protocol %s", obj->name, p->name);
674 return JIM_ERR;
675 }
676
677 if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_SYNC) {
678 retval = wrap_read_u32(target, tpiu_ap, obj->spot.base + TPIU_SSPSR_OFFSET, &value);
679 if (!(value & BIT(obj->port_width - 1))) {
680 LOG_ERROR("TPIU does not support port-width of %d bits", obj->port_width);
681 return JIM_ERR;
682 }
683 }
684
685 uint16_t prescaler = 1; /* dummy value */
686 unsigned int swo_pin_freq = obj->swo_pin_freq; /* could be replaced */
687
688 if (obj->out_filename && strcmp(obj->out_filename, "external") && obj->out_filename[0]) {
689 if (obj->out_filename[0] == ':') {
690 struct arm_tpiu_swo_priv_connection *priv = malloc(sizeof(*priv));
691 if (!priv) {
692 LOG_ERROR("Out of memory");
693 return JIM_ERR;
694 }
695 priv->obj = obj;
696 LOG_INFO("starting trace server for %s on %s", obj->name, &obj->out_filename[1]);
697 retval = add_service("tpiu_swo_trace", &obj->out_filename[1],
698 CONNECTION_LIMIT_UNLIMITED, arm_tpiu_swo_service_new_connection,
699 arm_tpiu_swo_service_input, arm_tpiu_swo_service_connection_closed,
700 priv, NULL);
701 if (retval != ERROR_OK) {
702 LOG_ERROR("Can't configure trace TCP port %s", &obj->out_filename[1]);
703 return JIM_ERR;
704 }
705 } else if (strcmp(obj->out_filename, "-")) {
706 obj->file = fopen(obj->out_filename, "ab");
707 if (!obj->file) {
708 LOG_ERROR("Can't open trace destination file \"%s\"", obj->out_filename);
709 return JIM_ERR;
710 }
711 }
712
713 retval = adapter_config_trace(true, obj->pin_protocol, obj->port_width,
714 &swo_pin_freq, obj->traceclkin_freq, &prescaler);
715 if (retval != ERROR_OK) {
716 LOG_ERROR("Failed to start adapter's trace");
717 arm_tpiu_swo_close_output(obj);
718 return JIM_ERR;
719 }
720
721 if (obj->swo_pin_freq != swo_pin_freq)
722 LOG_INFO("SWO pin data rate adjusted by adapter to %d Hz", swo_pin_freq);
723 obj->swo_pin_freq = swo_pin_freq;
724
725 target_register_timer_callback(arm_tpiu_swo_poll_trace, 1,
726 TARGET_TIMER_TYPE_PERIODIC, obj);
727
728 obj->en_capture = true;
729 } else if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_MANCHESTER || obj->pin_protocol == TPIU_SPPR_PROTOCOL_UART) {
730 prescaler = (obj->traceclkin_freq + obj->swo_pin_freq / 2) / obj->swo_pin_freq;
731 if (prescaler > TPIU_ACPR_MAX_PRESCALER)
732 prescaler = TPIU_ACPR_MAX_PRESCALER;
733 swo_pin_freq = obj->traceclkin_freq / prescaler;
734
735 if (obj->swo_pin_freq != swo_pin_freq)
736 LOG_INFO("SWO pin data rate adjusted to %d Hz", swo_pin_freq);
737 obj->swo_pin_freq = swo_pin_freq;
738 }
739
740 retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_CSPSR_OFFSET, BIT(obj->port_width - 1));
741 if (retval != ERROR_OK)
742 goto error_exit;
743
744 retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_ACPR_OFFSET, prescaler - 1);
745 if (retval != ERROR_OK)
746 goto error_exit;
747
748 retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_SPPR_OFFSET, obj->pin_protocol);
749 if (retval != ERROR_OK)
750 goto error_exit;
751
752 retval = wrap_read_u32(target, tpiu_ap, obj->spot.base + TPIU_FFCR_OFFSET, &value);
753 if (retval != ERROR_OK)
754 goto error_exit;
755 if (obj->en_formatter)
756 value |= BIT(1);
757 else
758 value &= ~BIT(1);
759 retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_FFCR_OFFSET, value);
760 if (retval != ERROR_OK)
761 goto error_exit;
762
763 arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_POST_ENABLE);
764
765 obj->enabled = true;
766 return JIM_OK;
767
768 error_exit:
769 LOG_ERROR("Error!");
770
771 if (obj->en_capture) {
772 obj->en_capture = false;
773
774 arm_tpiu_swo_close_output(obj);
775
776 target_unregister_timer_callback(arm_tpiu_swo_poll_trace, obj);
777
778 retval = adapter_config_trace(false, 0, 0, NULL, 0, NULL);
779 if (retval != ERROR_OK) {
780 LOG_ERROR("Failed to stop adapter's trace");
781 return JIM_ERR;
782 }
783 }
784 return JIM_ERR;
785 }
786
787 static int jim_arm_tpiu_swo_disable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
788 {
789 struct arm_tpiu_swo_object *obj = Jim_CmdPrivData(interp);
790
791 if (argc != 1) {
792 Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
793 return JIM_ERR;
794 }
795
796 if (!obj->enabled)
797 return JIM_OK;
798 obj->enabled = false;
799
800 arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_PRE_DISABLE);
801
802 if (obj->en_capture) {
803 obj->en_capture = false;
804
805 arm_tpiu_swo_close_output(obj);
806
807 target_unregister_timer_callback(arm_tpiu_swo_poll_trace, obj);
808
809 int retval = adapter_config_trace(false, 0, 0, NULL, 0, NULL);
810 if (retval != ERROR_OK) {
811 LOG_ERROR("Failed to stop adapter's trace");
812 return JIM_ERR;
813 }
814 }
815
816 arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_POST_DISABLE);
817 return JIM_OK;
818 }
819
820 static const struct command_registration arm_tpiu_swo_instance_command_handlers[] = {
821 {
822 .name = "configure",
823 .mode = COMMAND_ANY,
824 .jim_handler = jim_arm_tpiu_swo_configure,
825 .help = "configure a new TPIU/SWO for use",
826 .usage = "[attribute value ...]",
827 },
828 {
829 .name = "cget",
830 .mode = COMMAND_ANY,
831 .jim_handler = jim_arm_tpiu_swo_configure,
832 .help = "returns the specified TPIU/SWO attribute",
833 .usage = "attribute",
834 },
835 {
836 .name = "eventlist",
837 .mode = COMMAND_ANY,
838 .handler = handle_arm_tpiu_swo_event_list,
839 .help = "displays a table of events defined for this TPIU/SWO",
840 .usage = "",
841 },
842 {
843 .name = "enable",
844 .mode = COMMAND_ANY,
845 .jim_handler = jim_arm_tpiu_swo_enable,
846 .usage = "",
847 .help = "Enables the TPIU/SWO output",
848 },
849 {
850 .name = "disable",
851 .mode = COMMAND_EXEC,
852 .jim_handler = jim_arm_tpiu_swo_disable,
853 .usage = "",
854 .help = "Disables the TPIU/SWO output",
855 },
856 COMMAND_REGISTRATION_DONE
857 };
858
859 static int arm_tpiu_swo_create(Jim_Interp *interp, struct arm_tpiu_swo_object *obj)
860 {
861 struct command_context *cmd_ctx;
862 Jim_Cmd *cmd;
863 int e;
864
865 cmd_ctx = current_command_context(interp);
866 assert(cmd_ctx != NULL);
867
868 /* does this command exist? */
869 cmd = Jim_GetCommand(interp, Jim_NewStringObj(interp, obj->name, -1), JIM_ERRMSG);
870 if (cmd) {
871 Jim_SetResultFormatted(interp, "Command: %s Exists", obj->name);
872 return JIM_ERR;
873 }
874
875 /* now - create the new tpiu/swo name command */
876 const struct command_registration obj_commands[] = {
877 {
878 .name = obj->name,
879 .mode = COMMAND_ANY,
880 .help = "tpiu/swo instance command group",
881 .usage = "",
882 .chain = arm_tpiu_swo_instance_command_handlers,
883 },
884 COMMAND_REGISTRATION_DONE
885 };
886 e = register_commands(cmd_ctx, NULL, obj_commands);
887 if (ERROR_OK != e)
888 return JIM_ERR;
889
890 struct command *c = command_find_in_context(cmd_ctx, obj->name);
891 assert(c);
892 command_set_handler_data(c, obj);
893
894 list_add_tail(&obj->lh, &all_tpiu_swo);
895
896 return JIM_OK;
897 }
898
899 static int jim_arm_tpiu_swo_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
900 {
901 Jim_GetOptInfo goi;
902 Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
903 if (goi.argc < 1) {
904 Jim_WrongNumArgs(goi.interp, 1, goi.argv, "?name? ..options...");
905 return JIM_ERR;
906 }
907
908 struct arm_tpiu_swo_object *obj = calloc(1, sizeof(struct arm_tpiu_swo_object));
909 if (!obj) {
910 LOG_ERROR("Out of memory");
911 return JIM_ERR;
912 }
913 INIT_LIST_HEAD(&obj->connections);
914 adiv5_mem_ap_spot_init(&obj->spot);
915 obj->spot.base = TPIU_SWO_DEFAULT_BASE;
916 obj->port_width = 1;
917
918 Jim_Obj *n;
919 Jim_GetOpt_Obj(&goi, &n);
920 obj->name = strdup(Jim_GetString(n, NULL));
921 if (!obj->name) {
922 LOG_ERROR("Out of memory");
923 free(obj);
924 return JIM_ERR;
925 }
926
927 /* Do the rest as "configure" options */
928 goi.isconfigure = 1;
929 int e = arm_tpiu_swo_configure(&goi, obj);
930 if (e != JIM_OK)
931 goto err_exit;
932
933 if (!obj->spot.dap || obj->spot.ap_num == DP_APSEL_INVALID) {
934 Jim_SetResultString(goi.interp, "-dap and -ap-num required when creating TPIU", -1);
935 goto err_exit;
936 }
937
938 e = arm_tpiu_swo_create(goi.interp, obj);
939 if (e != JIM_OK)
940 goto err_exit;
941
942 return JIM_OK;
943
944 err_exit:
945 free(obj->name);
946 free(obj->out_filename);
947 free(obj);
948 return JIM_ERR;
949 }
950
951 static int jim_arm_tpiu_swo_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
952 {
953 struct arm_tpiu_swo_object *obj;
954
955 if (argc != 1) {
956 Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
957 return JIM_ERR;
958 }
959 Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
960 list_for_each_entry(obj, &all_tpiu_swo, lh) {
961 Jim_ListAppendElement(interp, Jim_GetResult(interp),
962 Jim_NewStringObj(interp, obj->name, -1));
963 }
964 return JIM_OK;
965 }
966
967 static int jim_arm_tpiu_swo_init(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
968 {
969 struct command_context *cmd_ctx = current_command_context(interp);
970 struct arm_tpiu_swo_object *obj;
971 int retval = JIM_OK;
972
973 if (argc != 1) {
974 Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
975 return JIM_ERR;
976 }
977 list_for_each_entry(obj, &all_tpiu_swo, lh) {
978 if (!obj->deferred_enable)
979 continue;
980 LOG_DEBUG("%s: running enable during init", obj->name);
981 int retval2 = command_run_linef(cmd_ctx, "%s enable", obj->name);
982 if (retval2 != ERROR_OK)
983 retval = JIM_ERR;
984 }
985 return retval;
986 }
987
988 /* START_DEPRECATED_TPIU */
989 /* DEPRECATED: emulation of old command 'tpiu config' */
990 COMMAND_HANDLER(handle_tpiu_deprecated_config_command)
991 {
992 struct target *target = get_current_target(CMD_CTX);
993 struct arm_tpiu_swo_object *obj = NULL;
994 int retval;
995
996 if (strcmp(target->type->name, "cortex_m") &&
997 strcmp(target->type->name, "hla_target")) {
998 LOG_ERROR(MSG "Current target is not a Cortex-M nor a HLA");
999 return ERROR_FAIL;
1000 }
1001
1002 if (!list_empty(&all_tpiu_swo)) {
1003 obj = list_first_entry(&all_tpiu_swo, typeof(*obj), lh);
1004 LOG_INFO(MSG "Using %s", obj->name);
1005 } else {
1006 struct cortex_m_common *cm = target_to_cm(target);
1007 struct adiv5_private_config *pc = target->private_config;
1008 struct adiv5_dap *dap = pc->dap;
1009 int ap_num = pc->ap_num;
1010 bool set_recheck_ap_cur_target = false;
1011
1012 LOG_INFO(MSG "Adding a TPIU \'%s.tpiu\' in the configuration", target_name(target));
1013
1014 if (ap_num == DP_APSEL_INVALID && transport_is_hla())
1015 ap_num = 0; /* HLA should only support AP 0 */
1016
1017 if (ap_num == DP_APSEL_INVALID && target_was_examined(target))
1018 ap_num = cm->armv7m.debug_ap->ap_num;
1019
1020 if (ap_num == DP_APSEL_INVALID) {
1021 LOG_INFO(MSG "Target %s uses AP autodetection. Adding TPIU on AP 0; can be revised later",
1022 target_name(target));
1023 ap_num = 0;
1024 set_recheck_ap_cur_target = true;
1025 }
1026
1027 LOG_INFO(MSG "Running: \'tpiu create %s.tpiu -dap %s -ap-num %d\'",
1028 target_name(target), adiv5_dap_name(dap), ap_num);
1029
1030 retval = command_run_linef(CMD_CTX, "tpiu create %s.tpiu -dap %s -ap-num %d",
1031 target_name(target), adiv5_dap_name(dap), ap_num);
1032 if (retval != ERROR_OK)
1033 return retval;
1034
1035 obj = list_first_entry(&all_tpiu_swo, typeof(*obj), lh);
1036 if (set_recheck_ap_cur_target)
1037 obj->recheck_ap_cur_target = true;
1038 }
1039
1040 unsigned int cmd_idx = 0;
1041 if (CMD_ARGC == cmd_idx)
1042 return ERROR_COMMAND_SYNTAX_ERROR;
1043
1044 if (!strcmp(CMD_ARGV[cmd_idx], "disable")) {
1045 if (CMD_ARGC != cmd_idx + 1)
1046 return ERROR_COMMAND_SYNTAX_ERROR;
1047 LOG_INFO(MSG "Running: \'%s disable\'", obj->name);
1048 return command_run_linef(CMD_CTX, "%s disable", obj->name);
1049 }
1050
1051 const char *output = NULL;
1052 const char *protocol;
1053 const char *formatter = NULL;
1054 const char *port_width = NULL;
1055 const char *trace_clk;
1056 const char *pin_clk = NULL;
1057 if (!strcmp(CMD_ARGV[cmd_idx], "internal")) {
1058 cmd_idx++;
1059 if (CMD_ARGC == cmd_idx)
1060 return ERROR_COMMAND_SYNTAX_ERROR;
1061 output = CMD_ARGV[cmd_idx];
1062 } else if (strcmp(CMD_ARGV[cmd_idx], "external"))
1063 return ERROR_COMMAND_SYNTAX_ERROR;
1064 cmd_idx++;
1065 if (CMD_ARGC == cmd_idx)
1066 return ERROR_COMMAND_SYNTAX_ERROR;
1067 if (!strcmp(CMD_ARGV[cmd_idx], "sync")) {
1068 protocol = CMD_ARGV[cmd_idx];
1069 cmd_idx++;
1070 if (CMD_ARGC == cmd_idx)
1071 return ERROR_COMMAND_SYNTAX_ERROR;
1072 port_width = CMD_ARGV[cmd_idx];
1073 } else {
1074 if (strcmp(CMD_ARGV[cmd_idx], "manchester") && strcmp(CMD_ARGV[cmd_idx], "uart"))
1075 return ERROR_COMMAND_SYNTAX_ERROR;
1076 protocol = CMD_ARGV[cmd_idx];
1077 cmd_idx++;
1078 if (CMD_ARGC == cmd_idx)
1079 return ERROR_COMMAND_SYNTAX_ERROR;
1080 formatter = CMD_ARGV[cmd_idx];
1081 }
1082 cmd_idx++;
1083 if (CMD_ARGC == cmd_idx)
1084 return ERROR_COMMAND_SYNTAX_ERROR;
1085 trace_clk = CMD_ARGV[cmd_idx];
1086 cmd_idx++;
1087 if (CMD_ARGC != cmd_idx) {
1088 pin_clk = CMD_ARGV[cmd_idx];
1089 cmd_idx++;
1090 }
1091 if (CMD_ARGC != cmd_idx)
1092 return ERROR_COMMAND_SYNTAX_ERROR;
1093
1094 LOG_INFO(MSG "Running: \'%s configure -protocol %s -traceclk %s" "%s%s" "%s%s" "%s%s" "%s%s\'",
1095 obj->name, protocol, trace_clk,
1096 pin_clk ? " -pin-freq " : "", pin_clk ? pin_clk : "",
1097 output ? " -output " : "", output ? output : "",
1098 formatter ? " -formatter " : "", formatter ? formatter : "",
1099 port_width ? " -port-width " : "", port_width ? port_width : "");
1100
1101 retval = command_run_linef(CMD_CTX,
1102 "%s configure -protocol %s -traceclk %s" "%s%s" "%s%s" "%s%s" "%s%s",
1103 obj->name, protocol, trace_clk,
1104 pin_clk ? " -pin-freq " : "", pin_clk ? pin_clk : "",
1105 output ? " -output " : "", output ? output : "",
1106 formatter ? " -formatter " : "", formatter ? formatter : "",
1107 port_width ? " -port-width " : "", port_width ? port_width : "");
1108 if (retval != ERROR_OK)
1109 return retval;
1110
1111 LOG_INFO(MSG "Running: \'%s enable\'", obj->name);
1112 retval = command_run_linef(CMD_CTX, "%s enable", obj->name);
1113 if (retval != ERROR_OK)
1114 return retval;
1115
1116 target_handle_event(target, TARGET_EVENT_TRACE_CONFIG);
1117 return ERROR_OK;
1118 }
1119
1120 static const struct command_registration arm_tpiu_deprecated_subcommand_handlers[] = {
1121 {
1122 .name = "config",
1123 .handler = handle_tpiu_deprecated_config_command,
1124 .mode = COMMAND_ANY,
1125 .help = "Configure TPIU features, DEPRECATED, use \'tpiu create\'",
1126 .usage = "(disable | "
1127 "((external | internal (<filename> | <:port> | -)) "
1128 "(sync <port width> | ((manchester | uart) <formatter enable>)) "
1129 "<TRACECLKIN freq> [<trace freq>]))",
1130 },
1131 COMMAND_REGISTRATION_DONE
1132 };
1133
1134 const struct command_registration arm_tpiu_deprecated_command_handlers[] = {
1135 {
1136 .name = "tpiu",
1137 .chain = arm_tpiu_deprecated_subcommand_handlers,
1138 .usage = "",
1139 .help = "tpiu command group",
1140 },
1141 COMMAND_REGISTRATION_DONE
1142 };
1143 /* END_DEPRECATED_TPIU */
1144
1145 static const struct command_registration arm_tpiu_swo_subcommand_handlers[] = {
1146 {
1147 .name = "create",
1148 .mode = COMMAND_ANY,
1149 .jim_handler = jim_arm_tpiu_swo_create,
1150 .usage = "name [-dap dap] [-ap-num num] [-address baseaddr]",
1151 .help = "Creates a new TPIU or SWO object",
1152 },
1153 {
1154 .name = "names",
1155 .mode = COMMAND_ANY,
1156 .jim_handler = jim_arm_tpiu_swo_names,
1157 .usage = "",
1158 .help = "Lists all registered TPIU and SWO objects by name",
1159 },
1160 {
1161 .name = "init",
1162 .mode = COMMAND_EXEC,
1163 .jim_handler = jim_arm_tpiu_swo_init,
1164 .usage = "",
1165 .help = "Initialize TPIU and SWO",
1166 },
1167 COMMAND_REGISTRATION_DONE
1168 };
1169
1170 static const struct command_registration arm_tpiu_swo_command_handlers[] = {
1171 {
1172 .name = "tpiu",
1173 .chain = arm_tpiu_swo_subcommand_handlers,
1174 .usage = "",
1175 .help = "tpiu command group",
1176 },
1177 {
1178 .name = "swo",
1179 .chain = arm_tpiu_swo_subcommand_handlers,
1180 .usage = "",
1181 .help = "swo command group",
1182 },
1183 COMMAND_REGISTRATION_DONE
1184 };
1185
1186 int arm_tpiu_swo_register_commands(struct command_context *cmd_ctx)
1187 {
1188 return register_commands(cmd_ctx, NULL, arm_tpiu_swo_command_handlers);
1189 }

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)