public inbox for linux-riscv@lists.infradead.org
 help / color / mirror / Atom feed
From: Zane Leung <liangzhen@linux.spacemit.com>
To: robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
	palmer@dabbelt.com, pjw@kernel.org, gregkh@linuxfoundation.org,
	alexander.shishkin@linux.intel.com, irogers@google.com
Cc: coresight@lists.linaro.org, peterz@infradead.org,
	mingo@redhat.com, namhyung@kernel.org, mark.rutland@arm.com,
	jolsa@kernel.org, adrian.hunter@intel.com,
	kan.liang@linux.intel.com, mchitale@gmail.com,
	anup@brainfault.org, atish.patra@linux.dev,
	andrew.jones@oss.qualcomm.com, sunilvl@oss.qualcomm.com,
	linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org,
	anup.patel@oss.qualcomm.com, mayuresh.chitale@oss.qualcomm.com,
	zhuangqiubin@linux.spacemit.com
Subject: [RFC PATCH 06/12] coresight rvtrace: Add timestamp component support for encoder and funnel
Date: Tue, 14 Apr 2026 11:41:47 +0800	[thread overview]
Message-ID: <20260414034153.3272485-7-liangzhen@linux.spacemit.com> (raw)
In-Reply-To: <20260414034153.3272485-1-liangzhen@linux.spacemit.com>

From: liangzhen <zhen.liang@spacemit.com>

Implement timestamp as a configurable sub-component for both encoder
and funnel drivers.

Signed-off-by: liangzhen <zhen.liang@spacemit.com>
---
 drivers/hwtracing/coresight/Makefile          |   2 +-
 .../coresight/rvtrace-encoder-core.c          |  42 ++-
 .../coresight/rvtrace-encoder-sysfs.c         |  50 ++++
 drivers/hwtracing/coresight/rvtrace-encoder.h |   8 +
 drivers/hwtracing/coresight/rvtrace-funnel.c  |  95 +++++-
 drivers/hwtracing/coresight/rvtrace-funnel.h  |   8 +
 .../hwtracing/coresight/rvtrace-timestamp.c   | 278 ++++++++++++++++++
 .../hwtracing/coresight/rvtrace-timestamp.h   |  64 ++++
 8 files changed, 543 insertions(+), 4 deletions(-)
 create mode 100644 drivers/hwtracing/coresight/rvtrace-timestamp.c
 create mode 100644 drivers/hwtracing/coresight/rvtrace-timestamp.h

diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
index 2264a313a773..3ad1b0399f86 100644
--- a/drivers/hwtracing/coresight/Makefile
+++ b/drivers/hwtracing/coresight/Makefile
@@ -58,7 +58,7 @@ obj-$(CONFIG_CORESIGHT_CTCU) += coresight-ctcu.o
 coresight-ctcu-y := coresight-ctcu-core.o
 obj-$(CONFIG_CORESIGHT_KUNIT_TESTS) += coresight-kunit-tests.o
 obj-$(CONFIG_RVTRACE) += rvtrace.o
-rvtrace-y := rvtrace-core.o
+rvtrace-y := rvtrace-core.o rvtrace-timestamp.o
 obj-$(CONFIG_RVTRACE_ATBBRIDGE) += rvtrace-atbbridge.o
 obj-$(CONFIG_RVTRACE_FUNNEL) += rvtrace-funnel.o
 obj-$(CONFIG_RVTRACE_ENCODER) += rvtrace-encoder.o
diff --git a/drivers/hwtracing/coresight/rvtrace-encoder-core.c b/drivers/hwtracing/coresight/rvtrace-encoder-core.c
index 149a3cd97602..7bd075b8ce4f 100644
--- a/drivers/hwtracing/coresight/rvtrace-encoder-core.c
+++ b/drivers/hwtracing/coresight/rvtrace-encoder-core.c
@@ -14,9 +14,11 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
+#include <linux/property.h>
 #include <linux/rvtrace.h>
 
 #include "rvtrace-encoder.h"
+#include "rvtrace-timestamp.h"
 #include "coresight-etm-perf.h"
 
 static int boot_enable;
@@ -172,6 +174,10 @@ static void encoder_set_config(struct rvtrace_component *comp)
 			 config->inst_syncmax);
 		config->inst_syncmax = BMVAL(val, 20, 23);
 	}
+
+	/* Configure timestamp only if encoder has timestamp component */
+	if (encoder_data->has_timestamp && encoder_data->ts_ctrl)
+		timestamp_set_config(comp, dev, &encoder_data->ts_config);
 }
 
 static int encoder_enable_hw(struct rvtrace_component *comp)
