Add initial implementation of RISC-V Trace atbbridge driver. The atbbridge is defined in the RISC-V Trace Control Interface specification.
Signed-off-by: Zane Leung liangzhen@linux.spacemit.com --- drivers/hwtracing/gtrace/Kconfig | 15 ++ drivers/hwtracing/gtrace/Makefile | 1 + drivers/hwtracing/gtrace/rvtrace-atbbridge.c | 153 +++++++++++++++++++ drivers/hwtracing/gtrace/rvtrace-platform.c | 3 + drivers/hwtracing/gtrace/rvtrace.h | 1 + 5 files changed, 173 insertions(+) create mode 100644 drivers/hwtracing/gtrace/rvtrace-atbbridge.c
diff --git a/drivers/hwtracing/gtrace/Kconfig b/drivers/hwtracing/gtrace/Kconfig index f6026965c54d..3af47d7c3ce3 100644 --- a/drivers/hwtracing/gtrace/Kconfig +++ b/drivers/hwtracing/gtrace/Kconfig @@ -71,3 +71,18 @@ config RVTRACE_FUNNEL
To compile this driver as a module, choose M here: the module will be called rvtrace-funnel. + +config RVTRACE_ATBBRIDGE + tristate "RISC-V Trace ATB Bridge driver" + depends on RVTRACE + default y + help + This driver provides support for the RISC-V trace ATB bridge + component which is defined by the RISC-V Trace Control Interface + specification. The ATB bridge converts the RISC-V trace stream + to the ARM Advanced Trace Bus (ATB) protocol, allowing RISC-V + trace sources to feed into ARM CoreSight trace components. It is + a link component in the trace path. + + To compile this driver as a module, choose M here: the module + will be called rvtrace-atbbridge. diff --git a/drivers/hwtracing/gtrace/Makefile b/drivers/hwtracing/gtrace/Makefile index b60d3cfe5248..3f1dcb5664a2 100644 --- a/drivers/hwtracing/gtrace/Makefile +++ b/drivers/hwtracing/gtrace/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_RVTRACE_ENCODER) += rvtrace-encoder.o rvtrace-encoder-y := rvtrace-encoder-core.o rvtrace-encoder-sysfs.o obj-$(CONFIG_RVTRACE_RAMSINK) += rvtrace-ramsink.o obj-$(CONFIG_RVTRACE_FUNNEL) += rvtrace-funnel.o +obj-$(CONFIG_RVTRACE_ATBBRIDGE) += rvtrace-atbbridge.o diff --git a/drivers/hwtracing/gtrace/rvtrace-atbbridge.c b/drivers/hwtracing/gtrace/rvtrace-atbbridge.c new file mode 100644 index 000000000000..92a59ed80a11 --- /dev/null +++ b/drivers/hwtracing/gtrace/rvtrace-atbbridge.c @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2026 Spacemit Technologies, Inc. + */ + +#include <linux/device.h> +#include <linux/gtrace.h> +#include <linux/idr.h> +#include <linux/types.h> +#include <linux/bitfield.h> +#include "rvtrace.h" + +#define RVTRACE_ATBBRIDGE_CTRL_ATID_MASK GENMASK(14, 8) +#define RVTRACE_ATBBRIDGE_ATID_MIN 0x1 +#define RVTRACE_ATBBRIDGE_ATID_MAX 0x6f + +static DEFINE_IDA(rvtrace_atbbridge_atid_ida); + +struct rvtrace_atbbridge_priv { + int atid; +}; + +static int rvtrace_atbbridge_start(struct gtrace_component *comp) +{ + int ret; + + ret = gtrace_enable_component(comp); + if (ret) + dev_err(&comp->dev, "failed to start atbbridge.\n"); + + return ret; +} + +static int rvtrace_atbbridge_stop(struct gtrace_component *comp) +{ + int ret; + + ret = gtrace_disable_component(comp); + if (ret) + dev_err(&comp->dev, "failed to stop atbbridge.\n"); + + return ret; +} + +static ssize_t cpu_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct gtrace_component *comp = to_gtrace_component(dev); + + return sysfs_emit(buf, "%d\n", comp->pdata->bound_cpu); +} +static DEVICE_ATTR_RO(cpu); + +static ssize_t atid_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct gtrace_component *comp = to_gtrace_component(dev); + struct rvtrace_atbbridge_priv *priv = dev_get_drvdata(&comp->dev); + + return sysfs_emit(buf, "%u\n", priv->atid); +} +static DEVICE_ATTR_RO(atid); + +static struct attribute *rvtrace_atbbridge_attrs[] = { + &dev_attr_cpu.attr, + &dev_attr_atid.attr, + NULL, +}; + +static const struct attribute_group rvtrace_atbbridge_group = { + .attrs = rvtrace_atbbridge_attrs, +}; + +const struct attribute_group *rvtrace_atbbridge_groups[] = { + &rvtrace_atbbridge_group, + NULL, +}; +EXPORT_SYMBOL_GPL(rvtrace_atbbridge_groups); + +static void rvtrace_atbbridge_cleanup(struct gtrace_component *comp) +{ + struct rvtrace_atbbridge_priv *priv = dev_get_drvdata(&comp->dev); + + ida_free(&rvtrace_atbbridge_atid_ida, priv->atid); +} + +static int rvtrace_atbbridge_probe(struct gtrace_component *comp) +{ + struct rvtrace_atbbridge_priv *priv; + u32 val; + + priv = devm_kzalloc(&comp->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->atid = ida_alloc_range(&rvtrace_atbbridge_atid_ida, + RVTRACE_ATBBRIDGE_ATID_MIN, + RVTRACE_ATBBRIDGE_ATID_MAX, + GFP_KERNEL); + if (priv->atid < 0) { + dev_err(&comp->dev, "failed to allocate ATID.\n"); + return priv->atid; + } + + val = gtrace_read32(comp->pdata, RVTRACE_COMPONENT_CTRL_OFFSET); + val &= ~RVTRACE_ATBBRIDGE_CTRL_ATID_MASK; + val |= FIELD_PREP(RVTRACE_ATBBRIDGE_CTRL_ATID_MASK, priv->atid); + gtrace_write32(comp->pdata, val, RVTRACE_COMPONENT_CTRL_OFFSET); + + dev_set_drvdata(&comp->dev, priv); + + return 0; +} + +static void rvtrace_atbbridge_remove(struct gtrace_component *comp) +{ + rvtrace_atbbridge_cleanup(comp); +} + +static const struct gtrace_component_id rvtrace_atbbridge_ids[] = { + { .type = GTRACE_RVTRACE_ATBBRIDGE, + .version = rvtrace_component_mkversion(1, 0), }, + {}, +}; + +static struct gtrace_driver rvtrace_atbbridge_driver = { + .id_table = rvtrace_atbbridge_ids, + .probe = rvtrace_atbbridge_probe, + .remove = rvtrace_atbbridge_remove, + .start = rvtrace_atbbridge_start, + .stop = rvtrace_atbbridge_stop, + .driver = { + .name = "rvtrace-atbbridge", + }, +}; + +static int __init rvtrace_atbbridge_init(void) +{ + return gtrace_register_driver(&rvtrace_atbbridge_driver); +} + +static void __exit rvtrace_atbbridge_exit(void) +{ + gtrace_unregister_driver(&rvtrace_atbbridge_driver); + ida_destroy(&rvtrace_atbbridge_atid_ida); +} + +module_init(rvtrace_atbbridge_init); +module_exit(rvtrace_atbbridge_exit); + +MODULE_AUTHOR("Zane Leung"); +MODULE_DESCRIPTION("RISC-V Trace ATB Bridge Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwtracing/gtrace/rvtrace-platform.c b/drivers/hwtracing/gtrace/rvtrace-platform.c index ad8daa06e13e..9bd315867082 100644 --- a/drivers/hwtracing/gtrace/rvtrace-platform.c +++ b/drivers/hwtracing/gtrace/rvtrace-platform.c @@ -136,6 +136,9 @@ static int rvtrace_platform_probe(struct platform_device *pdev) case GTRACE_RVTRACE_FUNNEL: pdata->groups = rvtrace_funnel_groups; break; + case GTRACE_RVTRACE_ATBBRIDGE: + pdata->groups = rvtrace_atbbridge_groups; + break; default: pdata->groups = NULL; } diff --git a/drivers/hwtracing/gtrace/rvtrace.h b/drivers/hwtracing/gtrace/rvtrace.h index a345ba110267..5cbe3405e274 100644 --- a/drivers/hwtracing/gtrace/rvtrace.h +++ b/drivers/hwtracing/gtrace/rvtrace.h @@ -121,5 +121,6 @@ extern const struct gtrace_hw_ops rvtrace_hw_ops; /* Sysfs attribute groups for RISC-V trace components */ extern const struct attribute_group *rvtrace_encoder_groups[]; extern const struct attribute_group *rvtrace_funnel_groups[]; +extern const struct attribute_group *rvtrace_atbbridge_groups[];
#endif /* __LINUX_RVTRACE_H__ */