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