@@ -192,6 +198,16 @@ static int encoder_enable_hw(struct rvtrace_component *comp)
 	if (ret)
 		goto done;
 
+	/* Enable timestamp only if encoder has timestamp component */
+	if (encoder_data->has_timestamp && encoder_data->ts_ctrl) {
+		ret = timestamp_enable(comp);
+		if (ret) {
+			dev_warn(&encoder_data->csdev->dev,
+				 "Failed to enable timestamp\n");
+			ret = 0;  /* Don't fail encoder enable if timestamp fails */
+		}
+	}
+
 	val = readl_relaxed(comp->base + RVTRACE_COMPONENT_CTRL_OFFSET);
 	val |= RVTRACE_ENCODER_ITRACE;
 	writel_relaxed(val, comp->base + RVTRACE_COMPONENT_CTRL_OFFSET);
@@ -283,6 +299,10 @@ static void encoder_disable_hw(struct rvtrace_component *comp)
 {
 	struct encoder_data *encoder_data = rvtrace_component_data(comp);
 
+	/* Disable timestamp only if encoder has timestamp component */
+	if (encoder_data->has_timestamp && encoder_data->ts_ctrl)
+		timestamp_disable(comp);
+
 	if (rvtrace_disable_component(comp))
 		dev_err(&encoder_data->csdev->dev,
 			"timeout while waiting for Trace Encoder become disabled\n");
@@ -431,6 +451,26 @@ static int encoder_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, comp);
 
+	/* Check if encoder has timestamp component from device tree early */
+	encoder_data->has_timestamp = fwnode_property_present(dev->fwnode,
+							      "riscv,timestamp-present");
+	if (encoder_data->has_timestamp) {
+		if (rvtrace_init_timestamp(comp, &encoder_data->ts_config)) {
+			dev_err(dev, "Timestamp initialization failed\n");
+			return -EINVAL;
+		}
+
+		/* TODO: Default to enabling timestamp control if present, as
+		 * encoder_data->ts_ctrl can be configured via sysfs attribute,
+		 * but not through perf_event at this time. Future versions may
+		 * add support for configuring timestamps via perf_event.
+		 */
+		encoder_data->ts_ctrl = true;
+	}
+
+	/* Set component data before registration so is_visible callbacks can access it */
+	comp->id.data = encoder_data;
+
 	desc.name = devm_kasprintf(dev, GFP_KERNEL, "encoder%d", comp->cpu);
 	if (!desc.name)
 		return -ENOMEM;
@@ -452,8 +492,6 @@ static int encoder_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	comp->id.data = encoder_data;
-
 	rvtrace_cpu_encoder[comp->cpu] = comp;
 
 	encoder_set_default(comp);
diff --git a/drivers/hwtracing/coresight/rvtrace-encoder-sysfs.c b/drivers/hwtracing/coresight/rvtrace-encoder-sysfs.c
index c89af4cb591a..520f5a16f9a0 100644
--- a/drivers/hwtracing/coresight/rvtrace-encoder-sysfs.c
+++ b/drivers/hwtracing/coresight/rvtrace-encoder-sysfs.c
@@ -7,6 +7,7 @@
 #include <linux/sysfs.h>
 #include <linux/rvtrace.h>
 #include "rvtrace-encoder.h"
+#include "rvtrace-timestamp.h"
 #include "coresight-priv.h"
 
 static ssize_t cpu_show(struct device *dev,
@@ -48,9 +49,38 @@ static ssize_t reset_store(struct device *dev,
 }
 static DEVICE_ATTR_WO(reset);
 
+static ssize_t ts_ctrl_show(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	struct rvtrace_component *comp = dev_get_drvdata(dev->parent);
+	struct encoder_data *encoder_data = rvtrace_component_data(comp);
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n", encoder_data->ts_ctrl);
+}
+
+static ssize_t ts_ctrl_store(struct device *dev,
+			    struct device_attribute *attr,
+			    const char *buf, size_t size)
+{
+	unsigned long val;
+	struct rvtrace_component *comp = dev_get_drvdata(dev->parent);
+	struct encoder_data *encoder_data = rvtrace_component_data(comp);
+
+	if (kstrtoul(buf, 10, &val))
+		return -EINVAL;
+
+	spin_lock(&encoder_data->spinlock);
+	encoder_data->ts_ctrl = !!val;
+	spin_unlock(&encoder_data->spinlock);
+
+	return size;
+}
+static DEVICE_ATTR_RW(ts_ctrl);
+
 static struct attribute *trace_encoder_attrs[] = {
 	&dev_attr_cpu.attr,
 	&dev_attr_reset.attr,
+	&dev_attr_ts_ctrl.attr,
 	NULL,
 };
 
@@ -285,6 +315,19 @@ static struct attribute *trace_encoder_features_attrs[] = {
 	NULL,
 };
 
+static umode_t timestamp_attr_is_visible(struct kobject *kobj,
+					 struct attribute *attr, int idx)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct rvtrace_component *comp = dev_get_drvdata(dev->parent);
+	struct encoder_data *encoder_data = rvtrace_component_data(comp);
+
+	if (encoder_data->has_timestamp)
+		return attr->mode;
+
+	return 0;
+}
+
 static const struct attribute_group trace_encoder_group = {
 	.attrs = trace_encoder_attrs,
 };
