adi_v5: enforce check on AP number value
[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 target_addr_t base;
35 struct adiv5_ap *ap;
36 };
37
38 struct arm_cti_object {
39 struct list_head lh;
40 struct arm_cti cti;
41 int ap_num;
42 char *name;
43 };
44
45 static LIST_HEAD(all_cti);
46
47 const char *arm_cti_name(struct arm_cti *self)
48 {
49 struct arm_cti_object *obj = container_of(self, struct arm_cti_object, cti);
50 return obj->name;
51 }
52
53 struct arm_cti *cti_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o)
54 {
55 struct arm_cti_object *obj = NULL;
56 const char *name;
57 bool found = false;
58
59 name = Jim_GetString(o, NULL);
60
61 list_for_each_entry(obj, &all_cti, lh) {
62 if (!strcmp(name, obj->name)) {
63 found = true;
64 break;
65 }
66 }
67
68 if (found)
69 return &obj->cti;
70 return NULL;
71 }
72
73 static int arm_cti_mod_reg_bits(struct arm_cti *self, unsigned int reg, uint32_t mask, uint32_t value)
74 {
75 uint32_t tmp;
76
77 /* Read register */
78 int retval = mem_ap_read_atomic_u32(self->ap, self->base + reg, &tmp);
79 if (ERROR_OK != retval)
80 return retval;
81
82 /* clear bitfield */
83 tmp &= ~mask;
84 /* put new value */
85 tmp |= value & mask;
86
87 /* write new value */
88 return mem_ap_write_atomic_u32(self->ap, self->base + reg, tmp);
89 }
90
91 int arm_cti_enable(struct arm_cti *self, bool enable)
92 {
93 uint32_t val = enable ? 1 : 0;
94
95 return mem_ap_write_atomic_u32(self->ap, self->base + CTI_CTR, val);
96 }
97
98 int arm_cti_ack_events(struct arm_cti *self, uint32_t event)
99 {
100 int retval;
101 uint32_t tmp;
102
103 retval = mem_ap_write_atomic_u32(self->ap, self->base + CTI_INACK, event);
104 if (retval == ERROR_OK) {
105 int64_t then = timeval_ms();
106 for (;;) {
107 retval = mem_ap_read_atomic_u32(self->ap, self->base + CTI_TROUT_STATUS, &tmp);
108 if (retval != ERROR_OK)
109 break;
110 if ((tmp & event) == 0)
111 break;
112 if (timeval_ms() > then + 1000) {
113 LOG_ERROR("timeout waiting for target");
114 retval = ERROR_TARGET_TIMEOUT;
115 break;
116 }
117 }
118 }
119
120 return retval;
121 }
122
123 int arm_cti_gate_channel(struct arm_cti *self, uint32_t channel)
124 {
125 if (channel > 31)
126 return ERROR_COMMAND_ARGUMENT_INVALID;
127
128 return arm_cti_mod_reg_bits(self, CTI_GATE, CTI_CHNL(channel), 0);
129 }
130
131 int arm_cti_ungate_channel(struct arm_cti *self, uint32_t channel)
132 {
133 if (channel > 31)
134 return ERROR_COMMAND_ARGUMENT_INVALID;
135
136 return arm_cti_mod_reg_bits(self, CTI_GATE, CTI_CHNL(channel), 0xFFFFFFFF);
137 }
138
139 int arm_cti_write_reg(struct arm_cti *self, unsigned int reg, uint32_t value)
140 {
141 return mem_ap_write_atomic_u32(self->ap, self->base + reg, value);
142 }
143
144 int arm_cti_read_reg(struct arm_cti *self, unsigned int reg, uint32_t *p_value)
145 {
146 if (p_value == NULL)
147 return ERROR_COMMAND_ARGUMENT_INVALID;
148
149 return mem_ap_read_atomic_u32(self->ap, self->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[26];
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 };
210
211 static int cti_find_reg_offset(const char *name)
212 {
213 unsigned int i;
214
215 for (i = 0; i < ARRAY_SIZE(cti_names); i++) {
216 if (!strcmp(name, cti_names[i].label))
217 return cti_names[i].offset;
218 }
219 return -1;
220 }
221
222 int arm_cti_cleanup_all(void)
223 {
224 struct arm_cti_object *obj, *tmp;
225
226 list_for_each_entry_safe(obj, tmp, &all_cti, lh) {
227 free(obj->name);
228 free(obj);
229 }
230
231 return ERROR_OK;
232 }
233
234 COMMAND_HANDLER(handle_cti_dump)
235 {
236 struct arm_cti_object *obj = CMD_DATA;
237 struct arm_cti *cti = &obj->cti;
238 int retval = ERROR_OK;
239
240 for (int i = 0; (retval == ERROR_OK) && (i < (int)ARRAY_SIZE(cti_names)); i++)
241 retval = mem_ap_read_u32(cti->ap,
242 cti->base + cti_names[i].offset, cti_names[i].p_val);
243
244 if (retval == ERROR_OK)
245 retval = dap_run(cti->ap->dap);
246
247 if (retval != ERROR_OK)
248 return JIM_ERR;
249
250 for (int i = 0; i < (int)ARRAY_SIZE(cti_names); i++)
251 command_print(CMD_CTX, "%8.8s (0x%04"PRIx32") 0x%08"PRIx32,
252 cti_names[i].label, cti_names[i].offset, *cti_names[i].p_val);
253
254 return JIM_OK;
255 }
256
257 COMMAND_HANDLER(handle_cti_enable)
258 {
259 struct arm_cti_object *obj = CMD_DATA;
260 Jim_Interp *interp = CMD_CTX->interp;
261 struct arm_cti *cti = &obj->cti;
262 bool on_off;
263
264 if (CMD_ARGC != 1) {
265 Jim_SetResultString(interp, "wrong number of args", -1);
266 return ERROR_FAIL;
267 }
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_object *obj = CMD_DATA;
277 Jim_Interp *interp = CMD_CTX->interp;
278 struct arm_cti *cti = &obj->cti;
279 bool on_off;
280
281 if (CMD_ARGC != 1) {
282 Jim_SetResultString(interp, "wrong number of args", -1);
283 return ERROR_FAIL;
284 }
285
286 COMMAND_PARSE_ON_OFF(CMD_ARGV[0], on_off);
287
288 return arm_cti_write_reg(cti, 0xf00, on_off ? 0x1 : 0x0);
289 }
290
291 COMMAND_HANDLER(handle_cti_write)
292 {
293 struct arm_cti_object *obj = CMD_DATA;
294 Jim_Interp *interp = CMD_CTX->interp;
295 struct arm_cti *cti = &obj->cti;
296 int offset;
297 uint32_t value;
298
299 if (CMD_ARGC != 2) {
300 Jim_SetResultString(interp, "Wrong numer of args", -1);
301 return ERROR_FAIL;
302 }
303
304 offset = cti_find_reg_offset(CMD_ARGV[0]);
305 if (offset < 0)
306 return ERROR_FAIL;
307
308 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
309
310 return arm_cti_write_reg(cti, offset, value);
311 }
312
313 COMMAND_HANDLER(handle_cti_read)
314 {
315 struct arm_cti_object *obj = CMD_DATA;
316 Jim_Interp *interp = CMD_CTX->interp;
317 struct arm_cti *cti = &obj->cti;
318 int offset;
319 int retval;
320 uint32_t value;
321
322 if (CMD_ARGC != 1) {
323 Jim_SetResultString(interp, "Wrong numer of args", -1);
324 return ERROR_FAIL;
325 }
326
327 offset = cti_find_reg_offset(CMD_ARGV[0]);
328 if (offset < 0)
329 return ERROR_FAIL;
330
331 retval = arm_cti_read_reg(cti, offset, &value);
332 if (retval != ERROR_OK)
333 return retval;
334
335 command_print(CMD_CTX, "0x%08"PRIx32, value);
336
337 return ERROR_OK;
338 }
339
340 static const struct command_registration cti_instance_command_handlers[] = {
341 {
342 .name = "dump",
343 .mode = COMMAND_EXEC,
344 .handler = handle_cti_dump,
345 .help = "dump CTI registers",
346 .usage = "",
347 },
348 {
349 .name = "enable",
350 .mode = COMMAND_EXEC,
351 .handler = handle_cti_enable,
352 .help = "enable or disable the CTI",
353 .usage = "'on'|'off'",
354 },
355 {
356 .name = "testmode",
357 .mode = COMMAND_EXEC,
358 .handler = handle_cti_testmode,
359 .help = "enable or disable integration test mode",
360 .usage = "'on'|'off'",
361 },
362 {
363 .name = "write",
364 .mode = COMMAND_EXEC,
365 .handler = handle_cti_write,
366 .help = "write to a CTI register",
367 .usage = "register_name value",
368 },
369 {
370 .name = "read",
371 .mode = COMMAND_EXEC,
372 .handler = handle_cti_read,
373 .help = "read a CTI register",
374 .usage = "register_name",
375 },
376 COMMAND_REGISTRATION_DONE
377 };
378
379 enum cti_cfg_param {
380 CFG_DAP,
381 CFG_AP_NUM,
382 CFG_CTIBASE
383 };
384
385 static const Jim_Nvp nvp_config_opts[] = {
386 { .name = "-dap", .value = CFG_DAP },
387 { .name = "-ctibase", .value = CFG_CTIBASE },
388 { .name = "-ap-num", .value = CFG_AP_NUM },
389 { .name = NULL, .value = -1 }
390 };
391
392 static int cti_configure(Jim_GetOptInfo *goi, struct arm_cti_object *cti)
393 {
394 struct adiv5_dap *dap = NULL;
395 Jim_Nvp *n;
396 jim_wide w;
397 int e;
398
399 /* parse config or cget options ... */
400 while (goi->argc > 0) {
401 Jim_SetEmptyResult(goi->interp);
402
403 e = Jim_GetOpt_Nvp(goi, nvp_config_opts, &n);
404 if (e != JIM_OK) {
405 Jim_GetOpt_NvpUnknown(goi, nvp_config_opts, 0);
406 return e;
407 }
408 switch (n->value) {
409 case CFG_DAP: {
410 Jim_Obj *o_t;
411 e = Jim_GetOpt_Obj(goi, &o_t);
412 if (e != JIM_OK)
413 return e;
414 dap = dap_instance_by_jim_obj(goi->interp, o_t);
415 if (dap == NULL) {
416 Jim_SetResultString(goi->interp, "-dap is invalid", -1);
417 return JIM_ERR;
418 }
419 /* loop for more */
420 break;
421 }
422 case CFG_CTIBASE:
423 e = Jim_GetOpt_Wide(goi, &w);
424 if (e != JIM_OK)
425 return e;
426 cti->cti.base = (uint32_t)w;
427 /* loop for more */
428 break;
429
430 case CFG_AP_NUM:
431 e = Jim_GetOpt_Wide(goi, &w);
432 if (e != JIM_OK)
433 return e;
434 if (w < 0 || w > DP_APSEL_MAX) {
435 Jim_SetResultString(goi->interp, "-ap-num is invalid", -1);
436 return JIM_ERR;
437 }
438 cti->ap_num = (uint32_t)w;
439 }
440 }
441
442 if (dap == NULL) {
443 Jim_SetResultString(goi->interp, "-dap required when creating CTI", -1);
444 return JIM_ERR;
445 }
446
447 cti->cti.ap = dap_ap(dap, cti->ap_num);
448
449 return JIM_OK;
450 }
451
452 static int cti_create(Jim_GetOptInfo *goi)
453 {
454 struct command_context *cmd_ctx;
455 static struct arm_cti_object *cti;
456 Jim_Obj *new_cmd;
457 Jim_Cmd *cmd;
458 const char *cp;
459 int e;
460
461 cmd_ctx = current_command_context(goi->interp);
462 assert(cmd_ctx != NULL);
463
464 if (goi->argc < 3) {
465 Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ..options...");
466 return JIM_ERR;
467 }
468 /* COMMAND */
469 Jim_GetOpt_Obj(goi, &new_cmd);
470 /* does this command exist? */
471 cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_ERRMSG);
472 if (cmd) {
473 cp = Jim_GetString(new_cmd, NULL);
474 Jim_SetResultFormatted(goi->interp, "Command: %s Exists", cp);
475 return JIM_ERR;
476 }
477
478 /* Create it */
479 cti = calloc(1, sizeof(struct arm_cti_object));
480 if (cti == NULL)
481 return JIM_ERR;
482
483 e = cti_configure(goi, cti);
484 if (e != JIM_OK) {
485 free(cti);
486 return e;
487 }
488
489 cp = Jim_GetString(new_cmd, NULL);
490 cti->name = strdup(cp);
491
492 /* now - create the new cti name command */
493 const struct command_registration cti_subcommands[] = {
494 {
495 .chain = cti_instance_command_handlers,
496 },
497 COMMAND_REGISTRATION_DONE
498 };
499 const struct command_registration cti_commands[] = {
500 {
501 .name = cp,
502 .mode = COMMAND_ANY,
503 .help = "cti instance command group",
504 .usage = "",
505 .chain = cti_subcommands,
506 },
507 COMMAND_REGISTRATION_DONE
508 };
509 e = register_commands(cmd_ctx, NULL, cti_commands);
510 if (ERROR_OK != e)
511 return JIM_ERR;
512
513 struct command *c = command_find_in_context(cmd_ctx, cp);
514 assert(c);
515 command_set_handler_data(c, cti);
516
517 list_add_tail(&cti->lh, &all_cti);
518
519 return (ERROR_OK == e) ? JIM_OK : JIM_ERR;
520 }
521
522 static int jim_cti_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
523 {
524 Jim_GetOptInfo goi;
525 Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
526 if (goi.argc < 2) {
527 Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv,
528 "<name> [<cti_options> ...]");
529 return JIM_ERR;
530 }
531 return cti_create(&goi);
532 }
533
534 static int jim_cti_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
535 {
536 struct arm_cti_object *obj;
537
538 if (argc != 1) {
539 Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
540 return JIM_ERR;
541 }
542 Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
543 list_for_each_entry(obj, &all_cti, lh) {
544 Jim_ListAppendElement(interp, Jim_GetResult(interp),
545 Jim_NewStringObj(interp, obj->name, -1));
546 }
547 return JIM_OK;
548 }
549
550
551 static const struct command_registration cti_subcommand_handlers[] = {
552 {
553 .name = "create",
554 .mode = COMMAND_ANY,
555 .jim_handler = jim_cti_create,
556 .usage = "name '-chain-position' name [options ...]",
557 .help = "Creates a new CTI object",
558 },
559 {
560 .name = "names",
561 .mode = COMMAND_ANY,
562 .jim_handler = jim_cti_names,
563 .usage = "",
564 .help = "Lists all registered CTI objects by name",
565 },
566 COMMAND_REGISTRATION_DONE
567 };
568
569 static const struct command_registration cti_command_handlers[] = {
570 {
571 .name = "cti",
572 .mode = COMMAND_CONFIG,
573 .help = "CTI commands",
574 .chain = cti_subcommand_handlers,
575 },
576 COMMAND_REGISTRATION_DONE
577 };
578
579 int cti_register_commands(struct command_context *cmd_ctx)
580 {
581 return register_commands(cmd_ctx, NULL, cti_command_handlers);
582 }
583