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

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)