This is an automated email from Gerrit. "liangzhen <[email protected]>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9031
-- gerrit commit dce3227c3bc9083ad7afbf1cd3a13c9899f58200 Author: liangzhen <[email protected]> Date: Wed Oct 22 19:49:25 2025 +0800 target: cstrace: Add coresight funnel support Add support for the coresight funnel component. Change-Id: I9057c690a9dde39ae154db7cad6fd41ae3b90fa9 Signed-off-by: liangzhen <[email protected]> diff --git a/doc/openocd.texi b/doc/openocd.texi index afbf0e5317..931bbda429 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -10330,6 +10330,9 @@ You must set the @option{-dap} @emph{dap_name} @option{-ap-num} @emph{apn} here. @deffn {Command} {cstrace types} Lists all supported coresight component types. At this writing, the supported coresight component types are: +@itemize +@item @code{funnel} - this a coresight funnel component. +@end itemize @end deffn @deffn {Command} {cstrace names} @@ -10379,6 +10382,20 @@ Write @var{value} to the coresight component register with the symbolic name @va Print the value read from the coresight component register with the symbolic name @var{reg_name}. @end deffn +@subsection Funnel Component +When the coresight component is a @code{funnel} type, the configure +configparams specific to the @code{funnel} are: +@itemize +@item @option{-ports} @emph{ports_mask} - funnel ports opened or closed by +@command{component_name enable} and @command{component_name disable}. +@item @option{-priority} @emph{priority} - sets the priority of each port of the funnel. +@end itemize +The commands specific to the @code{funnel} are: +@itemize +@item @command{component_name funnel enable} @var{port} - enable a funnel port. +@item @command{component_name funnel disable} @var{port} - disable a funnel port. +@end itemize + @anchor{armcrosstrigger} @section ARM Cross-Trigger Interface @cindex CTI diff --git a/src/target/Makefile.am b/src/target/Makefile.am index 35f0cb60b7..10176ccba1 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -112,7 +112,8 @@ ARM_DEBUG_SRC = \ %D%/etm_dummy.c \ %D%/arm_tpiu_swo.c \ %D%/arm_cti.c \ - %D%/coresight_trace.c + %D%/coresight_trace.c \ + %D%/coresight_funnel.c AVR32_SRC = \ %D%/avr32_ap7k.c \ diff --git a/src/target/coresight_funnel.c b/src/target/coresight_funnel.c new file mode 100644 index 0000000000..3684f3eee9 --- /dev/null +++ b/src/target/coresight_funnel.c @@ -0,0 +1,321 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2025 by liangzhen * + * [email protected] * + ***************************************************************************/ + +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <helper/log.h> +#include <helper/types.h> +#include <helper/command.h> +#include <helper/jim-nvp.h> +#include "coresight_trace.h" + +#define CS_FUNNEL_FUNCTL 0x000 +#define CS_FUNNEL_PRICTL 0x004 + +#define CS_FUNNEL_PRICTL_RESET_VAL 0xfac688 + +#define CS_FUNNEL_HOLDTIME_MASK 0xf00 +#define CS_FUNNEL_HOLDTIME 0x7 +#define CS_FUNNEL_ENSx_MASK 0xff +#define CS_FUNNEL_PORTS_MAX 0x8 + +struct cs_funnel_private_config { + uint32_t ports; + uint32_t priority; +}; + +static inline struct cs_funnel_private_config +*cs_funnel_private_config(struct cstrace_component *comp) +{ + assert(comp->private_config); + return comp->private_config; +} + +static struct cs_funnel_private_config *alloc_default_cs_funnel_private_config(void) +{ + struct cs_funnel_private_config *config = malloc(sizeof(struct cs_funnel_private_config)); + if (!config) { + LOG_ERROR("Out of memory!"); + return NULL; + } + + config->ports = (1 << CS_FUNNEL_PORTS_MAX) - 1; + config->priority = CS_FUNNEL_PRICTL_RESET_VAL; + + return config; +} + +#define CS_FUNNEL_CONFIG(F) struct cs_funnel_private_config *F = cs_funnel_private_config(comp); + +static const struct { + uint32_t offset; + const char *label; +} funnel_names[] = { + { CS_FUNNEL_FUNCTL, "FUNCTL" }, + { CS_FUNNEL_PRICTL, "PRICTL" }, +}; + +static int funnel_find_reg_offset(const char *name) +{ + for (size_t i = 0; i < ARRAY_SIZE(funnel_names); i++) { + if (!strcasecmp(name, funnel_names[i].label)) + return funnel_names[i].offset; + } + + LOG_ERROR("unknown coresight funnel register %s", name); + return -1; +} + +static int funnel_create(struct cstrace_component *comp) +{ + LOG_DEBUG("funnel_create()"); + struct cs_funnel_private_config *config = comp->private_config; + if (!config) { + config = alloc_default_cs_funnel_private_config(); + if (!config) + return ERROR_FAIL; + comp->private_config = config; + } + return ERROR_OK; +} + +enum funnel_cfg_opts { + CS_FUNNEL_CFG_PORTS, + CS_FUNNEL_CFG_PRIORITY, +}; + +static struct jim_nvp nvp_config_opts[] = { + { .name = "-ports", .value = CS_FUNNEL_CFG_PORTS }, + { .name = "-priority", .value = CS_FUNNEL_CFG_PRIORITY }, + { .name = NULL, .value = -1 } +}; + +static int funnel_jim_configure(struct cstrace_component *comp, struct jim_getopt_info *goi) +{ + struct cs_funnel_private_config *config = comp->private_config; + if (!config) { + config = alloc_default_cs_funnel_private_config(); + if (!config) + return JIM_ERR; + comp->private_config = config; + } + + if (!goi->argc) + return JIM_OK; + + struct jim_nvp *n; + int e = jim_nvp_name2value_obj(goi->interp, nvp_config_opts, goi->argv[0], &n); + + if (e != JIM_OK) + return JIM_CONTINUE; + + e = jim_getopt_obj(goi, NULL); + if (e != JIM_OK) + return e; + + if (!goi->is_configure && goi->argc > 0) { + /*no arguments */ + Jim_WrongNumArgs(goi->interp, 2, goi->argv - 2, ""); + return JIM_ERR; + } + + switch (n->value) { + case CS_FUNNEL_CFG_PORTS: + if (goi->is_configure) { + jim_wide w; + e = jim_getopt_wide(goi, &w); + if (e != JIM_OK) + return e; + if (w < 1 && w > CS_FUNNEL_ENSx_MASK) { + Jim_SetResultString(goi->interp, "Invalid ports!", -1); + return JIM_ERR; + } + config->ports = (uint32_t)w; + } else { + Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, config->ports)); + } + break; + case CS_FUNNEL_CFG_PRIORITY: + if (goi->is_configure) { + jim_wide w; + e = jim_getopt_wide(goi, &w); + if (e != JIM_OK) + return e; + config->priority = (uint32_t)w; + } else { + Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, config->priority)); + } + break; + } + return JIM_OK; +} + +static int funnel_enable(struct cstrace_component *comp) +{ + CS_FUNNEL_CONFIG(config); + + uint32_t functl; + if (coresight_read_reg(comp, CS_FUNNEL_FUNCTL, &functl) != ERROR_OK) + return ERROR_FAIL; + + functl = set_field(functl, CS_FUNNEL_HOLDTIME_MASK, CS_FUNNEL_HOLDTIME); + functl |= config->ports; + if (coresight_write_reg(comp, CS_FUNNEL_FUNCTL, functl) != ERROR_OK) + return ERROR_FAIL; + + return coresight_write_reg(comp, CS_FUNNEL_PRICTL, config->priority); +} + +static int funnel_disable(struct cstrace_component *comp) +{ + uint32_t functl; + if (coresight_read_reg(comp, CS_FUNNEL_FUNCTL, &functl) != ERROR_OK) + return ERROR_FAIL; + + functl = set_field(functl, CS_FUNNEL_ENSx_MASK, 0x0); + + return coresight_write_reg(comp, CS_FUNNEL_FUNCTL, functl); +} + +static int funnel_status(struct cstrace_component *comp, struct command_invocation *cmd) +{ + uint32_t functl, ports; + if (coresight_read_reg(comp, CS_FUNNEL_FUNCTL, &functl) != ERROR_OK) + return ERROR_FAIL; + + ports = get_field(functl, CS_FUNNEL_ENSx_MASK); + + for (size_t i = 0; i < CS_FUNNEL_PORTS_MAX; i++) { + command_print(cmd, "funnel port %zu: %s", i, (ports & 1) ? "enabled" : "disabled"); + ports >>= 1; + } + + return ERROR_OK; +} + +static int funnel_write(struct cstrace_component *comp, const char *reg_name, uint32_t value) +{ + int offset = funnel_find_reg_offset(reg_name); + if (offset < 0) + return ERROR_FAIL; + + return coresight_write_reg(comp, offset, value); +} + +static int funnel_read(struct cstrace_component *comp, const char *reg_name, uint32_t *value) +{ + int offset = funnel_find_reg_offset(reg_name); + if (offset < 0) + return ERROR_FAIL; + + return coresight_read_reg(comp, offset, value); +} + +COMMAND_HANDLER(handle_funnel_enable) +{ + struct cstrace_component *comp = CMD_DATA; + uint32_t functl, port; + int retval; + + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], port); + if (port >= CS_FUNNEL_PORTS_MAX) { + command_print(CMD, "invalid funnel port number (0-7)"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + if (coresight_unlock(comp) != ERROR_OK) + return ERROR_FAIL; + + if (coresight_read_reg(comp, CS_FUNNEL_FUNCTL, &functl) != ERROR_OK) + return ERROR_FAIL; + + functl |= (1 << port); + retval = coresight_write_reg(comp, CS_FUNNEL_FUNCTL, functl); + + if (coresight_lock(comp) != ERROR_OK) + return ERROR_FAIL; + + return retval; +} + +COMMAND_HANDLER(handle_funnel_disable) +{ + struct cstrace_component *comp = CMD_DATA; + uint32_t functl, port; + int retval; + + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], port); + if (port >= CS_FUNNEL_PORTS_MAX) { + command_print(CMD, "invalid funnel port number (0-7)"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + if (coresight_unlock(comp) != ERROR_OK) + return ERROR_FAIL; + + if (coresight_read_reg(comp, CS_FUNNEL_FUNCTL, &functl) != ERROR_OK) + return ERROR_FAIL; + + functl &= ~(1 << port); + retval = coresight_write_reg(comp, CS_FUNNEL_FUNCTL, functl); + + if (coresight_lock(comp) != ERROR_OK) + return ERROR_FAIL; + + return retval; +} + +static const struct command_registration funnel_exec_command_handlers[] = { + { + .name = "enable", + .mode = COMMAND_EXEC, + .handler = handle_funnel_enable, + .help = "enable funnel port", + .usage = "<port>", + }, + { + .name = "disable", + .mode = COMMAND_EXEC, + .handler = handle_funnel_disable, + .help = "disable funnel port", + .usage = "<port>", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration funnel_command_handlers[] = { + { + .name = "funnel", + .mode = COMMAND_ANY, + .help = "Funnel Command Group", + .usage = "", + .chain = funnel_exec_command_handlers + }, + COMMAND_REGISTRATION_DONE +}; + +struct coresight_type coresight_funnel = { + .name = "funnel", + + .coresight_create = funnel_create, + .coresight_jim_configure = funnel_jim_configure, + + .enable = funnel_enable, + .disable = funnel_disable, + .status = funnel_status, + .write = funnel_write, + .read = funnel_read, + + .commands = funnel_command_handlers, +}; diff --git a/src/target/coresight_trace.c b/src/target/coresight_trace.c index dda03654d7..9cbc7804ef 100644 --- a/src/target/coresight_trace.c +++ b/src/target/coresight_trace.c @@ -23,6 +23,7 @@ static OOCD_LIST_HEAD(all_cstrace_component); static struct coresight_type *coresight_type[] = { + &coresight_funnel, }; int coresight_write_reg(const struct cstrace_component *comp, unsigned int reg, uint32_t value) diff --git a/src/target/coresight_trace.h b/src/target/coresight_trace.h index a0b9303630..8bf33ba044 100644 --- a/src/target/coresight_trace.h +++ b/src/target/coresight_trace.h @@ -68,4 +68,6 @@ int cstrace_cleanup_all(void); int cstrace_register_commands(struct command_context *cmd_ctx); +extern struct coresight_type coresight_funnel; + #endif /* OPENOCD_TARGET_CORESIGHT_TRACE_H */ --
