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

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)