96927bf9459cf75c37a7f1dd91cf9782faf6e6c9
[openocd.git] / src / target / arm_cti.c
1 /***************************************************************************
2 * Copyright (C) 2016 by Matthias Welwarsky *
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, write to the *
16 * Free Software Foundation, Inc., *
17 * *
18 ***************************************************************************/
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <stdlib.h>
25 #include <stdint.h>
26 #include "target/arm_adi_v5.h"
27 #include "target/arm_cti.h"
28 #include "target/target.h"
29 #include "helper/time_support.h"
30 #include "helper/list.h"
31 #include "helper/command.h"
32
33 struct arm_cti {
34 struct list_head lh;
35 char *name;
36 struct adiv5_mem_ap_spot spot;
37 };
38
39 static LIST_HEAD(all_cti);
40
41 const char *arm_cti_name(struct arm_cti *self)
42 {
43 return self->name;
44 }
45
46 struct arm_cti *cti_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o)
47 {
48 struct arm_cti *obj = NULL;
49 const char *name;
50 bool found = false;
51
52 name = Jim_GetString(o, NULL);
53
54 list_for_each_entry(obj, &all_cti, lh) {
55 if (!strcmp(name, obj->name)) {
56 found = true;
57 break;
58 }
59 }
60
61 if (found)
62 return obj;
63 return NULL;
64 }
65
66 static int arm_cti_mod_reg_bits(struct arm_cti *self, unsigned int reg, uint32_t mask, uint32_t value)
67 {
68 struct adiv5_ap *ap = dap_ap(self->spot.dap, self->spot.ap_num);
69 uint32_t tmp;
70
71 /* Read register */
72 int retval = mem_ap_read_atomic_u32(ap, self->spot.base + reg, &tmp);
73 if (retval != ERROR_OK)
74 return retval;
75
76 /* clear bitfield */
77 tmp &= ~mask;
78 /* put new value */
79 tmp |= value & mask;
80
81 /* write new value */
82 return mem_ap_write_atomic_u32(ap, self->spot.base + reg, tmp);
83 }
84
85 int arm_cti_enable(struct arm_cti *self, bool enable)
86 {
87 struct adiv5_ap *ap = dap_ap(self->spot.dap, self->spot.ap_num);
88 uint32_t val = enable ? 1 : 0;
89
90 return mem_ap_write_atomic_u32(ap, self->spot.base + CTI_CTR, val);
91 }
92
93 int arm_cti_ack_events(struct arm_cti *self, uint32_t event)
94 {
95 struct adiv5_ap *ap = dap_ap(self->spot.dap, self->spot.ap_num);
96 int retval;
97 uint32_t tmp;
98
99 retval = mem_ap_write_atomic_u32(ap, self->spot.base + CTI_INACK, event);
100 if (retval == ERROR_OK) {
101 int64_t then = timeval_ms();
102 for (;;) {
103 retval = mem_ap_read_atomic_u32(ap, self->spot.base + CTI_TROUT_STATUS, &tmp);
104 if (retval != ERROR_OK)
105 break;
106 if ((tmp & event) == 0)
107 break;
108 if (timeval_ms() > then + 1000) {
109 LOG_ERROR("timeout waiting for target");
110 retval = ERROR_TARGET_TIMEOUT;
111 break;
112 }
113 }
114 }
115
116 return retval;
117 }
118
119 int arm_cti_gate_channel(struct arm_cti *self, uint32_t channel)
120 {
121 if (channel > 31)
122 return ERROR_COMMAND_ARGUMENT_INVALID;
123
124 return arm_cti_mod_reg_bits(self, CTI_GATE, CTI_CHNL(channel), 0);
125 }
126
127 int arm_cti_ungate_channel(struct arm_cti *self, uint32_t channel)
128 {
129 if (channel > 31)
130 return ERROR_COMMAND_ARGUMENT_INVALID;
131
132 return arm_cti_mod_reg_bits(self, CTI_GATE, CTI_CHNL(channel), 0xFFFFFFFF);
133 }
134
135 int arm_cti_write_reg(struct arm_cti *self, unsigned int reg, uint32_t value)
136 {
137 struct adiv5_ap *ap = dap_ap(self->spot.dap, self->spot.ap_num);
138
139 return mem_ap_write_atomic_u32(ap, self->spot.base + reg, value);
140 }
141
142 int arm_cti_read_reg(struct arm_cti *self, unsigned int reg, uint32_t *p_value)
143 {
144 struct adiv5_ap *ap = dap_ap(self->spot.dap, self->spot.ap_num);
145
146 if (!p_value)
147 return ERROR_COMMAND_ARGUMENT_INVALID;
148
149 return mem_ap_read_atomic_u32(ap, self->spot.base + reg, p_value);
150 }
151
152 int arm_cti_pulse_channel(struct arm_cti *self, uint32_t channel)
153 {
154 if (channel > 31)
155 return ERROR_COMMAND_ARGUMENT_INVALID;
156
157 return arm_cti_write_reg(self, CTI_APPPULSE, CTI_CHNL(channel));
158 }
159
160 int arm_cti_set_channel(struct arm_cti *self, uint32_t channel)
161 {
162 if (channel > 31)
163 return ERROR_COMMAND_ARGUMENT_INVALID;
164
165 return arm_cti_write_reg(self, CTI_APPSET, CTI_CHNL(channel));
166 }
167
168 int arm_cti_clear_channel(struct arm_cti *self, uint32_t channel)
169 {
170 if (channel > 31)
171 return ERROR_COMMAND_ARGUMENT_INVALID;
172
173 return arm_cti_write_reg(self, CTI_APPCLEAR, CTI_CHNL(channel));
174 }
175
176 static uint32_t cti_regs[28];
177
178 static const struct {
179 uint32_t offset;
180 const char *label;
181 uint32_t *p_val;
182 } cti_names[] = {
183 { CTI_CTR, "CTR", &cti_regs[0] },
184 { CTI_GATE, "GATE", &cti_regs[1] },
185 { CTI_INEN0, "INEN0", &cti_regs[2] },
186 { CTI_INEN1, "INEN1", &cti_regs[3] },
187 { CTI_INEN2, "INEN2", &cti_regs[4] },
188 { CTI_INEN3, "INEN3", &cti_regs[5] },
189 { CTI_INEN4, "INEN4", &cti_regs[6] },
190 { CTI_INEN5, "INEN5", &cti_regs[7] },
191 { CTI_INEN6, "INEN6", &cti_regs[8] },
192 { CTI_INEN7, "INEN7", &cti_regs[9] },
193 { CTI_INEN8, "INEN8", &cti_regs[10] },
194 { CTI_OUTEN0, "OUTEN0", &cti_regs[11] },
195 { CTI_OUTEN1, "OUTEN1", &cti_regs[12] },
196 { CTI_OUTEN2, "OUTEN2", &cti_regs[13] },
197 { CTI_OUTEN3, "OUTEN3", &cti_regs[14] },
198 { CTI_OUTEN4, "OUTEN4", &cti_regs[15] },
199 { CTI_OUTEN5, "OUTEN5", &cti_regs[16] },
200 { CTI_OUTEN6, "OUTEN6", &cti_regs[17] },
201 { CTI_OUTEN7, "OUTEN7", &cti_regs[18] },
202 { CTI_OUTEN8, "OUTEN8", &cti_regs[19] },
203 { CTI_TRIN_STATUS, "TRIN", &cti_regs[20] },
204 { CTI_TROUT_STATUS, "TROUT", &cti_regs[21] },
205 { CTI_CHIN_STATUS, "CHIN", &cti_regs[22] },
206 { CTI_CHOU_STATUS, "CHOUT", &cti_regs[23] },
207 { CTI_APPSET, "APPSET", &cti_regs[24] },
208 { CTI_APPCLEAR, "APPCLR", &cti_regs[25] },
209 { CTI_APPPULSE, "APPPULSE", &cti_regs[26] },
210 { CTI_INACK, "INACK", &cti_regs[27] },
211 };
212
213 static int cti_find_reg_offset(const char *name)
214 {
215 unsigned int i;
216
217 for (i = 0; i < ARRAY_SIZE(cti_names); i++) {
218 if (!strcmp(name, cti_names[i].label))
219 return cti_names[i].offset;
220 }
221
222 LOG_ERROR("unknown CTI register %s", name);
223 return -1;
224 }
225
226 int arm_cti_cleanup_all(void)
227 {
228 struct arm_cti *obj, *tmp;
229
230 list_for_each_entry_safe(obj, tmp, &all_cti, lh) {
231 free(obj->name);
232 free(obj);
233 }
234
235 return ERROR_OK;
236 }
237
238 COMMAND_HANDLER(handle_cti_dump)
239 {
240 struct arm_cti *cti = CMD_DATA;
241 struct adiv5_ap *ap = dap_ap(cti->spot.dap, cti->spot.ap_num);
242 int retval = ERROR_OK;
243
244 for (int i = 0; (retval == ERROR_OK) && (i < (int)ARRAY_SIZE(cti_names)); i++)
245 retval = mem_ap_read_u32(ap,
246 cti->spot.base + cti_names[i].offset, cti_names[i].p_val);
247
248 if (retval == ERROR_OK)
249 retval = dap_run(ap->dap);
250
251 if (retval != ERROR_OK)
252 return JIM_ERR;
253
254 for (int i = 0; i < (int)ARRAY_SIZE(cti_names); i++)
255 command_print(CMD, "%8.8s (0x%04"PRIx32") 0x%08"PRIx32,
256 cti_names[i].label, cti_names[i].offset, *cti_names[i].p_val);
257
258 return JIM_OK;
259 }
260
261 COMMAND_HANDLER(handle_cti_enable)
262 {
263 struct arm_cti *cti = CMD_DATA;
264 bool on_off;
265
266 if (CMD_ARGC != 1)
267 return ERROR_COMMAND_SYNTAX_ERROR;
268
269 COMMAND_PARSE_ON_OFF(CMD_ARGV[0], on_off);
270
271 return arm_cti_enable(cti, on_off);
272 }
273
274 COMMAND_HANDLER(handle_cti_testmode)
275 {
276 struct arm_cti *cti = CMD_DATA;
277 bool on_off;
278
279 if (CMD_ARGC != 1)
280 return ERROR_COMMAND_SYNTAX_ERROR;
281
282 COMMAND_PARSE_ON_OFF(CMD_ARGV[0], on_off);
283
284 return arm_cti_write_reg(cti, 0xf00, on_off ? 0x1 : 0x0);
285 }
286
287 COMMAND_HANDLER(handle_cti_write)
288 {
289 struct arm_cti *cti = CMD_DATA;
290 int offset;
291 uint32_t value;
292
293 if (CMD_ARGC != 2)
294 return ERROR_COMMAND_SYNTAX_ERROR;
295
296 offset = cti_find_reg_offset(CMD_ARGV[0]);
297 if (offset < 0)
298 return ERROR_FAIL;
299
300 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
301
302 return arm_cti_write_reg(cti, offset, value);
303 }
304
305 COMMAND_HANDLER(handle_cti_read)
306 {
307 struct arm_cti *cti = CMD_DATA;
308 int offset;
309 int retval;
310 uint32_t value;
311
312 if (CMD_ARGC != 1)
313 return ERROR_COMMAND_SYNTAX_ERROR;
314
315 offset = cti_find_reg_offset(CMD_ARGV[0]);
316 if (offset < 0)
317 return ERROR_FAIL;
318
319 retval = arm_cti_read_reg(cti, offset, &value);
320 if (retval != ERROR_OK)
321 return retval;
322
323 command_print(CMD, "0x%08"PRIx32, value);
324
325 return ERROR_OK;
326 }
327
328 COMMAND_HANDLER(handle_cti_ack)
329 {
330 struct arm_cti *cti = CMD_DATA;
331 uint32_t event;
332
333 if (CMD_ARGC != 1)
334 return ERROR_COMMAND_SYNTAX_ERROR;
335
336 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], event);
337
338 int retval = arm_cti_ack_events(cti, 1 << event);
339
340
341 if (retval != ERROR_OK)
342 return retval;
343
344 return ERROR_OK;
345 }
346
347 COMMAND_HANDLER(handle_cti_channel)
348 {
349 struct arm_cti *cti = CMD_DATA;
350 int retval = ERROR_OK;
351 uint32_t ch_num;
352
353 if (CMD_ARGC != 2)
354 return ERROR_COMMAND_SYNTAX_ERROR;
355
356 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], ch_num);
357
358 if (!strcmp(CMD_ARGV[1], "gate"))
359 retval = arm_cti_gate_channel(cti, ch_num);
360 else if (!strcmp(CMD_ARGV[1], "ungate"))
361 retval = arm_cti_ungate_channel(cti, ch_num);
362 else if (!strcmp(CMD_ARGV[1], "pulse"))
363 retval = arm_cti_pulse_channel(cti, ch_num);
364 else if (!strcmp(CMD_ARGV[1], "set"))
365 retval = arm_cti_set_channel(cti, ch_num);
366 else if (!strcmp(CMD_ARGV[1], "clear"))
367 retval = arm_cti_clear_channel(cti, ch_num);
368 else {
369 command_print(CMD, "Possible channel operations: gate|ungate|set|clear|pulse");
370 return ERROR_COMMAND_ARGUMENT_INVALID;
371 }
372
373 if (retval != ERROR_OK)
374 return retval;
375
376 return ERROR_OK;
377 }
378
379 static const struct command_registration cti_instance_command_handlers[] = {
380 {
381 .name = "dump",
382 .mode = COMMAND_EXEC,
383 .handler = handle_cti_dump,
384 .help = "dump CTI registers",
385 .usage = "",
386 },
387 {
388 .name = "enable",
389 .mode = COMMAND_EXEC,
390 .handler = handle_cti_enable,
391 .help = "enable or disable the CTI",
392 .usage = "'on'|'off'",
393 },
394 {
395 .name = "testmode",
396 .mode = COMMAND_EXEC,
397 .handler = handle_cti_testmode,
398 .help = "enable or disable integration test mode",
399 .usage = "'on'|'off'",
400 },
401 {
402 .name = "write",
403 .mode = COMMAND_EXEC,
404 .handler = handle_cti_write,
405 .help = "write to a CTI register",
406 .usage = "register_name value",
407 },
408 {
409 .name = "read",
410 .mode = COMMAND_EXEC,
411 .handler = handle_cti_read,
412 .help = "read a CTI register",
413 .usage = "register_name",
414 },
415 {
416 .name = "ack",
417 .mode = COMMAND_EXEC,
418 .handler = handle_cti_ack,
419 .help = "acknowledge a CTI event",
420 .usage = "event",
421 },
422 {
423 .name = "channel",
424 .mode = COMMAND_EXEC,
425 .handler = handle_cti_channel,
426 .help = "do an operation on one CTI channel, possible operations: "
427 "gate, ungate, set, clear and pulse",
428 .usage = "channel_number operation",
429 },
430 COMMAND_REGISTRATION_DONE
431 };
432
433 static int cti_configure(struct jim_getopt_info *goi, struct arm_cti *cti)
434 {
435 /* parse config or cget options ... */
436 while (goi->argc > 0) {
437 int e = adiv5_jim_mem_ap_spot_configure(&cti->spot, goi);
438
439 if (e == JIM_CONTINUE)
440 Jim_SetResultFormatted(goi->interp, "unknown option '%s'",
441 Jim_String(goi->argv[0]));
442
443 if (e != JIM_OK)
444 return JIM_ERR;
445 }
446
447 if (!cti->spot.dap) {
448 Jim_SetResultString(goi->interp, "-dap required when creating CTI", -1);
449 return JIM_ERR;
450 }
451
452 return JIM_OK;
453 }
454 static int cti_create(struct jim_getopt_info *goi)
455 {
456 struct command_context *cmd_ctx;
457 static struct arm_cti *cti;
458 Jim_Obj *new_cmd;
459 Jim_Cmd *cmd;
460 const char *cp;
461 int e;
462
463 cmd_ctx = current_command_context(goi->interp);
464 assert(cmd_ctx);
465
466 if (goi->argc < 3) {
467 Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ..options...");
468 return JIM_ERR;
469 }
470 /* COMMAND */
471 jim_getopt_obj(goi, &new_cmd);
472 /* does this command exist? */
473 cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_NONE);
474 if (cmd) {
475 cp = Jim_GetString(new_cmd, NULL);
476 Jim_SetResultFormatted(goi->interp, "Command: %s Exists", cp);
477 return JIM_ERR;
478 }
479
480 /* Create it */
481 cti = calloc(1, sizeof(*cti));
482 if (!cti)
483 return JIM_ERR;
484
485 adiv5_mem_ap_spot_init(&cti->spot);
486
487 /* Do the rest as "configure" options */
488 goi->isconfigure = 1;
489 e = cti_configure(goi, cti);
490 if (e != JIM_OK) {
491 free(cti);
492 return e;
493 }
494
495 cp = Jim_GetString(new_cmd, NULL);
496 cti->name = strdup(cp);
497
498 /* now - create the new cti name command */
499 const struct command_registration cti_subcommands[] = {
500 {
501 .chain = cti_instance_command_handlers,
502 },
503 COMMAND_REGISTRATION_DONE
504 };
505 const struct command_registration cti_commands[] = {
506 {
507 .name = cp,
508 .mode = COMMAND_ANY,
509 .help = "cti instance command group",
510 .usage = "",
511 .chain = cti_subcommands,
512 },
513 COMMAND_REGISTRATION_DONE
514 };
515 e = register_commands_with_data(cmd_ctx, NULL, cti_commands, cti);
516 if (e != ERROR_OK)
517 return JIM_ERR;
518
519 list_add_tail(&cti->lh, &all_cti);
520
521 return JIM_OK;
522 }
523
524 static int jim_cti_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
525 {
526 struct jim_getopt_info goi;
527 jim_getopt_setup(&goi, interp, argc - 1, argv + 1);
528 if (goi.argc < 2) {
529 Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv,
530 "<name> [<cti_options> ...]");
531 return JIM_ERR;
532 }
533 return cti_create(&goi);
534 }
535
536 static int jim_cti_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
537 {
538 struct arm_cti *obj;
539
540 if (argc != 1) {
541 Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
542 return JIM_ERR;
543 }
544 Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
545 list_for_each_entry(obj, &all_cti, lh) {
546 Jim_ListAppendElement(interp, Jim_GetResult(interp),
547 Jim_NewStringObj(interp, obj->name, -1));
548 }
549 return JIM_OK;
550 }
551
552
553 static const struct command_registration cti_subcommand_handlers[] = {
554 {
555 .name = "create",
556 .mode = COMMAND_ANY,
557 .jim_handler = jim_cti_create,
558 .usage = "name '-chain-position' name [options ...]",
559 .help = "Creates a new CTI object",
560 },
561 {
562 .name = "names",
563 .mode = COMMAND_ANY,
564 .jim_handler = jim_cti_names,
565 .usage = "",
566 .help = "Lists all registered CTI objects by name",
567 },
568 COMMAND_REGISTRATION_DONE
569 };
570
571 static const struct command_registration cti_command_handlers[] = {
572 {
573 .name = "cti",
574 .mode = COMMAND_CONFIG,
575 .help = "CTI commands",
576 .chain = cti_subcommand_handlers,
577 .usage = "",
578 },
579 COMMAND_REGISTRATION_DONE
580 };
581
582 int cti_register_commands(struct command_context *cmd_ctx)
583 {
584 return register_commands(cmd_ctx, NULL, cti_command_handlers);
585 }

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)