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>
28 #define TRACE_BUF_SIZE 4096
30 static int armv7m_poll_trace(void *target
)
32 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
33 uint8_t buf
[TRACE_BUF_SIZE
];
34 size_t size
= sizeof(buf
);
37 retval
= adapter_poll_trace(buf
, &size
);
38 if (retval
!= ERROR_OK
|| !size
)
41 target_call_trace_callbacks(target
, size
, buf
);
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
);
47 LOG_ERROR("Error writing to the trace destination file");
55 int armv7m_trace_tpiu_config(struct target
*target
)
57 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
58 struct armv7m_trace_config
*trace_config
= &armv7m
->trace_config
;
62 target_unregister_timer_callback(armv7m_poll_trace
, target
);
65 retval
= adapter_config_trace(trace_config
->config_type
== INTERNAL
,
66 trace_config
->pin_protocol
,
67 trace_config
->port_size
,
68 &trace_config
->trace_freq
);
69 if (retval
!= ERROR_OK
)
72 if (!trace_config
->trace_freq
) {
73 LOG_ERROR("Trace port frequency is 0, can't enable TPIU");
77 prescaler
= trace_config
->traceclkin_freq
/ trace_config
->trace_freq
;
79 if (trace_config
->traceclkin_freq
% trace_config
->trace_freq
) {
81 int trace_freq
= trace_config
->traceclkin_freq
/ prescaler
;
82 LOG_INFO("Can not obtain %u trace port frequency from %u TRACECLKIN frequency, using %u instead",
83 trace_config
->trace_freq
, trace_config
->traceclkin_freq
,
85 trace_config
->trace_freq
= trace_freq
;
86 retval
= adapter_config_trace(trace_config
->config_type
== INTERNAL
,
87 trace_config
->pin_protocol
,
88 trace_config
->port_size
,
89 &trace_config
->trace_freq
);
90 if (retval
!= ERROR_OK
)
94 retval
= target_write_u32(target
, TPIU_CSPSR
, 1 << trace_config
->port_size
);
95 if (retval
!= ERROR_OK
)
98 retval
= target_write_u32(target
, TPIU_ACPR
, prescaler
- 1);
99 if (retval
!= ERROR_OK
)
102 retval
= target_write_u32(target
, TPIU_SPPR
, trace_config
->pin_protocol
);
103 if (retval
!= ERROR_OK
)
107 retval
= target_read_u32(target
, TPIU_FFCR
, &ffcr
);
108 if (retval
!= ERROR_OK
)
110 if (trace_config
->formatter
)
114 retval
= target_write_u32(target
, TPIU_FFCR
, ffcr
);
115 if (retval
!= ERROR_OK
)
118 if (trace_config
->config_type
== INTERNAL
)
119 target_register_timer_callback(armv7m_poll_trace
, 1, 1, target
);
121 target_call_event_callbacks(target
, TARGET_EVENT_TRACE_CONFIG
);
126 int armv7m_trace_itm_config(struct target
*target
)
128 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
129 struct armv7m_trace_config
*trace_config
= &armv7m
->trace_config
;
132 retval
= target_write_u32(target
, ITM_LAR
, ITM_LAR_KEY
);
133 if (retval
!= ERROR_OK
)
136 /* Enable ITM, TXENA, set TraceBusID and other parameters */
137 retval
= target_write_u32(target
, ITM_TCR
, (1 << 0) | (1 << 3) |
138 (trace_config
->itm_diff_timestamps
<< 1) |
139 (trace_config
->itm_synchro_packets
<< 2) |
140 (trace_config
->itm_async_timestamps
<< 4) |
141 (trace_config
->itm_ts_prescale
<< 8) |
142 (trace_config
->trace_bus_id
<< 16));
143 if (retval
!= ERROR_OK
)
146 for (unsigned int i
= 0; i
< 8; i
++) {
147 retval
= target_write_u32(target
, ITM_TER0
+ i
* 4,
148 trace_config
->itm_ter
[i
]);
149 if (retval
!= ERROR_OK
)
156 static void close_trace_file(struct armv7m_common
*armv7m
)
158 if (armv7m
->trace_config
.trace_file
)
159 fclose(armv7m
->trace_config
.trace_file
);
160 armv7m
->trace_config
.trace_file
= NULL
;
163 COMMAND_HANDLER(handle_tpiu_config_command
)
165 struct target
*target
= get_current_target(CMD_CTX
);
166 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
168 unsigned int cmd_idx
= 0;
170 if (CMD_ARGC
== cmd_idx
)
171 return ERROR_COMMAND_SYNTAX_ERROR
;
172 if (!strcmp(CMD_ARGV
[cmd_idx
], "disable")) {
173 if (CMD_ARGC
== cmd_idx
+ 1) {
174 close_trace_file(armv7m
);
176 armv7m
->trace_config
.config_type
= DISABLED
;
177 if (CMD_CTX
->mode
== COMMAND_EXEC
)
178 return armv7m_trace_tpiu_config(target
);
182 } else if (!strcmp(CMD_ARGV
[cmd_idx
], "external") ||
183 !strcmp(CMD_ARGV
[cmd_idx
], "internal")) {
184 close_trace_file(armv7m
);
186 armv7m
->trace_config
.config_type
= EXTERNAL
;
187 if (!strcmp(CMD_ARGV
[cmd_idx
], "internal")) {
189 if (CMD_ARGC
== cmd_idx
)
190 return ERROR_COMMAND_SYNTAX_ERROR
;
192 armv7m
->trace_config
.config_type
= INTERNAL
;
194 if (strcmp(CMD_ARGV
[cmd_idx
], "-") != 0) {
195 armv7m
->trace_config
.trace_file
= fopen(CMD_ARGV
[cmd_idx
], "ab");
196 if (!armv7m
->trace_config
.trace_file
) {
197 LOG_ERROR("Can't open trace destination file");
203 if (CMD_ARGC
== cmd_idx
)
204 return ERROR_COMMAND_SYNTAX_ERROR
;
206 if (!strcmp(CMD_ARGV
[cmd_idx
], "sync")) {
207 armv7m
->trace_config
.pin_protocol
= SYNC
;
210 if (CMD_ARGC
== cmd_idx
)
211 return ERROR_COMMAND_SYNTAX_ERROR
;
213 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[cmd_idx
], armv7m
->trace_config
.port_size
);
215 if (!strcmp(CMD_ARGV
[cmd_idx
], "manchester"))
216 armv7m
->trace_config
.pin_protocol
= ASYNC_MANCHESTER
;
217 else if (!strcmp(CMD_ARGV
[cmd_idx
], "uart"))
218 armv7m
->trace_config
.pin_protocol
= ASYNC_UART
;
220 return ERROR_COMMAND_SYNTAX_ERROR
;
223 if (CMD_ARGC
== cmd_idx
)
224 return ERROR_COMMAND_SYNTAX_ERROR
;
226 COMMAND_PARSE_ON_OFF(CMD_ARGV
[cmd_idx
], armv7m
->trace_config
.formatter
);
230 if (CMD_ARGC
== cmd_idx
)
231 return ERROR_COMMAND_SYNTAX_ERROR
;
233 COMMAND_PARSE_NUMBER(uint
, CMD_ARGV
[cmd_idx
], armv7m
->trace_config
.traceclkin_freq
);
236 if (CMD_ARGC
!= cmd_idx
) {
237 COMMAND_PARSE_NUMBER(uint
, CMD_ARGV
[cmd_idx
], armv7m
->trace_config
.trace_freq
);
240 if (armv7m
->trace_config
.config_type
!= INTERNAL
) {
241 LOG_ERROR("Trace port frequency can't be omitted in external capture mode");
242 return ERROR_COMMAND_SYNTAX_ERROR
;
244 armv7m
->trace_config
.trace_freq
= 0;
247 if (CMD_ARGC
== cmd_idx
) {
248 if (CMD_CTX
->mode
== COMMAND_EXEC
)
249 return armv7m_trace_tpiu_config(target
);
255 return ERROR_COMMAND_SYNTAX_ERROR
;
258 COMMAND_HANDLER(handle_itm_port_command
)
260 struct target
*target
= get_current_target(CMD_CTX
);
261 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
262 unsigned int reg_idx
;
267 return ERROR_COMMAND_SYNTAX_ERROR
;
269 COMMAND_PARSE_NUMBER(u8
, CMD_ARGV
[0], port
);
270 COMMAND_PARSE_ON_OFF(CMD_ARGV
[1], enable
);
274 armv7m
->trace_config
.itm_ter
[reg_idx
] |= (1 << port
);
276 armv7m
->trace_config
.itm_ter
[reg_idx
] &= ~(1 << port
);
278 if (CMD_CTX
->mode
== COMMAND_EXEC
)
279 return armv7m_trace_itm_config(target
);
284 COMMAND_HANDLER(handle_itm_ports_command
)
286 struct target
*target
= get_current_target(CMD_CTX
);
287 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
291 return ERROR_COMMAND_SYNTAX_ERROR
;
293 COMMAND_PARSE_ON_OFF(CMD_ARGV
[0], enable
);
294 memset(armv7m
->trace_config
.itm_ter
, enable
? 0xff : 0,
295 sizeof(armv7m
->trace_config
.itm_ter
));
297 if (CMD_CTX
->mode
== COMMAND_EXEC
)
298 return armv7m_trace_itm_config(target
);
303 static const struct command_registration tpiu_command_handlers
[] = {
306 .handler
= handle_tpiu_config_command
,
308 .help
= "Configure TPIU features",
309 .usage
= "(disable | "
310 "((external | internal <filename>) "
311 "(sync <port width> | ((manchester | uart) <formatter enable>)) "
312 "<TRACECLKIN freq> [<trace freq>]))",
314 COMMAND_REGISTRATION_DONE
317 static const struct command_registration itm_command_handlers
[] = {
320 .handler
= handle_itm_port_command
,
322 .help
= "Enable or disable ITM stimulus port",
323 .usage
= "<port> (0|1|on|off)",
327 .handler
= handle_itm_ports_command
,
329 .help
= "Enable or disable all ITM stimulus ports",
330 .usage
= "(0|1|on|off)",
332 COMMAND_REGISTRATION_DONE
335 const struct command_registration armv7m_trace_command_handlers
[] = {
339 .help
= "tpiu command group",
341 .chain
= tpiu_command_handlers
,
346 .help
= "itm command group",
348 .chain
= itm_command_handlers
,
350 COMMAND_REGISTRATION_DONE