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
arm_cti_name(struct arm_cti * self)41 const char *arm_cti_name(struct arm_cti *self)
42 {
43 return self->name;
44 }
45
cti_instance_by_jim_obj(Jim_Interp * interp,Jim_Obj * o)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
arm_cti_mod_reg_bits(struct arm_cti * self,unsigned int reg,uint32_t mask,uint32_t value)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 (ERROR_OK != retval)
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
arm_cti_enable(struct arm_cti * self,bool enable)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
arm_cti_ack_events(struct arm_cti * self,uint32_t event)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
arm_cti_gate_channel(struct arm_cti * self,uint32_t channel)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
arm_cti_ungate_channel(struct arm_cti * self,uint32_t channel)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
arm_cti_write_reg(struct arm_cti * self,unsigned int reg,uint32_t value)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
arm_cti_read_reg(struct arm_cti * self,unsigned int reg,uint32_t * p_value)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 == NULL)
147 return ERROR_COMMAND_ARGUMENT_INVALID;
148
149 return mem_ap_read_atomic_u32(ap, self->spot.base + reg, p_value);
150 }
151
arm_cti_pulse_channel(struct arm_cti * self,uint32_t channel)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
arm_cti_set_channel(struct arm_cti * self,uint32_t channel)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
arm_cti_clear_channel(struct arm_cti * self,uint32_t channel)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
cti_find_reg_offset(const char * name)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
arm_cti_cleanup_all(void)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
COMMAND_HANDLER(handle_cti_dump)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
COMMAND_HANDLER(handle_cti_enable)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
COMMAND_HANDLER(handle_cti_testmode)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
COMMAND_HANDLER(handle_cti_write)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
COMMAND_HANDLER(handle_cti_read)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
COMMAND_HANDLER(handle_cti_ack)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
COMMAND_HANDLER(handle_cti_channel)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
cti_configure(Jim_GetOptInfo * goi,struct arm_cti * cti)433 static int cti_configure(Jim_GetOptInfo *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 if (e != JIM_OK)
439 return e;
440 }
441
442 if (!cti->spot.dap) {
443 Jim_SetResultString(goi->interp, "-dap required when creating CTI", -1);
444 return JIM_ERR;
445 }
446
447 return JIM_OK;
448 }
cti_create(Jim_GetOptInfo * goi)449 static int cti_create(Jim_GetOptInfo *goi)
450 {
451 struct command_context *cmd_ctx;
452 static struct arm_cti *cti;
453 Jim_Obj *new_cmd;
454 Jim_Cmd *cmd;
455 const char *cp;
456 int e;
457
458 cmd_ctx = current_command_context(goi->interp);
459 assert(cmd_ctx != NULL);
460
461 if (goi->argc < 3) {
462 Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ..options...");
463 return JIM_ERR;
464 }
465 /* COMMAND */
466 Jim_GetOpt_Obj(goi, &new_cmd);
467 /* does this command exist? */
468 cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_ERRMSG);
469 if (cmd) {
470 cp = Jim_GetString(new_cmd, NULL);
471 Jim_SetResultFormatted(goi->interp, "Command: %s Exists", cp);
472 return JIM_ERR;
473 }
474
475 /* Create it */
476 cti = calloc(1, sizeof(*cti));
477 if (cti == NULL)
478 return JIM_ERR;
479
480 adiv5_mem_ap_spot_init(&cti->spot);
481
482 /* Do the rest as "configure" options */
483 goi->isconfigure = 1;
484 e = cti_configure(goi, cti);
485 if (e != JIM_OK) {
486 free(cti);
487 return e;
488 }
489
490 cp = Jim_GetString(new_cmd, NULL);
491 cti->name = strdup(cp);
492
493 /* now - create the new cti name command */
494 const struct command_registration cti_subcommands[] = {
495 {
496 .chain = cti_instance_command_handlers,
497 },
498 COMMAND_REGISTRATION_DONE
499 };
500 const struct command_registration cti_commands[] = {
501 {
502 .name = cp,
503 .mode = COMMAND_ANY,
504 .help = "cti instance command group",
505 .usage = "",
506 .chain = cti_subcommands,
507 },
508 COMMAND_REGISTRATION_DONE
509 };
510 e = register_commands(cmd_ctx, NULL, cti_commands);
511 if (ERROR_OK != e)
512 return JIM_ERR;
513
514 struct command *c = command_find_in_context(cmd_ctx, cp);
515 assert(c);
516 command_set_handler_data(c, cti);
517
518 list_add_tail(&cti->lh, &all_cti);
519
520 return (ERROR_OK == e) ? JIM_OK : JIM_ERR;
521 }
522
jim_cti_create(Jim_Interp * interp,int argc,Jim_Obj * const * argv)523 static int jim_cti_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
524 {
525 Jim_GetOptInfo goi;
526 Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
527 if (goi.argc < 2) {
528 Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv,
529 "<name> [<cti_options> ...]");
530 return JIM_ERR;
531 }
532 return cti_create(&goi);
533 }
534
jim_cti_names(Jim_Interp * interp,int argc,Jim_Obj * const * argv)535 static int jim_cti_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
536 {
537 struct arm_cti *obj;
538
539 if (argc != 1) {
540 Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
541 return JIM_ERR;
542 }
543 Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
544 list_for_each_entry(obj, &all_cti, lh) {
545 Jim_ListAppendElement(interp, Jim_GetResult(interp),
546 Jim_NewStringObj(interp, obj->name, -1));
547 }
548 return JIM_OK;
549 }
550
551
552 static const struct command_registration cti_subcommand_handlers[] = {
553 {
554 .name = "create",
555 .mode = COMMAND_ANY,
556 .jim_handler = jim_cti_create,
557 .usage = "name '-chain-position' name [options ...]",
558 .help = "Creates a new CTI object",
559 },
560 {
561 .name = "names",
562 .mode = COMMAND_ANY,
563 .jim_handler = jim_cti_names,
564 .usage = "",
565 .help = "Lists all registered CTI objects by name",
566 },
567 COMMAND_REGISTRATION_DONE
568 };
569
570 static const struct command_registration cti_command_handlers[] = {
571 {
572 .name = "cti",
573 .mode = COMMAND_CONFIG,
574 .help = "CTI commands",
575 .chain = cti_subcommand_handlers,
576 .usage = "",
577 },
578 COMMAND_REGISTRATION_DONE
579 };
580
cti_register_commands(struct command_context * cmd_ctx)581 int cti_register_commands(struct command_context *cmd_ctx)
582 {
583 return register_commands(cmd_ctx, NULL, cti_command_handlers);
584 }
585