[RFC PATCH 02/12] coresight: Initial implementation of RISC-V trace driver

Zane Leung liangzhen at linux.spacemit.com
Mon Apr 13 20:41:43 PDT 2026


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

Implement some common driver interfaces RISC-V trace
where RISC-V trace components are instantiated by a
common platform driver and a separate RISC-V trace
driver for each type of RISC-V trace component.

Signed-off-by: liangzhen <zhen.liang at spacemit.com>
---
 drivers/hwtracing/coresight/Kconfig        |   8 ++
 drivers/hwtracing/coresight/Makefile       |   2 +
 drivers/hwtracing/coresight/rvtrace-core.c | 135 +++++++++++++++++++++
 include/linux/rvtrace.h                    | 116 ++++++++++++++++++
 4 files changed, 261 insertions(+)
 create mode 100644 drivers/hwtracing/coresight/rvtrace-core.c
 create mode 100644 include/linux/rvtrace.h

diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig
index 2b1ebe3f614d..5adeaf78a080 100644
--- a/drivers/hwtracing/coresight/Kconfig
+++ b/drivers/hwtracing/coresight/Kconfig
@@ -280,4 +280,12 @@ config CORESIGHT_TNOC
 	  To compile this driver as a module, choose M here: the module will be
 	  called coresight-tnoc.
 
+config RVTRACE
+	bool "RISC-V Trace Support"
+	help
+	  This enables support for the RISC-V trace drivers. drivers
+	  (including Trace Encoder, Trace Funnel and  ATB Bridge) are
+	  dynamically aggregated with CoreSight trace infrastructure
+	  at run time to form a complete trace path.
+
 endif
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
index ab16d06783a5..c21a9e25e148 100644
--- a/drivers/hwtracing/coresight/Makefile
+++ b/drivers/hwtracing/coresight/Makefile
@@ -57,3 +57,5 @@ obj-$(CONFIG_CORESIGHT_DUMMY) += coresight-dummy.o
 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
