1 /***************************************************************************
2 * Copyright (C) 2015 Paul Fertser <fercerpav@gmail.com> *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
16 ***************************************************************************/
22 #include <target/target.h>
23 #include <target/armv7m.h>
24 #include <target/cortex_m.h>
25 #include <target/armv7m_trace.h>
26 #include <jtag/interface.h>
27 #include <helper/time_support.h>
29 #define TRACE_BUF_SIZE 4096
31 static int armv7m_poll_trace(void *target
)
33 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
34 uint8_t buf
[TRACE_BUF_SIZE
];
35 size_t size
= sizeof(buf
);
38 retval
= adapter_poll_trace(buf
, &size
);
39 if (retval
!= ERROR_OK
|| !size
)
42 target_call_trace_callbacks(target
, size
, buf
);
44 switch (armv7m
->trace_config
.internal_channel
) {
45 case TRACE_INTERNAL_CHANNEL_FILE
:
46 if (armv7m
->trace_config
.trace_file
!= NULL
) {
47 if (fwrite(buf
, 1, size
, armv7m
->trace_config
.trace_file
) == size
)
48 fflush(armv7m
->trace_config
.trace_file
);
50 LOG_ERROR("Error writing to the trace destination file");
55 case TRACE_INTERNAL_CHANNEL_TCP
:
56 if (armv7m
->trace_config
.trace_service
!= NULL
) {
57 /* broadcast to all service connections */
58 struct connection
*connection
= armv7m
->trace_config
.trace_service
->connections
;
61 if (connection_write(connection
, buf
, size
) != (int) size
)
64 connection
= connection
->next
;
67 if (retval
!= ERROR_OK
) {
68 LOG_ERROR("Error streaming the trace to TCP/IP port");
73 case TRACE_INTERNAL_CHANNEL_TCL_ONLY
:
75 * the trace data is sent to TCL by calling the target_call_trace_callbacks
79 LOG_ERROR("unsupported trace internal channel");
86 int armv7m_trace_tpiu_config(struct target
*target
)
88 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
89 struct armv7m_trace_config
*trace_config
= &armv7m
->trace_config
;
90 uint16_t prescaler
= TPIU_ACPR_MAX_SWOSCALER
+ 1;
93 target_unregister_timer_callback(armv7m_poll_trace
, target
);
95 retval
= adapter_config_trace(trace_config
->config_type
== TRACE_CONFIG_TYPE_INTERNAL
,
96 trace_config
->pin_protocol
, trace_config
->port_size
,
97 &trace_config
->trace_freq
, trace_config
->traceclkin_freq
, &prescaler
);
99 if (retval
!= ERROR_OK
)
102 if (trace_config
->config_type
== TRACE_CONFIG_TYPE_EXTERNAL
) {
103 prescaler
= trace_config
->traceclkin_freq
/ trace_config
->trace_freq
;
105 if (trace_config
->traceclkin_freq
% trace_config
->trace_freq
) {
108 int trace_freq
= trace_config
->traceclkin_freq
/ prescaler
;
109 LOG_INFO("Can not obtain %u trace port frequency from %u "
110 "TRACECLKIN frequency, using %u instead",
111 trace_config
->trace_freq
, trace_config
->traceclkin_freq
,
114 trace_config
->trace_freq
= trace_freq
;
118 if (!trace_config
->trace_freq
) {
119 LOG_ERROR("Trace port frequency is 0, can't enable TPIU");
123 retval
= target_write_u32(target
, TPIU_CSPSR
, 1 << trace_config
->port_size
);
124 if (retval
!= ERROR_OK
)
127 retval
= target_write_u32(target
, TPIU_ACPR
, prescaler
- 1);
128 if (retval
!= ERROR_OK
)
131 retval
= target_write_u32(target
, TPIU_SPPR
, trace_config
->pin_protocol
);
132 if (retval
!= ERROR_OK
)
136 retval
= target_read_u32(target
, TPIU_FFCR
, &ffcr
);
137 if (retval
!= ERROR_OK
)
139 if (trace_config
->formatter
)
143 retval
= target_write_u32(target
, TPIU_FFCR
, ffcr
);
144 if (retval
!= ERROR_OK
)
147 if (trace_config
->config_type
== TRACE_CONFIG_TYPE_INTERNAL
)
148 target_register_timer_callback(armv7m_poll_trace
, 1,
149 TARGET_TIMER_TYPE_PERIODIC
, target
);
151 target_call_event_callbacks(target
, TARGET_EVENT_TRACE_CONFIG
);
156 int armv7m_trace_itm_config(struct target
*target
)
158 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
159 struct armv7m_trace_config
*trace_config
= &armv7m
->trace_config
;
162 retval
= target_write_u32(target
, ITM_LAR
, ITM_LAR_KEY
);
163 if (retval
!= ERROR_OK
)
166 /* pg315 of CoreSight Components
167 * It is recommended that the ITMEn bit is cleared and waits for the
168 * ITMBusy bit to be cleared, before changing any fields in the
169 * Control Register, otherwise the behavior can be unpredictable.
172 retval
= target_read_u32(target
, ITM_TCR
, &itm_tcr
);
173 if (retval
!= ERROR_OK
)
175 retval
= target_write_u32(target
,
177 itm_tcr
& ~ITM_TCR_ITMENA_BIT
179 if (retval
!= ERROR_OK
)
182 int64_t then
= timeval_ms() + 1000;
184 retval
= target_read_u32(target
, ITM_TCR
, &itm_tcr
);
185 if (retval
!= ERROR_OK
)
187 if (timeval_ms() > then
) {
188 LOG_ERROR("timeout waiting for ITM_TCR_BUSY_BIT");
191 } while (itm_tcr
& ITM_TCR_BUSY_BIT
);
193 /* Enable ITM, TXENA, set TraceBusID and other parameters */
194 retval
= target_write_u32(target
, ITM_TCR
, (1 << 0) | (1 << 3) |
195 (trace_config
->itm_diff_timestamps
<< 1) |
196 (trace_config
->itm_synchro_packets
<< 2) |
197 (trace_config
->itm_async_timestamps
<< 4) |
198 (trace_config
->itm_ts_prescale
<< 8) |
199 (trace_config
->trace_bus_id
<< 16));
200 if (retval
!= ERROR_OK
)
203 for (unsigned int i
= 0; i
< 8; i
++) {
204 retval
= target_write_u32(target
, ITM_TER0
+ i
* 4,
205 trace_config
->itm_ter
[i
]);
206 if (retval
!= ERROR_OK
)
213 static void close_trace_channel(struct armv7m_common
*armv7m
)
215 switch (armv7m
->trace_config
.internal_channel
) {
216 case TRACE_INTERNAL_CHANNEL_FILE
:
217 if (armv7m
->trace_config
.trace_file
)
218 fclose(armv7m
->trace_config
.trace_file
);
219 armv7m
->trace_config
.trace_file
= NULL
;
221 case TRACE_INTERNAL_CHANNEL_TCP
:
222 if (armv7m
->trace_config
.trace_service
)
223 remove_service(armv7m
->trace_config
.trace_service
->name
, armv7m
->trace_config
.trace_service
->port
);
224 armv7m
->trace_config
.trace_service
= NULL
;
226 case TRACE_INTERNAL_CHANNEL_TCL_ONLY
:
228 * the trace polling is disabled in the beginning of armv7m_trace_tpiu_config
232 LOG_ERROR("unsupported trace internal channel");
236 static int trace_new_connection(struct connection
*connection
)
242 static int trace_input(struct connection
*connection
)
244 /* create a dummy buffer to check if the connection is still active */
245 const int buf_len
= 100;
246 unsigned char buf
[buf_len
];
247 int bytes_read
= connection_read(connection
, buf
, buf_len
);
250 return ERROR_SERVER_REMOTE_CLOSED
;
251 else if (bytes_read
== -1) {
252 LOG_ERROR("error during read: %s", strerror(errno
));
253 return ERROR_SERVER_REMOTE_CLOSED
;
259 static int trace_connection_closed(struct connection
*connection
)
261 /* nothing to do, no connection->priv to free */
265 extern struct command_context
*global_cmd_ctx
;
267 int armv7m_trace_tpiu_exit(struct target
*target
)
269 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
271 if (global_cmd_ctx
->mode
== COMMAND_CONFIG
||
272 armv7m
->trace_config
.config_type
== TRACE_CONFIG_TYPE_DISABLED
)
275 close_trace_channel(armv7m
);
276 armv7m
->trace_config
.config_type
= TRACE_CONFIG_TYPE_DISABLED
;
277 return armv7m_trace_tpiu_config(target
);
280 COMMAND_HANDLER(handle_tpiu_config_command
)
282 struct target
*target
= get_current_target(CMD_CTX
);
283 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
285 unsigned int cmd_idx
= 0;
287 if (CMD_ARGC
== cmd_idx
)
288 return ERROR_COMMAND_SYNTAX_ERROR
;
289 if (!strcmp(CMD_ARGV
[cmd_idx
], "disable")) {
290 if (CMD_ARGC
== cmd_idx
+ 1) {
291 close_trace_channel(armv7m
);
293 armv7m
->trace_config
.config_type
= TRACE_CONFIG_TYPE_DISABLED
;
294 if (CMD_CTX
->mode
== COMMAND_EXEC
)
295 return armv7m_trace_tpiu_config(target
);
299 } else if (!strcmp(CMD_ARGV
[cmd_idx
], "external") ||
300 !strcmp(CMD_ARGV
[cmd_idx
], "internal")) {
301 close_trace_channel(armv7m
);
303 armv7m
->trace_config
.config_type
= TRACE_CONFIG_TYPE_EXTERNAL
;
304 if (!strcmp(CMD_ARGV
[cmd_idx
], "internal")) {
306 if (CMD_ARGC
== cmd_idx
)
307 return ERROR_COMMAND_SYNTAX_ERROR
;
309 armv7m
->trace_config
.config_type
= TRACE_CONFIG_TYPE_INTERNAL
;
310 armv7m
->trace_config
.internal_channel
= TRACE_INTERNAL_CHANNEL_TCL_ONLY
;
312 if (strcmp(CMD_ARGV
[cmd_idx
], "-") != 0) {
313 if (CMD_ARGV
[cmd_idx
][0] == ':') {
314 armv7m
->trace_config
.internal_channel
= TRACE_INTERNAL_CHANNEL_TCP
;
316 int ret
= add_service("armv7m_trace", &(CMD_ARGV
[cmd_idx
][1]),
317 CONNECTION_LIMIT_UNLIMITED
, trace_new_connection
, trace_input
,
318 trace_connection_closed
, NULL
, &armv7m
->trace_config
.trace_service
);
319 if (ret
!= ERROR_OK
) {
320 LOG_ERROR("Can't configure trace TCP port");
324 armv7m
->trace_config
.internal_channel
= TRACE_INTERNAL_CHANNEL_FILE
;
325 armv7m
->trace_config
.trace_file
= fopen(CMD_ARGV
[cmd_idx
], "ab");
326 if (!armv7m
->trace_config
.trace_file
) {
327 LOG_ERROR("Can't open trace destination file");
334 if (CMD_ARGC
== cmd_idx
)
335 return ERROR_COMMAND_SYNTAX_ERROR
;
337 if (!strcmp(CMD_ARGV
[cmd_idx
], "sync")) {
338 armv7m
->trace_config
.pin_protocol
= TPIU_PIN_PROTOCOL_SYNC
;
341 if (CMD_ARGC
== cmd_idx
)
342 return ERROR_COMMAND_SYNTAX_ERROR
;
344 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[cmd_idx
], armv7m
->trace_config
.port_size
);
346 if (!strcmp(CMD_ARGV
[cmd_idx
], "manchester"))
347 armv7m
->trace_config
.pin_protocol
= TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER
;
348 else if (!strcmp(CMD_ARGV
[cmd_idx
], "uart"))
349 armv7m
->trace_config
.pin_protocol
= TPIU_PIN_PROTOCOL_ASYNC_UART
;
351 return ERROR_COMMAND_SYNTAX_ERROR
;
354 if (CMD_ARGC
== cmd_idx
)
355 return ERROR_COMMAND_SYNTAX_ERROR
;
357 COMMAND_PARSE_ON_OFF(CMD_ARGV
[cmd_idx
], armv7m
->trace_config
.formatter
);
361 if (CMD_ARGC
== cmd_idx
)
362 return ERROR_COMMAND_SYNTAX_ERROR
;
364 COMMAND_PARSE_NUMBER(uint
, CMD_ARGV
[cmd_idx
], armv7m
->trace_config
.traceclkin_freq
);
367 if (CMD_ARGC
!= cmd_idx
) {
368 COMMAND_PARSE_NUMBER(uint
, CMD_ARGV
[cmd_idx
], armv7m
->trace_config
.trace_freq
);
371 if (armv7m
->trace_config
.config_type
!= TRACE_CONFIG_TYPE_INTERNAL
) {
372 LOG_ERROR("Trace port frequency can't be omitted in external capture mode");
373 return ERROR_COMMAND_SYNTAX_ERROR
;
375 armv7m
->trace_config
.trace_freq
= 0;
378 if (CMD_ARGC
== cmd_idx
) {
379 if (CMD_CTX
->mode
== COMMAND_EXEC
)
380 return armv7m_trace_tpiu_config(target
);
386 return ERROR_COMMAND_SYNTAX_ERROR
;
389 COMMAND_HANDLER(handle_itm_port_command
)
391 struct target
*target
= get_current_target(CMD_CTX
);
392 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
393 unsigned int reg_idx
;
398 return ERROR_COMMAND_SYNTAX_ERROR
;
400 COMMAND_PARSE_NUMBER(u8
, CMD_ARGV
[0], port
);
401 COMMAND_PARSE_ON_OFF(CMD_ARGV
[1], enable
);
405 armv7m
->trace_config
.itm_ter
[reg_idx
] |= (1 << port
);
407 armv7m
->trace_config
.itm_ter
[reg_idx
] &= ~(1 << port
);
409 if (CMD_CTX
->mode
== COMMAND_EXEC
)
410 return armv7m_trace_itm_config(target
);
415 COMMAND_HANDLER(handle_itm_ports_command
)
417 struct target
*target
= get_current_target(CMD_CTX
);
418 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
422 return ERROR_COMMAND_SYNTAX_ERROR
;
424 COMMAND_PARSE_ON_OFF(CMD_ARGV
[0], enable
);
425 memset(armv7m
->trace_config
.itm_ter
, enable
? 0xff : 0,
426 sizeof(armv7m
->trace_config
.itm_ter
));
428 if (CMD_CTX
->mode
== COMMAND_EXEC
)
429 return armv7m_trace_itm_config(target
);
434 static const struct command_registration tpiu_command_handlers
[] = {
437 .handler
= handle_tpiu_config_command
,
439 .help
= "Configure TPIU features",
440 .usage
= "(disable | "
441 "((external | internal (<filename> | <:port> | -)) "
442 "(sync <port width> | ((manchester | uart) <formatter enable>)) "
443 "<TRACECLKIN freq> [<trace freq>]))",
445 COMMAND_REGISTRATION_DONE
448 static const struct command_registration itm_command_handlers
[] = {
451 .handler
= handle_itm_port_command
,
453 .help
= "Enable or disable ITM stimulus port",
454 .usage
= "<port> (0|1|on|off)",
458 .handler
= handle_itm_ports_command
,
460 .help
= "Enable or disable all ITM stimulus ports",
461 .usage
= "(0|1|on|off)",
463 COMMAND_REGISTRATION_DONE
466 const struct command_registration armv7m_trace_command_handlers
[] = {
470 .help
= "tpiu command group",
472 .chain
= tpiu_command_handlers
,
477 .help
= "itm command group",
479 .chain
= itm_command_handlers
,
481 COMMAND_REGISTRATION_DONE
Linking to existing account procedure
If you already have an account and want to add another login method
you
MUST first sign in with your existing account and
then change URL to read
https://review.openocd.org/login/?link
to get to this page again but this time it'll work for linking. Thank you.
SSH host keys fingerprints
1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=.. |
|+o.. . |
|*.o . . |
|+B . . . |
|Bo. = o S |
|Oo.+ + = |
|oB=.* = . o |
| =+=.+ + E |
|. .=o . o |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)