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 /* START_DEPRECATED_TPIU */
42 #include <target/cortex_m.h>
43 #include <target/target_type.h>
44 #define MSG "DEPRECATED \'tpiu config\' command: "
45 /* END_DEPRECATED_TPIU */
47 #define TCP_SERVICE_NAME "tpiu_swo_trace"
49 /* default for Cortex-M3 and Cortex-M4 specific TPIU */
50 #define TPIU_SWO_DEFAULT_BASE 0xE0040000
52 #define TPIU_SSPSR_OFFSET 0x000
53 #define TPIU_CSPSR_OFFSET 0x004
54 #define TPIU_ACPR_OFFSET 0x010
55 #define TPIU_SPPR_OFFSET 0x0F0
56 #define TPIU_FFSR_OFFSET 0x300
57 #define TPIU_FFCR_OFFSET 0x304
58 #define TPIU_FSCR_OFFSET 0x308
59 #define TPIU_DEVID_OFFSET 0xfc8
61 #define TPIU_ACPR_MAX_PRESCALER 0x1fff
62 #define TPIU_SPPR_PROTOCOL_SYNC (TPIU_PIN_PROTOCOL_SYNC)
63 #define TPIU_SPPR_PROTOCOL_MANCHESTER (TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER)
64 #define TPIU_SPPR_PROTOCOL_UART (TPIU_PIN_PROTOCOL_ASYNC_UART)
65 #define TPIU_DEVID_NOSUPPORT_SYNC BIT(9)
66 #define TPIU_DEVID_SUPPORT_MANCHESTER BIT(10)
67 #define TPIU_DEVID_SUPPORT_UART BIT(11)
69 enum arm_tpiu_swo_event
{
70 TPIU_SWO_EVENT_PRE_ENABLE
,
71 TPIU_SWO_EVENT_POST_ENABLE
,
72 TPIU_SWO_EVENT_PRE_DISABLE
,
73 TPIU_SWO_EVENT_POST_DISABLE
,
76 static const struct jim_nvp nvp_arm_tpiu_swo_event
[] = {
77 { .value
= TPIU_SWO_EVENT_PRE_ENABLE
, .name
= "pre-enable" },
78 { .value
= TPIU_SWO_EVENT_POST_ENABLE
, .name
= "post-enable" },
79 { .value
= TPIU_SWO_EVENT_PRE_DISABLE
, .name
= "pre-disable" },
80 { .value
= TPIU_SWO_EVENT_POST_DISABLE
, .name
= "post-disable" },
83 struct arm_tpiu_swo_event_action
{
84 enum arm_tpiu_swo_event event
;
87 struct arm_tpiu_swo_event_action
*next
;
90 struct arm_tpiu_swo_object
{
92 struct adiv5_mem_ap_spot spot
;
94 struct arm_tpiu_swo_event_action
*event_action
;
95 /* record enable before init */
99 /** Handle to output trace data in INTERNAL capture mode */
100 /** Synchronous output port width */
104 unsigned int pin_protocol
;
105 /** Enable formatter */
107 /** frequency of TRACECLKIN (usually matches HCLK) */
108 unsigned int traceclkin_freq
;
109 /** SWO pin frequency */
110 unsigned int swo_pin_freq
;
111 /** where to dump the captured output trace data */
113 /** track TCP connections */
114 struct list_head connections
;
115 /* START_DEPRECATED_TPIU */
116 bool recheck_ap_cur_target
;
117 /* END_DEPRECATED_TPIU */
120 struct arm_tpiu_swo_connection
{
122 struct connection
*connection
;
125 struct arm_tpiu_swo_priv_connection
{
126 struct arm_tpiu_swo_object
*obj
;
129 static LIST_HEAD(all_tpiu_swo
);
131 #define ARM_TPIU_SWO_TRACE_BUF_SIZE 4096
133 static int arm_tpiu_swo_poll_trace(void *priv
)
135 struct arm_tpiu_swo_object
*obj
= priv
;
136 uint8_t buf
[ARM_TPIU_SWO_TRACE_BUF_SIZE
];
137 size_t size
= sizeof(buf
);
138 struct arm_tpiu_swo_connection
*c
;
140 int retval
= adapter_poll_trace(buf
, &size
);
141 if (retval
!= ERROR_OK
|| !size
)
144 target_call_trace_callbacks(/*target*/NULL
, size
, buf
);
147 if (fwrite(buf
, 1, size
, obj
->file
) == size
) {
150 LOG_ERROR("Error writing to the SWO trace destination file");
155 if (obj
->out_filename
&& obj
->out_filename
[0] == ':')
156 list_for_each_entry(c
, &obj
->connections
, lh
)
157 if (connection_write(c
->connection
, buf
, size
) != (int)size
)
163 static void arm_tpiu_swo_handle_event(struct arm_tpiu_swo_object
*obj
, enum arm_tpiu_swo_event event
)
165 for (struct arm_tpiu_swo_event_action
*ea
= obj
->event_action
; ea
; ea
= ea
->next
) {
166 if (ea
->event
!= event
)
169 LOG_DEBUG("TPIU/SWO: %s event: %s (%d) action : %s",
171 jim_nvp_value2name_simple(nvp_arm_tpiu_swo_event
, event
)->name
,
173 Jim_GetString(ea
->body
, NULL
));
175 /* prevent event execution to change current target */
176 struct command_context
*cmd_ctx
= current_command_context(ea
->interp
);
177 struct target
*saved_target
= cmd_ctx
->current_target
;
178 int retval
= Jim_EvalObj(ea
->interp
, ea
->body
);
179 cmd_ctx
->current_target
= saved_target
;
181 if (retval
== JIM_RETURN
)
182 retval
= ea
->interp
->returnCode
;
183 if (retval
== JIM_OK
|| retval
== ERROR_COMMAND_CLOSE_CONNECTION
)
186 Jim_MakeErrorMessage(ea
->interp
);
187 LOG_USER("Error executing event %s on TPIU/SWO %s:\n%s",
188 jim_nvp_value2name_simple(nvp_arm_tpiu_swo_event
, event
)->name
,
190 Jim_GetString(Jim_GetResult(ea
->interp
), NULL
));
191 /* clean both error code and stacktrace before return */
192 Jim_Eval(ea
->interp
, "error \"\" \"\"");
197 static void arm_tpiu_swo_close_output(struct arm_tpiu_swo_object
*obj
)
203 if (obj
->out_filename
&& obj
->out_filename
[0] == ':')
204 remove_service(TCP_SERVICE_NAME
, &obj
->out_filename
[1]);
207 int arm_tpiu_swo_cleanup_all(void)
209 struct arm_tpiu_swo_object
*obj
, *tmp
;
211 list_for_each_entry_safe(obj
, tmp
, &all_tpiu_swo
, lh
) {
213 arm_tpiu_swo_handle_event(obj
, TPIU_SWO_EVENT_PRE_DISABLE
);
215 arm_tpiu_swo_close_output(obj
);
217 if (obj
->en_capture
) {
218 target_unregister_timer_callback(arm_tpiu_swo_poll_trace
, obj
);
220 int retval
= adapter_config_trace(false, 0, 0, NULL
, 0, NULL
);
221 if (retval
!= ERROR_OK
)
222 LOG_ERROR("Failed to stop adapter's trace");
226 arm_tpiu_swo_handle_event(obj
, TPIU_SWO_EVENT_POST_DISABLE
);
228 struct arm_tpiu_swo_event_action
*ea
= obj
->event_action
;
230 struct arm_tpiu_swo_event_action
*next
= ea
->next
;
231 Jim_DecrRefCount(ea
->interp
, ea
->body
);
237 free(obj
->out_filename
);
244 static int arm_tpiu_swo_service_new_connection(struct connection
*connection
)
246 struct arm_tpiu_swo_priv_connection
*priv
= connection
->service
->priv
;
247 struct arm_tpiu_swo_object
*obj
= priv
->obj
;
248 struct arm_tpiu_swo_connection
*c
= malloc(sizeof(*c
));
250 LOG_ERROR("Out of memory");
253 c
->connection
= connection
;
254 list_add(&c
->lh
, &obj
->connections
);
258 static int arm_tpiu_swo_service_input(struct connection
*connection
)
260 /* read a dummy buffer to check if the connection is still active */
262 int bytes_read
= connection_read(connection
, &dummy
, sizeof(dummy
));
264 if (bytes_read
== 0) {
265 return ERROR_SERVER_REMOTE_CLOSED
;
266 } else if (bytes_read
== -1) {
267 LOG_ERROR("error during read: %s", strerror(errno
));
268 return ERROR_SERVER_REMOTE_CLOSED
;
274 static int arm_tpiu_swo_service_connection_closed(struct connection
*connection
)
276 struct arm_tpiu_swo_priv_connection
*priv
= connection
->service
->priv
;
277 struct arm_tpiu_swo_object
*obj
= priv
->obj
;
278 struct arm_tpiu_swo_connection
*c
, *tmp
;
280 list_for_each_entry_safe(c
, tmp
, &obj
->connections
, lh
)
281 if (c
->connection
== connection
) {
286 LOG_ERROR("Failed to find connection to close!");
290 COMMAND_HANDLER(handle_arm_tpiu_swo_event_list
)
292 struct arm_tpiu_swo_object
*obj
= CMD_DATA
;
294 command_print(CMD
, "Event actions for TPIU/SWO %s\n", obj
->name
);
295 command_print(CMD
, "%-25s | Body", "Event");
296 command_print(CMD
, "------------------------- | "
297 "----------------------------------------");
299 for (struct arm_tpiu_swo_event_action
*ea
= obj
->event_action
; ea
; ea
= ea
->next
) {
300 struct jim_nvp
*opt
= jim_nvp_value2name_simple(nvp_arm_tpiu_swo_event
, ea
->event
);
301 command_print(CMD
, "%-25s | %s",
302 opt
->name
, Jim_GetString(ea
->body
, NULL
));
304 command_print(CMD
, "***END***");
308 enum arm_tpiu_swo_cfg_param
{
318 static const struct jim_nvp nvp_arm_tpiu_swo_config_opts
[] = {
319 { .name
= "-port-width", .value
= CFG_PORT_WIDTH
},
320 { .name
= "-protocol", .value
= CFG_PROTOCOL
},
321 { .name
= "-formatter", .value
= CFG_FORMATTER
},
322 { .name
= "-traceclk", .value
= CFG_TRACECLKIN
},
323 { .name
= "-pin-freq", .value
= CFG_BITRATE
},
324 { .name
= "-output", .value
= CFG_OUTFILE
},
325 { .name
= "-event", .value
= CFG_EVENT
},
326 /* handled by mem_ap_spot, added for jim_getopt_nvp_unknown() */
327 { .name
= "-dap", .value
= -1 },
328 { .name
= "-ap-num", .value
= -1 },
329 { .name
= "-baseaddr", .value
= -1 },
330 { .name
= NULL
, .value
= -1 },
333 static const struct jim_nvp nvp_arm_tpiu_swo_protocol_opts
[] = {
334 { .name
= "sync", .value
= TPIU_SPPR_PROTOCOL_SYNC
},
335 { .name
= "uart", .value
= TPIU_SPPR_PROTOCOL_UART
},
336 { .name
= "manchester", .value
= TPIU_SPPR_PROTOCOL_MANCHESTER
},
337 { .name
= NULL
, .value
= -1 },
340 static const struct jim_nvp nvp_arm_tpiu_swo_bool_opts
[] = {
341 { .name
= "on", .value
= 1 },
342 { .name
= "yes", .value
= 1 },
343 { .name
= "1", .value
= 1 },
344 { .name
= "true", .value
= 1 },
345 { .name
= "off", .value
= 0 },
346 { .name
= "no", .value
= 0 },
347 { .name
= "0", .value
= 0 },
348 { .name
= "false", .value
= 0 },
349 { .name
= NULL
, .value
= -1 },
352 static int arm_tpiu_swo_configure(struct jim_getopt_info
*goi
, struct arm_tpiu_swo_object
*obj
)
356 if (goi
->isconfigure
&& obj
->enabled
) {
357 Jim_SetResultFormatted(goi
->interp
, "Cannot configure TPIU/SWO; %s is enabled!", obj
->name
);
361 /* parse config or cget options ... */
362 while (goi
->argc
> 0) {
363 Jim_SetEmptyResult(goi
->interp
);
365 int e
= adiv5_jim_mem_ap_spot_configure(&obj
->spot
, goi
);
372 e
= jim_getopt_nvp(goi
, nvp_arm_tpiu_swo_config_opts
, &n
);
374 jim_getopt_nvp_unknown(goi
, nvp_arm_tpiu_swo_config_opts
, 0);
380 if (goi
->isconfigure
) {
382 e
= jim_getopt_wide(goi
, &port_width
);
385 if (port_width
< 1 || port_width
> 32) {
386 Jim_SetResultString(goi
->interp
, "Invalid port width!", -1);
389 obj
->port_width
= (uint32_t)port_width
;
393 Jim_SetResult(goi
->interp
, Jim_NewIntObj(goi
->interp
, obj
->port_width
));
397 if (goi
->isconfigure
) {
399 e
= jim_getopt_nvp(goi
, nvp_arm_tpiu_swo_protocol_opts
, &p
);
402 obj
->pin_protocol
= p
->value
;
407 e
= jim_nvp_value2name(goi
->interp
, nvp_arm_tpiu_swo_protocol_opts
, obj
->pin_protocol
, &p
);
409 Jim_SetResultString(goi
->interp
, "protocol error", -1);
412 Jim_SetResult(goi
->interp
, Jim_NewStringObj(goi
->interp
, p
->name
, -1));
416 if (goi
->isconfigure
) {
418 e
= jim_getopt_nvp(goi
, nvp_arm_tpiu_swo_bool_opts
, &p
);
421 obj
->en_formatter
= p
->value
;
426 e
= jim_nvp_value2name(goi
->interp
, nvp_arm_tpiu_swo_bool_opts
, obj
->en_formatter
, &p
);
428 Jim_SetResultString(goi
->interp
, "formatter error", -1);
431 Jim_SetResult(goi
->interp
, Jim_NewStringObj(goi
->interp
, p
->name
, -1));
435 if (goi
->isconfigure
) {
437 e
= jim_getopt_wide(goi
, &clk
);
440 obj
->traceclkin_freq
= clk
;
444 Jim_SetResult(goi
->interp
, Jim_NewIntObj(goi
->interp
, obj
->traceclkin_freq
));
448 if (goi
->isconfigure
) {
450 e
= jim_getopt_wide(goi
, &clk
);
453 obj
->swo_pin_freq
= clk
;
457 Jim_SetResult(goi
->interp
, Jim_NewIntObj(goi
->interp
, obj
->swo_pin_freq
));
461 if (goi
->isconfigure
) {
463 e
= jim_getopt_string(goi
, &s
, NULL
);
468 long port
= strtol(s
+ 1, &end
, 0);
469 if (port
<= 0 || port
> UINT16_MAX
|| *end
!= '\0') {
470 Jim_SetResultFormatted(goi
->interp
, "Invalid TCP port \'%s\'", s
+ 1);
474 free(obj
->out_filename
);
475 obj
->out_filename
= strdup(s
);
476 if (!obj
->out_filename
) {
477 LOG_ERROR("Out of memory");
483 if (obj
->out_filename
)
484 Jim_SetResult(goi
->interp
, Jim_NewStringObj(goi
->interp
, obj
->out_filename
, -1));
488 if (goi
->isconfigure
) {
490 Jim_WrongNumArgs(goi
->interp
, goi
->argc
, goi
->argv
, "-event ?event-name? ?EVENT-BODY?");
494 if (goi
->argc
!= 1) {
495 Jim_WrongNumArgs(goi
->interp
, goi
->argc
, goi
->argv
, "-event ?event-name?");
503 struct arm_tpiu_swo_event_action
*ea
= obj
->event_action
;
505 e
= jim_getopt_nvp(goi
, nvp_arm_tpiu_swo_event
, &p
);
507 jim_getopt_nvp_unknown(goi
, nvp_arm_tpiu_swo_event
, 1);
512 /* replace existing? */
513 if (ea
->event
== (enum arm_tpiu_swo_event
)p
->value
)
518 if (goi
->isconfigure
) {
520 ea
= calloc(1, sizeof(*ea
));
522 LOG_ERROR("Out of memory");
525 ea
->next
= obj
->event_action
;
526 obj
->event_action
= ea
;
529 Jim_DecrRefCount(ea
->interp
, ea
->body
);
530 ea
->event
= p
->value
;
531 ea
->interp
= goi
->interp
;
532 jim_getopt_obj(goi
, &o
);
533 ea
->body
= Jim_DuplicateObj(goi
->interp
, o
);
534 Jim_IncrRefCount(ea
->body
);
537 Jim_SetResult(goi
->interp
, Jim_DuplicateObj(goi
->interp
, ea
->body
));
547 Jim_WrongNumArgs(goi
->interp
, goi
->argc
, goi
->argv
, "NO PARAMS");
551 static int jim_arm_tpiu_swo_configure(Jim_Interp
*interp
, int argc
, Jim_Obj
* const *argv
)
553 struct command
*c
= jim_to_command(interp
);
554 struct jim_getopt_info goi
;
556 jim_getopt_setup(&goi
, interp
, argc
- 1, argv
+ 1);
557 goi
.isconfigure
= !strcmp(c
->name
, "configure");
559 Jim_WrongNumArgs(goi
.interp
, goi
.argc
, goi
.argv
,
560 "missing: -option ...");
563 struct arm_tpiu_swo_object
*obj
= c
->jim_handler_data
;
564 return arm_tpiu_swo_configure(&goi
, obj
);
567 static int wrap_write_u32(struct target
*target
, struct adiv5_ap
*tpiu_ap
,
568 target_addr_t address
, uint32_t value
)
570 if (transport_is_hla())
571 return target_write_u32(target
, address
, value
);
573 return mem_ap_write_atomic_u32(tpiu_ap
, address
, value
);
576 static int wrap_read_u32(struct target
*target
, struct adiv5_ap
*tpiu_ap
,
577 target_addr_t address
, uint32_t *value
)
579 if (transport_is_hla())
580 return target_read_u32(target
, address
, value
);
582 return mem_ap_read_atomic_u32(tpiu_ap
, address
, value
);
585 static int jim_arm_tpiu_swo_enable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
587 struct command
*c
= jim_to_command(interp
);
588 struct arm_tpiu_swo_object
*obj
= c
->jim_handler_data
;
589 struct command_context
*cmd_ctx
= current_command_context(interp
);
590 struct adiv5_ap
*tpiu_ap
= dap_ap(obj
->spot
.dap
, obj
->spot
.ap_num
);
595 Jim_WrongNumArgs(interp
, 1, argv
, "Too many parameters");
599 if (cmd_ctx
->mode
== COMMAND_CONFIG
) {
600 LOG_DEBUG("%s: enable deferred", obj
->name
);
601 obj
->deferred_enable
= true;
608 if (transport_is_hla() && obj
->spot
.ap_num
> 0) {
609 LOG_ERROR("Invalid access port %d. Only AP#0 allowed with hla transport", obj
->spot
.ap_num
);
613 if (!obj
->traceclkin_freq
) {
614 LOG_ERROR("Trace clock-in frequency not set");
618 if (obj
->pin_protocol
== TPIU_SPPR_PROTOCOL_MANCHESTER
|| obj
->pin_protocol
== TPIU_SPPR_PROTOCOL_UART
)
619 if (!obj
->swo_pin_freq
) {
620 LOG_ERROR("SWO pin frequency not set");
624 struct target
*target
= get_current_target(cmd_ctx
);
626 /* START_DEPRECATED_TPIU */
627 if (obj
->recheck_ap_cur_target
) {
628 if (strcmp(target
->type
->name
, "cortex_m") &&
629 strcmp(target
->type
->name
, "hla_target")) {
630 LOG_ERROR(MSG
"Current target is not a Cortex-M nor a HLA");
633 if (!target_was_examined(target
)) {
634 LOG_ERROR(MSG
"Current target not examined yet");
637 struct cortex_m_common
*cm
= target_to_cm(target
);
638 obj
->recheck_ap_cur_target
= false;
639 obj
->spot
.ap_num
= cm
->armv7m
.debug_ap
->ap_num
;
640 tpiu_ap
= dap_ap(obj
->spot
.dap
, obj
->spot
.ap_num
);
641 if (obj
->spot
.ap_num
== 0)
642 LOG_INFO(MSG
"Confirmed TPIU %s is on AP 0", obj
->name
);
644 LOG_INFO(MSG
"Target %s is on AP %d. Revised command is "
645 "\'tpiu create %s -dap %s -ap-num %d\'",
646 target_name(target
), obj
->spot
.ap_num
,
647 obj
->name
, adiv5_dap_name(obj
->spot
.dap
), obj
->spot
.ap_num
);
649 /* END_DEPRECATED_TPIU */
651 /* trigger the event before any attempt to R/W in the TPIU/SWO */
652 arm_tpiu_swo_handle_event(obj
, TPIU_SWO_EVENT_PRE_ENABLE
);
654 retval
= wrap_read_u32(target
, tpiu_ap
, obj
->spot
.base
+ TPIU_DEVID_OFFSET
, &value
);
655 if (retval
!= ERROR_OK
) {
656 LOG_ERROR("Unable to read %s", obj
->name
);
659 switch (obj
->pin_protocol
) {
660 case TPIU_SPPR_PROTOCOL_SYNC
:
661 value
= !(value
& TPIU_DEVID_NOSUPPORT_SYNC
);
663 case TPIU_SPPR_PROTOCOL_UART
:
664 value
&= TPIU_DEVID_SUPPORT_UART
;
666 case TPIU_SPPR_PROTOCOL_MANCHESTER
:
667 value
&= TPIU_DEVID_SUPPORT_MANCHESTER
;
674 jim_nvp_value2name(interp
, nvp_arm_tpiu_swo_protocol_opts
, obj
->pin_protocol
, &p
);
675 LOG_ERROR("%s does not support protocol %s", obj
->name
, p
->name
);
679 if (obj
->pin_protocol
== TPIU_SPPR_PROTOCOL_SYNC
) {
680 retval
= wrap_read_u32(target
, tpiu_ap
, obj
->spot
.base
+ TPIU_SSPSR_OFFSET
, &value
);
681 if (!(value
& BIT(obj
->port_width
- 1))) {
682 LOG_ERROR("TPIU does not support port-width of %d bits", obj
->port_width
);
687 uint16_t prescaler
= 1; /* dummy value */
688 unsigned int swo_pin_freq
= obj
->swo_pin_freq
; /* could be replaced */
690 if (obj
->out_filename
&& strcmp(obj
->out_filename
, "external") && obj
->out_filename
[0]) {
691 if (obj
->out_filename
[0] == ':') {
692 struct arm_tpiu_swo_priv_connection
*priv
= malloc(sizeof(*priv
));
694 LOG_ERROR("Out of memory");
698 LOG_INFO("starting trace server for %s on %s", obj
->name
, &obj
->out_filename
[1]);
699 retval
= add_service("tpiu_swo_trace", &obj
->out_filename
[1],
700 CONNECTION_LIMIT_UNLIMITED
, arm_tpiu_swo_service_new_connection
,
701 arm_tpiu_swo_service_input
, arm_tpiu_swo_service_connection_closed
,
703 if (retval
!= ERROR_OK
) {
704 LOG_ERROR("Can't configure trace TCP port %s", &obj
->out_filename
[1]);
707 } else if (strcmp(obj
->out_filename
, "-")) {
708 obj
->file
= fopen(obj
->out_filename
, "ab");
710 LOG_ERROR("Can't open trace destination file \"%s\"", obj
->out_filename
);
715 retval
= adapter_config_trace(true, obj
->pin_protocol
, obj
->port_width
,
716 &swo_pin_freq
, obj
->traceclkin_freq
, &prescaler
);
717 if (retval
!= ERROR_OK
) {
718 LOG_ERROR("Failed to start adapter's trace");
719 arm_tpiu_swo_close_output(obj
);
723 if (obj
->swo_pin_freq
!= swo_pin_freq
)
724 LOG_INFO("SWO pin data rate adjusted by adapter to %d Hz", swo_pin_freq
);
725 obj
->swo_pin_freq
= swo_pin_freq
;
727 target_register_timer_callback(arm_tpiu_swo_poll_trace
, 1,
728 TARGET_TIMER_TYPE_PERIODIC
, obj
);
730 obj
->en_capture
= true;
731 } else if (obj
->pin_protocol
== TPIU_SPPR_PROTOCOL_MANCHESTER
|| obj
->pin_protocol
== TPIU_SPPR_PROTOCOL_UART
) {
732 prescaler
= (obj
->traceclkin_freq
+ obj
->swo_pin_freq
/ 2) / obj
->swo_pin_freq
;
733 if (prescaler
> TPIU_ACPR_MAX_PRESCALER
)
734 prescaler
= TPIU_ACPR_MAX_PRESCALER
;
735 swo_pin_freq
= obj
->traceclkin_freq
/ prescaler
;
737 if (obj
->swo_pin_freq
!= swo_pin_freq
)
738 LOG_INFO("SWO pin data rate adjusted to %d Hz", swo_pin_freq
);
739 obj
->swo_pin_freq
= swo_pin_freq
;
742 retval
= wrap_write_u32(target
, tpiu_ap
, obj
->spot
.base
+ TPIU_CSPSR_OFFSET
, BIT(obj
->port_width
- 1));
743 if (retval
!= ERROR_OK
)
746 retval
= wrap_write_u32(target
, tpiu_ap
, obj
->spot
.base
+ TPIU_ACPR_OFFSET
, prescaler
- 1);
747 if (retval
!= ERROR_OK
)
750 retval
= wrap_write_u32(target
, tpiu_ap
, obj
->spot
.base
+ TPIU_SPPR_OFFSET
, obj
->pin_protocol
);
751 if (retval
!= ERROR_OK
)
754 retval
= wrap_read_u32(target
, tpiu_ap
, obj
->spot
.base
+ TPIU_FFCR_OFFSET
, &value
);
755 if (retval
!= ERROR_OK
)
757 if (obj
->en_formatter
)
761 retval
= wrap_write_u32(target
, tpiu_ap
, obj
->spot
.base
+ TPIU_FFCR_OFFSET
, value
);
762 if (retval
!= ERROR_OK
)
765 arm_tpiu_swo_handle_event(obj
, TPIU_SWO_EVENT_POST_ENABLE
);
767 /* START_DEPRECATED_TPIU */
768 target_handle_event(target
, TARGET_EVENT_TRACE_CONFIG
);
769 /* END_DEPRECATED_TPIU */
777 if (obj
->en_capture
) {
778 obj
->en_capture
= false;
780 arm_tpiu_swo_close_output(obj
);
782 target_unregister_timer_callback(arm_tpiu_swo_poll_trace
, obj
);
784 retval
= adapter_config_trace(false, 0, 0, NULL
, 0, NULL
);
785 if (retval
!= ERROR_OK
) {
786 LOG_ERROR("Failed to stop adapter's trace");
793 static int jim_arm_tpiu_swo_disable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
795 struct command
*c
= jim_to_command(interp
);
796 struct arm_tpiu_swo_object
*obj
= c
->jim_handler_data
;
799 Jim_WrongNumArgs(interp
, 1, argv
, "Too many parameters");
805 obj
->enabled
= false;
807 arm_tpiu_swo_handle_event(obj
, TPIU_SWO_EVENT_PRE_DISABLE
);
809 if (obj
->en_capture
) {
810 obj
->en_capture
= false;
812 arm_tpiu_swo_close_output(obj
);
814 target_unregister_timer_callback(arm_tpiu_swo_poll_trace
, obj
);
816 int retval
= adapter_config_trace(false, 0, 0, NULL
, 0, NULL
);
817 if (retval
!= ERROR_OK
) {
818 LOG_ERROR("Failed to stop adapter's trace");
823 arm_tpiu_swo_handle_event(obj
, TPIU_SWO_EVENT_POST_DISABLE
);
825 /* START_DEPRECATED_TPIU */
826 struct command_context
*cmd_ctx
= current_command_context(interp
);
827 struct target
*target
= get_current_target(cmd_ctx
);
828 target_handle_event(target
, TARGET_EVENT_TRACE_CONFIG
);
829 /* END_DEPRECATED_TPIU */
834 static const struct command_registration arm_tpiu_swo_instance_command_handlers
[] = {
838 .jim_handler
= jim_arm_tpiu_swo_configure
,
839 .help
= "configure a new TPIU/SWO for use",
840 .usage
= "[attribute value ...]",
845 .jim_handler
= jim_arm_tpiu_swo_configure
,
846 .help
= "returns the specified TPIU/SWO attribute",
847 .usage
= "attribute",
852 .handler
= handle_arm_tpiu_swo_event_list
,
853 .help
= "displays a table of events defined for this TPIU/SWO",
859 .jim_handler
= jim_arm_tpiu_swo_enable
,
861 .help
= "Enables the TPIU/SWO output",
865 .mode
= COMMAND_EXEC
,
866 .jim_handler
= jim_arm_tpiu_swo_disable
,
868 .help
= "Disables the TPIU/SWO output",
870 COMMAND_REGISTRATION_DONE
873 static int arm_tpiu_swo_create(Jim_Interp
*interp
, struct arm_tpiu_swo_object
*obj
)
875 struct command_context
*cmd_ctx
;
879 cmd_ctx
= current_command_context(interp
);
882 /* does this command exist? */
883 cmd
= Jim_GetCommand(interp
, Jim_NewStringObj(interp
, obj
->name
, -1), JIM_NONE
);
885 Jim_SetResultFormatted(interp
, "Command: %s Exists", obj
->name
);
889 /* now - create the new tpiu/swo name command */
890 const struct command_registration obj_commands
[] = {
894 .help
= "tpiu/swo instance command group",
896 .chain
= arm_tpiu_swo_instance_command_handlers
,
898 COMMAND_REGISTRATION_DONE
900 e
= register_commands_with_data(cmd_ctx
, NULL
, obj_commands
, obj
);
904 list_add_tail(&obj
->lh
, &all_tpiu_swo
);
909 static int jim_arm_tpiu_swo_create(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
911 struct jim_getopt_info goi
;
912 jim_getopt_setup(&goi
, interp
, argc
- 1, argv
+ 1);
914 Jim_WrongNumArgs(goi
.interp
, 1, goi
.argv
, "?name? ..options...");
918 struct arm_tpiu_swo_object
*obj
= calloc(1, sizeof(struct arm_tpiu_swo_object
));
920 LOG_ERROR("Out of memory");
923 INIT_LIST_HEAD(&obj
->connections
);
924 adiv5_mem_ap_spot_init(&obj
->spot
);
925 obj
->spot
.base
= TPIU_SWO_DEFAULT_BASE
;
929 jim_getopt_obj(&goi
, &n
);
930 obj
->name
= strdup(Jim_GetString(n
, NULL
));
932 LOG_ERROR("Out of memory");
937 /* Do the rest as "configure" options */
939 int e
= arm_tpiu_swo_configure(&goi
, obj
);
943 if (!obj
->spot
.dap
|| obj
->spot
.ap_num
== DP_APSEL_INVALID
) {
944 Jim_SetResultString(goi
.interp
, "-dap and -ap-num required when creating TPIU", -1);
948 e
= arm_tpiu_swo_create(goi
.interp
, obj
);
956 free(obj
->out_filename
);
961 static int jim_arm_tpiu_swo_names(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
963 struct arm_tpiu_swo_object
*obj
;
966 Jim_WrongNumArgs(interp
, 1, argv
, "Too many parameters");
969 Jim_SetResult(interp
, Jim_NewListObj(interp
, NULL
, 0));
970 list_for_each_entry(obj
, &all_tpiu_swo
, lh
) {
971 Jim_ListAppendElement(interp
, Jim_GetResult(interp
),
972 Jim_NewStringObj(interp
, obj
->name
, -1));
977 static int jim_arm_tpiu_swo_init(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
979 struct command_context
*cmd_ctx
= current_command_context(interp
);
980 struct arm_tpiu_swo_object
*obj
;
984 Jim_WrongNumArgs(interp
, 1, argv
, "Too many parameters");
987 list_for_each_entry(obj
, &all_tpiu_swo
, lh
) {
988 if (!obj
->deferred_enable
)
990 LOG_DEBUG("%s: running enable during init", obj
->name
);
991 int retval2
= command_run_linef(cmd_ctx
, "%s enable", obj
->name
);
992 if (retval2
!= ERROR_OK
)
998 /* START_DEPRECATED_TPIU */
999 /* DEPRECATED: emulation of old command 'tpiu config' */
1000 COMMAND_HANDLER(handle_tpiu_deprecated_config_command
)
1002 struct target
*target
= get_current_target(CMD_CTX
);
1003 struct arm_tpiu_swo_object
*obj
= NULL
;
1006 if (strcmp(target
->type
->name
, "cortex_m") &&
1007 strcmp(target
->type
->name
, "hla_target")) {
1008 LOG_ERROR(MSG
"Current target is not a Cortex-M nor a HLA");
1012 if (!list_empty(&all_tpiu_swo
)) {
1013 obj
= list_first_entry(&all_tpiu_swo
, typeof(*obj
), lh
);
1014 LOG_INFO(MSG
"Using %s", obj
->name
);
1016 struct cortex_m_common
*cm
= target_to_cm(target
);
1017 struct adiv5_private_config
*pc
= target
->private_config
;
1018 struct adiv5_dap
*dap
= pc
->dap
;
1019 int ap_num
= pc
->ap_num
;
1020 bool set_recheck_ap_cur_target
= false;
1022 LOG_INFO(MSG
"Adding a TPIU \'%s.tpiu\' in the configuration", target_name(target
));
1024 if (ap_num
== DP_APSEL_INVALID
&& transport_is_hla())
1025 ap_num
= 0; /* HLA should only support AP 0 */
1027 if (ap_num
== DP_APSEL_INVALID
&& target_was_examined(target
))
1028 ap_num
= cm
->armv7m
.debug_ap
->ap_num
;
1030 if (ap_num
== DP_APSEL_INVALID
) {
1031 LOG_INFO(MSG
"Target %s uses AP autodetection. Adding TPIU on AP 0; can be revised later",
1032 target_name(target
));
1034 set_recheck_ap_cur_target
= true;
1037 LOG_INFO(MSG
"Running: \'tpiu create %s.tpiu -dap %s -ap-num %d\'",
1038 target_name(target
), adiv5_dap_name(dap
), ap_num
);
1040 retval
= command_run_linef(CMD_CTX
, "tpiu create %s.tpiu -dap %s -ap-num %d",
1041 target_name(target
), adiv5_dap_name(dap
), ap_num
);
1042 if (retval
!= ERROR_OK
)
1045 obj
= list_first_entry(&all_tpiu_swo
, typeof(*obj
), lh
);
1046 if (set_recheck_ap_cur_target
)
1047 obj
->recheck_ap_cur_target
= true;
1050 unsigned int cmd_idx
= 0;
1051 if (cmd_idx
== CMD_ARGC
)
1052 return ERROR_COMMAND_SYNTAX_ERROR
;
1054 if (!strcmp(CMD_ARGV
[cmd_idx
], "disable")) {
1055 if (CMD_ARGC
!= cmd_idx
+ 1)
1056 return ERROR_COMMAND_SYNTAX_ERROR
;
1057 LOG_INFO(MSG
"Running: \'%s disable\'", obj
->name
);
1058 return command_run_linef(CMD_CTX
, "%s disable", obj
->name
);
1061 const char *output
= NULL
;
1062 const char *protocol
;
1063 const char *formatter
= NULL
;
1064 const char *port_width
= NULL
;
1065 const char *trace_clk
;
1066 const char *pin_clk
= NULL
;
1067 if (!strcmp(CMD_ARGV
[cmd_idx
], "internal")) {
1069 if (cmd_idx
== CMD_ARGC
)
1070 return ERROR_COMMAND_SYNTAX_ERROR
;
1071 output
= CMD_ARGV
[cmd_idx
];
1072 } else if (strcmp(CMD_ARGV
[cmd_idx
], "external"))
1073 return ERROR_COMMAND_SYNTAX_ERROR
;
1075 if (cmd_idx
== CMD_ARGC
)
1076 return ERROR_COMMAND_SYNTAX_ERROR
;
1077 if (!strcmp(CMD_ARGV
[cmd_idx
], "sync")) {
1078 protocol
= CMD_ARGV
[cmd_idx
];
1080 if (cmd_idx
== CMD_ARGC
)
1081 return ERROR_COMMAND_SYNTAX_ERROR
;
1082 port_width
= CMD_ARGV
[cmd_idx
];
1084 if (strcmp(CMD_ARGV
[cmd_idx
], "manchester") && strcmp(CMD_ARGV
[cmd_idx
], "uart"))
1085 return ERROR_COMMAND_SYNTAX_ERROR
;
1086 protocol
= CMD_ARGV
[cmd_idx
];
1088 if (cmd_idx
== CMD_ARGC
)
1089 return ERROR_COMMAND_SYNTAX_ERROR
;
1090 formatter
= CMD_ARGV
[cmd_idx
];
1093 if (cmd_idx
== CMD_ARGC
)
1094 return ERROR_COMMAND_SYNTAX_ERROR
;
1095 trace_clk
= CMD_ARGV
[cmd_idx
];
1097 if (cmd_idx
!= CMD_ARGC
) {
1098 pin_clk
= CMD_ARGV
[cmd_idx
];
1101 if (cmd_idx
!= CMD_ARGC
)
1102 return ERROR_COMMAND_SYNTAX_ERROR
;
1104 LOG_INFO(MSG
"Running: \'%s configure -protocol %s -traceclk %s" "%s%s" "%s%s" "%s%s" "%s%s\'",
1105 obj
->name
, protocol
, trace_clk
,
1106 pin_clk
? " -pin-freq " : "", pin_clk
? pin_clk
: "",
1107 output
? " -output " : "", output
? output
: "",
1108 formatter
? " -formatter " : "", formatter
? formatter
: "",
1109 port_width
? " -port-width " : "", port_width
? port_width
: "");
1111 retval
= command_run_linef(CMD_CTX
,
1112 "%s configure -protocol %s -traceclk %s" "%s%s" "%s%s" "%s%s" "%s%s",
1113 obj
->name
, protocol
, trace_clk
,
1114 pin_clk
? " -pin-freq " : "", pin_clk
? pin_clk
: "",
1115 output
? " -output " : "", output
? output
: "",
1116 formatter
? " -formatter " : "", formatter
? formatter
: "",
1117 port_width
? " -port-width " : "", port_width
? port_width
: "");
1118 if (retval
!= ERROR_OK
)
1121 LOG_INFO(MSG
"Running: \'%s enable\'", obj
->name
);
1122 retval
= command_run_linef(CMD_CTX
, "%s enable", obj
->name
);
1123 if (retval
!= ERROR_OK
)
1129 static const struct command_registration arm_tpiu_deprecated_subcommand_handlers
[] = {
1132 .handler
= handle_tpiu_deprecated_config_command
,
1133 .mode
= COMMAND_ANY
,
1134 .help
= "Configure TPIU features, DEPRECATED, use \'tpiu create\'",
1135 .usage
= "(disable | "
1136 "((external | internal (<filename> | <:port> | -)) "
1137 "(sync <port width> | ((manchester | uart) <formatter enable>)) "
1138 "<TRACECLKIN freq> [<trace freq>]))",
1140 COMMAND_REGISTRATION_DONE
1143 const struct command_registration arm_tpiu_deprecated_command_handlers
[] = {
1146 .chain
= arm_tpiu_deprecated_subcommand_handlers
,
1148 .help
= "tpiu command group",
1150 COMMAND_REGISTRATION_DONE
1152 /* END_DEPRECATED_TPIU */
1154 static const struct command_registration arm_tpiu_swo_subcommand_handlers
[] = {
1157 .mode
= COMMAND_ANY
,
1158 .jim_handler
= jim_arm_tpiu_swo_create
,
1159 .usage
= "name [-dap dap] [-ap-num num] [-address baseaddr]",
1160 .help
= "Creates a new TPIU or SWO object",
1164 .mode
= COMMAND_ANY
,
1165 .jim_handler
= jim_arm_tpiu_swo_names
,
1167 .help
= "Lists all registered TPIU and SWO objects by name",
1171 .mode
= COMMAND_EXEC
,
1172 .jim_handler
= jim_arm_tpiu_swo_init
,
1174 .help
= "Initialize TPIU and SWO",
1176 COMMAND_REGISTRATION_DONE
1179 static const struct command_registration arm_tpiu_swo_command_handlers
[] = {
1182 .chain
= arm_tpiu_swo_subcommand_handlers
,
1184 .help
= "tpiu command group",
1188 .chain
= arm_tpiu_swo_subcommand_handlers
,
1190 .help
= "swo command group",
1192 COMMAND_REGISTRATION_DONE
1195 int arm_tpiu_swo_register_commands(struct command_context
*cmd_ctx
)
1197 return register_commands(cmd_ctx
, NULL
, arm_tpiu_swo_command_handlers
);