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/+/9212

-- gerrit

commit d003c5913c3707a7962995fbd874bfe29d11c00d
Author: liangzhen <[email protected]>
Date:   Thu Oct 23 19:24:04 2025 +0800

    target: cstrace: Add coresight tmc support
    
    Add support for the coresight tmc component.
    
    Change-Id: I726753dff7dfa604dc7634a50179039bcdf9422a
    Signed-off-by: liangzhen <[email protected]>

diff --git a/doc/openocd.texi b/doc/openocd.texi
index 931bbda429..1aec747d43 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -10332,6 +10332,7 @@ You must set the @option{-dap} @emph{dap_name} 
@option{-ap-num} @emph{apn} here.
 Lists all supported coresight component types. At this writing, the supported 
coresight component types are:
 @itemize
 @item @code{funnel} - this a coresight funnel component.
+@item @code{tmc} - this a coresight tmc component.
 @end itemize
 @end deffn
 
@@ -10396,6 +10397,19 @@ The commands specific to the @code{funnel} are:
 @item @command{component_name funnel disable} @var{port} - disable a funnel 
port.
 @end itemize
 
+@subsection TMC Component
+When the coresight component is a @code{tmc} type, the configure
+configparams specific to the @code{tmc} are:
+@itemize
+@item @option{-tmc-type} @code{etb|etf|etr} - set the TMC type.
+@item @option{-hwaddr} @emph{addr} - set the trace buffer address in system 
memory.
+@item @option{-buf-size} @emph{size} - set the trace buffer size in system 
memory.
+@end itemize
+The commands specific to the @code{tmc} is:
+@itemize
+@item @command{component_name tmc dump} @var{filename} - dump trace data.
+@end itemize
+
 @anchor{armcrosstrigger}
 @section ARM Cross-Trigger Interface
 @cindex CTI
diff --git a/src/target/Makefile.am b/src/target/Makefile.am
index 10176ccba1..040c6223e2 100644
--- a/src/target/Makefile.am
+++ b/src/target/Makefile.am
@@ -113,7 +113,8 @@ ARM_DEBUG_SRC = \
        %D%/arm_tpiu_swo.c \
        %D%/arm_cti.c \
        %D%/coresight_trace.c \
-       %D%/coresight_funnel.c
+       %D%/coresight_funnel.c \
+       %D%/coresight_tmc.c
 
 AVR32_SRC = \
        %D%/avr32_ap7k.c \
