jtag: linuxgpiod: drop extra parenthesis
[openocd.git] / src / target / armv7m_trace.c
1 /***************************************************************************
2 * Copyright (C) 2015 Paul Fertser <fercerpav@gmail.com> *
3 * *
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. *
8 * *
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. *
13 * *
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 ***************************************************************************/
17
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
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
28 #define TRACE_BUF_SIZE 4096
29
30 static int armv7m_poll_trace(void *target)
31 {
32 struct armv7m_common *armv7m = target_to_armv7m(target);
33 uint8_t buf[TRACE_BUF_SIZE];
34 size_t size = sizeof(buf);
35 int retval;
36
37 retval = adapter_poll_trace(buf, &size);
38 if (retval != ERROR_OK || !size)
39 return retval;
40
41 target_call_trace_callbacks(target, size, buf);
42
43 switch (armv7m->trace_config.internal_channel) {
44 case TRACE_INTERNAL_CHANNEL_FILE:
45 if (armv7m->trace_config.trace_file != NULL) {
46 if (fwrite(buf, 1, size, armv7m->trace_config.trace_file) == size)
47 fflush(armv7m->trace_config.trace_file);
48 else {
49 LOG_ERROR("Error writing to the trace destination file");
50 return ERROR_FAIL;
51 }
52 }
53 break;
54 case TRACE_INTERNAL_CHANNEL_TCP:
55 if (armv7m->trace_config.trace_service != NULL) {
56 /* broadcast to all service connections */
57 struct connection *connection = armv7m->trace_config.trace_service->connections;
58 retval = ERROR_OK;
59 while (connection) {
60 if (connection_write(connection, buf, size) != (int) size)
61 retval = ERROR_FAIL;
62
63 connection = connection->next;
64 }
65
66 if (retval != ERROR_OK) {
67 LOG_ERROR("Error streaming the trace to TCP/IP port");
68 return ERROR_FAIL;
69 }
70 }
71 break;
72 case TRACE_INTERNAL_CHANNEL_TCL_ONLY:
73 /* nothing to do :
74 * the trace data is sent to TCL by calling the target_call_trace_callbacks
75 **/
76 break;
77 default:
78 LOG_ERROR("unsupported trace internal channel");
79 return ERROR_FAIL;
80 }
81
82 return ERROR_OK;
83 }
84
85 int armv7m_trace_tpiu_config(struct target *target)
86 {
87 struct armv7m_common *armv7m = target_to_armv7m(target);
88 struct armv7m_trace_config *trace_config = &armv7m->trace_config;
89 uint16_t prescaler;
90 int retval;
91
92 target_unregister_timer_callback(armv7m_poll_trace, target);
93
94 retval = adapter_config_trace(trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL,
95 trace_config->pin_protocol, trace_config->port_size,
96 &trace_config->trace_freq, trace_config->traceclkin_freq, &prescaler);
97
98 if (retval != ERROR_OK)
99 return retval;
100
101 if (trace_config->config_type == TRACE_CONFIG_TYPE_EXTERNAL) {
102 prescaler = trace_config->traceclkin_freq / trace_config->trace_freq;
103
104 if (trace_config->traceclkin_freq % trace_config->trace_freq) {
105 prescaler++;
106
107 int trace_freq = trace_config->traceclkin_freq / prescaler;
108 LOG_INFO("Can not obtain %u trace port frequency from %u "
109 "TRACECLKIN frequency, using %u instead",
110 trace_config->trace_freq, trace_config->traceclkin_freq,
111 trace_freq);
112
113 trace_config->trace_freq = trace_freq;
114 }
115 }
116
117 if (!trace_config->trace_freq) {
118 LOG_ERROR("Trace port frequency is 0, can't enable TPIU");
119 return ERROR_FAIL;
120 }
121
122 retval = target_write_u32(target, TPIU_CSPSR, 1 << trace_config->port_size);
123 if (retval != ERROR_OK)
124 return retval;
125
126 retval = target_write_u32(target, TPIU_ACPR, prescaler - 1);
127 if (retval != ERROR_OK)
128 return retval;
129
130 retval = target_write_u32(target, TPIU_SPPR, trace_config->pin_protocol);
131 if (retval != ERROR_OK)
132 return retval;
133
134 uint32_t ffcr;
135 retval = target_read_u32(target, TPIU_FFCR, &ffcr);
136 if (retval != ERROR_OK)
137 return retval;
138 if (trace_config->formatter)
139 ffcr |= (1 << 1);
140 else
141 ffcr &= ~(1 << 1);
142 retval = target_write_u32(target, TPIU_FFCR, ffcr);
143 if (retval != ERROR_OK)
144 return retval;
145
146 if (trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL)
147 target_register_timer_callback(armv7m_poll_trace, 1,
148 TARGET_TIMER_TYPE_PERIODIC, target);
149
150 target_call_event_callbacks(target, TARGET_EVENT_TRACE_CONFIG);
151
152 return ERROR_OK;
153 }
154
155 int armv7m_trace_itm_config(struct target *target)
156 {
157 struct armv7m_common *armv7m = target_to_armv7m(target);
158 struct armv7m_trace_config *trace_config = &armv7m->trace_config;
159 int retval;
160
161 retval = target_write_u32(target, ITM_LAR, ITM_LAR_KEY);
162 if (retval != ERROR_OK)
163 return retval;
164
165 /* Enable ITM, TXENA, set TraceBusID and other parameters */
166 retval = target_write_u32(target, ITM_TCR, (1 << 0) | (1 << 3) |
167 (trace_config->itm_diff_timestamps << 1) |
168 (trace_config->itm_synchro_packets << 2) |
169 (trace_config->itm_async_timestamps << 4) |
170 (trace_config->itm_ts_prescale << 8) |
171 (trace_config->trace_bus_id << 16));
172 if (retval != ERROR_OK)
173 return retval;
174
175 for (unsigned int i = 0; i < 8; i++) {
176 retval = target_write_u32(target, ITM_TER0 + i * 4,
177 trace_config->itm_ter[i]);
178 if (retval != ERROR_OK)
179 return retval;
180 }
181
182 return ERROR_OK;
183 }
184
185 static void close_trace_channel(struct armv7m_common *armv7m)
186 {
187 switch (armv7m->trace_config.internal_channel) {
188 case TRACE_INTERNAL_CHANNEL_FILE:
189 if (armv7m->trace_config.trace_file)
190 fclose(armv7m->trace_config.trace_file);
191 armv7m->trace_config.trace_file = NULL;
192 break;
193 case TRACE_INTERNAL_CHANNEL_TCP:
194 if (armv7m->trace_config.trace_service)
195 remove_service(armv7m->trace_config.trace_service->name, armv7m->trace_config.trace_service->port);
196 armv7m->trace_config.trace_service = NULL;
197 break;
198 case TRACE_INTERNAL_CHANNEL_TCL_ONLY:
199 /* nothing to do:
200 * the trace polling is disabled in the beginning of armv7m_trace_tpiu_config
201 **/
202 break;
203 default:
204 LOG_ERROR("unsupported trace internal channel");
205 }
206 }
207
208 static int trace_new_connection(struct connection *connection)
209 {
210 /* nothing to do */
211 return ERROR_OK;
212 }
213
214 static int trace_input(struct connection *connection)
215 {
216 /* create a dummy buffer to check if the connection is still active */
217 const int buf_len = 100;
218 unsigned char buf[buf_len];
219 int bytes_read = connection_read(connection, buf, buf_len);
220
221 if (bytes_read == 0)
222 return ERROR_SERVER_REMOTE_CLOSED;
223 else if (bytes_read == -1) {
224 LOG_ERROR("error during read: %s", strerror(errno));
225 return ERROR_SERVER_REMOTE_CLOSED;
226 }
227
228 return ERROR_OK;
229 }
230
231 static int trace_connection_closed(struct connection *connection)
232 {
233 /* nothing to do, no connection->priv to free */
234 return ERROR_OK;
235 }
236
237 COMMAND_HANDLER(handle_tpiu_config_command)
238 {
239 struct target *target = get_current_target(CMD_CTX);
240 struct armv7m_common *armv7m = target_to_armv7m(target);
241
242 unsigned int cmd_idx = 0;
243
244 if (CMD_ARGC == cmd_idx)
245 return ERROR_COMMAND_SYNTAX_ERROR;
246 if (!strcmp(CMD_ARGV[cmd_idx], "disable")) {
247 if (CMD_ARGC == cmd_idx + 1) {
248 close_trace_channel(armv7m);
249
250 armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_DISABLED;
251 if (CMD_CTX->mode == COMMAND_EXEC)
252 return armv7m_trace_tpiu_config(target);
253 else
254 return ERROR_OK;
255 }
256 } else if (!strcmp(CMD_ARGV[cmd_idx], "external") ||
257 !strcmp(CMD_ARGV[cmd_idx], "internal")) {
258 close_trace_channel(armv7m);
259
260 armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_EXTERNAL;
261 if (!strcmp(CMD_ARGV[cmd_idx], "internal")) {
262 cmd_idx++;
263 if (CMD_ARGC == cmd_idx)
264 return ERROR_COMMAND_SYNTAX_ERROR;
265
266 armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_INTERNAL;
267 armv7m->trace_config.internal_channel = TRACE_INTERNAL_CHANNEL_TCL_ONLY;
268
269 if (strcmp(CMD_ARGV[cmd_idx], "-") != 0) {
270 if (CMD_ARGV[cmd_idx][0] == ':') {
271 armv7m->trace_config.internal_channel = TRACE_INTERNAL_CHANNEL_TCP;
272
273 int ret = add_service("armv7m_trace", &(CMD_ARGV[cmd_idx][1]),
274 CONNECTION_LIMIT_UNLIMITED, trace_new_connection, trace_input,
275 trace_connection_closed, NULL, &armv7m->trace_config.trace_service);
276 if (ret != ERROR_OK) {
277 LOG_ERROR("Can't configure trace TCP port");
278 return ERROR_FAIL;
279 }
280 } else {
281 armv7m->trace_config.internal_channel = TRACE_INTERNAL_CHANNEL_FILE;
282 armv7m->trace_config.trace_file = fopen(CMD_ARGV[cmd_idx], "ab");
283 if (!armv7m->trace_config.trace_file) {
284 LOG_ERROR("Can't open trace destination file");
285 return ERROR_FAIL;
286 }
287 }
288 }
289 }
290 cmd_idx++;
291 if (CMD_ARGC == cmd_idx)
292 return ERROR_COMMAND_SYNTAX_ERROR;
293
294 if (!strcmp(CMD_ARGV[cmd_idx], "sync")) {
295 armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_SYNC;
296
297 cmd_idx++;
298 if (CMD_ARGC == cmd_idx)
299 return ERROR_COMMAND_SYNTAX_ERROR;
300
301 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[cmd_idx], armv7m->trace_config.port_size);
302 } else {
303 if (!strcmp(CMD_ARGV[cmd_idx], "manchester"))
304 armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER;
305 else if (!strcmp(CMD_ARGV[cmd_idx], "uart"))
306 armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_ASYNC_UART;
307 else
308 return ERROR_COMMAND_SYNTAX_ERROR;
309
310 cmd_idx++;
311 if (CMD_ARGC == cmd_idx)
312 return ERROR_COMMAND_SYNTAX_ERROR;
313
314 COMMAND_PARSE_ON_OFF(CMD_ARGV[cmd_idx], armv7m->trace_config.formatter);
315 }
316
317 cmd_idx++;
318 if (CMD_ARGC == cmd_idx)
319 return ERROR_COMMAND_SYNTAX_ERROR;
320
321 COMMAND_PARSE_NUMBER(uint, CMD_ARGV[cmd_idx], armv7m->trace_config.traceclkin_freq);
322
323 cmd_idx++;
324 if (CMD_ARGC != cmd_idx) {
325 COMMAND_PARSE_NUMBER(uint, CMD_ARGV[cmd_idx], armv7m->trace_config.trace_freq);
326 cmd_idx++;
327 } else {
328 if (armv7m->trace_config.config_type != TRACE_CONFIG_TYPE_INTERNAL) {
329 LOG_ERROR("Trace port frequency can't be omitted in external capture mode");
330 return ERROR_COMMAND_SYNTAX_ERROR;
331 }
332 armv7m->trace_config.trace_freq = 0;
333 }
334
335 if (CMD_ARGC == cmd_idx) {
336 if (CMD_CTX->mode == COMMAND_EXEC)
337 return armv7m_trace_tpiu_config(target);
338 else
339 return ERROR_OK;
340 }
341 }
342
343 return ERROR_COMMAND_SYNTAX_ERROR;
344 }
345
346 COMMAND_HANDLER(handle_itm_port_command)
347 {
348 struct target *target = get_current_target(CMD_CTX);
349 struct armv7m_common *armv7m = target_to_armv7m(target);
350 unsigned int reg_idx;
351 uint8_t port;
352 bool enable;
353
354 if (CMD_ARGC != 2)
355 return ERROR_COMMAND_SYNTAX_ERROR;
356
357 COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], port);
358 COMMAND_PARSE_ON_OFF(CMD_ARGV[1], enable);
359 reg_idx = port / 32;
360 port = port % 32;
361 if (enable)
362 armv7m->trace_config.itm_ter[reg_idx] |= (1 << port);
363 else
364 armv7m->trace_config.itm_ter[reg_idx] &= ~(1 << port);
365
366 if (CMD_CTX->mode == COMMAND_EXEC)
367 return armv7m_trace_itm_config(target);
368 else
369 return ERROR_OK;
370 }
371
372 COMMAND_HANDLER(handle_itm_ports_command)
373 {
374 struct target *target = get_current_target(CMD_CTX);
375 struct armv7m_common *armv7m = target_to_armv7m(target);
376 bool enable;
377
378 if (CMD_ARGC != 1)
379 return ERROR_COMMAND_SYNTAX_ERROR;
380
381 COMMAND_PARSE_ON_OFF(CMD_ARGV[0], enable);
382 memset(armv7m->trace_config.itm_ter, enable ? 0xff : 0,
383 sizeof(armv7m->trace_config.itm_ter));
384
385 if (CMD_CTX->mode == COMMAND_EXEC)
386 return armv7m_trace_itm_config(target);
387 else
388 return ERROR_OK;
389 }
390
391 static const struct command_registration tpiu_command_handlers[] = {
392 {
393 .name = "config",
394 .handler = handle_tpiu_config_command,
395 .mode = COMMAND_ANY,
396 .help = "Configure TPIU features",
397 .usage = "(disable | "
398 "((external | internal (<filename> | <:port> | -)) "
399 "(sync <port width> | ((manchester | uart) <formatter enable>)) "
400 "<TRACECLKIN freq> [<trace freq>]))",
401 },
402 COMMAND_REGISTRATION_DONE
403 };
404
405 static const struct command_registration itm_command_handlers[] = {
406 {
407 .name = "port",
408 .handler = handle_itm_port_command,
409 .mode = COMMAND_ANY,
410 .help = "Enable or disable ITM stimulus port",
411 .usage = "<port> (0|1|on|off)",
412 },
413 {
414 .name = "ports",
415 .handler = handle_itm_ports_command,
416 .mode = COMMAND_ANY,
417 .help = "Enable or disable all ITM stimulus ports",
418 .usage = "(0|1|on|off)",
419 },
420 COMMAND_REGISTRATION_DONE
421 };
422
423 const struct command_registration armv7m_trace_command_handlers[] = {
424 {
425 .name = "tpiu",
426 .mode = COMMAND_ANY,
427 .help = "tpiu command group",
428 .usage = "",
429 .chain = tpiu_command_handlers,
430 },
431 {
432 .name = "itm",
433 .mode = COMMAND_ANY,
434 .help = "itm command group",
435 .usage = "",
436 .chain = itm_command_handlers,
437 },
438 COMMAND_REGISTRATION_DONE
439 };

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)