[RFC PATCH 02/12] coresight: Initial implementation of RISC-V trace driver
From: Zane Leung
Date: Mon Apr 13 2026 - 23:44:11 EST
From: liangzhen <zhen.liang@xxxxxxxxxxxx>
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@xxxxxxxxxxxx>
---
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