diff --git a/src/target/coresight_tmc.c b/src/target/coresight_tmc.c
new file mode 100644
index 0000000000..d420daf8aa
--- /dev/null
+++ b/src/target/coresight_tmc.c
@@ -0,0 +1,641 @@
+/* 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 <time.h>
+#include <helper/log.h>
+#include <helper/types.h>
+#include <helper/command.h>
+#include <helper/jim-nvp.h>
+#include <helper/fileio.h>
+#include <helper/time_support.h>
+#include "coresight_trace.h"
+
+#define CS_TMC_RSZ                 0x004
+#define CS_TMC_STS                 0x00c
+#define CS_TMC_RRD                 0x010
+#define CS_TMC_RRP                 0x014
+#define CS_TMC_RWP                 0x018
+#define CS_TMC_TRG                 0x01c
+#define CS_TMC_CTL                 0x020
+#define CS_TMC_RWD                 0x024
+#define CS_TMC_MODE                0x028
+#define CS_TMC_LBUFLEVEL           0x02c
+#define CS_TMC_CBUFLEVEL           0x030
+#define CS_TMC_BUFWM               0x034
+#define CS_TMC_RRPHI               0x038
+#define CS_TMC_RWPHI               0x03c
+#define CS_TMC_AXICTL              0x110
+#define CS_TMC_DBALO               0x118
+#define CS_TMC_DBAHI               0x11c
+#define CS_TMC_FFSR                0x300
+#define CS_TMC_FFCR                0x304
+#define CS_TMC_PSCR                0x308
+#define CS_TMC_ITMISCOP0           0xee0
+#define CS_TMC_ITTRFLIN                    0xee8
+#define CS_TMC_ITATBDATA0          0xeec
+#define CS_TMC_ITATBCTR2           0xef0
+#define CS_TMC_ITATBCTR1           0xef4
+#define CS_TMC_ITATBCTR0           0xef8
+#define CS_TMC_AUTHSTATUS          0xfb8
+
+/* register description */
+/* CS_TMC_CTL - 0x020 */
+#define CS_TMC_CTL_CAPT_EN         1
+/* CS_TMC_STS - 0x00C */
+#define CS_TMC_STS_FULL                    0x1
+#define CS_TMC_STS_TRIGGERED       0x2
+#define CS_TMC_STS_TMCREADY        0x4
+#define CS_TMC_STS_MEMERR          0x20
+/* CS_TMC_FFCR - 0x304 */
+#define CS_TMC_FFCR_EN_FMT         0x1
+#define CS_TMC_FFCR_EN_TI          0x2
+#define CS_TMC_FFCR_FON_FLIN       0x10
+#define CS_TMC_FFCR_FON_TRIG_EVT    0x20
+#define CS_TMC_FFCR_FLUSHMAN       0x40
+#define CS_TMC_FFCR_TRIGON_TRIGIN   0x100
+#define CS_TMC_FFCR_STOP_ON_FLUSH   0x1000
+
+#define CS_TMC_ETR_BUF_SIZE_MIN            0x00100000
+#define CS_TMC_ETR_BUF_SIZE_MAX            0x100000000
+
+enum cs_tmc_type {
+       CS_TMC_TYPE_ETB,
+       CS_TMC_TYPE_ETF,
+       CS_TMC_TYPE_ETR,
+};
+
+enum cs_tmc_mode {
+       CS_TMC_MODE_CIRCULAR_BUFFER,
+       CS_TMC_MODE_SOFTWARE_FIFO,
+       CS_TMC_MODE_HARDWARE_FIFO,
+};
+
+struct cs_tmc_private_config {
+       enum cs_tmc_type type;
+       target_addr_t hwaddr;
+       uint64_t buf_size;
+};
+
+static inline struct cs_tmc_private_config
+*cs_tmc_private_config(struct cstrace_component *comp)
+{
+       assert(comp->private_config);
+       return comp->private_config;
+}
+
+static struct cs_tmc_private_config *alloc_default_cs_tmc_private_config(void)
+{
+       struct cs_tmc_private_config *config =  malloc(sizeof(struct 
cs_tmc_private_config));
+       if (!config) {
+               LOG_ERROR("Out of memory!");
+               return NULL;
+       }
+
+       // default etr
+       config->type = CS_TMC_TYPE_ETR;
+       config->buf_size = CS_TMC_ETR_BUF_SIZE_MIN;
+
+       return config;
+}
+
+#define CS_TMC_CONFIG(T) struct cs_tmc_private_config *T = 
cs_tmc_private_config(comp);
+
+static const struct {
+       uint32_t offset;
+       const char *label;
+} tmc_names[] = {
+       { CS_TMC_RSZ, "RSZ" },
+       { CS_TMC_STS, "STS" },
+       { CS_TMC_RRD, "RRD" },
+       { CS_TMC_RRP, "RRP" },
+       { CS_TMC_RWP, "RWP" },
+       { CS_TMC_TRG, "TRG" },
+       { CS_TMC_CTL, "CTL" },
+       { CS_TMC_RWD, "RWD" },
+       { CS_TMC_MODE, "MODE" },
+       { CS_TMC_LBUFLEVEL, "LBUFLEVEL" },
+       { CS_TMC_CBUFLEVEL, "CBUFLEVEL" },
+       { CS_TMC_BUFWM, "BUFWM" },
+       { CS_TMC_RRPHI, "RRPHI" },
+       { CS_TMC_RWPHI, "RWPHI" },
+       { CS_TMC_AXICTL, "AXICTL" },
+       { CS_TMC_DBALO, "DBALO" },
+       { CS_TMC_DBAHI, "DBAHI" },
+       { CS_TMC_FFSR, "FFSR" },
+       { CS_TMC_PSCR, "PSCR" },
+       { CS_TMC_ITMISCOP0, "ITMISCOP0" },
+       { CS_TMC_ITTRFLIN, "ITTRFLIN" },
+       { CS_TMC_ITATBDATA0, "ITATBDATA0" },
+       { CS_TMC_ITATBCTR2, "ITATBCTR2" },
+       { CS_TMC_ITATBCTR1, "ITATBCTR1" },
+       { CS_TMC_ITATBCTR0, "ITATBCTR0" },
+       { CS_TMC_AUTHSTATUS, "AUTHSTATUS" },
+};
+
+static int tmc_find_reg_offset(const char *name)
+{
+       for (size_t i = 0; i < ARRAY_SIZE(tmc_names); i++) {
+               if (!strcasecmp(name, tmc_names[i].label))
+                       return tmc_names[i].offset;
+       }
+
+       LOG_ERROR("unknown coresight tmc register %s", name);
+       return -1;
+}
+
+static int tmc_create(struct cstrace_component *comp)
+{
+       LOG_DEBUG("tmc_create()");
+       struct cs_tmc_private_config *config = comp->private_config;
+       if (!config) {
+               config = alloc_default_cs_tmc_private_config();
+               if (!config)
+                       return ERROR_FAIL;
+               comp->private_config = config;
+       }
+
+       return ERROR_OK;
+}
+
+static struct jim_nvp nvp_type_opts[] = {
+       { .name = "etb", .value = CS_TMC_TYPE_ETB },
+       { .name = "etf", .value = CS_TMC_TYPE_ETF },
+       { .name = "etr", .value = CS_TMC_TYPE_ETR },
+       { .name = NULL, .value = -1 }
+};
+
+enum tmc_cfg_opts {
+       CS_TMC_CFG_TYPE,
+       CS_TMC_CFG_HWADDR,
+       CS_TMC_CFG_BUFSIZE
+};
+
+static struct jim_nvp nvp_config_opts[] = {
+       { .name = "-tmc-type", .value = CS_TMC_CFG_TYPE },
+       { .name = "-hwaddr", .value = CS_TMC_CFG_HWADDR },
+       { .name = "-buf-size", .value = CS_TMC_CFG_BUFSIZE },
+       { .name = NULL, .value = -1 }
+};
+
+static int tmc_jim_configure(struct cstrace_component *comp, struct 
jim_getopt_info *goi)
+{
+       struct cs_tmc_private_config *config = comp->private_config;
+       if (!config) {
+               config = alloc_default_cs_tmc_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_TMC_CFG_TYPE:
+               if (goi->is_configure) {
+                       struct jim_nvp *type_nvp;
+                       e = jim_getopt_nvp(goi, nvp_type_opts, &type_nvp);
+                       if (e != JIM_OK) {
+                               jim_getopt_nvp_unknown(goi, nvp_type_opts, 
/*hadprefix*/ true);
+                               return e;
+                       }
+                       config->type = type_nvp->value;
+               } else {
+                       Jim_SetResultString(goi->interp, 
jim_nvp_value2name_simple(nvp_type_opts, config->type)->name, -1);
+               }
+               break;
+       case CS_TMC_CFG_HWADDR:
+               if (goi->is_configure) {
+                       jim_wide w;
+                       e = jim_getopt_wide(goi, &w);
+                       if (e != JIM_OK)
+                               return e;
+                       config->hwaddr = (target_addr_t)w;
+               } else {
+                       Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, 
config->hwaddr));
+               }
+               break;
+       case CS_TMC_CFG_BUFSIZE:
+               if (goi->is_configure) {
+                       jim_wide w;
+                       e = jim_getopt_wide(goi, &w);
+                       if (e != JIM_OK)
+                               return e;
+                       if (w < CS_TMC_ETR_BUF_SIZE_MIN && w > 
CS_TMC_ETR_BUF_SIZE_MAX) {
+                               Jim_SetResultString(goi->interp, "Invalid TMC 
ETR bufsize (1M-4GB)!", -1);
+                               return JIM_ERR;
+                       }
+                       config->buf_size = (uint64_t)w;
+               } else {
+                               Jim_SetResult(goi->interp, 
Jim_NewIntObj(goi->interp, config->buf_size));
+               }
+               break;
+       }
+       return JIM_OK;
+}
+
+static int tmc_write_rrp(struct cstrace_component *comp, uint64_t rrp)
+{
+       if (coresight_write_reg(comp, CS_TMC_RRP, rrp & 0xffffffff) != ERROR_OK)
+               return ERROR_FAIL;
+
+       return coresight_write_reg(comp, CS_TMC_RRPHI, rrp >> 32);
+}
+
+static int tmc_write_rwp(struct cstrace_component *comp, uint64_t rwp)
+{
+       if (coresight_write_reg(comp, CS_TMC_RWP, rwp & 0xffffffff) != ERROR_OK)
+               return ERROR_FAIL;
+
+       return coresight_write_reg(comp, CS_TMC_RWPHI, rwp >> 32);
+}
+
+static int tmc_read_rrp(struct cstrace_component *comp, uint64_t *rrp)
+{
+       uint32_t regval;
+       if (coresight_read_reg(comp, CS_TMC_RRP, &regval) != ERROR_OK)
+               return ERROR_FAIL;
+       *rrp = regval;
+
+       if (coresight_read_reg(comp, CS_TMC_RRPHI, &regval) != ERROR_OK)
+               return ERROR_FAIL;
+       *rrp |= (uint64_t)regval << 32;
+
+       return ERROR_OK;
+}
+
+static int tmc_read_rwp(struct cstrace_component *comp, uint64_t *rwp)
+{
+       uint32_t regval;
+       if (coresight_read_reg(comp, CS_TMC_RWP, &regval) != ERROR_OK)
+               return ERROR_FAIL;
+       *rwp = regval;
+
+       if (coresight_read_reg(comp, CS_TMC_RWPHI, &regval) != ERROR_OK)
+       *rwp |= (uint64_t)regval << 32;
+
+       return ERROR_OK;
+}
+
+static int tmc_wait_for_tmcready(struct cstrace_component *comp)
+{
+       return coresight_poll_register(comp, CS_TMC_STS, CS_TMC_STS_TMCREADY,
+                                      1, CORESIGHT_TIMEOUT);
+}
+
+static int tmc_flush_and_stop(struct cstrace_component *comp)
+{
+       uint32_t ffcr;
+       if (coresight_read_reg(comp, CS_TMC_FFCR, &ffcr) != ERROR_OK)
+               return ERROR_FAIL;
+
+       ffcr |= CS_TMC_FFCR_STOP_ON_FLUSH;
+       if (coresight_write_reg(comp, CS_TMC_FFCR, ffcr) != ERROR_OK)
+               return ERROR_FAIL;
+
+       ffcr |= CS_TMC_FFCR_FLUSHMAN;
+       if (coresight_write_reg(comp, CS_TMC_FFCR, ffcr) != ERROR_OK)
+               return ERROR_FAIL;
+
+       /* Ensure flush completes */
+       if (coresight_poll_register(comp, CS_TMC_FFCR, CS_TMC_FFCR_FLUSHMAN,
+                                   0, CORESIGHT_TIMEOUT))
+               return ERROR_FAIL;
+
+       return tmc_wait_for_tmcready(comp);
+}
+
+static int tmc_enable_hw(struct cstrace_component *comp)
+{
+       return coresight_write_reg(comp, CS_TMC_CTL, CS_TMC_CTL_CAPT_EN);
+}
+
+static int tmc_disable_hw(struct cstrace_component *comp)
+{
+       if (tmc_flush_and_stop(comp) != ERROR_OK)
+               return ERROR_FAIL;
+
+       return coresight_write_reg(comp, CS_TMC_CTL, 0x0);
+}
+
+static int tmc_etb_enable(struct cstrace_component *comp)
+{
+       if (coresight_write_reg(comp, CS_TMC_MODE, CS_TMC_MODE_CIRCULAR_BUFFER) 
!= ERROR_OK)
+               return ERROR_FAIL;
+
+       if (coresight_write_reg(comp, CS_TMC_FFCR, CS_TMC_FFCR_EN_FMT | 
CS_TMC_FFCR_EN_TI |
+                               CS_TMC_FFCR_FON_FLIN | CS_TMC_FFCR_FON_TRIG_EVT 
|
+                               CS_TMC_FFCR_TRIGON_TRIGIN) != ERROR_OK)
+               return ERROR_FAIL;
+
+       return tmc_enable_hw(comp);
+}
+
+static int tmc_etf_enable(struct cstrace_component *comp)
+{
+       /* ETF are considered as a link component and use Hardware FIFO mode by 
default here, 
+        * if you want to use a ETF as a sink, you can consider it as a ETB.
+        */
+       if (coresight_write_reg(comp, CS_TMC_MODE, CS_TMC_MODE_HARDWARE_FIFO) 
!= ERROR_OK)
+               return ERROR_FAIL;
+
+       if (coresight_write_reg(comp, CS_TMC_FFCR, CS_TMC_FFCR_EN_FMT | 
CS_TMC_FFCR_EN_TI) != ERROR_OK)
+               return ERROR_FAIL;
+
+       if (coresight_write_reg(comp, CS_TMC_BUFWM, 0x0) != ERROR_OK)
+               return ERROR_FAIL;
+
+       return tmc_enable_hw(comp);
+}
+
+static int tmc_etr_enable(struct cstrace_component *comp)
+{
+       CS_TMC_CONFIG(config);
+
+       if (coresight_write_reg(comp, CS_TMC_RSZ, config->buf_size / 4) != 
ERROR_OK)
+               return ERROR_FAIL;
+
+       if (coresight_write_reg(comp, CS_TMC_FFCR, CS_TMC_FFCR_EN_FMT | 
CS_TMC_FFCR_EN_TI |
+                               CS_TMC_FFCR_FON_FLIN | CS_TMC_FFCR_FON_TRIG_EVT 
|
+                               CS_TMC_FFCR_TRIGON_TRIGIN) != ERROR_OK)
+               return ERROR_FAIL;
+
+       if (coresight_write_reg(comp, CS_TMC_DBALO, config->hwaddr & 
0xffffffff) != ERROR_OK
+)
+               return ERROR_FAIL;
+
+       if (coresight_write_reg(comp, CS_TMC_DBAHI, config->hwaddr >> 32) != 
ERROR_OK)
+               return ERROR_FAIL;
+
+       if (tmc_write_rrp(comp, config->hwaddr) != ERROR_OK)
+               return ERROR_FAIL;
+
+       if (tmc_write_rwp(comp, config->hwaddr) != ERROR_OK)
+               return ERROR_FAIL;
+
+       return tmc_enable_hw(comp);
+}
+
+static int tmc_enable(struct cstrace_component *comp)
+{
+       CS_TMC_CONFIG(config);
+
+       int retval = tmc_wait_for_tmcready(comp);
+       if (retval != ERROR_OK)
+               return retval;
+
+       switch (config->type) {
+       case CS_TMC_TYPE_ETB:
+               retval = tmc_etb_enable(comp);
+               break;
+       case CS_TMC_TYPE_ETF:
+               retval = tmc_etf_enable(comp);
+               break;
+       case CS_TMC_TYPE_ETR:
+               retval = tmc_etr_enable(comp);
+               break;
+       default:
+               return ERROR_FAIL;
+       }
+
+       return retval;
+}
+
+static int tmc_disable(struct cstrace_component *comp)
+{
+       CS_TMC_CONFIG(config);
+
+       int retval;
+
+       switch (config->type) {
+       case CS_TMC_TYPE_ETB:
+       case CS_TMC_TYPE_ETF:
+       case CS_TMC_TYPE_ETR:
+               retval = tmc_disable_hw(comp);
+               break;
+       default:
+               return ERROR_FAIL;
+       }
+
+       return retval;
+}
+
+static int tmc_status(struct cstrace_component *comp, struct 
command_invocation *cmd)
+{
+       uint32_t rsz, sts, ctl, ffsr, ffcr;
+       uint64_t rrp, rwp;
+
+       if (tmc_wait_for_tmcready(comp) != ERROR_OK)
+               return ERROR_FAIL;
+
+       if (tmc_read_rrp(comp, &rrp) != ERROR_OK)
+               return ERROR_FAIL;
+       if (tmc_read_rwp(comp, &rwp) != ERROR_OK)
+               return ERROR_FAIL;
+       if (coresight_read_reg(comp, CS_TMC_RSZ, &rsz) != ERROR_OK)
+               return ERROR_FAIL;
+       if (coresight_read_reg(comp, CS_TMC_STS, &sts) != ERROR_OK)
+               return ERROR_FAIL;
+       if (coresight_read_reg(comp, CS_TMC_CTL, &ctl) != ERROR_OK)
+               return ERROR_FAIL;
+       if (coresight_read_reg(comp, CS_TMC_FFSR, &ffsr) != ERROR_OK)
+               return ERROR_FAIL;
+       if (coresight_read_reg(comp, CS_TMC_FFCR, &ffcr) != ERROR_OK)
+               return ERROR_FAIL;
+
+       command_print(CMD, "Depth:       0x%" PRIx64, (uint64_t)rsz * 4);
+       command_print(CMD, "Status:      0x%x", sts);
+       command_print(CMD, "ARM read ptr:     0x%" PRIx64, rrp);
+       command_print(CMD, "ARM write ptr:    0x%" PRIx64, rwp);
+       command_print(CMD, "Control:          0x%x", ctl);
+       command_print(CMD, "Flush status:     0x%x", ffsr);
+       command_print(CMD, "Flush control:    0x%x", ffcr);
+
+       return ERROR_OK;
+}
+
+static int tmc_write(struct cstrace_component *comp, const char *reg_name, 
uint32_t value)
+{
+       int offset = tmc_find_reg_offset(reg_name);
+       if (offset < 0)
+               return ERROR_FAIL;
+
+       return coresight_write_reg(comp, offset, value);
+}
+
+static int tmc_read(struct cstrace_component *comp, const char *reg_name, 
uint32_t *value)
+{
+       int offset = tmc_find_reg_offset(reg_name);
+       if (offset < 0)
+               return ERROR_FAIL;
+
+       return coresight_read_reg(comp, offset, value);
+}
+
+static int tmc_etb_dump(struct cstrace_component *comp, struct fileio *fileio)
+{
+       uint32_t read_data;
+
+       while (1) {
+               if (coresight_read_reg(comp, CS_TMC_RRD, &read_data) != 
ERROR_OK)
+                       return ERROR_FAIL;
+
+               if (read_data == 0xffffffff)
+                       break;
+
+               if (fileio_write_u32(fileio, read_data) != ERROR_OK)
+                       return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int tmc_etr_dump(struct cstrace_component *comp, struct fileio *fileio)
+{
+       CS_TMC_CONFIG(config);
+
+       int retval;
+       uint8_t *buffer;
+       target_addr_t address;
+       uint64_t size;
+       uint64_t rrp, rwp;
+
+       if (tmc_read_rrp(comp, &rrp) != ERROR_OK)
+               return ERROR_FAIL;
+       if (tmc_read_rwp(comp, &rwp) != ERROR_OK)
+               return ERROR_FAIL;
+
+       address = config->hwaddr;
+       size = rwp - rrp;
+
+       uint32_t buf_size = (size > 4096) ? 4096 : size;
+       buffer = malloc(buf_size);
+       if (!buffer)
+               return ERROR_FAIL;
+
+       while (size > 0) {
+               size_t size_written;
+               uint32_t this_run_size = (size > buf_size) ? buf_size : size;
+               retval = coresight_read_buffer(comp, address, this_run_size, 
buffer);
+               if (retval != ERROR_OK)
+                       break;
+
+               retval = fileio_write(fileio, this_run_size, buffer, 
&size_written);
+               if (retval != ERROR_OK)
+                       break;
+
+               size -= this_run_size;
+               address += this_run_size;
+       }
+
+       free(buffer);
+
+       return retval;
+}
+
+COMMAND_HANDLER(handle_tmc_dump)
+{
+       struct cstrace_component *comp = CMD_DATA;
+       struct fileio *fileio;
+       int retval, retvaltemp;
+       struct duration bench;
+
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       retval = fileio_open(&fileio, CMD_ARGV[0], FILEIO_WRITE, FILEIO_BINARY);
+       if (retval != ERROR_OK)
+               return retval;
+
+       CS_TMC_CONFIG(config);
+
+       duration_start(&bench);
+
+       switch (config->type) {
+       case CS_TMC_TYPE_ETB:
+               retval = tmc_etb_dump(comp, fileio);
+               break;
+       case CS_TMC_TYPE_ETF:
+               break;
+       case CS_TMC_TYPE_ETR:
+               retval = tmc_etr_dump(comp, fileio);
+               break;
+       default:
+               return ERROR_FAIL;
+       }
+
+       if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) {
+               size_t filesize;
+               retval = fileio_size(fileio, &filesize);
+               if (retval != ERROR_OK)
+                       return retval;
+               command_print(CMD, "dumped %zu bytes in %fs (%0.3f KiB/s)", 
filesize,
+                             duration_elapsed(&bench), duration_kbps(&bench, 
filesize));
+       }
+
+       retvaltemp = fileio_close(fileio);
+       if (retvaltemp != ERROR_OK)
+               return retvaltemp;
+
+       return retval;
+}
+
+static const struct command_registration tmc_exec_command_handlers[] = {
+       {
+               .name  = "dump",
+               .mode  = COMMAND_EXEC,
+               .handler = handle_tmc_dump,
+               .help  = "tmc dump trace",
+               .usage = "<filename>",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration tmc_command_handlers[] = {
+       {
+               .name = "tmc",
+               .mode = COMMAND_ANY,
+               .help = "TMC Command Group",
+               .usage = "",
+               .chain = tmc_exec_command_handlers
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+struct coresight_type coresight_tmc = {
+       .name = "tmc",
+
+       .coresight_create = tmc_create,
+       .coresight_jim_configure = tmc_jim_configure,
+
+       .enable = tmc_enable,
+       .disable = tmc_disable,
+       .status = tmc_status,
+       .write = tmc_write,
+       .read = tmc_read,
+
+       .commands = tmc_command_handlers,
+};
diff --git a/src/target/coresight_trace.c b/src/target/coresight_trace.c
index 9cbc7804ef..436754700c 100644
--- a/src/target/coresight_trace.c
+++ b/src/target/coresight_trace.c
@@ -24,6 +24,7 @@ static OOCD_LIST_HEAD(all_cstrace_component);
 
 static struct coresight_type *coresight_type[] = {
        &coresight_funnel,
+       &coresight_tmc,
 };
 
 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 8bf33ba044..ecd7957824 100644
--- a/src/target/coresight_trace.h
+++ b/src/target/coresight_trace.h
@@ -69,5 +69,6 @@ int cstrace_cleanup_all(void);
 int cstrace_register_commands(struct command_context *cmd_ctx);
 
 extern struct coresight_type coresight_funnel;
+extern struct coresight_type coresight_tmc;
 
 #endif /* OPENOCD_TARGET_CORESIGHT_TRACE_H */

-- 

Reply via email to