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
);
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
);
68 if (retval
!= ERROR_OK
)
71 if (!trace_config
->trace_freq
) {
72 LOG_ERROR("Trace port frequency is 0, can't enable TPIU");
76 retval
= target_write_u32(target
, TPIU_CSPSR
, 1 << trace_config
->port_size
);
77 if (retval
!= ERROR_OK
)
80 retval
= target_write_u32(target
, TPIU_ACPR
, prescaler
- 1);
81 if (retval
!= ERROR_OK
)
84 retval
= target_write_u32(target
, TPIU_SPPR
, trace_config
->pin_protocol
);
85 if (retval
!= ERROR_OK
)
89 retval
= target_read_u32(target
, TPIU_FFCR
, &ffcr
);
90 if (retval
!= ERROR_OK
)
92 if (trace_config
->formatter
)
96 retval
= target_write_u32(target
, TPIU_FFCR
, ffcr
);
97 if (retval
!= ERROR_OK
)
100 if (trace_config
->config_type
== TRACE_CONFIG_TYPE_INTERNAL
)
101 target_register_timer_callback(armv7m_poll_trace
, 1,
102 TARGET_TIMER_TYPE_PERIODIC
, target
);
104 target_call_event_callbacks(target
, TARGET_EVENT_TRACE_CONFIG
);
109 int armv7m_trace_itm_config(struct target
*target
)
111 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
112 struct armv7m_trace_config
*trace_config
= &armv7m
->trace_config
;
115 retval
= target_write_u32(target
, ITM_LAR
, ITM_LAR_KEY
);
116 if (retval
!= ERROR_OK
)
119 /* Enable ITM, TXENA, set TraceBusID and other parameters */
120 retval
= target_write_u32(target
, ITM_TCR
, (1 << 0) | (1 << 3) |
121 (trace_config
->itm_diff_timestamps
<< 1) |
122 (trace_config
->itm_synchro_packets
<< 2) |
123 (trace_config
->itm_async_timestamps
<< 4) |
124 (trace_config
->itm_ts_prescale
<< 8) |
125 (trace_config
->trace_bus_id
<< 16));
126 if (retval
!= ERROR_OK
)
129 for (unsigned int i
= 0; i
< 8; i
++) {
130 retval
= target_write_u32(target
, ITM_TER0
+ i
* 4,
131 trace_config
->itm_ter
[i
]);
132 if (retval
!= ERROR_OK
)
139 static void close_trace_file(struct armv7m_common
*armv7m
)
141 if (armv7m
->trace_config
.trace_file
)
142 fclose(armv7m
->trace_config
.trace_file
);
143 armv7m
->trace_config
.trace_file
= NULL
;
146 COMMAND_HANDLER(handle_tpiu_config_command
)
148 struct target
*target
= get_current_target(CMD_CTX
);
149 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
151 unsigned int cmd_idx
= 0;
153 if (CMD_ARGC
== cmd_idx
)
154 return ERROR_COMMAND_SYNTAX_ERROR
;
155 if (!strcmp(CMD_ARGV
[cmd_idx
], "disable")) {
156 if (CMD_ARGC
== cmd_idx
+ 1) {
157 close_trace_file(armv7m
);
159 armv7m
->trace_config
.config_type
= TRACE_CONFIG_TYPE_DISABLED
;
160 if (CMD_CTX
->mode
== COMMAND_EXEC
)
161 return armv7m_trace_tpiu_config(target
);
165 } else if (!strcmp(CMD_ARGV
[cmd_idx
], "external") ||
166 !strcmp(CMD_ARGV
[cmd_idx
], "internal")) {
167 close_trace_file(armv7m
);
169 armv7m
->trace_config
.config_type
= TRACE_CONFIG_TYPE_EXTERNAL
;
170 if (!strcmp(CMD_ARGV
[cmd_idx
], "internal")) {
172 if (CMD_ARGC
== cmd_idx
)
173 return ERROR_COMMAND_SYNTAX_ERROR
;
175 armv7m
->trace_config
.config_type
= TRACE_CONFIG_TYPE_INTERNAL
;
177 if (strcmp(CMD_ARGV
[cmd_idx
], "-") != 0) {
178 armv7m
->trace_config
.trace_file
= fopen(CMD_ARGV
[cmd_idx
], "ab");
179 if (!armv7m
->trace_config
.trace_file
) {
180 LOG_ERROR("Can't open trace destination file");
186 if (CMD_ARGC
== cmd_idx
)
187 return ERROR_COMMAND_SYNTAX_ERROR
;
189 if (!strcmp(CMD_ARGV
[cmd_idx
], "sync")) {
190 armv7m
->trace_config
.pin_protocol
= TPIU_PIN_PROTOCOL_SYNC
;
193 if (CMD_ARGC
== cmd_idx
)
194 return ERROR_COMMAND_SYNTAX_ERROR
;
196 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[cmd_idx
], armv7m
->trace_config
.port_size
);
198 if (!strcmp(CMD_ARGV
[cmd_idx
], "manchester"))
199 armv7m
->trace_config
.pin_protocol
= TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER
;
200 else if (!strcmp(CMD_ARGV
[cmd_idx
], "uart"))
201 armv7m
->trace_config
.pin_protocol
= TPIU_PIN_PROTOCOL_ASYNC_UART
;
203 return ERROR_COMMAND_SYNTAX_ERROR
;
206 if (CMD_ARGC
== cmd_idx
)
207 return ERROR_COMMAND_SYNTAX_ERROR
;
209 COMMAND_PARSE_ON_OFF(CMD_ARGV
[cmd_idx
], armv7m
->trace_config
.formatter
);
213 if (CMD_ARGC
== cmd_idx
)
214 return ERROR_COMMAND_SYNTAX_ERROR
;
216 COMMAND_PARSE_NUMBER(uint
, CMD_ARGV
[cmd_idx
], armv7m
->trace_config
.traceclkin_freq
);
219 if (CMD_ARGC
!= cmd_idx
) {
220 COMMAND_PARSE_NUMBER(uint
, CMD_ARGV
[cmd_idx
], armv7m
->trace_config
.trace_freq
);
223 if (armv7m
->trace_config
.config_type
!= TRACE_CONFIG_TYPE_INTERNAL
) {
224 LOG_ERROR("Trace port frequency can't be omitted in external capture mode");
225 return ERROR_COMMAND_SYNTAX_ERROR
;
227 armv7m
->trace_config
.trace_freq
= 0;
230 if (CMD_ARGC
== cmd_idx
) {
231 if (CMD_CTX
->mode
== COMMAND_EXEC
)
232 return armv7m_trace_tpiu_config(target
);
238 return ERROR_COMMAND_SYNTAX_ERROR
;
241 COMMAND_HANDLER(handle_itm_port_command
)
243 struct target
*target
= get_current_target(CMD_CTX
);
244 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
245 unsigned int reg_idx
;
250 return ERROR_COMMAND_SYNTAX_ERROR
;
252 COMMAND_PARSE_NUMBER(u8
, CMD_ARGV
[0], port
);
253 COMMAND_PARSE_ON_OFF(CMD_ARGV
[1], enable
);
257 armv7m
->trace_config
.itm_ter
[reg_idx
] |= (1 << port
);
259 armv7m
->trace_config
.itm_ter
[reg_idx
] &= ~(1 << port
);
261 if (CMD_CTX
->mode
== COMMAND_EXEC
)
262 return armv7m_trace_itm_config(target
);
267 COMMAND_HANDLER(handle_itm_ports_command
)
269 struct target
*target
= get_current_target(CMD_CTX
);
270 struct armv7m_common
*armv7m
= target_to_armv7m(target
);
274 return ERROR_COMMAND_SYNTAX_ERROR
;
276 COMMAND_PARSE_ON_OFF(CMD_ARGV
[0], enable
);
277 memset(armv7m
->trace_config
.itm_ter
, enable
? 0xff : 0,
278 sizeof(armv7m
->trace_config
.itm_ter
));
280 if (CMD_CTX
->mode
== COMMAND_EXEC
)
281 return armv7m_trace_itm_config(target
);
286 static const struct command_registration tpiu_command_handlers
[] = {
289 .handler
= handle_tpiu_config_command
,
291 .help
= "Configure TPIU features",
292 .usage
= "(disable | "
293 "((external | internal <filename>) "
294 "(sync <port width> | ((manchester | uart) <formatter enable>)) "
295 "<TRACECLKIN freq> [<trace freq>]))",
297 COMMAND_REGISTRATION_DONE
300 static const struct command_registration itm_command_handlers
[] = {
303 .handler
= handle_itm_port_command
,
305 .help
= "Enable or disable ITM stimulus port",
306 .usage
= "<port> (0|1|on|off)",
310 .handler
= handle_itm_ports_command
,
312 .help
= "Enable or disable all ITM stimulus ports",
313 .usage
= "(0|1|on|off)",
315 COMMAND_REGISTRATION_DONE
318 const struct command_registration armv7m_trace_command_handlers
[] = {
322 .help
= "tpiu command group",
324 .chain
= tpiu_command_handlers
,
329 .help
= "itm command group",
331 .chain
= itm_command_handlers
,
333 COMMAND_REGISTRATION_DONE