1 /* SPDX-License-Identifier: GPL-2.0-or-later */
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).
12 * Relevant specifications from ARM include:
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
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"
41 #define TCP_SERVICE_NAME "tpiu_swo_trace"
43 /* default for Cortex-M3 and Cortex-M4 specific TPIU */
44 #define TPIU_SWO_DEFAULT_BASE 0xE0040000
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
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)
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
,
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" },
77 struct arm_tpiu_swo_event_action
{
78 enum arm_tpiu_swo_event event
;
81 struct arm_tpiu_swo_event_action
*next
;
84 struct arm_tpiu_swo_object
{
86 struct adiv5_mem_ap_spot spot
;
88 struct arm_tpiu_swo_event_action
*event_action
;
89 /* record enable before init */
93 /** Handle to output trace data in INTERNAL capture mode */
94 /** Synchronous output port width */
98 unsigned int pin_protocol
;
99 /** Enable 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 */
107 /** track TCP connections */
108 struct list_head connections
;
111 struct arm_tpiu_swo_connection
{
113 struct connection
*connection
;
116 struct arm_tpiu_swo_priv_connection
{
117 struct arm_tpiu_swo_object
*obj
;
120 static LIST_HEAD(all_tpiu_swo
);
122 #define ARM_TPIU_SWO_TRACE_BUF_SIZE 4096
124 static int arm_tpiu_swo_poll_trace(void *priv
)
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
;
131 int retval
= adapter_poll_trace(buf
, &size
);
132 if (retval
!= ERROR_OK
|| !size
)
135 target_call_trace_callbacks(/*target*/NULL
, size
, buf
);
138 if (fwrite(buf
, 1, size
, obj
->file
) == size
) {
141 LOG_ERROR("Error writing to the SWO trace destination file");
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
)
154 static void arm_tpiu_swo_handle_event(struct arm_tpiu_swo_object
*obj
, enum arm_tpiu_swo_event event
)
156 for (struct arm_tpiu_swo_event_action
*ea
= obj
->event_action
; ea
; ea
= ea
->next
) {
157 if (ea
->event
!= event
)
160 LOG_DEBUG("TPIU/SWO: %s event: %s (%d) action : %s",
162 Jim_Nvp_value2name_simple(nvp_arm_tpiu_swo_event
, event
)->name
,
164 Jim_GetString(ea
->body
, NULL
));
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
;
172 if (retval
== JIM_RETURN
)
173 retval
= ea
->interp
->returnCode
;
174 if (retval
== JIM_OK
|| retval
== ERROR_COMMAND_CLOSE_CONNECTION
)
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
,
181 Jim_GetString(Jim_GetResult(ea
->interp
), NULL
));
182 /* clean both error code and stacktrace before return */
183 Jim_Eval(ea
->interp
, "error \"\" \"\"");
188 static void arm_tpiu_swo_close_output(struct arm_tpiu_swo_object
*obj
)
194 if (obj
->out_filename
&& obj
->out_filename
[0] == ':')
195 remove_service(TCP_SERVICE_NAME
, &obj
->out_filename
[1]);
198 int arm_tpiu_swo_cleanup_all(void)
200 struct arm_tpiu_swo_object
*obj
, *tmp
;
202 list_for_each_entry_safe(obj
, tmp
, &all_tpiu_swo
, lh
) {
204 arm_tpiu_swo_handle_event(obj
, TPIU_SWO_EVENT_PRE_DISABLE
);
206 arm_tpiu_swo_close_output(obj
);
208 if (obj
->en_capture
) {
209 target_unregister_timer_callback(arm_tpiu_swo_poll_trace
, obj
);
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");
217 arm_tpiu_swo_handle_event(obj
, TPIU_SWO_EVENT_POST_DISABLE
);
219 struct arm_tpiu_swo_event_action
*ea
= obj
->event_action
;
221 struct arm_tpiu_swo_event_action
*next
= ea
->next
;
222 Jim_DecrRefCount(ea
->interp
, ea
->body
);
228 free(obj
->out_filename
);
235 static int arm_tpiu_swo_service_new_connection(struct connection
*connection
)
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
));
241 LOG_ERROR("Out of memory");
244 c
->connection
= connection
;
245 list_add(&c
->lh
, &obj
->connections
);
249 static int arm_tpiu_swo_service_input(struct connection
*connection
)
251 /* read a dummy buffer to check if the connection is still active */
253 int bytes_read
= connection_read(connection
, &dummy
, sizeof(dummy
));
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
;
265 static int arm_tpiu_swo_service_connection_closed(struct connection
*connection
)
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
;
271 list_for_each_entry_safe(c
, tmp
, &obj
->connections
, lh
)
272 if (c
->connection
== connection
) {
277 LOG_ERROR("Failed to find connection to close!");
281 COMMAND_HANDLER(handle_arm_tpiu_swo_event_list
)
283 struct arm_tpiu_swo_object
*obj
= CMD_DATA
;
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 "----------------------------------------");
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
));
295 command_print(CMD
, "***END***");
299 enum arm_tpiu_swo_cfg_param
{
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 },
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 },
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 },
343 static int arm_tpiu_swo_configure(Jim_GetOptInfo
*goi
, struct arm_tpiu_swo_object
*obj
)
347 if (goi
->isconfigure
&& obj
->enabled
) {
348 Jim_SetResultFormatted(goi
->interp
, "Cannot configure TPIU/SWO; %s is enabled!", obj
->name
);
352 /* parse config or cget options ... */
353 while (goi
->argc
> 0) {
354 Jim_SetEmptyResult(goi
->interp
);
356 int e
= adiv5_jim_mem_ap_spot_configure(&obj
->spot
, goi
);
363 e
= Jim_GetOpt_Nvp(goi
, nvp_arm_tpiu_swo_config_opts
, &n
);
365 Jim_GetOpt_NvpUnknown(goi
, nvp_arm_tpiu_swo_config_opts
, 0);
371 if (goi
->isconfigure
) {
373 e
= Jim_GetOpt_Wide(goi
, &port_width
);
376 if (port_width
< 1 || port_width
> 32) {
377 Jim_SetResultString(goi
->interp
, "Invalid port width!", -1);
380 obj
->port_width
= (uint32_t)port_width
;
384 Jim_SetResult(goi
->interp
, Jim_NewIntObj(goi
->interp
, obj
->port_width
));
388 if (goi
->isconfigure
) {
390 e
= Jim_GetOpt_Nvp(goi
, nvp_arm_tpiu_swo_protocol_opts
, &p
);
393 obj
->pin_protocol
= p
->value
;
398 e
= Jim_Nvp_value2name(goi
->interp
, nvp_arm_tpiu_swo_protocol_opts
, obj
->pin_protocol
, &p
);
400 Jim_SetResultString(goi
->interp
, "protocol error", -1);
403 Jim_SetResult(goi
->interp
, Jim_NewStringObj(goi
->interp
, p
->name
, -1));
407 if (goi
->isconfigure
) {
409 e
= Jim_GetOpt_Nvp(goi
, nvp_arm_tpiu_swo_bool_opts
, &p
);
412 obj
->en_formatter
= p
->value
;
417 e
= Jim_Nvp_value2name(goi
->interp
, nvp_arm_tpiu_swo_bool_opts
, obj
->en_formatter
, &p
);
419 Jim_SetResultString(goi
->interp
, "formatter error", -1);
422 Jim_SetResult(goi
->interp
, Jim_NewStringObj(goi
->interp
, p
->name
, -1));
426 if (goi
->isconfigure
) {
428 e
= Jim_GetOpt_Wide(goi
, &clk
);
431 obj
->traceclkin_freq
= clk
;
435 Jim_SetResult(goi
->interp
, Jim_NewIntObj(goi
->interp
, obj
->traceclkin_freq
));
439 if (goi
->isconfigure
) {
441 e
= Jim_GetOpt_Wide(goi
, &clk
);
444 obj
->swo_pin_freq
= clk
;
448 Jim_SetResult(goi
->interp
, Jim_NewIntObj(goi
->interp
, obj
->swo_pin_freq
));
452 if (goi
->isconfigure
) {
454 e
= Jim_GetOpt_String(goi
, &s
, NULL
);
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);
465 free(obj
->out_filename
);
466 obj
->out_filename
= strdup(s
);
467 if (!obj
->out_filename
) {
468 LOG_ERROR("Out of memory");
474 if (obj
->out_filename
)
475 Jim_SetResult(goi
->interp
, Jim_NewStringObj(goi
->interp
, obj
->out_filename
, -1));
479 if (goi
->isconfigure
) {
481 Jim_WrongNumArgs(goi
->interp
, goi
->argc
, goi
->argv
, "-event ?event-name? ?EVENT-BODY?");
485 if (goi
->argc
!= 1) {
486 Jim_WrongNumArgs(goi
->interp
, goi
->argc
, goi
->argv
, "-event ?event-name?");
494 struct arm_tpiu_swo_event_action
*ea
= obj
->event_action
;
496 e
= Jim_GetOpt_Nvp(goi
, nvp_arm_tpiu_swo_event
, &p
);
498 Jim_GetOpt_NvpUnknown(goi
, nvp_arm_tpiu_swo_event
, 1);
503 /* replace existing? */
504 if (ea
->event
== (enum arm_tpiu_swo_event
)p
->value
)
509 if (goi
->isconfigure
) {
511 ea
= calloc(1, sizeof(*ea
));
513 LOG_ERROR("Out of memory");
516 ea
->next
= obj
->event_action
;
517 obj
->event_action
= ea
;
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
);
528 Jim_SetResult(goi
->interp
, Jim_DuplicateObj(goi
->interp
, ea
->body
));
538 Jim_WrongNumArgs(goi
->interp
, goi
->argc
, goi
->argv
, "NO PARAMS");
542 static int jim_arm_tpiu_swo_configure(Jim_Interp
*interp
, int argc
, Jim_Obj
* const *argv
)
546 Jim_GetOpt_Setup(&goi
, interp
, argc
- 1, argv
+ 1);
547 goi
.isconfigure
= !strcmp(Jim_GetString(argv
[0], NULL
), "configure");
549 Jim_WrongNumArgs(goi
.interp
, goi
.argc
, goi
.argv
,
550 "missing: -option ...");
553 struct arm_tpiu_swo_object
*obj
= Jim_CmdPrivData(interp
);
554 return arm_tpiu_swo_configure(&goi
, obj
);
557 static int wrap_write_u32(struct target
*target
, struct adiv5_ap
*tpiu_ap
,
558 target_addr_t address
, uint32_t value
)
560 if (transport_is_hla())
561 return target_write_u32(target
, address
, value
);
563 return mem_ap_write_atomic_u32(tpiu_ap
, address
, value
);
566 static int wrap_read_u32(struct target
*target
, struct adiv5_ap
*tpiu_ap
,
567 target_addr_t address
, uint32_t *value
)
569 if (transport_is_hla())
570 return target_read_u32(target
, address
, value
);
572 return mem_ap_read_atomic_u32(tpiu_ap
, address
, value
);
575 static int jim_arm_tpiu_swo_enable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
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
);
584 Jim_WrongNumArgs(interp
, 1, argv
, "Too many parameters");
588 if (cmd_ctx
->mode
== COMMAND_CONFIG
) {
589 LOG_DEBUG("%s: enable deferred", obj
->name
);
590 obj
->deferred_enable
= true;
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
);
602 if (!obj
->traceclkin_freq
) {
603 LOG_ERROR("Trace clock-in frequency not set");
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");
613 struct target
*target
= get_current_target(cmd_ctx
);
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
);
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
);
623 switch (obj
->pin_protocol
) {
624 case TPIU_SPPR_PROTOCOL_SYNC
:
625 value
= !(value
& TPIU_DEVID_NOSUPPORT_SYNC
);
627 case TPIU_SPPR_PROTOCOL_UART
:
628 value
&= TPIU_DEVID_SUPPORT_UART
;
630 case TPIU_SPPR_PROTOCOL_MANCHESTER
:
631 value
&= TPIU_DEVID_SUPPORT_MANCHESTER
;
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
);
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
);
651 uint16_t prescaler
= 1; /* dummy value */
652 unsigned int swo_pin_freq
= obj
->swo_pin_freq
; /* could be replaced */
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
));
658 LOG_ERROR("Out of memory");
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
,
667 if (retval
!= ERROR_OK
) {
668 LOG_ERROR("Can't configure trace TCP port %s", &obj
->out_filename
[1]);
671 } else if (strcmp(obj
->out_filename
, "-")) {
672 obj
->file
= fopen(obj
->out_filename
, "ab");
674 LOG_ERROR("Can't open trace destination file \"%s\"", obj
->out_filename
);
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
);
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
;
691 target_register_timer_callback(arm_tpiu_swo_poll_trace
, 1,
692 TARGET_TIMER_TYPE_PERIODIC
, obj
);
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
;
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
;
706 retval
= wrap_write_u32(target
, tpiu_ap
, obj
->spot
.base
+ TPIU_CSPSR_OFFSET
, BIT(obj
->port_width
- 1));
707 if (retval
!= ERROR_OK
)
710 retval
= wrap_write_u32(target
, tpiu_ap
, obj
->spot
.base
+ TPIU_ACPR_OFFSET
, prescaler
- 1);
711 if (retval
!= ERROR_OK
)
714 retval
= wrap_write_u32(target
, tpiu_ap
, obj
->spot
.base
+ TPIU_SPPR_OFFSET
, obj
->pin_protocol
);
715 if (retval
!= ERROR_OK
)
718 retval
= wrap_read_u32(target
, tpiu_ap
, obj
->spot
.base
+ TPIU_FFCR_OFFSET
, &value
);
719 if (retval
!= ERROR_OK
)
721 if (obj
->en_formatter
)
725 retval
= wrap_write_u32(target
, tpiu_ap
, obj
->spot
.base
+ TPIU_FFCR_OFFSET
, value
);
726 if (retval
!= ERROR_OK
)
729 arm_tpiu_swo_handle_event(obj
, TPIU_SWO_EVENT_POST_ENABLE
);
737 if (obj
->en_capture
) {
738 obj
->en_capture
= false;
740 arm_tpiu_swo_close_output(obj
);
742 target_unregister_timer_callback(arm_tpiu_swo_poll_trace
, obj
);
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");
753 static int jim_arm_tpiu_swo_disable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
755 struct arm_tpiu_swo_object
*obj
= Jim_CmdPrivData(interp
);
758 Jim_WrongNumArgs(interp
, 1, argv
, "Too many parameters");
764 obj
->enabled
= false;
766 arm_tpiu_swo_handle_event(obj
, TPIU_SWO_EVENT_PRE_DISABLE
);
768 if (obj
->en_capture
) {
769 obj
->en_capture
= false;
771 arm_tpiu_swo_close_output(obj
);
773 target_unregister_timer_callback(arm_tpiu_swo_poll_trace
, obj
);
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");
782 arm_tpiu_swo_handle_event(obj
, TPIU_SWO_EVENT_POST_DISABLE
);
786 static const struct command_registration arm_tpiu_swo_instance_command_handlers
[] = {
790 .jim_handler
= jim_arm_tpiu_swo_configure
,
791 .help
= "configure a new TPIU/SWO for use",
792 .usage
= "[attribute value ...]",
797 .jim_handler
= jim_arm_tpiu_swo_configure
,
798 .help
= "returns the specified TPIU/SWO attribute",
799 .usage
= "attribute",
804 .handler
= handle_arm_tpiu_swo_event_list
,
805 .help
= "displays a table of events defined for this TPIU/SWO",
811 .jim_handler
= jim_arm_tpiu_swo_enable
,
813 .help
= "Enables the TPIU/SWO output",
817 .mode
= COMMAND_EXEC
,
818 .jim_handler
= jim_arm_tpiu_swo_disable
,
820 .help
= "Disables the TPIU/SWO output",
822 COMMAND_REGISTRATION_DONE
825 static int arm_tpiu_swo_create(Jim_Interp
*interp
, struct arm_tpiu_swo_object
*obj
)
827 struct command_context
*cmd_ctx
;
831 cmd_ctx
= current_command_context(interp
);
832 assert(cmd_ctx
!= NULL
);
834 /* does this command exist? */
835 cmd
= Jim_GetCommand(interp
, Jim_NewStringObj(interp
, obj
->name
, -1), JIM_ERRMSG
);
837 Jim_SetResultFormatted(interp
, "Command: %s Exists", obj
->name
);
841 /* now - create the new tpiu/swo name command */
842 const struct command_registration obj_commands
[] = {
846 .help
= "tpiu/swo instance command group",
848 .chain
= arm_tpiu_swo_instance_command_handlers
,
850 COMMAND_REGISTRATION_DONE
852 e
= register_commands(cmd_ctx
, NULL
, obj_commands
);
856 struct command
*c
= command_find_in_context(cmd_ctx
, obj
->name
);
858 command_set_handler_data(c
, obj
);
860 list_add_tail(&obj
->lh
, &all_tpiu_swo
);
865 static int jim_arm_tpiu_swo_create(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
868 Jim_GetOpt_Setup(&goi
, interp
, argc
- 1, argv
+ 1);
870 Jim_WrongNumArgs(goi
.interp
, 1, goi
.argv
, "?name? ..options...");
874 struct arm_tpiu_swo_object
*obj
= calloc(1, sizeof(struct arm_tpiu_swo_object
));
876 LOG_ERROR("Out of memory");
879 INIT_LIST_HEAD(&obj
->connections
);
880 adiv5_mem_ap_spot_init(&obj
->spot
);
881 obj
->spot
.base
= TPIU_SWO_DEFAULT_BASE
;
885 Jim_GetOpt_Obj(&goi
, &n
);
886 obj
->name
= strdup(Jim_GetString(n
, NULL
));
888 LOG_ERROR("Out of memory");
893 /* Do the rest as "configure" options */
895 int e
= arm_tpiu_swo_configure(&goi
, obj
);
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);
904 e
= arm_tpiu_swo_create(goi
.interp
, obj
);
912 free(obj
->out_filename
);
917 static int jim_arm_tpiu_swo_names(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
919 struct arm_tpiu_swo_object
*obj
;
922 Jim_WrongNumArgs(interp
, 1, argv
, "Too many parameters");
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));
933 static int jim_arm_tpiu_swo_init(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
935 struct command_context
*cmd_ctx
= current_command_context(interp
);
936 struct arm_tpiu_swo_object
*obj
;
940 Jim_WrongNumArgs(interp
, 1, argv
, "Too many parameters");
943 list_for_each_entry(obj
, &all_tpiu_swo
, lh
) {
944 if (!obj
->deferred_enable
)
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
)
954 static const struct command_registration arm_tpiu_swo_subcommand_handlers
[] = {
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",
965 .jim_handler
= jim_arm_tpiu_swo_names
,
967 .help
= "Lists all registered TPIU and SWO objects by name",
971 .mode
= COMMAND_EXEC
,
972 .jim_handler
= jim_arm_tpiu_swo_init
,
974 .help
= "Initialize TPIU and SWO",
976 COMMAND_REGISTRATION_DONE
979 static const struct command_registration arm_tpiu_swo_command_handlers
[] = {
982 .chain
= arm_tpiu_swo_subcommand_handlers
,
984 .help
= "tpiu command group",
988 .chain
= arm_tpiu_swo_subcommand_handlers
,
990 .help
= "swo command group",
992 COMMAND_REGISTRATION_DONE
995 int arm_tpiu_swo_register_commands(struct command_context
*cmd_ctx
)
997 return register_commands(cmd_ctx
, NULL
, arm_tpiu_swo_command_handlers
);