61891cb57e4f7ca805f0082ac4f99e62920455f0
[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 #define TCP_SERVICE_NAME "tpiu_swo_trace"
42
43 /* default for Cortex-M3 and Cortex-M4 specific TPIU */
44 #define TPIU_SWO_DEFAULT_BASE 0xE0040000
45
46 #define TPIU_SSPSR_OFFSET 0x000
47 #define TPIU_CSPSR_OFFSET 0x004
48 #define TPIU_ACPR_OFFSET 0x010
49 #define TPIU_SPPR_OFFSET 0x0F0
50 #define TPIU_FFSR_OFFSET 0x300
51 #define TPIU_FFCR_OFFSET 0x304
52 #define TPIU_FSCR_OFFSET 0x308
53 #define TPIU_DEVID_OFFSET 0xfc8
54
55 #define TPIU_ACPR_MAX_PRESCALER 0x1fff
56 #define TPIU_SPPR_PROTOCOL_SYNC 0x0 /**< synchronous trace output */
57 #define TPIU_SPPR_PROTOCOL_MANCHESTER 0x1 /**< asynchronous output with NRZ coding */
58 #define TPIU_SPPR_PROTOCOL_UART 0x2 /**< asynchronous output with Manchester coding */
59 #define TPIU_DEVID_NOSUPPORT_SYNC BIT(9)
60 #define TPIU_DEVID_SUPPORT_MANCHESTER BIT(10)
61 #define TPIU_DEVID_SUPPORT_UART BIT(11)
62
63 enum arm_tpiu_swo_event {
64 TPIU_SWO_EVENT_PRE_ENABLE,
65 TPIU_SWO_EVENT_POST_ENABLE,
66 TPIU_SWO_EVENT_PRE_DISABLE,
67 TPIU_SWO_EVENT_POST_DISABLE,
68 };
69
70 static const Jim_Nvp nvp_arm_tpiu_swo_event[] = {
71 { .value = TPIU_SWO_EVENT_PRE_ENABLE, .name = "pre-enable" },
72 { .value = TPIU_SWO_EVENT_POST_ENABLE, .name = "post-enable" },
73 { .value = TPIU_SWO_EVENT_PRE_DISABLE, .name = "pre-disable" },
74 { .value = TPIU_SWO_EVENT_POST_DISABLE, .name = "post-disable" },
75 };
76
77 struct arm_tpiu_swo_event_action {
78 enum arm_tpiu_swo_event event;
79 Jim_Interp *interp;
80 Jim_Obj *body;
81 struct arm_tpiu_swo_event_action *next;
82 };
83
84 struct arm_tpiu_swo_object {
85 struct list_head lh;
86 struct adiv5_mem_ap_spot spot;
87 char *name;
88 struct arm_tpiu_swo_event_action *event_action;
89 /* record enable before init */
90 bool deferred_enable;
91 bool enabled;
92 bool en_capture;
93 /** Handle to output trace data in INTERNAL capture mode */
94 /** Synchronous output port width */
95 uint32_t port_width;
96 FILE *file;
97 /** output mode */
98 unsigned int pin_protocol;
99 /** Enable formatter */
100 bool en_formatter;
101 /** frequency of TRACECLKIN (usually matches HCLK) */
102 unsigned int traceclkin_freq;
103 /** SWO pin frequency */
104 unsigned int swo_pin_freq;
105 /** where to dump the captured output trace data */
106 char *out_filename;
107 /** track TCP connections */
108 struct list_head connections;
109 };
110
111 struct arm_tpiu_swo_connection {
112 struct list_head lh;
113 struct connection *connection;
114 };
115
116 struct arm_tpiu_swo_priv_connection {
117 struct arm_tpiu_swo_object *obj;
118 };
119
120 static LIST_HEAD(all_tpiu_swo);
121
122 #define ARM_TPIU_SWO_TRACE_BUF_SIZE 4096
123
124 static int arm_tpiu_swo_poll_trace(void *priv)
125 {
126 struct arm_tpiu_swo_object *obj = priv;
127 uint8_t buf[ARM_TPIU_SWO_TRACE_BUF_SIZE];
128 size_t size = sizeof(buf);
129 struct arm_tpiu_swo_connection *c;
130
131 int retval = adapter_poll_trace(buf, &size);
132 if (retval != ERROR_OK || !size)
133 return retval;
134
135 target_call_trace_callbacks(/*target*/NULL, size, buf);
136
137 if (obj->file) {
138 if (fwrite(buf, 1, size, obj->file) == size) {
139 fflush(obj->file);
140 } else {
141 LOG_ERROR("Error writing to the SWO trace destination file");
142 return ERROR_FAIL;
143 }
144 }
145
146 if (obj->out_filename && obj->out_filename[0] == ':')
147 list_for_each_entry(c, &obj->connections, lh)
148 if (connection_write(c->connection, buf, size) != (int)size)
149 retval = ERROR_FAIL;
150
151 return ERROR_OK;
152 }
153
154 static void arm_tpiu_swo_handle_event(struct arm_tpiu_swo_object *obj, enum arm_tpiu_swo_event event)
155 {
156 for (struct arm_tpiu_swo_event_action *ea = obj->event_action; ea; ea = ea->next) {
157 if (ea->event != event)
158 continue;
159
160 LOG_DEBUG("TPIU/SWO: %s event: %s (%d) action : %s",
161 obj->name,
162 Jim_Nvp_value2name_simple(nvp_arm_tpiu_swo_event, event)->name,
163 event,
164 Jim_GetString(ea->body, NULL));
165
166 /* prevent event execution to change current target */
167 struct command_context *cmd_ctx = current_command_context(ea->interp);
168 struct target *saved_target = cmd_ctx->current_target;
169 int retval = Jim_EvalObj(ea->interp, ea->body);
170 cmd_ctx->current_target = saved_target;
171
172 if (retval == JIM_RETURN)
173 retval = ea->interp->returnCode;
174 if (retval == JIM_OK || retval == ERROR_COMMAND_CLOSE_CONNECTION)
175 return;
176
177 Jim_MakeErrorMessage(ea->interp);
178 LOG_USER("Error executing event %s on TPIU/SWO %s:\n%s",
179 Jim_Nvp_value2name_simple(nvp_arm_tpiu_swo_event, event)->name,
180 obj->name,
181 Jim_GetString(Jim_GetResult(ea->interp), NULL));
182 /* clean both error code and stacktrace before return */
183 Jim_Eval(ea->interp, "error \"\" \"\"");
184 return;
185 }
186 }
187
188 static void arm_tpiu_swo_close_output(struct arm_tpiu_swo_object *obj)
189 {
190 if (obj->file) {
191 fclose(obj->file);
192 obj->file = NULL;
193 }
194 if (obj->out_filename && obj->out_filename[0] == ':')
195 remove_service(TCP_SERVICE_NAME, &obj->out_filename[1]);
196 }
197
198 int arm_tpiu_swo_cleanup_all(void)
199 {
200 struct arm_tpiu_swo_object *obj, *tmp;
201
202 list_for_each_entry_safe(obj, tmp, &all_tpiu_swo, lh) {
203 if (obj->enabled)
204 arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_PRE_DISABLE);
205
206 arm_tpiu_swo_close_output(obj);
207
208 if (obj->en_capture) {
209 target_unregister_timer_callback(arm_tpiu_swo_poll_trace, obj);
210
211 int retval = adapter_config_trace(false, 0, 0, NULL, 0, NULL);
212 if (retval != ERROR_OK)
213 LOG_ERROR("Failed to stop adapter's trace");
214 }
215
216 if (obj->enabled)
217 arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_POST_DISABLE);
218
219 struct arm_tpiu_swo_event_action *ea = obj->event_action;
220 while (ea) {
221 struct arm_tpiu_swo_event_action *next = ea->next;
222 Jim_DecrRefCount(ea->interp, ea->body);
223 free(ea);
224 ea = next;
225 }
226
227 free(obj->name);
228 free(obj->out_filename);
229 free(obj);
230 }
231
232 return ERROR_OK;
233 }
234
235 static int arm_tpiu_swo_service_new_connection(struct connection *connection)
236 {
237 struct arm_tpiu_swo_priv_connection *priv = connection->service->priv;
238 struct arm_tpiu_swo_object *obj = priv->obj;
239 struct arm_tpiu_swo_connection *c = malloc(sizeof(*c));
240 if (!c) {
241 LOG_ERROR("Out of memory");
242 return ERROR_FAIL;
243 }
244 c->connection = connection;
245 list_add(&c->lh, &obj->connections);
246 return ERROR_OK;
247 }
248
249 static int arm_tpiu_swo_service_input(struct connection *connection)
250 {
251 /* read a dummy buffer to check if the connection is still active */
252 long dummy;
253 int bytes_read = connection_read(connection, &dummy, sizeof(dummy));
254
255 if (bytes_read == 0) {
256 return ERROR_SERVER_REMOTE_CLOSED;
257 } else if (bytes_read == -1) {
258 LOG_ERROR("error during read: %s", strerror(errno));
259 return ERROR_SERVER_REMOTE_CLOSED;
260 }
261
262 return ERROR_OK;
263 }
264
265 static int arm_tpiu_swo_service_connection_closed(struct connection *connection)
266 {
267 struct arm_tpiu_swo_priv_connection *priv = connection->service->priv;
268 struct arm_tpiu_swo_object *obj = priv->obj;
269 struct arm_tpiu_swo_connection *c, *tmp;
270
271 list_for_each_entry_safe(c, tmp, &obj->connections, lh)
272 if (c->connection == connection) {
273 list_del(&c->lh);
274 free(c);
275 return ERROR_OK;
276 }
277 LOG_ERROR("Failed to find connection to close!");
278 return ERROR_FAIL;
279 }
280
281 COMMAND_HANDLER(handle_arm_tpiu_swo_event_list)
282 {
283 struct arm_tpiu_swo_object *obj = CMD_DATA;
284
285 command_print(CMD, "Event actions for TPIU/SWO %s\n", obj->name);
286 command_print(CMD, "%-25s | Body", "Event");
287 command_print(CMD, "------------------------- | "
288 "----------------------------------------");
289
290 for (struct arm_tpiu_swo_event_action *ea = obj->event_action; ea; ea = ea->next) {
291 Jim_Nvp *opt = Jim_Nvp_value2name_simple(nvp_arm_tpiu_swo_event, ea->event);
292 command_print(CMD, "%-25s | %s",
293 opt->name, Jim_GetString(ea->body, NULL));
294 }
295 command_print(CMD, "***END***");
296 return ERROR_OK;
297 }
298
299 enum arm_tpiu_swo_cfg_param {
300 CFG_PORT_WIDTH,
301 CFG_PROTOCOL,
302 CFG_FORMATTER,
303 CFG_TRACECLKIN,
304 CFG_BITRATE,
305 CFG_OUTFILE,
306 CFG_EVENT,
307 };
308
309 static const Jim_Nvp nvp_arm_tpiu_swo_config_opts[] = {
310 { .name = "-port-width", .value = CFG_PORT_WIDTH },
311 { .name = "-protocol", .value = CFG_PROTOCOL },
312 { .name = "-formatter", .value = CFG_FORMATTER },
313 { .name = "-traceclk", .value = CFG_TRACECLKIN },
314 { .name = "-pin-freq", .value = CFG_BITRATE },
315 { .name = "-output", .value = CFG_OUTFILE },
316 { .name = "-event", .value = CFG_EVENT },
317 /* handled by mem_ap_spot, added for Jim_GetOpt_NvpUnknown() */
318 { .name = "-dap", .value = -1 },
319 { .name = "-ap-num", .value = -1 },
320 { .name = "-baseaddr", .value = -1 },
321 { .name = NULL, .value = -1 },
322 };
323
324 static const Jim_Nvp nvp_arm_tpiu_swo_protocol_opts[] = {
325 { .name = "sync", .value = TPIU_SPPR_PROTOCOL_SYNC },
326 { .name = "uart", .value = TPIU_SPPR_PROTOCOL_UART },
327 { .name = "manchester", .value = TPIU_SPPR_PROTOCOL_MANCHESTER },
328 { .name = NULL, .value = -1 },
329 };
330
331 static const Jim_Nvp nvp_arm_tpiu_swo_bool_opts[] = {
332 { .name = "on", .value = 1 },
333 { .name = "yes", .value = 1 },
334 { .name = "1", .value = 1 },
335 { .name = "true", .value = 1 },
336 { .name = "off", .value = 0 },
337 { .name = "no", .value = 0 },
338 { .name = "0", .value = 0 },
339 { .name = "false", .value = 0 },
340 { .name = NULL, .value = -1 },
341 };
342
343 static int arm_tpiu_swo_configure(Jim_GetOptInfo *goi, struct arm_tpiu_swo_object *obj)
344 {
345 assert(obj != NULL);
346
347 if (goi->isconfigure && obj->enabled) {
348 Jim_SetResultFormatted(goi->interp, "Cannot configure TPIU/SWO; %s is enabled!", obj->name);
349 return JIM_ERR;
350 }
351
352 /* parse config or cget options ... */
353 while (goi->argc > 0) {
354 Jim_SetEmptyResult(goi->interp);
355
356 int e = adiv5_jim_mem_ap_spot_configure(&obj->spot, goi);
357 if (e == JIM_OK)
358 continue;
359 if (e == JIM_ERR)
360 return e;
361
362 Jim_Nvp *n;
363 e = Jim_GetOpt_Nvp(goi, nvp_arm_tpiu_swo_config_opts, &n);
364 if (e != JIM_OK) {
365 Jim_GetOpt_NvpUnknown(goi, nvp_arm_tpiu_swo_config_opts, 0);
366 return e;
367 }
368
369 switch (n->value) {
370 case CFG_PORT_WIDTH:
371 if (goi->isconfigure) {
372 jim_wide port_width;
373 e = Jim_GetOpt_Wide(goi, &port_width);
374 if (e != JIM_OK)
375 return e;
376 if (port_width < 1 || port_width > 32) {
377 Jim_SetResultString(goi->interp, "Invalid port width!", -1);
378 return JIM_ERR;
379 }
380 obj->port_width = (uint32_t)port_width;
381 } else {
382 if (goi->argc)
383 goto err_no_params;
384 Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, obj->port_width));
385 }
386 break;
387 case CFG_PROTOCOL:
388 if (goi->isconfigure) {
389 Jim_Nvp *p;
390 e = Jim_GetOpt_Nvp(goi, nvp_arm_tpiu_swo_protocol_opts, &p);
391 if (e != JIM_OK)
392 return e;
393 obj->pin_protocol = p->value;
394 } else {
395 if (goi->argc)
396 goto err_no_params;
397 Jim_Nvp *p;
398 e = Jim_Nvp_value2name(goi->interp, nvp_arm_tpiu_swo_protocol_opts, obj->pin_protocol, &p);
399 if (e != JIM_OK) {
400 Jim_SetResultString(goi->interp, "protocol error", -1);
401 return JIM_ERR;
402 }
403 Jim_SetResult(goi->interp, Jim_NewStringObj(goi->interp, p->name, -1));
404 }
405 break;
406 case CFG_FORMATTER:
407 if (goi->isconfigure) {
408 Jim_Nvp *p;
409 e = Jim_GetOpt_Nvp(goi, nvp_arm_tpiu_swo_bool_opts, &p);
410 if (e != JIM_OK)
411 return e;
412 obj->en_formatter = p->value;
413 } else {
414 if (goi->argc)
415 goto err_no_params;
416 Jim_Nvp *p;
417 e = Jim_Nvp_value2name(goi->interp, nvp_arm_tpiu_swo_bool_opts, obj->en_formatter, &p);
418 if (e != JIM_OK) {
419 Jim_SetResultString(goi->interp, "formatter error", -1);
420 return JIM_ERR;
421 }
422 Jim_SetResult(goi->interp, Jim_NewStringObj(goi->interp, p->name, -1));
423 }
424 break;
425 case CFG_TRACECLKIN:
426 if (goi->isconfigure) {
427 jim_wide clk;
428 e = Jim_GetOpt_Wide(goi, &clk);
429 if (e != JIM_OK)
430 return e;
431 obj->traceclkin_freq = clk;
432 } else {
433 if (goi->argc)
434 goto err_no_params;
435 Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, obj->traceclkin_freq));
436 }
437 break;
438 case CFG_BITRATE:
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->swo_pin_freq = clk;
445 } else {
446 if (goi->argc)
447 goto err_no_params;
448 Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, obj->swo_pin_freq));
449 }
450 break;
451 case CFG_OUTFILE:
452 if (goi->isconfigure) {
453 const char *s;
454 e = Jim_GetOpt_String(goi, &s, NULL);
455 if (e != JIM_OK)
456 return e;
457 if (s[0] == ':') {
458 char *end;
459 long port = strtol(s + 1, &end, 0);
460 if (port <= 0 || port > UINT16_MAX || *end != '\0') {
461 Jim_SetResultFormatted(goi->interp, "Invalid TCP port \'%s\'", s + 1);
462 return JIM_ERR;
463 }
464 }
465 free(obj->out_filename);
466 obj->out_filename = strdup(s);
467 if (!obj->out_filename) {
468 LOG_ERROR("Out of memory");
469 return JIM_ERR;
470 }
471 } else {
472 if (goi->argc)
473 goto err_no_params;
474 if (obj->out_filename)
475 Jim_SetResult(goi->interp, Jim_NewStringObj(goi->interp, obj->out_filename, -1));
476 }
477 break;
478 case CFG_EVENT:
479 if (goi->isconfigure) {
480 if (goi->argc < 2) {
481 Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name? ?EVENT-BODY?");
482 return JIM_ERR;
483 }
484 } else {
485 if (goi->argc != 1) {
486 Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name?");
487 return JIM_ERR;
488 }
489 }
490
491 {
492 Jim_Nvp *p;
493 Jim_Obj *o;
494 struct arm_tpiu_swo_event_action *ea = obj->event_action;
495
496 e = Jim_GetOpt_Nvp(goi, nvp_arm_tpiu_swo_event, &p);
497 if (e != JIM_OK) {
498 Jim_GetOpt_NvpUnknown(goi, nvp_arm_tpiu_swo_event, 1);
499 return e;
500 }
501
502 while (ea) {
503 /* replace existing? */
504 if (ea->event == (enum arm_tpiu_swo_event)p->value)
505 break;
506 ea = ea->next;
507 }
508
509 if (goi->isconfigure) {
510 if (!ea) {
511 ea = calloc(1, sizeof(*ea));
512 if (!ea) {
513 LOG_ERROR("Out of memory");
514 return JIM_ERR;
515 }
516 ea->next = obj->event_action;
517 obj->event_action = ea;
518 }
519 if (ea->body)
520 Jim_DecrRefCount(ea->interp, ea->body);
521 ea->event = p->value;
522 ea->interp = goi->interp;
523 Jim_GetOpt_Obj(goi, &o);
524 ea->body = Jim_DuplicateObj(goi->interp, o);
525 Jim_IncrRefCount(ea->body);
526 } else {
527 if (ea)
528 Jim_SetResult(goi->interp, Jim_DuplicateObj(goi->interp, ea->body));
529 }
530 }
531 break;
532 }
533 }
534
535 return JIM_OK;
536
537 err_no_params:
538 Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS");
539 return JIM_ERR;
540 }
541
542 static int jim_arm_tpiu_swo_configure(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
543 {
544 Jim_GetOptInfo goi;
545
546 Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
547 goi.isconfigure = !strcmp(Jim_GetString(argv[0], NULL), "configure");
548 if (goi.argc < 1) {
549 Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv,
550 "missing: -option ...");
551 return JIM_ERR;
552 }
553 struct arm_tpiu_swo_object *obj = Jim_CmdPrivData(interp);
554 return arm_tpiu_swo_configure(&goi, obj);
555 }
556
557 static int wrap_write_u32(struct target *target, struct adiv5_ap *tpiu_ap,
558 target_addr_t address, uint32_t value)
559 {
560 if (transport_is_hla())
561 return target_write_u32(target, address, value);
562 else
563 return mem_ap_write_atomic_u32(tpiu_ap, address, value);
564 }
565
566 static int wrap_read_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_read_u32(target, address, value);
571 else
572 return mem_ap_read_atomic_u32(tpiu_ap, address, value);
573 }
574
575 static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
576 {
577 struct arm_tpiu_swo_object *obj = Jim_CmdPrivData(interp);
578 struct command_context *cmd_ctx = current_command_context(interp);
579 struct adiv5_ap *tpiu_ap = dap_ap(obj->spot.dap, obj->spot.ap_num);
580 uint32_t value;
581 int retval;
582
583 if (argc != 1) {
584 Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
585 return JIM_ERR;
586 }
587
588 if (cmd_ctx->mode == COMMAND_CONFIG) {
589 LOG_DEBUG("%s: enable deferred", obj->name);
590 obj->deferred_enable = true;
591 return JIM_OK;
592 }
593
594 if (obj->enabled)
595 return JIM_OK;
596
597 if (transport_is_hla() && obj->spot.ap_num > 0) {
598 LOG_ERROR("Invalid access port %d. Only AP#0 allowed with hla transport", obj->spot.ap_num);
599 return JIM_ERR;
600 }
601
602 if (!obj->traceclkin_freq) {
603 LOG_ERROR("Trace clock-in frequency not set");
604 return JIM_ERR;
605 }
606
607 if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_MANCHESTER || obj->pin_protocol == TPIU_SPPR_PROTOCOL_UART)
608 if (!obj->swo_pin_freq) {
609 LOG_ERROR("SWO pin frequency not set");
610 return JIM_ERR;
611 }
612
613 struct target *target = get_current_target(cmd_ctx);
614
615 /* trigger the event before any attempt to R/W in the TPIU/SWO */
616 arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_PRE_ENABLE);
617
618 retval = wrap_read_u32(target, tpiu_ap, obj->spot.base + TPIU_DEVID_OFFSET, &value);
619 if (retval != ERROR_OK) {
620 LOG_ERROR("Unable to read %s", obj->name);
621 return JIM_ERR;
622 }
623 switch (obj->pin_protocol) {
624 case TPIU_SPPR_PROTOCOL_SYNC:
625 value = !(value & TPIU_DEVID_NOSUPPORT_SYNC);
626 break;
627 case TPIU_SPPR_PROTOCOL_UART:
628 value &= TPIU_DEVID_SUPPORT_UART;
629 break;
630 case TPIU_SPPR_PROTOCOL_MANCHESTER:
631 value &= TPIU_DEVID_SUPPORT_MANCHESTER;
632 break;
633 default:
634 value = 0;
635 }
636 if (!value) {
637 Jim_Nvp *p;
638 Jim_Nvp_value2name(interp, nvp_arm_tpiu_swo_protocol_opts, obj->pin_protocol, &p);
639 LOG_ERROR("%s does not support protocol %s", obj->name, p->name);
640 return JIM_ERR;
641 }
642
643 if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_SYNC) {
644 retval = wrap_read_u32(target, tpiu_ap, obj->spot.base + TPIU_SSPSR_OFFSET, &value);
645 if (!(value & BIT(obj->port_width - 1))) {
646 LOG_ERROR("TPIU does not support port-width of %d bits", obj->port_width);
647 return JIM_ERR;
648 }
649 }
650
651 uint16_t prescaler = 1; /* dummy value */
652 unsigned int swo_pin_freq = obj->swo_pin_freq; /* could be replaced */
653
654 if (obj->out_filename && strcmp(obj->out_filename, "external") && obj->out_filename[0]) {
655 if (obj->out_filename[0] == ':') {
656 struct arm_tpiu_swo_priv_connection *priv = malloc(sizeof(*priv));
657 if (!priv) {
658 LOG_ERROR("Out of memory");
659 return JIM_ERR;
660 }
661 priv->obj = obj;
662 LOG_INFO("starting trace server for %s on %s", obj->name, &obj->out_filename[1]);
663 retval = add_service("tpiu_swo_trace", &obj->out_filename[1],
664 CONNECTION_LIMIT_UNLIMITED, arm_tpiu_swo_service_new_connection,
665 arm_tpiu_swo_service_input, arm_tpiu_swo_service_connection_closed,
666 priv, NULL);
667 if (retval != ERROR_OK) {
668 LOG_ERROR("Can't configure trace TCP port %s", &obj->out_filename[1]);
669 return JIM_ERR;
670 }
671 } else if (strcmp(obj->out_filename, "-")) {
672 obj->file = fopen(obj->out_filename, "ab");
673 if (!obj->file) {
674 LOG_ERROR("Can't open trace destination file \"%s\"", obj->out_filename);
675 return JIM_ERR;
676 }
677 }
678
679 retval = adapter_config_trace(true, obj->pin_protocol, obj->port_width,
680 &swo_pin_freq, obj->traceclkin_freq, &prescaler);
681 if (retval != ERROR_OK) {
682 LOG_ERROR("Failed to start adapter's trace");
683 arm_tpiu_swo_close_output(obj);
684 return JIM_ERR;
685 }
686
687 if (obj->swo_pin_freq != swo_pin_freq)
688 LOG_INFO("SWO pin data rate adjusted by adapter to %d Hz", swo_pin_freq);
689 obj->swo_pin_freq = swo_pin_freq;
690
691 target_register_timer_callback(arm_tpiu_swo_poll_trace, 1,
692 TARGET_TIMER_TYPE_PERIODIC, obj);
693
694 obj->en_capture = true;
695 } else if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_MANCHESTER || obj->pin_protocol == TPIU_SPPR_PROTOCOL_UART) {
696 prescaler = (obj->traceclkin_freq + obj->swo_pin_freq / 2) / obj->swo_pin_freq;
697 if (prescaler > TPIU_ACPR_MAX_PRESCALER)
698 prescaler = TPIU_ACPR_MAX_PRESCALER;
699 swo_pin_freq = obj->traceclkin_freq / prescaler;
700
701 if (obj->swo_pin_freq != swo_pin_freq)
702 LOG_INFO("SWO pin data rate adjusted to %d Hz", swo_pin_freq);
703 obj->swo_pin_freq = swo_pin_freq;
704 }
705
706 retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_CSPSR_OFFSET, BIT(obj->port_width - 1));
707 if (retval != ERROR_OK)
708 goto error_exit;
709
710 retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_ACPR_OFFSET, prescaler - 1);
711 if (retval != ERROR_OK)
712 goto error_exit;
713
714 retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_SPPR_OFFSET, obj->pin_protocol);
715 if (retval != ERROR_OK)
716 goto error_exit;
717
718 retval = wrap_read_u32(target, tpiu_ap, obj->spot.base + TPIU_FFCR_OFFSET, &value);
719 if (retval != ERROR_OK)
720 goto error_exit;
721 if (obj->en_formatter)
722 value |= BIT(1);
723 else
724 value &= ~BIT(1);
725 retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_FFCR_OFFSET, value);
726 if (retval != ERROR_OK)
727 goto error_exit;
728
729 arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_POST_ENABLE);
730
731 obj->enabled = true;
732 return JIM_OK;
733
734 error_exit:
735 LOG_ERROR("Error!");
736
737 if (obj->en_capture) {
738 obj->en_capture = false;
739
740 arm_tpiu_swo_close_output(obj);
741
742 target_unregister_timer_callback(arm_tpiu_swo_poll_trace, obj);
743
744 retval = adapter_config_trace(false, 0, 0, NULL, 0, NULL);
745 if (retval != ERROR_OK) {
746 LOG_ERROR("Failed to stop adapter's trace");
747 return JIM_ERR;
748 }
749 }
750 return JIM_ERR;
751 }
752
753 static int jim_arm_tpiu_swo_disable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
754 {
755 struct arm_tpiu_swo_object *obj = Jim_CmdPrivData(interp);
756
757 if (argc != 1) {
758 Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
759 return JIM_ERR;
760 }
761
762 if (!obj->enabled)
763 return JIM_OK;
764 obj->enabled = false;
765
766 arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_PRE_DISABLE);
767
768 if (obj->en_capture) {
769 obj->en_capture = false;
770
771 arm_tpiu_swo_close_output(obj);
772
773 target_unregister_timer_callback(arm_tpiu_swo_poll_trace, obj);
774
775 int retval = adapter_config_trace(false, 0, 0, NULL, 0, NULL);
776 if (retval != ERROR_OK) {
777 LOG_ERROR("Failed to stop adapter's trace");
778 return JIM_ERR;
779 }
780 }
781
782 arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_POST_DISABLE);
783 return JIM_OK;
784 }
785
786 static const struct command_registration arm_tpiu_swo_instance_command_handlers[] = {
787 {
788 .name = "configure",
789 .mode = COMMAND_ANY,
790 .jim_handler = jim_arm_tpiu_swo_configure,
791 .help = "configure a new TPIU/SWO for use",
792 .usage = "[attribute value ...]",
793 },
794 {
795 .name = "cget",
796 .mode = COMMAND_ANY,
797 .jim_handler = jim_arm_tpiu_swo_configure,
798 .help = "returns the specified TPIU/SWO attribute",
799 .usage = "attribute",
800 },
801 {
802 .name = "eventlist",
803 .mode = COMMAND_ANY,
804 .handler = handle_arm_tpiu_swo_event_list,
805 .help = "displays a table of events defined for this TPIU/SWO",
806 .usage = "",
807 },
808 {
809 .name = "enable",
810 .mode = COMMAND_ANY,
811 .jim_handler = jim_arm_tpiu_swo_enable,
812 .usage = "",
813 .help = "Enables the TPIU/SWO output",
814 },
815 {
816 .name = "disable",
817 .mode = COMMAND_EXEC,
818 .jim_handler = jim_arm_tpiu_swo_disable,
819 .usage = "",
820 .help = "Disables the TPIU/SWO output",
821 },
822 COMMAND_REGISTRATION_DONE
823 };
824
825 static int arm_tpiu_swo_create(Jim_Interp *interp, struct arm_tpiu_swo_object *obj)
826 {
827 struct command_context *cmd_ctx;
828 Jim_Cmd *cmd;
829 int e;
830
831 cmd_ctx = current_command_context(interp);
832 assert(cmd_ctx != NULL);
833
834 /* does this command exist? */
835 cmd = Jim_GetCommand(interp, Jim_NewStringObj(interp, obj->name, -1), JIM_ERRMSG);
836 if (cmd) {
837 Jim_SetResultFormatted(interp, "Command: %s Exists", obj->name);
838 return JIM_ERR;
839 }
840
841 /* now - create the new tpiu/swo name command */
842 const struct command_registration obj_commands[] = {
843 {
844 .name = obj->name,
845 .mode = COMMAND_ANY,
846 .help = "tpiu/swo instance command group",
847 .usage = "",
848 .chain = arm_tpiu_swo_instance_command_handlers,
849 },
850 COMMAND_REGISTRATION_DONE
851 };
852 e = register_commands(cmd_ctx, NULL, obj_commands);
853 if (ERROR_OK != e)
854 return JIM_ERR;
855
856 struct command *c = command_find_in_context(cmd_ctx, obj->name);
857 assert(c);
858 command_set_handler_data(c, obj);
859
860 list_add_tail(&obj->lh, &all_tpiu_swo);
861
862 return JIM_OK;
863 }
864
865 static int jim_arm_tpiu_swo_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
866 {
867 Jim_GetOptInfo goi;
868 Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
869 if (goi.argc < 1) {
870 Jim_WrongNumArgs(goi.interp, 1, goi.argv, "?name? ..options...");
871 return JIM_ERR;
872 }
873
874 struct arm_tpiu_swo_object *obj = calloc(1, sizeof(struct arm_tpiu_swo_object));
875 if (!obj) {
876 LOG_ERROR("Out of memory");
877 return JIM_ERR;
878 }
879 INIT_LIST_HEAD(&obj->connections);
880 adiv5_mem_ap_spot_init(&obj->spot);
881 obj->spot.base = TPIU_SWO_DEFAULT_BASE;
882 obj->port_width = 1;
883
884 Jim_Obj *n;
885 Jim_GetOpt_Obj(&goi, &n);
886 obj->name = strdup(Jim_GetString(n, NULL));
887 if (!obj->name) {
888 LOG_ERROR("Out of memory");
889 free(obj);
890 return JIM_ERR;
891 }
892
893 /* Do the rest as "configure" options */
894 goi.isconfigure = 1;
895 int e = arm_tpiu_swo_configure(&goi, obj);
896 if (e != JIM_OK)
897 goto err_exit;
898
899 if (!obj->spot.dap || obj->spot.ap_num == DP_APSEL_INVALID) {
900 Jim_SetResultString(goi.interp, "-dap and -ap-num required when creating TPIU", -1);
901 goto err_exit;
902 }
903
904 e = arm_tpiu_swo_create(goi.interp, obj);
905 if (e != JIM_OK)
906 goto err_exit;
907
908 return JIM_OK;
909
910 err_exit:
911 free(obj->name);
912 free(obj->out_filename);
913 free(obj);
914 return JIM_ERR;
915 }
916
917 static int jim_arm_tpiu_swo_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
918 {
919 struct arm_tpiu_swo_object *obj;
920
921 if (argc != 1) {
922 Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
923 return JIM_ERR;
924 }
925 Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
926 list_for_each_entry(obj, &all_tpiu_swo, lh) {
927 Jim_ListAppendElement(interp, Jim_GetResult(interp),
928 Jim_NewStringObj(interp, obj->name, -1));
929 }
930 return JIM_OK;
931 }
932
933 static int jim_arm_tpiu_swo_init(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
934 {
935 struct command_context *cmd_ctx = current_command_context(interp);
936 struct arm_tpiu_swo_object *obj;
937 int retval = JIM_OK;
938
939 if (argc != 1) {
940 Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
941 return JIM_ERR;
942 }
943 list_for_each_entry(obj, &all_tpiu_swo, lh) {
944 if (!obj->deferred_enable)
945 continue;
946 LOG_DEBUG("%s: running enable during init", obj->name);
947 int retval2 = command_run_linef(cmd_ctx, "%s enable", obj->name);
948 if (retval2 != ERROR_OK)
949 retval = JIM_ERR;
950 }
951 return retval;
952 }
953
954 static const struct command_registration arm_tpiu_swo_subcommand_handlers[] = {
955 {
956 .name = "create",
957 .mode = COMMAND_ANY,
958 .jim_handler = jim_arm_tpiu_swo_create,
959 .usage = "name [-dap dap] [-ap-num num] [-address baseaddr]",
960 .help = "Creates a new TPIU or SWO object",
961 },
962 {
963 .name = "names",
964 .mode = COMMAND_ANY,
965 .jim_handler = jim_arm_tpiu_swo_names,
966 .usage = "",
967 .help = "Lists all registered TPIU and SWO objects by name",
968 },
969 {
970 .name = "init",
971 .mode = COMMAND_EXEC,
972 .jim_handler = jim_arm_tpiu_swo_init,
973 .usage = "",
974 .help = "Initialize TPIU and SWO",
975 },
976 COMMAND_REGISTRATION_DONE
977 };
978
979 static const struct command_registration arm_tpiu_swo_command_handlers[] = {
980 {
981 .name = "tpiu",
982 .chain = arm_tpiu_swo_subcommand_handlers,
983 .usage = "",
984 .help = "tpiu command group",
985 },
986 {
987 .name = "swo",
988 .chain = arm_tpiu_swo_subcommand_handlers,
989 .usage = "",
990 .help = "swo command group",
991 },
992 COMMAND_REGISTRATION_DONE
993 };
994
995 int arm_tpiu_swo_register_commands(struct command_context *cmd_ctx)
996 {
997 return register_commands(cmd_ctx, NULL, arm_tpiu_swo_command_handlers);
998 }

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)