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/+/9213
-- gerrit commit 38cf8f3e36dce575ee39d1070429c0a5f23179c1 Author: liangzhen <[email protected]> Date: Mon Oct 27 13:58:39 2025 +0800 target: cstrace: Add coresight timestamp support Add support for the coresight timestamp component. Change-Id: Ib02ab2e1b146e0ecd16c38dad9a2dae7a4dea6f1 Signed-off-by: liangzhen <[email protected]> diff --git a/doc/openocd.texi b/doc/openocd.texi index 1aec747d43..a0f2134c76 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -10333,6 +10333,7 @@ Lists all supported coresight component types. At this writing, the supported co @itemize @item @code{funnel} - this a coresight funnel component. @item @code{tmc} - this a coresight tmc component. +@item @code{timestamp} - this a coresight timestamp component. @end itemize @end deffn @@ -10410,6 +10411,14 @@ The commands specific to the @code{tmc} is: @item @command{component_name tmc dump} @var{filename} - dump trace data. @end itemize +@subsection Timestamp Component +When the coresight component is a @code{timestamp} type, the configure +configparams specific to the @code{timestamp} are: +@itemize +@item @option{-halt-debug} @code{on|off} - set timestamp run or halt on debug. +@item @option{-cntval} @emph{cntval} - set the current counter value. +@end itemize + @anchor{armcrosstrigger} @section ARM Cross-Trigger Interface @cindex CTI diff --git a/src/target/Makefile.am b/src/target/Makefile.am index 040c6223e2..976987b5b6 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -114,7 +114,8 @@ ARM_DEBUG_SRC = \ %D%/arm_cti.c \ %D%/coresight_trace.c \ %D%/coresight_funnel.c \ - %D%/coresight_tmc.c + %D%/coresight_tmc.c \ + %D%/coresight_timestamp.c AVR32_SRC = \ %D%/avr32_ap7k.c \ diff --git a/src/target/coresight_timestamp.c b/src/target/coresight_timestamp.c new file mode 100644 index 0000000000..1ae6127562 --- /dev/null +++ b/src/target/coresight_timestamp.c @@ -0,0 +1,247 @@ +/* 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_TIMESTAMP_CNTCR 0x000 +#define CS_TIMESTAMP_CNTSR 0x004 +#define CS_TIMESTAMP_CNTCVL 0x008 +#define CS_TIMESTAMP_CNTCVU 0x00c + +/* register description */ +/* CS_TIMESTAMP_CNTCR - 0x000 */ +#define CS_TIMESTAMP_CNTCR_EN 0x1 +#define CS_TIMESTAMP_CNTCR_HDBG 0x2 + +/* CS_TIMESTAMP_CNTSR - 0x004 */ +#define CS_TIMESTAMP_CNTSR_DBGH 0x2 + +struct cs_timestamp_private_config { + bool halt_debug; + uint64_t cntval; +}; + +static inline struct cs_timestamp_private_config +*cs_timestamp_private_config(struct cstrace_component *comp) +{ + assert(comp->private_config); + return comp->private_config; +} + +static struct cs_timestamp_private_config *alloc_default_cs_timestamp_private_config(void) +{ + struct cs_timestamp_private_config *config = malloc(sizeof(struct cs_timestamp_private_config)); + if (!config) { + LOG_ERROR("Out of memory!"); + return NULL; + } + + config->halt_debug = false; + + return config; +} + +#define CS_TIMESTAMP_CONFIG(F) struct cs_timestamp_private_config *F = cs_timestamp_private_config(comp); + +static const struct { + uint32_t offset; + const char *label; +} timestamp_names[] = { + { CS_TIMESTAMP_CNTCR, "CNTCR" }, + { CS_TIMESTAMP_CNTSR, "CNTSR" }, + { CS_TIMESTAMP_CNTCVL, "CNTCVL" }, + { CS_TIMESTAMP_CNTCVU, "CNTCVU" }, +}; + +static int timestamp_find_reg_offset(const char *name) +{ + for (size_t i = 0; i < ARRAY_SIZE(timestamp_names); i++) { + if (!strcasecmp(name, timestamp_names[i].label)) + return timestamp_names[i].offset; + } + + LOG_ERROR("unknown coresight timestamp register %s", name); + return -1; +} + +static int timestamp_create(struct cstrace_component *comp) +{ + LOG_DEBUG("timestamp_create()"); + struct cs_timestamp_private_config *config = comp->private_config; + if (!config) { + config = alloc_default_cs_timestamp_private_config(); + if (!config) + return ERROR_FAIL; + comp->private_config = config; + } + return ERROR_OK; +} + +static struct jim_nvp nvp_halt_debug_opts[] = { + { .name = "off", .value = false }, + { .name = "on", .value = true }, + { .name = NULL, .value = -1 } +}; + +enum timestamp_cfg_opts { + CS_TIMESTAMP_CFG_HDBG, + CS_TIMESTAMP_CFG_CNTVAL +}; + +static struct jim_nvp nvp_config_opts[] = { + { .name = "-halt-debug", .value = CS_TIMESTAMP_CFG_HDBG }, + { .name = "-cntval", .value = CS_TIMESTAMP_CFG_CNTVAL }, + { .name = NULL, .value = -1 } +}; + +static int timestamp_jim_configure(struct cstrace_component *comp, struct jim_getopt_info *goi) +{ + struct cs_timestamp_private_config *config = comp->private_config; + if (!config) { + config = alloc_default_cs_timestamp_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_TIMESTAMP_CFG_HDBG: + if (goi->is_configure) { + struct jim_nvp *halt_debug_nvp; + e = jim_getopt_nvp(goi, nvp_halt_debug_opts, &halt_debug_nvp); + if (e != JIM_OK) { + jim_getopt_nvp_unknown(goi, nvp_halt_debug_opts, /*hadprefix*/ true); + return e; + } + config->halt_debug = halt_debug_nvp->value; + } else { + Jim_SetResultString(goi->interp, jim_nvp_value2name_simple(nvp_halt_debug_opts, config->halt_debug)->name, -1); + } + break; + case CS_TIMESTAMP_CFG_CNTVAL: + if (goi->is_configure) { + jim_wide w; + e = jim_getopt_wide(goi, &w); + if (e != JIM_OK) + return e; + config->cntval = (uint64_t)w; + } else { + Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, config->cntval)); + } + break; + } + return JIM_OK; +} + +static int timestamp_enable(struct cstrace_component *comp) +{ + CS_TIMESTAMP_CONFIG(config); + + if (coresight_write_reg(comp, CS_TIMESTAMP_CNTCVL, config->cntval & 0xffffffff) != ERROR_OK) + return ERROR_FAIL; + + if (coresight_write_reg(comp, CS_TIMESTAMP_CNTCVU, config->cntval >> 32) != ERROR_OK) + return ERROR_FAIL; + + uint32_t cntcr = CS_TIMESTAMP_CNTCR_EN; + cntcr = set_field(cntcr, CS_TIMESTAMP_CNTCR_HDBG, config->halt_debug); + + return coresight_write_reg(comp, CS_TIMESTAMP_CNTCR, cntcr); +} + +static int timestamp_disable(struct cstrace_component *comp) +{ + uint32_t cntcr; + if (coresight_read_reg(comp, CS_TIMESTAMP_CNTCR, &cntcr) != ERROR_OK) + return ERROR_FAIL; + + cntcr = set_field(cntcr, CS_TIMESTAMP_CNTCR_EN, 0x0); + + return coresight_write_reg(comp, CS_TIMESTAMP_CNTCR, cntcr); +} + +static int timestamp_status(struct cstrace_component *comp, struct command_invocation *cmd) +{ + uint32_t cntcr, cntsr, cntcvl, cntcvu; + + if (coresight_read_reg(comp, CS_TIMESTAMP_CNTCR, &cntcr) != ERROR_OK) + return ERROR_FAIL; + + if (coresight_read_reg(comp, CS_TIMESTAMP_CNTSR, &cntsr) != ERROR_OK) + return ERROR_FAIL; + + if (coresight_read_reg(comp, CS_TIMESTAMP_CNTCVL, &cntcvl) != ERROR_OK) + return ERROR_FAIL; + + if (coresight_read_reg(comp, CS_TIMESTAMP_CNTCVU, &cntcvu) != ERROR_OK) + return ERROR_FAIL; + + command_print(CMD, "Timestamp counter status: %s", get_field(cntcr, CS_TIMESTAMP_CNTCR_EN) ? "enabled" : "disabled"); + command_print(CMD, "Timestamp counter in debug mode: %s", + jim_nvp_value2name_simple(nvp_halt_debug_opts, get_field(cntsr, CS_TIMESTAMP_CNTSR_DBGH))->name); + command_print(CMD, "Timestamp counter value lower: 0x%x", cntcvl); + command_print(CMD, "Timestamp counter value upper: 0x%x", cntcvu); + + return ERROR_OK; +} + +static int timestamp_write(struct cstrace_component *comp, const char *reg_name, uint32_t value) +{ + int offset = timestamp_find_reg_offset(reg_name); + if (offset < 0) + return ERROR_FAIL; + + return coresight_write_reg(comp, offset, value); +} + +static int timestamp_read(struct cstrace_component *comp, const char *reg_name, uint32_t *value) +{ + int offset = timestamp_find_reg_offset(reg_name); + if (offset < 0) + return ERROR_FAIL; + + return coresight_read_reg(comp, offset, value); +} + +struct coresight_type coresight_timestamp = { + .name = "timestamp", + + .coresight_create = timestamp_create, + .coresight_jim_configure = timestamp_jim_configure, + + .enable = timestamp_enable, + .disable = timestamp_disable, + .status = timestamp_status, + .write = timestamp_write, + .read = timestamp_read, +}; diff --git a/src/target/coresight_trace.c b/src/target/coresight_trace.c index 436754700c..e0e6360cb6 100644 --- a/src/target/coresight_trace.c +++ b/src/target/coresight_trace.c @@ -25,6 +25,7 @@ static OOCD_LIST_HEAD(all_cstrace_component); static struct coresight_type *coresight_type[] = { &coresight_funnel, &coresight_tmc, + &coresight_timestamp, }; 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 ecd7957824..c4bcb465ab 100644 --- a/src/target/coresight_trace.h +++ b/src/target/coresight_trace.h @@ -70,5 +70,6 @@ int cstrace_register_commands(struct command_context *cmd_ctx); extern struct coresight_type coresight_funnel; extern struct coresight_type coresight_tmc; +extern struct coresight_type coresight_timestamp; #endif /* OPENOCD_TARGET_CORESIGHT_TRACE_H */ --
