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 if (armv7m->trace_config.trace_file != NULL) {
44 if (fwrite(buf, 1, size, armv7m->trace_config.trace_file) == size)
45 fflush(armv7m->trace_config.trace_file);
46 else {
47 LOG_ERROR("Error writing to the trace destination file");
48 return ERROR_FAIL;
49 }
50 }
51
52 return ERROR_OK;
53 }
54
55 int armv7m_trace_tpiu_config(struct target *target)
56 {
57 struct armv7m_common *armv7m = target_to_armv7m(target);
58 struct armv7m_trace_config *trace_config = &armv7m->trace_config;
59 uint16_t prescaler;
60 int retval;
61
62 target_unregister_timer_callback(armv7m_poll_trace, target);
63
64 retval = adapter_config_trace(trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL,
65 trace_config->pin_protocol, trace_config->port_size,
66 &trace_config->trace_freq, trace_config->traceclkin_freq, &prescaler);
67
68 if (retval != ERROR_OK)
69 return retval;
70
71 if (trace_config->config_type == TRACE_CONFIG_TYPE_EXTERNAL) {
72 prescaler = trace_config->traceclkin_freq / trace_config->trace_freq;
73
74 if (trace_config->traceclkin_freq % trace_config->trace_freq) {
75 prescaler++;
76
77 int trace_freq = trace_config->traceclkin_freq / prescaler;
78 LOG_INFO("Can not obtain %u trace port frequency from %u "
79 "TRACECLKIN frequency, using %u instead",
80 trace_config->trace_freq, trace_config->traceclkin_freq,
81 trace_freq);
82
83 trace_config->trace_freq = trace_freq;
84 }
85 }
86
87 if (!trace_config->trace_freq) {
88 LOG_ERROR("Trace port frequency is 0, can't enable TPIU");
89 return ERROR_FAIL;
90 }
91
92 retval = target_write_u32(target, TPIU_CSPSR, 1 << trace_config->port_size);
93 if (retval != ERROR_OK)
94 return retval;
95
96 retval = target_write_u32(target, TPIU_ACPR, prescaler - 1);
97 if (retval != ERROR_OK)
98 return retval;
99
100 retval = target_write_u32(target, TPIU_SPPR, trace_config->pin_protocol);
101 if (retval != ERROR_OK)
102 return retval;
103
104 uint32_t ffcr;
105 retval = target_read_u32(target, TPIU_FFCR, &ffcr);
106 if (retval != ERROR_OK)
107 return retval;
108 if (trace_config->formatter)
109 ffcr |= (1 << 1);
110 else
111 ffcr &= ~(1 << 1);
112 retval = target_write_u32(target, TPIU_FFCR, ffcr);
113 if (retval != ERROR_OK)
114 return retval;
115
116 if (trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL)
117 target_register_timer_callback(armv7m_poll_trace, 1,
118 TARGET_TIMER_TYPE_PERIODIC, target);
119
120 target_call_event_callbacks(target, TARGET_EVENT_TRACE_CONFIG);
121
122 return ERROR_OK;
123 }
124
125 int armv7m_trace_itm_config(struct target *target)
126 {
127 struct armv7m_common *armv7m = target_to_armv7m(target);
128 struct armv7m_trace_config *trace_config = &armv7m->trace_config;
129 int retval;
130
131 retval = target_write_u32(target, ITM_LAR, ITM_LAR_KEY);
132 if (retval != ERROR_OK)
133 return retval;
134
135 /* Enable ITM, TXENA, set TraceBusID and other parameters */
136 retval = target_write_u32(target, ITM_TCR, (1 << 0) | (1 << 3) |
137 (trace_config->itm_diff_timestamps << 1) |
138 (trace_config->itm_synchro_packets << 2) |
139 (trace_config->itm_async_timestamps << 4) |
140 (trace_config->itm_ts_prescale << 8) |
141 (trace_config->trace_bus_id << 16));
142 if (retval != ERROR_OK)
143 return retval;
144
145 for (unsigned int i = 0; i < 8; i++) {
146 retval = target_write_u32(target, ITM_TER0 + i * 4,
147 trace_config->itm_ter[i]);
148 if (retval != ERROR_OK)
149 return retval;
150 }
151
152 return ERROR_OK;
153 }
154
155 static void close_trace_file(struct armv7m_common *armv7m)
156 {
157 if (armv7m->trace_config.trace_file)
158 fclose(armv7m->trace_config.trace_file);
159 armv7m->trace_config.trace_file = NULL;
160 }
161
162 COMMAND_HANDLER(handle_tpiu_config_command)
163 {
164 struct target *target = get_current_target(CMD_CTX);
165 struct armv7m_common *armv7m = target_to_armv7m(target);
166
167 unsigned int cmd_idx = 0;
168
169 if (CMD_ARGC == cmd_idx)
170 return ERROR_COMMAND_SYNTAX_ERROR;
171 if (!strcmp(CMD_ARGV[cmd_idx], "disable")) {
172 if (CMD_ARGC == cmd_idx + 1) {
173 close_trace_file(armv7m);
174
175 armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_DISABLED;
176 if (CMD_CTX->mode == COMMAND_EXEC)
177 return armv7m_trace_tpiu_config(target);
178 else
179 return ERROR_OK;
180 }
181 } else if (!strcmp(CMD_ARGV[cmd_idx], "external") ||
182 !strcmp(CMD_ARGV[cmd_idx], "internal")) {
183 close_trace_file(armv7m);
184
185 armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_EXTERNAL;
186 if (!strcmp(CMD_ARGV[cmd_idx], "internal")) {
187 cmd_idx++;
188 if (CMD_ARGC == cmd_idx)
189 return ERROR_COMMAND_SYNTAX_ERROR;
190
191 armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_INTERNAL;
192
193 if (strcmp(CMD_ARGV[cmd_idx], "-") != 0) {
194 armv7m->trace_config.trace_file = fopen(CMD_ARGV[cmd_idx], "ab");
195 if (!armv7m->trace_config.trace_file) {
196 LOG_ERROR("Can't open trace destination file");
197 return ERROR_FAIL;
198 }
199 }
200 }
201 cmd_idx++;
202 if (CMD_ARGC == cmd_idx)
203 return ERROR_COMMAND_SYNTAX_ERROR;
204
205 if (!strcmp(CMD_ARGV[cmd_idx], "sync")) {
206 armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_SYNC;
207
208 cmd_idx++;
209 if (CMD_ARGC == cmd_idx)
210 return ERROR_COMMAND_SYNTAX_ERROR;
211
212 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[cmd_idx], armv7m->trace_config.port_size);
213 } else {
214 if (!strcmp(CMD_ARGV[cmd_idx], "manchester"))
215 armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER;
216 else if (!strcmp(CMD_ARGV[cmd_idx], "uart"))
217 armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_ASYNC_UART;
218 else
219 return ERROR_COMMAND_SYNTAX_ERROR;
220
221 cmd_idx++;
222 if (CMD_ARGC == cmd_idx)
223 return ERROR_COMMAND_SYNTAX_ERROR;
224
225 COMMAND_PARSE_ON_OFF(CMD_ARGV[cmd_idx], armv7m->trace_config.formatter);
226 }
227
228 cmd_idx++;
229 if (CMD_ARGC == cmd_idx)
230 return ERROR_COMMAND_SYNTAX_ERROR;
231
232 COMMAND_PARSE_NUMBER(uint, CMD_ARGV[cmd_idx], armv7m->trace_config.traceclkin_freq);
233
234 cmd_idx++;
235 if (CMD_ARGC != cmd_idx) {
236 COMMAND_PARSE_NUMBER(uint, CMD_ARGV[cmd_idx], armv7m->trace_config.trace_freq);
237 cmd_idx++;
238 } else {
239 if (armv7m->trace_config.config_type != TRACE_CONFIG_TYPE_INTERNAL) {
240 LOG_ERROR("Trace port frequency can't be omitted in external capture mode");
241 return ERROR_COMMAND_SYNTAX_ERROR;
242 }
243 armv7m->trace_config.trace_freq = 0;
244 }
245
246 if (CMD_ARGC == cmd_idx) {
247 if (CMD_CTX->mode == COMMAND_EXEC)
248 return armv7m_trace_tpiu_config(target);
249 else
250 return ERROR_OK;
251 }
252 }
253
254 return ERROR_COMMAND_SYNTAX_ERROR;
255 }
256
257 COMMAND_HANDLER(handle_itm_port_command)
258 {
259 struct target *target = get_current_target(CMD_CTX);
260 struct armv7m_common *armv7m = target_to_armv7m(target);
261 unsigned int reg_idx;
262 uint8_t port;
263 bool enable;
264
265 if (CMD_ARGC != 2)
266 return ERROR_COMMAND_SYNTAX_ERROR;
267
268 COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], port);
269 COMMAND_PARSE_ON_OFF(CMD_ARGV[1], enable);
270 reg_idx = port / 32;
271 port = port % 32;
272 if (enable)
273 armv7m->trace_config.itm_ter[reg_idx] |= (1 << port);
274 else
275 armv7m->trace_config.itm_ter[reg_idx] &= ~(1 << port);
276
277 if (CMD_CTX->mode == COMMAND_EXEC)
278 return armv7m_trace_itm_config(target);
279 else
280 return ERROR_OK;
281 }
282
283 COMMAND_HANDLER(handle_itm_ports_command)
284 {
285 struct target *target = get_current_target(CMD_CTX);
286 struct armv7m_common *armv7m = target_to_armv7m(target);
287 bool enable;
288
289 if (CMD_ARGC != 1)
290 return ERROR_COMMAND_SYNTAX_ERROR;
291
292 COMMAND_PARSE_ON_OFF(CMD_ARGV[0], enable);
293 memset(armv7m->trace_config.itm_ter, enable ? 0xff : 0,
294 sizeof(armv7m->trace_config.itm_ter));
295
296 if (CMD_CTX->mode == COMMAND_EXEC)
297 return armv7m_trace_itm_config(target);
298 else
299 return ERROR_OK;
300 }
301
302 static const struct command_registration tpiu_command_handlers[] = {
303 {
304 .name = "config",
305 .handler = handle_tpiu_config_command,
306 .mode = COMMAND_ANY,
307 .help = "Configure TPIU features",
308 .usage = "(disable | "
309 "((external | internal <filename>) "
310 "(sync <port width> | ((manchester | uart) <formatter enable>)) "
311 "<TRACECLKIN freq> [<trace freq>]))",
312 },
313 COMMAND_REGISTRATION_DONE
314 };
315
316 static const struct command_registration itm_command_handlers[] = {
317 {
318 .name = "port",
319 .handler = handle_itm_port_command,
320 .mode = COMMAND_ANY,
321 .help = "Enable or disable ITM stimulus port",
322 .usage = "<port> (0|1|on|off)",
323 },
324 {
325 .name = "ports",
326 .handler = handle_itm_ports_command,
327 .mode = COMMAND_ANY,
328 .help = "Enable or disable all ITM stimulus ports",
329 .usage = "(0|1|on|off)",
330 },
331 COMMAND_REGISTRATION_DONE
332 };
333
334 const struct command_registration armv7m_trace_command_handlers[] = {
335 {
336 .name = "tpiu",
337 .mode = COMMAND_ANY,
338 .help = "tpiu command group",
339 .usage = "",
340 .chain = tpiu_command_handlers,
341 },
342 {
343 .name = "itm",
344 .mode = COMMAND_ANY,
345 .help = "itm command group",
346 .usage = "",
347 .chain = itm_command_handlers,
348 },
349 COMMAND_REGISTRATION_DONE
350 };

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)