diff --git a/drivers/hwtracing/coresight/rvtrace-core.c b/drivers/hwtracing/coresight/rvtrace-core.c
new file mode 100644
index 000000000000..c74f43869d8b
--- /dev/null
+++ b/drivers/hwtracing/coresight/rvtrace-core.c
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright(C) 2026 Spacemit Limited. All rights reserved.
+ */
+
+#include <linux/delay.h>
+#include <linux/percpu.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/rvtrace.h>
+
+int rvtrace_poll_bit(struct rvtrace_component *comp, int offset,
+		     int bit, int bitval)
+{
+	int i = RVTRACE_TIMEOUT_US;
+	u32 val;
+
+	while (i--) {
+		val = readl_relaxed(comp->base + offset);
+		if (((val >> bit) & 0x1) == bitval)
+			break;
+		udelay(1);
+	}
+
+	return (i < 0) ? -ETIMEDOUT : 0;
+}
+EXPORT_SYMBOL_GPL(rvtrace_poll_bit);
+
+int rvtrace_enable_component(struct rvtrace_component *comp)
+{
+	u32 val;
+
+	val = readl_relaxed(comp->base + RVTRACE_COMPONENT_CTRL_OFFSET);
+	val |= BIT(RVTRACE_COMPONENT_CTRL_ENABLE_SHIFT);
+	writel_relaxed(val, comp->base + RVTRACE_COMPONENT_CTRL_OFFSET);
+	return rvtrace_poll_bit(comp, RVTRACE_COMPONENT_CTRL_OFFSET,
+				RVTRACE_COMPONENT_CTRL_ENABLE_SHIFT, 1);
+}
+EXPORT_SYMBOL_GPL(rvtrace_enable_component);
+
+int rvtrace_disable_component(struct rvtrace_component *comp)
+{
+	u32 val;
+
+	val = readl_relaxed(comp->base + RVTRACE_COMPONENT_CTRL_OFFSET);
+	val &= ~BIT(RVTRACE_COMPONENT_CTRL_ENABLE_SHIFT);
+	writel_relaxed(val, comp->base + RVTRACE_COMPONENT_CTRL_OFFSET);
+	return rvtrace_poll_bit(comp, RVTRACE_COMPONENT_CTRL_OFFSET,
+				RVTRACE_COMPONENT_CTRL_ENABLE_SHIFT, 0);
+}
+EXPORT_SYMBOL_GPL(rvtrace_disable_component);
+
+int rvtrace_component_reset(struct rvtrace_component *comp)
+{
+	int ret;
+
+	writel_relaxed(0, comp->base + RVTRACE_COMPONENT_CTRL_OFFSET);
+	ret = rvtrace_poll_bit(comp, RVTRACE_COMPONENT_CTRL_OFFSET,
+			       RVTRACE_COMPONENT_CTRL_ACTIVE_SHIFT, 0);
+	if (ret)
+		return ret;
+
+	writel_relaxed(RVTRACE_COMPONENT_CTRL_ACTIVE_MASK,
+			comp->base + RVTRACE_COMPONENT_CTRL_OFFSET);
+	return rvtrace_poll_bit(comp, RVTRACE_COMPONENT_CTRL_OFFSET,
+				RVTRACE_COMPONENT_CTRL_ACTIVE_SHIFT, 1);
+}
+EXPORT_SYMBOL_GPL(rvtrace_component_reset);
+
+struct rvtrace_component *rvtrace_register_component(struct platform_device *pdev)
+{
+	int ret;
+	void __iomem *base;
+	struct device *dev = &pdev->dev;
+	struct rvtrace_component *comp;
+	struct resource *res;
+	struct device_node *node;
+	u32 impl, type, major, minor;
+
+	comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL);
+	if (!comp) {
+		ret = -ENOMEM;
+		goto err_out;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(base)) {
+		ret = -EINVAL;
+		goto err_out;
+	}
+	comp->base = base;
+
+	comp->cpu = -1;
+	for (int i = 0; ; i++) {
+		node = of_parse_phandle(dev->of_node, "cpus", i);
+		if (!node)
+			break;
+
+		ret = of_cpu_node_to_id(node);
+		of_node_put(node);
+		if (ret >= 0 && cpu_online(ret)) {
+			comp->cpu = ret;
+			break;
+		}
+	}
+
+	if (comp->cpu < 0) {
+		dev_err(dev, "No valid CPU found in 'cpus' property\n");
+		ret = -EINVAL;
+		goto err_out;
+	}
+
+	ret = rvtrace_component_reset(comp);
+	if (ret)
+		goto err_out;
+	comp->was_reset = true;
+
+	impl = readl_relaxed(comp->base + RVTRACE_COMPONENT_IMPL_OFFSET);
+	type = (impl >> RVTRACE_COMPONENT_IMPL_TYPE_SHIFT) &
+		RVTRACE_COMPONENT_IMPL_TYPE_MASK;
+	major = (impl >> RVTRACE_COMPONENT_IMPL_VERMAJOR_SHIFT) &
+		RVTRACE_COMPONENT_IMPL_VERMAJOR_MASK;
+	minor = (impl >> RVTRACE_COMPONENT_IMPL_VERMINOR_SHIFT) &
+		RVTRACE_COMPONENT_IMPL_VERMINOR_MASK;
+
+	comp->id.type = type;
+	comp->id.version = rvtrace_component_mkversion(major, minor);
+
+	return comp;
+
+err_out:
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(rvtrace_register_component);
diff --git a/include/linux/rvtrace.h b/include/linux/rvtrace.h
new file mode 100644
index 000000000000..e7028d82f8fd
--- /dev/null
+++ b/include/linux/rvtrace.h
@@ -0,0 +1,116 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(C) 2026 Spacemit Limited. All rights reserved.
+ */
+
+#ifndef __LINUX_RVTRACE_H__
+#define __LINUX_RVTRACE_H__
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/coresight.h>
+#include <linux/types.h>
+
+/* Control register common across all RISC-V trace components */
+#define RVTRACE_COMPONENT_CTRL_OFFSET		0x000
+#define RVTRACE_COMPONENT_CTRL_ACTIVE_MASK	0x1
+#define RVTRACE_COMPONENT_CTRL_ACTIVE_SHIFT	0
+#define RVTRACE_COMPONENT_CTRL_ENABLE_MASK	0x1
+#define RVTRACE_COMPONENT_CTRL_ENABLE_SHIFT	1
+#define RVTRACE_COMPONENT_CTRL_EMPTY_SHIFT	3
+
+/* Implementation register common across all RISC-V trace components */
+#define RVTRACE_COMPONENT_IMPL_OFFSET		0x004
+#define RVTRACE_COMPONENT_IMPL_VERMAJOR_MASK	0xf
+#define RVTRACE_COMPONENT_IMPL_VERMAJOR_SHIFT	0
+#define RVTRACE_COMPONENT_IMPL_VERMINOR_MASK	0xf
+#define RVTRACE_COMPONENT_IMPL_VERMINOR_SHIFT	4
+#define RVTRACE_COMPONENT_IMPL_TYPE_MASK	0xf
+#define RVTRACE_COMPONENT_IMPL_TYPE_SHIFT	8
+
+#define RVTRACE_TIMEOUT_US			100
+
+/* Possible component types defined by the RISC-V Trace Control Interface */
+enum rvtrace_component_type {
+	RVTRACE_COMPONENT_TYPE_RESV0,
+	RVTRACE_COMPONENT_TYPE_ENCODER, /* 0x1 */
+	RVTRACE_COMPONENT_TYPE_RESV2,
+	RVTRACE_COMPONENT_TYPE_RESV3,
+	RVTRACE_COMPONENT_TYPE_RESV4,
+	RVTRACE_COMPONENT_TYPE_RESV5,
+	RVTRACE_COMPONENT_TYPE_RESV6,
+	RVTRACE_COMPONENT_TYPE_RESV7,
+	RVTRACE_COMPONENT_TYPE_FUNNEL, /* 0x8 */
+	RVTRACE_COMPONENT_TYPE_RAMSINK, /* 0x9 */
+	RVTRACE_COMPONENT_TYPE_PIBSINK, /* 0xA */
+	RVTRACE_COMPONENT_TYPE_RESV11,
+	RVTRACE_COMPONENT_TYPE_RESV12,
+	RVTRACE_COMPONENT_TYPE_RESV13,
+	RVTRACE_COMPONENT_TYPE_ATBBRIDGE, /* 0xE */
+	RVTRACE_COMPONENT_TYPE_RESV15,
+	RVTRACE_COMPONENT_TYPE_MAX
+};
+
+/* Encoding/decoding macros for RISC-V trace component version */
+#define rvtrace_component_version_major(__version)	\
+	(((__version) >> 16) & 0xffff)
+#define rvtrace_component_version_minor(__version)	\
+	((__version) & 0xffff)
+#define rvtrace_component_mkversion(__major, __minor)	\
+	((((__major) & 0xffff) << 16) |	((__minor) & 0xffff))
+
+/**
+ * struct rvtrace_component_id - Details to identify or match a RISC-V trace component
+ * @type:      Type of the component
+ * @version:   Version of the component
+ * @data:      Data pointer for driver use
+ */
+struct rvtrace_component_id {
+	enum rvtrace_component_type type;
+	u32 version;
+	void *data;
+};
+
+/**
+ * struct rvtrace_component - Representation of a RISC-V trace component
+ * base:             Memory mapped base address for the component
+ * id:               Details to match the component
+ * dev:              Device instance
+ * cpu:              The cpu this component is affined to
+ * was_reset:        Flag showing whether RISC-V trace driver was reset successfully
+ */
+struct rvtrace_component {
+	void __iomem *base;
+	struct rvtrace_component_id id;
+	struct device *dev;
+	int cpu;
+	bool was_reset;
+};
+
+struct component_enable_arg {
+	struct rvtrace_component *comp;
+	int rc;
+};
+
+struct rvtrace_component *rvtrace_register_component(struct platform_device *pdev);
+
+int rvtrace_poll_bit(struct rvtrace_component *comp, int offset,
+		     int bit, int bitval);
+
+int rvtrace_enable_component(struct rvtrace_component *comp);
+int rvtrace_disable_component(struct rvtrace_component *comp);
+int rvtrace_component_reset(struct rvtrace_component *comp);
+
+static inline void *rvtrace_component_data(struct rvtrace_component *comp)
+{
+	return comp->id.data;
+}
+
+static inline int rvtrace_comp_is_empty(struct rvtrace_component *comp)
+{
+	return rvtrace_poll_bit(comp, RVTRACE_COMPONENT_CTRL_OFFSET,
+				RVTRACE_COMPONENT_CTRL_EMPTY_SHIFT, 1);
+}
+
+#endif
-- 
2.34.1




More information about the linux-riscv mailing list