@@ -304,10 +347,17 @@ static const struct attribute_group trace_encoder_features_group = {
 	.name = "features",
 };
 
+static const struct attribute_group trace_encoder_timestamp_group = {
+	.attrs = (struct attribute **)timestamp_attrs,
+	.name = "timestamp",
+	.is_visible = timestamp_attr_is_visible,
+};
+
 const struct attribute_group *trace_encoder_groups[] = {
 	&trace_encoder_group,
 	&trace_encoder_mgmt_group,
 	&trace_encoder_control_group,
 	&trace_encoder_features_group,
+	&trace_encoder_timestamp_group,
 	NULL,
 };
diff --git a/drivers/hwtracing/coresight/rvtrace-encoder.h b/drivers/hwtracing/coresight/rvtrace-encoder.h
index 44f2066ad869..7a0ada11de8d 100644
--- a/drivers/hwtracing/coresight/rvtrace-encoder.h
+++ b/drivers/hwtracing/coresight/rvtrace-encoder.h
@@ -9,6 +9,7 @@
 #include <asm/local.h>
 #include <linux/spinlock.h>
 #include "coresight-priv.h"
+#include "rvtrace-timestamp.h"
 
 /* Trace Encoder Control Register */
 #define RVTRACE_ENCODER_ITRACE				    BIT(2)
