arm_tpiu_swo: add support for independent TPIU and SWO
[fw/openocd] / 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 }