1 /***************************************************************************
2 * Copyright (C) 2016 by Matthias Welwarsky *
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. *
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. *
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., *
18 ***************************************************************************/
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"
38 struct arm_cti_object
{
45 static LIST_HEAD(all_cti
);
47 const char *arm_cti_name(struct arm_cti
*self
)
49 struct arm_cti_object
*obj
= container_of(self
, struct arm_cti_object
, cti
);
53 struct arm_cti
*cti_instance_by_jim_obj(Jim_Interp
*interp
, Jim_Obj
*o
)
55 struct arm_cti_object
*obj
= NULL
;
59 name
= Jim_GetString(o
, NULL
);
61 list_for_each_entry(obj
, &all_cti
, lh
) {
62 if (!strcmp(name
, obj
->name
)) {
73 static int arm_cti_mod_reg_bits(struct arm_cti
*self
, unsigned int reg
, uint32_t mask
, uint32_t value
)
78 int retval
= mem_ap_read_atomic_u32(self
->ap
, self
->base
+ reg
, &tmp
);
79 if (ERROR_OK
!= retval
)
88 return mem_ap_write_atomic_u32(self
->ap
, self
->base
+ reg
, tmp
);
91 int arm_cti_enable(struct arm_cti
*self
, bool enable
)
93 uint32_t val
= enable
? 1 : 0;
95 return mem_ap_write_atomic_u32(self
->ap
, self
->base
+ CTI_CTR
, val
);
98 int arm_cti_ack_events(struct arm_cti
*self
, uint32_t event
)
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();
107 retval
= mem_ap_read_atomic_u32(self
->ap
, self
->base
+ CTI_TROUT_STATUS
, &tmp
);
108 if (retval
!= ERROR_OK
)
110 if ((tmp
& event
) == 0)
112 if (timeval_ms() > then
+ 1000) {
113 LOG_ERROR("timeout waiting for target");
114 retval
= ERROR_TARGET_TIMEOUT
;
123 int arm_cti_gate_channel(struct arm_cti
*self
, uint32_t channel
)
126 return ERROR_COMMAND_ARGUMENT_INVALID
;
128 return arm_cti_mod_reg_bits(self
, CTI_GATE
, CTI_CHNL(channel
), 0);
131 int arm_cti_ungate_channel(struct arm_cti
*self
, uint32_t channel
)
134 return ERROR_COMMAND_ARGUMENT_INVALID
;
136 return arm_cti_mod_reg_bits(self
, CTI_GATE
, CTI_CHNL(channel
), 0xFFFFFFFF);
139 int arm_cti_write_reg(struct arm_cti
*self
, unsigned int reg
, uint32_t value
)
141 return mem_ap_write_atomic_u32(self
->ap
, self
->base
+ reg
, value
);
144 int arm_cti_read_reg(struct arm_cti
*self
, unsigned int reg
, uint32_t *p_value
)
147 return ERROR_COMMAND_ARGUMENT_INVALID
;
149 return mem_ap_read_atomic_u32(self
->ap
, self
->base
+ reg
, p_value
);
152 int arm_cti_pulse_channel(struct arm_cti
*self
, uint32_t channel
)
155 return ERROR_COMMAND_ARGUMENT_INVALID
;
157 return arm_cti_write_reg(self
, CTI_APPPULSE
, CTI_CHNL(channel
));
160 int arm_cti_set_channel(struct arm_cti
*self
, uint32_t channel
)
163 return ERROR_COMMAND_ARGUMENT_INVALID
;
165 return arm_cti_write_reg(self
, CTI_APPSET
, CTI_CHNL(channel
));
168 int arm_cti_clear_channel(struct arm_cti
*self
, uint32_t channel
)
171 return ERROR_COMMAND_ARGUMENT_INVALID
;
173 return arm_cti_write_reg(self
, CTI_APPCLEAR
, CTI_CHNL(channel
));
176 static uint32_t cti_regs
[28];
178 static const struct {
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] },
213 static int cti_find_reg_offset(const char *name
)
217 for (i
= 0; i
< ARRAY_SIZE(cti_names
); i
++) {
218 if (!strcmp(name
, cti_names
[i
].label
))
219 return cti_names
[i
].offset
;
222 LOG_ERROR("unknown CTI register %s", name
);
226 int arm_cti_cleanup_all(void)
228 struct arm_cti_object
*obj
, *tmp
;
230 list_for_each_entry_safe(obj
, tmp
, &all_cti
, lh
) {
238 COMMAND_HANDLER(handle_cti_dump
)
240 struct arm_cti_object
*obj
= CMD_DATA
;
241 struct arm_cti
*cti
= &obj
->cti
;
242 int retval
= ERROR_OK
;
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
);
248 if (retval
== ERROR_OK
)
249 retval
= dap_run(cti
->ap
->dap
);
251 if (retval
!= ERROR_OK
)
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
);
261 COMMAND_HANDLER(handle_cti_enable
)
263 struct arm_cti_object
*obj
= CMD_DATA
;
264 Jim_Interp
*interp
= CMD_CTX
->interp
;
265 struct arm_cti
*cti
= &obj
->cti
;
269 Jim_SetResultString(interp
, "wrong number of args", -1);
273 COMMAND_PARSE_ON_OFF(CMD_ARGV
[0], on_off
);
275 return arm_cti_enable(cti
, on_off
);
278 COMMAND_HANDLER(handle_cti_testmode
)
280 struct arm_cti_object
*obj
= CMD_DATA
;
281 Jim_Interp
*interp
= CMD_CTX
->interp
;
282 struct arm_cti
*cti
= &obj
->cti
;
286 Jim_SetResultString(interp
, "wrong number of args", -1);
290 COMMAND_PARSE_ON_OFF(CMD_ARGV
[0], on_off
);
292 return arm_cti_write_reg(cti
, 0xf00, on_off
? 0x1 : 0x0);
295 COMMAND_HANDLER(handle_cti_write
)
297 struct arm_cti_object
*obj
= CMD_DATA
;
298 Jim_Interp
*interp
= CMD_CTX
->interp
;
299 struct arm_cti
*cti
= &obj
->cti
;
304 Jim_SetResultString(interp
, "Wrong number of args", -1);
308 offset
= cti_find_reg_offset(CMD_ARGV
[0]);
312 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], value
);
314 return arm_cti_write_reg(cti
, offset
, value
);
317 COMMAND_HANDLER(handle_cti_read
)
319 struct arm_cti_object
*obj
= CMD_DATA
;
320 Jim_Interp
*interp
= CMD_CTX
->interp
;
321 struct arm_cti
*cti
= &obj
->cti
;
327 Jim_SetResultString(interp
, "Wrong number of args", -1);
331 offset
= cti_find_reg_offset(CMD_ARGV
[0]);
335 retval
= arm_cti_read_reg(cti
, offset
, &value
);
336 if (retval
!= ERROR_OK
)
339 command_print(CMD
, "0x%08"PRIx32
, value
);
344 COMMAND_HANDLER(handle_cti_ack
)
346 struct arm_cti_object
*obj
= CMD_DATA
;
347 struct arm_cti
*cti
= &obj
->cti
;
351 return ERROR_COMMAND_SYNTAX_ERROR
;
353 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], event
);
355 int retval
= arm_cti_ack_events(cti
, 1 << event
);
358 if (retval
!= ERROR_OK
)
364 COMMAND_HANDLER(handle_cti_channel
)
366 struct arm_cti_object
*obj
= CMD_DATA
;
367 struct arm_cti
*cti
= &obj
->cti
;
368 int retval
= ERROR_OK
;
372 return ERROR_COMMAND_SYNTAX_ERROR
;
374 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], ch_num
);
376 if (!strcmp(CMD_ARGV
[1], "gate"))
377 retval
= arm_cti_gate_channel(cti
, ch_num
);
378 else if (!strcmp(CMD_ARGV
[1], "ungate"))
379 retval
= arm_cti_ungate_channel(cti
, ch_num
);
380 else if (!strcmp(CMD_ARGV
[1], "pulse"))
381 retval
= arm_cti_pulse_channel(cti
, ch_num
);
382 else if (!strcmp(CMD_ARGV
[1], "set"))
383 retval
= arm_cti_set_channel(cti
, ch_num
);
384 else if (!strcmp(CMD_ARGV
[1], "clear"))
385 retval
= arm_cti_clear_channel(cti
, ch_num
);
387 command_print(CMD
, "Possible channel operations: gate|ungate|set|clear|pulse");
388 return ERROR_COMMAND_ARGUMENT_INVALID
;
391 if (retval
!= ERROR_OK
)
397 static const struct command_registration cti_instance_command_handlers
[] = {
400 .mode
= COMMAND_EXEC
,
401 .handler
= handle_cti_dump
,
402 .help
= "dump CTI registers",
407 .mode
= COMMAND_EXEC
,
408 .handler
= handle_cti_enable
,
409 .help
= "enable or disable the CTI",
410 .usage
= "'on'|'off'",
414 .mode
= COMMAND_EXEC
,
415 .handler
= handle_cti_testmode
,
416 .help
= "enable or disable integration test mode",
417 .usage
= "'on'|'off'",
421 .mode
= COMMAND_EXEC
,
422 .handler
= handle_cti_write
,
423 .help
= "write to a CTI register",
424 .usage
= "register_name value",
428 .mode
= COMMAND_EXEC
,
429 .handler
= handle_cti_read
,
430 .help
= "read a CTI register",
431 .usage
= "register_name",
435 .mode
= COMMAND_EXEC
,
436 .handler
= handle_cti_ack
,
437 .help
= "acknowledge a CTI event",
442 .mode
= COMMAND_EXEC
,
443 .handler
= handle_cti_channel
,
444 .help
= "do an operation on one CTI channel, possible operations: "
445 "gate, ungate, set, clear and pulse",
446 .usage
= "channel_number operation",
448 COMMAND_REGISTRATION_DONE
457 static const Jim_Nvp nvp_config_opts
[] = {
458 { .name
= "-dap", .value
= CFG_DAP
},
459 { .name
= "-ctibase", .value
= CFG_CTIBASE
},
460 { .name
= "-ap-num", .value
= CFG_AP_NUM
},
461 { .name
= NULL
, .value
= -1 }
464 static int cti_configure(Jim_GetOptInfo
*goi
, struct arm_cti_object
*cti
)
466 struct adiv5_dap
*dap
= NULL
;
471 /* parse config or cget options ... */
472 while (goi
->argc
> 0) {
473 Jim_SetEmptyResult(goi
->interp
);
475 e
= Jim_GetOpt_Nvp(goi
, nvp_config_opts
, &n
);
477 Jim_GetOpt_NvpUnknown(goi
, nvp_config_opts
, 0);
483 e
= Jim_GetOpt_Obj(goi
, &o_t
);
486 dap
= dap_instance_by_jim_obj(goi
->interp
, o_t
);
488 Jim_SetResultString(goi
->interp
, "-dap is invalid", -1);
495 e
= Jim_GetOpt_Wide(goi
, &w
);
498 cti
->cti
.base
= (uint32_t)w
;
503 e
= Jim_GetOpt_Wide(goi
, &w
);
506 if (w
< 0 || w
> DP_APSEL_MAX
) {
507 Jim_SetResultString(goi
->interp
, "-ap-num is invalid", -1);
510 cti
->ap_num
= (uint32_t)w
;
515 Jim_SetResultString(goi
->interp
, "-dap required when creating CTI", -1);
519 cti
->cti
.ap
= dap_ap(dap
, cti
->ap_num
);
524 static int cti_create(Jim_GetOptInfo
*goi
)
526 struct command_context
*cmd_ctx
;
527 static struct arm_cti_object
*cti
;
533 cmd_ctx
= current_command_context(goi
->interp
);
534 assert(cmd_ctx
!= NULL
);
537 Jim_WrongNumArgs(goi
->interp
, 1, goi
->argv
, "?name? ..options...");
541 Jim_GetOpt_Obj(goi
, &new_cmd
);
542 /* does this command exist? */
543 cmd
= Jim_GetCommand(goi
->interp
, new_cmd
, JIM_ERRMSG
);
545 cp
= Jim_GetString(new_cmd
, NULL
);
546 Jim_SetResultFormatted(goi
->interp
, "Command: %s Exists", cp
);
551 cti
= calloc(1, sizeof(struct arm_cti_object
));
555 e
= cti_configure(goi
, cti
);
561 cp
= Jim_GetString(new_cmd
, NULL
);
562 cti
->name
= strdup(cp
);
564 /* now - create the new cti name command */
565 const struct command_registration cti_subcommands
[] = {
567 .chain
= cti_instance_command_handlers
,
569 COMMAND_REGISTRATION_DONE
571 const struct command_registration cti_commands
[] = {
575 .help
= "cti instance command group",
577 .chain
= cti_subcommands
,
579 COMMAND_REGISTRATION_DONE
581 e
= register_commands(cmd_ctx
, NULL
, cti_commands
);
585 struct command
*c
= command_find_in_context(cmd_ctx
, cp
);
587 command_set_handler_data(c
, cti
);
589 list_add_tail(&cti
->lh
, &all_cti
);
591 return (ERROR_OK
== e
) ? JIM_OK
: JIM_ERR
;
594 static int jim_cti_create(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
597 Jim_GetOpt_Setup(&goi
, interp
, argc
- 1, argv
+ 1);
599 Jim_WrongNumArgs(goi
.interp
, goi
.argc
, goi
.argv
,
600 "<name> [<cti_options> ...]");
603 return cti_create(&goi
);
606 static int jim_cti_names(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
608 struct arm_cti_object
*obj
;
611 Jim_WrongNumArgs(interp
, 1, argv
, "Too many parameters");
614 Jim_SetResult(interp
, Jim_NewListObj(interp
, NULL
, 0));
615 list_for_each_entry(obj
, &all_cti
, lh
) {
616 Jim_ListAppendElement(interp
, Jim_GetResult(interp
),
617 Jim_NewStringObj(interp
, obj
->name
, -1));
623 static const struct command_registration cti_subcommand_handlers
[] = {
627 .jim_handler
= jim_cti_create
,
628 .usage
= "name '-chain-position' name [options ...]",
629 .help
= "Creates a new CTI object",
634 .jim_handler
= jim_cti_names
,
636 .help
= "Lists all registered CTI objects by name",
638 COMMAND_REGISTRATION_DONE
641 static const struct command_registration cti_command_handlers
[] = {
644 .mode
= COMMAND_CONFIG
,
645 .help
= "CTI commands",
646 .chain
= cti_subcommand_handlers
,
649 COMMAND_REGISTRATION_DONE
652 int cti_register_commands(struct command_context
*cmd_ctx
)
654 return register_commands(cmd_ctx
, NULL
, cti_command_handlers
);