@@ -126,7 +127,10 @@ struct encoder_config {
  * @spinlock:	    Only one at a time pls.
  * @sticky_enable:  True if trace encoder base configuration has been done.
  * @boot_enable:    True if we should start tracing at boot time.
+ * @has_timestamp:  True if this encoder has timestamp component.
+ * @ts_ctrl:        Controls the insertion of global timestamps in the trace streams.
  * @config:	    Structure holding configuration parameters.
+ * @ts_config:	    Timestamp configuration.
  */
 
 struct encoder_data {
@@ -134,10 +138,14 @@ struct encoder_data {
 	spinlock_t			spinlock;
 	bool				sticky_enable;
 	bool				boot_enable;
+	bool				has_timestamp;
+	bool				ts_ctrl;
 	struct encoder_config		config;
+	struct timestamp_config		ts_config;
 };
 
 extern const struct attribute_group *trace_encoder_groups[];
+extern const struct attribute *timestamp_attrs[];
 void encoder_set_default(struct rvtrace_component *comp);
 
 #endif
diff --git a/drivers/hwtracing/coresight/rvtrace-funnel.c b/drivers/hwtracing/coresight/rvtrace-funnel.c
index 0dc7799a64ac..ab7cdb29e5fd 100644
--- a/drivers/hwtracing/coresight/rvtrace-funnel.c
+++ b/drivers/hwtracing/coresight/rvtrace-funnel.c
@@ -6,9 +6,11 @@
 #include <linux/kernel.h>
 #include <linux/coresight.h>
 #include <linux/platform_device.h>
+#include <linux/property.h>
 #include <linux/rvtrace.h>
 
 #include "coresight-priv.h"
+#include "rvtrace-timestamp.h"
 #include "rvtrace-funnel.h"
 
 DEFINE_CORESIGHT_DEVLIST(funnel_devs, "rvtrace_funnel");
@@ -36,6 +38,16 @@ static int funnel_enable_hw(struct rvtrace_component *comp, int port)
 		ret = rvtrace_enable_component(comp);
 		if (ret)
 			goto done;
+
+		/* Enable timestamp only if funnel has timestamp component */
+		if (funnel_data->has_timestamp && funnel_data->ts_ctrl) {
+			ret = timestamp_enable(comp);
+			if (ret) {
+				dev_warn(&funnel_data->csdev->dev,
+					 "Failed to enable timestamp\n");
+				ret = 0;  /* Don't fail funnel enable if timestamp fails */
+			}
+		}
 	}
 
 done:
@@ -79,6 +91,10 @@ static void funnel_disable_hw(struct rvtrace_component *comp, int inport)
 	if (--funnel_data->input_refcnt != 0)
 		return;
 
+	/* Disable timestamp only if funnel has timestamp component */
+	if (funnel_data->has_timestamp && funnel_data->ts_ctrl)
+		timestamp_disable(comp);
+
 	writel_relaxed(RVTRACE_FUNNEL_DISINPUT_MASK, comp->base + RVTRACE_FUNNEL_DISINPUT_OFFSET);
 
 	if (rvtrace_disable_component(comp))
@@ -162,15 +178,72 @@ static ssize_t cpu_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(cpu);
 
+static ssize_t ts_ctrl_show(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	struct rvtrace_component *comp = dev_get_drvdata(dev->parent);
+	struct funnel_data *funnel_data = rvtrace_component_data(comp);
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n", funnel_data->ts_ctrl);
+}
+
+static ssize_t ts_ctrl_store(struct device *dev,
+			    struct device_attribute *attr,
+			    const char *buf, size_t size)
+{
+	unsigned long val;
+	struct rvtrace_component *comp = dev_get_drvdata(dev->parent);
+	struct funnel_data *funnel_data = rvtrace_component_data(comp);
+
+	if (kstrtoul(buf, 10, &val))
+		return -EINVAL;
+
+	spin_lock(&funnel_data->spinlock);
+	funnel_data->ts_ctrl = !!val;
+	spin_unlock(&funnel_data->spinlock);
+
+	return size;
+}
+static DEVICE_ATTR_RW(ts_ctrl);
+
 static struct attribute *trace_funnel_attrs[] = {
 	coresight_simple_reg32(control, RVTRACE_COMPONENT_CTRL_OFFSET),
 	coresight_simple_reg32(impl, RVTRACE_COMPONENT_IMPL_OFFSET),
 	coresight_simple_reg32(disinput, RVTRACE_FUNNEL_DISINPUT_OFFSET),
 	&dev_attr_reset.attr,
 	&dev_attr_cpu.attr,
+	&dev_attr_ts_ctrl.attr,
+	NULL,
+};
+
+static umode_t timestamp_attr_is_visible(struct kobject *kobj,
+					 struct attribute *attr, int idx)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct rvtrace_component *comp = dev_get_drvdata(dev->parent);
+	struct funnel_data *funnel_data = rvtrace_component_data(comp);
+
+	if (funnel_data->has_timestamp)
+		return attr->mode;
+
+	return 0;
+}
+
+static struct attribute_group trace_funnel_group = {
+	.attrs = trace_funnel_attrs,
+};
+
+static struct attribute_group trace_funnel_timestamp_group = {
+	.attrs = (struct attribute **)timestamp_attrs,
+	.name = "timestamp",
+	.is_visible = timestamp_attr_is_visible,
+};
+
+const struct attribute_group *trace_funnel_groups[] = {
+	&trace_funnel_group,
+	&trace_funnel_timestamp_group,
 	NULL,
 };
-ATTRIBUTE_GROUPS(trace_funnel);
 
 static int funnel_probe(struct platform_device *pdev)
 {
@@ -197,6 +270,26 @@ static int funnel_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, comp);
 
+	/* Check if funnel has timestamp component from device tree */
+	funnel_data->has_timestamp = fwnode_property_present(dev->fwnode,
+							     "riscv,timestamp-present");
+	if (funnel_data->has_timestamp) {
+		if (rvtrace_init_timestamp(comp, &funnel_data->ts_config)) {
+			dev_err(dev, "Timestamp initialization failed\n");
+			return -EINVAL;
+		}
+
+		/* TODO: Default to enabling timestamp control if present, as
+		 * encoder_data->ts_ctrl can be configured via sysfs attribute,
+		 * but not through perf_event at this time. Future versions may
+		 * add support for configuring timestamps via perf_event.
+		 */
+		funnel_data->ts_ctrl = true;
+	}
+
+	/* Set component data before registration so is_visible callbacks can access it */
+	comp->id.data = funnel_data;
+
 	desc.name = coresight_alloc_device_name(&funnel_devs, dev);
 	desc.access = CSDEV_ACCESS_IOMEM(comp->base);
 	desc.type = CORESIGHT_DEV_TYPE_LINK;
diff --git a/drivers/hwtracing/coresight/rvtrace-funnel.h b/drivers/hwtracing/coresight/rvtrace-funnel.h
index e5247e6c1bf5..34394f775faa 100644
--- a/drivers/hwtracing/coresight/rvtrace-funnel.h
+++ b/drivers/hwtracing/coresight/rvtrace-funnel.h
@@ -19,6 +19,9 @@
  * @spinlock:     Only one at a time pls.
  * @was_enabled:  Flag showing whether the Trace Funnel was enabled.
  * @input_refcnt: Record the number of funnel inputs
