target/arm_cti: fix regression from Tcl_return_values series
[fw/openocd] / 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[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_object *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_object *obj = CMD_DATA;
241         struct arm_cti *cti = &obj->cti;
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(cti->ap,
246                                 cti->base + cti_names[i].offset, cti_names[i].p_val);
247
248         if (retval == ERROR_OK)
249                 retval = dap_run(cti->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_object *obj = CMD_DATA;
264         struct arm_cti *cti = &obj->cti;
265         bool on_off;
266
267         if (CMD_ARGC != 1)
268                 return ERROR_COMMAND_SYNTAX_ERROR;
269
270         COMMAND_PARSE_ON_OFF(CMD_ARGV[0], on_off);
271
272         return arm_cti_enable(cti, on_off);
273 }
274
275 COMMAND_HANDLER(handle_cti_testmode)
276 {
277         struct arm_cti_object *obj = CMD_DATA;
278         struct arm_cti *cti = &obj->cti;
279         bool on_off;
280
281         if (CMD_ARGC != 1)
282                 return ERROR_COMMAND_SYNTAX_ERROR;
283
284         COMMAND_PARSE_ON_OFF(CMD_ARGV[0], on_off);
285
286         return arm_cti_write_reg(cti, 0xf00, on_off ? 0x1 : 0x0);
287 }
288
289 COMMAND_HANDLER(handle_cti_write)
290 {
291         struct arm_cti_object *obj = CMD_DATA;
292         struct arm_cti *cti = &obj->cti;
293         int offset;
294         uint32_t value;
295
296         if (CMD_ARGC != 2)
297                 return ERROR_COMMAND_SYNTAX_ERROR;
298
299         offset = cti_find_reg_offset(CMD_ARGV[0]);
300         if (offset < 0)
301                 return ERROR_FAIL;
302
303         COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
304
305         return arm_cti_write_reg(cti, offset, value);
306 }
307
308 COMMAND_HANDLER(handle_cti_read)
309 {
310         struct arm_cti_object *obj = CMD_DATA;
311         struct arm_cti *cti = &obj->cti;
312         int offset;
313         int retval;
314         uint32_t value;
315
316         if (CMD_ARGC != 1)
317                 return ERROR_COMMAND_SYNTAX_ERROR;
318
319         offset = cti_find_reg_offset(CMD_ARGV[0]);
320         if (offset < 0)
321                 return ERROR_FAIL;
322
323         retval = arm_cti_read_reg(cti, offset, &value);
324         if (retval != ERROR_OK)
325                 return retval;
326
327         command_print(CMD, "0x%08"PRIx32, value);
328
329         return ERROR_OK;
330 }
331
332 COMMAND_HANDLER(handle_cti_ack)
333 {
334         struct arm_cti_object *obj = CMD_DATA;
335         struct arm_cti *cti = &obj->cti;
336         uint32_t event;
337
338         if (CMD_ARGC != 1)
339                 return ERROR_COMMAND_SYNTAX_ERROR;
340
341         COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], event);
342
343         int retval = arm_cti_ack_events(cti, 1 << event);
344
345
346         if (retval != ERROR_OK)
347                 return retval;
348
349         return ERROR_OK;
350 }
351
352 COMMAND_HANDLER(handle_cti_channel)
353 {
354         struct arm_cti_object *obj = CMD_DATA;
355         struct arm_cti *cti = &obj->cti;
356         int retval = ERROR_OK;
357         uint32_t ch_num;
358
359         if (CMD_ARGC != 2)
360                 return ERROR_COMMAND_SYNTAX_ERROR;
361
362         COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], ch_num);
363
364         if (!strcmp(CMD_ARGV[1], "gate"))
365                 retval = arm_cti_gate_channel(cti, ch_num);
366         else if (!strcmp(CMD_ARGV[1], "ungate"))
367                 retval = arm_cti_ungate_channel(cti, ch_num);
368         else if (!strcmp(CMD_ARGV[1], "pulse"))
369                 retval = arm_cti_pulse_channel(cti, ch_num);
370         else if (!strcmp(CMD_ARGV[1], "set"))
371                 retval = arm_cti_set_channel(cti, ch_num);
372         else if (!strcmp(CMD_ARGV[1], "clear"))
373                 retval = arm_cti_clear_channel(cti, ch_num);
374         else {
375                 command_print(CMD, "Possible channel operations: gate|ungate|set|clear|pulse");
376                 return ERROR_COMMAND_ARGUMENT_INVALID;
377         }
378
379         if (retval != ERROR_OK)
380                 return retval;
381
382         return ERROR_OK;
383 }
384
385 static const struct command_registration cti_instance_command_handlers[] = {
386         {
387                 .name  = "dump",
388                 .mode  = COMMAND_EXEC,
389                 .handler = handle_cti_dump,
390                 .help  = "dump CTI registers",
391                 .usage = "",
392         },
393         {
394                 .name = "enable",
395                 .mode = COMMAND_EXEC,
396                 .handler = handle_cti_enable,
397                 .help = "enable or disable the CTI",
398                 .usage = "'on'|'off'",
399         },
400         {
401                 .name = "testmode",
402                 .mode = COMMAND_EXEC,
403                 .handler = handle_cti_testmode,
404                 .help = "enable or disable integration test mode",
405                 .usage = "'on'|'off'",
406         },
407         {
408                 .name = "write",
409                 .mode = COMMAND_EXEC,
410                 .handler = handle_cti_write,
411                 .help = "write to a CTI register",
412                 .usage = "register_name value",
413         },
414         {
415                 .name = "read",
416                 .mode = COMMAND_EXEC,
417                 .handler = handle_cti_read,
418                 .help = "read a CTI register",
419                 .usage = "register_name",
420         },
421         {
422                 .name = "ack",
423                 .mode = COMMAND_EXEC,
424                 .handler = handle_cti_ack,
425                 .help = "acknowledge a CTI event",
426                 .usage = "event",
427         },
428         {
429                 .name = "channel",
430                 .mode = COMMAND_EXEC,
431                 .handler = handle_cti_channel,
432                 .help = "do an operation on one CTI channel, possible operations: "
433                                 "gate, ungate, set, clear and pulse",
434                 .usage = "channel_number operation",
435         },
436         COMMAND_REGISTRATION_DONE
437 };
438
439 enum cti_cfg_param {
440         CFG_DAP,
441         CFG_AP_NUM,
442         CFG_CTIBASE
443 };
444
445 static const Jim_Nvp nvp_config_opts[] = {
446         { .name = "-dap",     .value = CFG_DAP },
447         { .name = "-ctibase", .value = CFG_CTIBASE },
448         { .name = "-ap-num",  .value = CFG_AP_NUM },
449         { .name = NULL, .value = -1 }
450 };
451
452 static int cti_configure(Jim_GetOptInfo *goi, struct arm_cti_object *cti)
453 {
454         struct adiv5_dap *dap = NULL;
455         Jim_Nvp *n;
456         jim_wide w;
457         int e;
458
459         /* parse config or cget options ... */
460         while (goi->argc > 0) {
461                 Jim_SetEmptyResult(goi->interp);
462
463                 e = Jim_GetOpt_Nvp(goi, nvp_config_opts, &n);
464                 if (e != JIM_OK) {
465                         Jim_GetOpt_NvpUnknown(goi, nvp_config_opts, 0);
466                         return e;
467                 }
468                 switch (n->value) {
469                 case CFG_DAP: {
470                         Jim_Obj *o_t;
471                         e = Jim_GetOpt_Obj(goi, &o_t);
472                         if (e != JIM_OK)
473                                 return e;
474                         dap = dap_instance_by_jim_obj(goi->interp, o_t);
475                         if (dap == NULL) {
476                                 Jim_SetResultString(goi->interp, "-dap is invalid", -1);
477                                 return JIM_ERR;
478                         }
479                         /* loop for more */
480                         break;
481                 }
482                 case CFG_CTIBASE:
483                         e = Jim_GetOpt_Wide(goi, &w);
484                         if (e != JIM_OK)
485                                 return e;
486                         cti->cti.base = (uint32_t)w;
487                         /* loop for more */
488                         break;
489
490                 case CFG_AP_NUM:
491                         e = Jim_GetOpt_Wide(goi, &w);
492                         if (e != JIM_OK)
493                                 return e;
494                         if (w < 0 || w > DP_APSEL_MAX) {
495                                 Jim_SetResultString(goi->interp, "-ap-num is invalid", -1);
496                                 return JIM_ERR;
497                         }
498                         cti->ap_num = (uint32_t)w;
499                 }
500         }
501
502         if (dap == NULL) {
503                 Jim_SetResultString(goi->interp, "-dap required when creating CTI", -1);
504                 return JIM_ERR;
505         }
506
507         cti->cti.ap = dap_ap(dap, cti->ap_num);
508
509         return JIM_OK;
510 }
511
512 static int cti_create(Jim_GetOptInfo *goi)
513 {
514         struct command_context *cmd_ctx;
515         static struct arm_cti_object *cti;
516         Jim_Obj *new_cmd;
517         Jim_Cmd *cmd;
518         const char *cp;
519         int e;
520
521         cmd_ctx = current_command_context(goi->interp);
522         assert(cmd_ctx != NULL);
523
524         if (goi->argc < 3) {
525                 Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ..options...");
526                 return JIM_ERR;
527         }
528         /* COMMAND */
529         Jim_GetOpt_Obj(goi, &new_cmd);
530         /* does this command exist? */
531         cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_ERRMSG);
532         if (cmd) {
533                 cp = Jim_GetString(new_cmd, NULL);
534                 Jim_SetResultFormatted(goi->interp, "Command: %s Exists", cp);
535                 return JIM_ERR;
536         }
537
538         /* Create it */
539         cti = calloc(1, sizeof(struct arm_cti_object));
540         if (cti == NULL)
541                 return JIM_ERR;
542
543         e = cti_configure(goi, cti);
544         if (e != JIM_OK) {
545                 free(cti);
546                 return e;
547         }
548
549         cp = Jim_GetString(new_cmd, NULL);
550         cti->name = strdup(cp);
551
552         /* now - create the new cti name command */
553         const struct command_registration cti_subcommands[] = {
554                 {
555                         .chain = cti_instance_command_handlers,
556                 },
557                 COMMAND_REGISTRATION_DONE
558         };
559         const struct command_registration cti_commands[] = {
560                 {
561                         .name = cp,
562                         .mode = COMMAND_ANY,
563                         .help = "cti instance command group",
564                         .usage = "",
565                         .chain = cti_subcommands,
566                 },
567                 COMMAND_REGISTRATION_DONE
568         };
569         e = register_commands(cmd_ctx, NULL, cti_commands);
570         if (ERROR_OK != e)
571                 return JIM_ERR;
572
573         struct command *c = command_find_in_context(cmd_ctx, cp);
574         assert(c);
575         command_set_handler_data(c, cti);
576
577         list_add_tail(&cti->lh, &all_cti);
578
579         return (ERROR_OK == e) ? JIM_OK : JIM_ERR;
580 }
581
582 static int jim_cti_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
583 {
584         Jim_GetOptInfo goi;
585         Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
586         if (goi.argc < 2) {
587                 Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv,
588                         "<name> [<cti_options> ...]");
589                 return JIM_ERR;
590         }
591         return cti_create(&goi);
592 }
593
594 static int jim_cti_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
595 {
596         struct arm_cti_object *obj;
597
598         if (argc != 1) {
599                 Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
600                 return JIM_ERR;
601         }
602         Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
603         list_for_each_entry(obj, &all_cti, lh) {
604                 Jim_ListAppendElement(interp, Jim_GetResult(interp),
605                         Jim_NewStringObj(interp, obj->name, -1));
606         }
607         return JIM_OK;
608 }
609
610
611 static const struct command_registration cti_subcommand_handlers[] = {
612         {
613                 .name = "create",
614                 .mode = COMMAND_ANY,
615                 .jim_handler = jim_cti_create,
616                 .usage = "name '-chain-position' name [options ...]",
617                 .help = "Creates a new CTI object",
618         },
619         {
620                 .name = "names",
621                 .mode = COMMAND_ANY,
622                 .jim_handler = jim_cti_names,
623                 .usage = "",
624                 .help = "Lists all registered CTI objects by name",
625         },
626         COMMAND_REGISTRATION_DONE
627 };
628
629 static const struct command_registration cti_command_handlers[] = {
630         {
631                 .name = "cti",
632                 .mode = COMMAND_CONFIG,
633                 .help = "CTI commands",
634                 .chain = cti_subcommand_handlers,
635                 .usage = "",
636         },
637         COMMAND_REGISTRATION_DONE
638 };
639
640 int cti_register_commands(struct command_context *cmd_ctx)
641 {
642         return register_commands(cmd_ctx, NULL, cti_command_handlers);
643 }
644