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