+ * @has_timestamp: True if this funnel has timestamp component.
+ * @ts_ctrl:      Controls the insertion of global timestamps in the trace streams.
+ * @ts_config:    Timestamp configuration.
  */
 struct funnel_data {
 	struct coresight_device	*csdev;
@@ -26,6 +29,11 @@ struct funnel_data {
 	bool			was_enabled;
 	u32			input_refcnt;
 	u32			disintput;
+	bool			has_timestamp;
+	bool			ts_ctrl;
+	struct timestamp_config	ts_config;
 };
 
+extern const struct attribute *timestamp_attrs[];
+
 #endif
diff --git a/drivers/hwtracing/coresight/rvtrace-timestamp.c b/drivers/hwtracing/coresight/rvtrace-timestamp.c
new file mode 100644
index 000000000000..a82714f43d7c
--- /dev/null
+++ b/drivers/hwtracing/coresight/rvtrace-timestamp.c
@@ -0,0 +1,278 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright(C) 2026 Spacemit Limited. All rights reserved.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/bitfield.h>
+#include <linux/sysfs.h>
+#include <linux/rvtrace.h>
+
+#include "rvtrace-timestamp.h"
+#include "rvtrace-encoder.h"
+#include "rvtrace-funnel.h"
+#include "coresight-priv.h"
+
+int timestamp_enable(struct rvtrace_component *comp)
+{
+	u32 val;
+
+	val = readl_relaxed(comp->base + RVTRACE_TIMESTAMP_CTRL_OFFSET);
+	val |= (RVTRACE_TIMESTAMP_ENABLE | RVTRACE_TIMESTAMP_COUNT);
+
+	writel_relaxed(val, comp->base + RVTRACE_TIMESTAMP_CTRL_OFFSET);
+
+	return rvtrace_poll_bit(comp, RVTRACE_TIMESTAMP_CTRL_OFFSET,
+				RVTRACE_TIMESTAMP_ENABLE_SHIFT, 1);
+}
+EXPORT_SYMBOL_GPL(timestamp_enable);
+
+void timestamp_disable(struct rvtrace_component *comp)
+{
+	u32 val;
+
+	val = readl_relaxed(comp->base + RVTRACE_TIMESTAMP_CTRL_OFFSET);
+	val &= ~(RVTRACE_TIMESTAMP_ENABLE | RVTRACE_TIMESTAMP_COUNT);
+	writel_relaxed(val, comp->base + RVTRACE_TIMESTAMP_CTRL_OFFSET);
+}
+EXPORT_SYMBOL_GPL(timestamp_disable);
+
+struct timestamp_config *timestamp_get_config(struct rvtrace_component *comp)
+{
+	if (comp->id.type == RVTRACE_COMPONENT_TYPE_ENCODER) {
+		struct encoder_data *encoder_data = rvtrace_component_data(comp);
+
+		return &encoder_data->ts_config;
+	} else if (comp->id.type == RVTRACE_COMPONENT_TYPE_FUNNEL) {
+		struct funnel_data *funnel_data = rvtrace_component_data(comp);
+
+		return &funnel_data->ts_config;
+	} else {
+		return NULL;
+	}
+}
+EXPORT_SYMBOL_GPL(timestamp_get_config);
+
+void timestamp_set_config(struct rvtrace_component *comp, struct device *dev,
+			  struct timestamp_config *config)
+{
+	u32 val;
+
+	val = readl_relaxed(comp->base + RVTRACE_TIMESTAMP_CTRL_OFFSET);
+
+	val |= (FIELD_PREP(RVTRACE_TIMESTAMP_RUN_IN_DEBUG, config->run_in_debug) |
+		FIELD_PREP(RVTRACE_TIMESTAMP_MODE, config->mode) |
+		FIELD_PREP(RVTRACE_TIMESTAMP_PRESCALE, config->prescale));
+
+	writel_relaxed(val, comp->base + RVTRACE_TIMESTAMP_CTRL_OFFSET);
+
+	/* Verify configuration was applied */
+	val = readl_relaxed(comp->base + RVTRACE_TIMESTAMP_CTRL_OFFSET);
+
+	if (BMVAL(val, 3, 3) != config->run_in_debug) {
+		dev_warn(dev, "timestamp run_in_debug %#x not supported\n",
+			 config->run_in_debug);
+		config->run_in_debug = BMVAL(val, 3, 3);
+	}
+
+	if (BMVAL(val, 4, 6) != config->mode) {
+		dev_warn(dev, "timestamp mode %#x not supported\n",
+			 config->mode);
+		config->mode = BMVAL(val, 4, 6);
+	}
+
+	if (BMVAL(val, 8, 9) != config->prescale) {
+		dev_warn(dev, "timestamp prescale %#x not supported\n",
+			 config->prescale);
+		config->prescale = BMVAL(val, 8, 9);
+	}
+}
+EXPORT_SYMBOL_GPL(timestamp_set_config);
+
+static int rvtrace_timestamp_reset(struct rvtrace_component *comp)
+{
+	int ret;
+
+	writel_relaxed(0, comp->base + RVTRACE_TIMESTAMP_CTRL_OFFSET);
+	ret = rvtrace_poll_bit(comp, RVTRACE_TIMESTAMP_CTRL_OFFSET,
+			       RVTRACE_TIMESTAMP_ACTIVE_SHIFT, 0);
+
+	if (ret)
+		return ret;
+
+	writel_relaxed(RVTRACE_TIMESTAMP_ACTIVE,
+			comp->base + RVTRACE_TIMESTAMP_CTRL_OFFSET);
+	return rvtrace_poll_bit(comp, RVTRACE_TIMESTAMP_CTRL_OFFSET,
+				RVTRACE_TIMESTAMP_ACTIVE_SHIFT, 1);
+}
+
+int rvtrace_init_timestamp(struct rvtrace_component *comp,
+			   struct timestamp_config *config)
+{
+	u32 val;
+	int ret;
+
+	val = readl_relaxed(comp->base + RVTRACE_TIMESTAMP_CTRL_OFFSET);
+	if (!FIELD_GET(RVTRACE_TIMESTAMP_ACTIVE, val)) {
+		ret = rvtrace_timestamp_reset(comp);
+		if (ret)
+			return ret;
+	}
+
+	val = readl_relaxed(comp->base + RVTRACE_TIMESTAMP_CTRL_OFFSET);
+
+	config->run_in_debug = !!(val & RVTRACE_TIMESTAMP_RUN_IN_DEBUG);
+	config->mode = BMVAL(val, 4, 6);
+	config->prescale = BMVAL(val, 8, 9);
+	config->width = BMVAL(val, 24, 29);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rvtrace_init_timestamp);
+
+static ssize_t run_in_debug_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct rvtrace_component *comp = dev_get_drvdata(dev->parent);
+	struct timestamp_config *config = timestamp_get_config(comp);
+
+	if (!config)
+		return -EINVAL;
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n", config->run_in_debug);
+}
+
+static ssize_t run_in_debug_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t size)
+{
+	struct rvtrace_component *comp = dev_get_drvdata(dev->parent);
+	struct timestamp_config *config = timestamp_get_config(comp);
+	unsigned long val;
+
+	if (!config)
+		return -EINVAL;
+
+	if (kstrtoul(buf, 10, &val))
+		return -EINVAL;
+
+	config->run_in_debug = !!val;
+
+	return size;
+}
+static DEVICE_ATTR_RW(run_in_debug);
+
+static const char * const modes_str[] = {
+	[TIMESTAMP_MODE_NONE] = "none",
+	[TIMESTAMP_MODE_EXTERNAL] = "external",
+	[TIMESTAMP_MODE_INTERNAL_SYSTEM] = "internal_system",
+	[TIMESTAMP_MODE_INTERNAL_CORE] = "internal_core",
+	[TIMESTAMP_MODE_SHARED] = "shared",
+};
+
+static ssize_t modes_available_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	return sysfs_emit(buf, "%s %s %s %s %s\n",
+			    modes_str[TIMESTAMP_MODE_NONE],
+			    modes_str[TIMESTAMP_MODE_EXTERNAL],
+			    modes_str[TIMESTAMP_MODE_INTERNAL_SYSTEM],
+			    modes_str[TIMESTAMP_MODE_INTERNAL_CORE],
+			    modes_str[TIMESTAMP_MODE_SHARED]);
+}
+static DEVICE_ATTR_RO(modes_available);
+
+static ssize_t mode_preferred_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct rvtrace_component *comp = dev_get_drvdata(dev->parent);
+	struct timestamp_config *config = timestamp_get_config(comp);
+
+	if (!config)
+		return -EINVAL;
+
+	return scnprintf(buf, PAGE_SIZE, "%s\n", modes_str[config->mode]);
+}
+
+static ssize_t mode_preferred_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t size)
+{
+	struct rvtrace_component *comp = dev_get_drvdata(dev->parent);
+	struct timestamp_config *config = timestamp_get_config(comp);
+
+	if (!config)
+		return -EINVAL;
+
+	if (sysfs_streq(buf, modes_str[TIMESTAMP_MODE_NONE]))
+		config->mode = TIMESTAMP_MODE_NONE;
+	else if (sysfs_streq(buf, modes_str[TIMESTAMP_MODE_EXTERNAL]))
+		config->mode = TIMESTAMP_MODE_EXTERNAL;
+	else if (sysfs_streq(buf, modes_str[TIMESTAMP_MODE_INTERNAL_SYSTEM]))
+		config->mode = TIMESTAMP_MODE_INTERNAL_SYSTEM;
+	else if (sysfs_streq(buf, modes_str[TIMESTAMP_MODE_INTERNAL_CORE]))
+		config->mode = TIMESTAMP_MODE_INTERNAL_CORE;
+	else if (sysfs_streq(buf, modes_str[TIMESTAMP_MODE_SHARED]))
+		config->mode = TIMESTAMP_MODE_SHARED;
+	else
+		return -EINVAL;
+	return size;
+}
+static DEVICE_ATTR_RW(mode_preferred);
+
+static ssize_t prescale_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct rvtrace_component *comp = dev_get_drvdata(dev->parent);
+	struct timestamp_config *config = timestamp_get_config(comp);
+
+	if (!config)
+		return -EINVAL;
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n", config->prescale);
+}
+
+static ssize_t prescale_store(struct device *dev,
+			      struct device_attribute *attr,
+			      const char *buf, size_t size)
+{
+	unsigned long val;
+	struct rvtrace_component *comp = dev_get_drvdata(dev->parent);
+	struct timestamp_config *config = timestamp_get_config(comp);
+
+	if (!config)
+		return -EINVAL;
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+
+	config->prescale = val;
+
+	return size;
+}
+static DEVICE_ATTR_RW(prescale);
+
+static ssize_t width_show(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	struct rvtrace_component *comp = dev_get_drvdata(dev->parent);
+	struct timestamp_config *config = timestamp_get_config(comp);
+
+	if (!config)
+		return -EINVAL;
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n", config->width);
+}
+static DEVICE_ATTR_RO(width);
+
+const struct attribute *timestamp_attrs[] = {
+	&dev_attr_run_in_debug.attr,
+	&dev_attr_modes_available.attr,
+	&dev_attr_mode_preferred.attr,
+	&dev_attr_prescale.attr,
+	&dev_attr_width.attr,
+	NULL,
+};
+EXPORT_SYMBOL_GPL(timestamp_attrs);
diff --git a/drivers/hwtracing/coresight/rvtrace-timestamp.h b/drivers/hwtracing/coresight/rvtrace-timestamp.h
new file mode 100644
index 000000000000..13cecddbd82c
--- /dev/null
+++ b/drivers/hwtracing/coresight/rvtrace-timestamp.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright(C) 2026 Spacemit Limited. All rights reserved.
+ * Author: liangzhen <zhen.liang@spacemit.com>
+ */
+
+#ifndef _RVTRACE_TIMESTAMP_H
+#define _RVTRACE_TIMESTAMP_H
+
+#include <linux/types.h>
+
+/* Timestamp Control Register */
+#define RVTRACE_TIMESTAMP_CTRL_OFFSET			0x040
+#define RVTRACE_TIMESTAMP_ACTIVE			BIT(0)
+#define RVTRACE_TIMESTAMP_COUNT				BIT(1)
+#define RVTRACE_TIMESTAMP_RESET				BIT(2)
+#define RVTRACE_TIMESTAMP_RUN_IN_DEBUG			BIT(3)
+#define RVTRACE_TIMESTAMP_MODE				GENMASK(6, 4)
+#define RVTRACE_TIMESTAMP_PRESCALE			GENMASK(9, 8)
+#define RVTRACE_TIMESTAMP_ENABLE			BIT(15)
+#define RVTRACE_TIMESTAMP_WIDTH				GENMASK(29, 24)
+
+#define RVTRACE_TIMESTAMP_ACTIVE_SHIFT			0
+#define RVTRACE_TIMESTAMP_ENABLE_SHIFT			15
+
+/* Timestamp Counter Lower Bits */
+#define RVTRACE_TIMESTAMP_COUNTER_LOW			0x048
+/* Timestamp Counter Upper Bits */
+#define RVTRACE_TIMESTAMP_COUNTER_HIGH			0x04C
+
+enum timestamp_mode {
+	TIMESTAMP_MODE_NONE = 0,
+	TIMESTAMP_MODE_EXTERNAL = 1,
+	TIMESTAMP_MODE_INTERNAL_SYSTEM = 2,
+	TIMESTAMP_MODE_INTERNAL_CORE = 3,
+	TIMESTAMP_MODE_SHARED = 4
+};
+
+/**
+ * struct timestamp_config - timestamp configuration for encoder/funnel
+ * @run_in_debug:       Continue timestamp counting in debug mode
+ * @mode:		Timestamp generation mode (periodic, event-triggered)
+ * @prescale:		Clock prescale factor (1, 4, 16, 64)
+ * @width:		Timestamp counter width in bits (0-63)
+ */
+struct timestamp_config {
+	bool				run_in_debug;
+	u8				mode;
+	u8				prescale;
+	u8				width;
+};
+
+struct rvtrace_component;
+
+/* Timestamp control functions */
+int timestamp_enable(struct rvtrace_component *comp);
+void timestamp_disable(struct rvtrace_component *comp);
+struct timestamp_config *timestamp_get_config(struct rvtrace_component *comp);
+void timestamp_set_config(struct rvtrace_component *comp, struct device *dev,
+			  struct timestamp_config *config);
+int rvtrace_init_timestamp(struct rvtrace_component *comp,
+			   struct timestamp_config *config);
+
+#endif
-- 
2.34.1


