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 */

-- 

Reply via email to