_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

  parent reply	other threads:[~2026-04-14  3:43 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-14  3:41 [RFC PATCH 00/12] Add Linux RISC-V trace support via CoreSight Zane Leung
2026-04-14  3:41 ` [RFC PATCH 01/12] coresight: Add RISC-V support to CoreSight tracing Zane Leung
2026-04-14  3:41 ` [RFC PATCH 02/12] coresight: Initial implementation of RISC-V trace driver Zane Leung
2026-04-14  3:41 ` [RFC PATCH 03/12] coresight: Add RISC-V Trace Encoder driver Zane Leung
2026-04-14  3:41 ` [RFC PATCH 04/12] coresight: Add RISC-V Trace Funnel driver Zane Leung
2026-04-14  3:41 ` [RFC PATCH 05/12] coresight: Add RISC-V Trace ATB Bridge driver Zane Leung
2026-04-14  3:41 ` Zane Leung [this message]
2026-04-14  3:41 ` [RFC PATCH 07/12] coresight: Add RISC-V PMU name support Zane Leung
2026-04-14  3:41 ` [RFC PATCH 08/12] perf tools: riscv: making rvtrace PMU listable Zane Leung
2026-04-14  3:41 ` [RFC PATCH 09/12] perf tools: Add RISC-V trace PMU record capabilities Zane Leung
2026-04-14 23:31   ` Bo Gan
2026-04-14  3:41 ` [RFC PATCH 10/12] perf tools: Add Nexus RISC-V Trace decoder Zane Leung
2026-04-14  3:41 ` [RFC PATCH 11/12] perf symbols: Add RISC-V PLT entry sizes Zane Leung
2026-04-14  3:41 ` [RFC PATCH 12/12] perf tools: Integrate RISC-V trace decoder into auxtrace Zane Leung
2026-04-14  4:15 ` [RFC PATCH 00/12] Add Linux RISC-V trace support via CoreSight Jie Gan
2026-04-14  8:08   ` Zane Leung
2026-04-14  7:23 ` Anup Patel
2026-04-14  9:04   ` Zane Leung
2026-04-15  0:10     ` Bo Gan
2026-04-15  1:23       ` Zane Leung

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260414034153.3272485-7-liangzhen@linux.spacemit.com \
    --to=liangzhen@linux.spacemit.com \
    --cc=adrian.hunter@intel.com \
    --cc=alexander.shishkin@linux.intel.com \
    --cc=andrew.jones@oss.qualcomm.com \
    --cc=anup.patel@oss.qualcomm.com \
    --cc=anup@brainfault.org \
    --cc=atish.patra@linux.dev \
    --cc=conor+dt@kernel.org \
    --cc=coresight@lists.linaro.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=irogers@google.com \
    --cc=jolsa@kernel.org \
    --cc=kan.liang@linux.intel.com \
    --cc=krzk+dt@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-riscv@lists.infradead.org \
    --cc=mark.rutland@arm.com \
    --cc=mayuresh.chitale@oss.qualcomm.com \
    --cc=mchitale@gmail.com \
    --cc=mingo@redhat.com \
    --cc=namhyung@kernel.org \
    --cc=palmer@dabbelt.com \
    --cc=peterz@infradead.org \
    --cc=pjw@kernel.org \
    --cc=robh@kernel.org \
    --cc=sunilvl@oss.qualcomm.com \
    --cc=zhuangqiubin@linux.spacemit.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox