File Index
Files and directories
Sign in
FILE

coresight-tnoc.c

File preview with syntax highlighting.

linux-6.19.14/drivers/hwtracing/coresight/coresight-tnoc.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
  4 */
  5
  6 #include <linux/amba/bus.h>
  7 #include <linux/coresight.h>
  8 #include <linux/device.h>
  9 #include <linux/io.h>
 10 #include <linux/kernel.h>
 11 #include <linux/module.h>
 12 #include <linux/of.h>
 13 #include <linux/platform_device.h>
 14
 15#include "coresight-priv.h"
 16#include "coresight-trace-id.h"
 17
 18#define TRACE_NOC_CTRL      0x008
 19#define TRACE_NOC_XLD       0x010
 20#define TRACE_NOC_FREQVAL   0x018
 21#define TRACE_NOC_SYNCR     0x020
 22
 23/* Enable generation of output ATB traffic.*/
 24#define TRACE_NOC_CTRL_PORTEN   BIT(0)
 25/* Sets the type of issued ATB FLAG packets.*/
 26#define TRACE_NOC_CTRL_FLAGTYPE BIT(7)
 27/* Sets the type of issued ATB FREQ packet*/
 28#define TRACE_NOC_CTRL_FREQTYPE BIT(8)
 29
 30#define TRACE_NOC_SYNC_INTERVAL	0xFFFF
 31
 32/*
 33 * struct trace_noc_drvdata - specifics associated to a trace noc component
 34 * @base:      memory mapped base address for this component.
 35 * @dev:       device node for trace_noc_drvdata.
 36 * @csdev:     component vitals needed by the framework.
 37 * @spinlock:  serialize enable/disable operation.
 38 * @atid:      id for the trace packet.
 39 */
 40struct trace_noc_drvdata {
 41	void __iomem		*base;
 42	struct device		*dev;
 43	struct coresight_device	*csdev;
 44	spinlock_t		spinlock;
 45	u32			atid;
 46};
 47
 48DEFINE_CORESIGHT_DEVLIST(trace_noc_devs, "traceNoc");
 49
 50static void trace_noc_enable_hw(struct trace_noc_drvdata *drvdata)
 51{
 52	u32 val;
 53
 54	/* Set ATID */
 55	writel_relaxed(drvdata->atid, drvdata->base + TRACE_NOC_XLD);
 56
 57	/* Set the data word count between 'SYNC' packets */
 58	writel_relaxed(TRACE_NOC_SYNC_INTERVAL, drvdata->base + TRACE_NOC_SYNCR);
 59
 60	/* Set the Control register:
 61	 * - Set the FLAG packets to 'FLAG' packets
 62	 * - Set the FREQ packets to 'FREQ_TS' packets
 63	 * - Enable generation of output ATB traffic
 64	 */
 65
 66	val = readl_relaxed(drvdata->base + TRACE_NOC_CTRL);
 67
 68	val &= ~TRACE_NOC_CTRL_FLAGTYPE;
 69	val |= TRACE_NOC_CTRL_FREQTYPE;
 70	val |= TRACE_NOC_CTRL_PORTEN;
 71
 72	writel(val, drvdata->base + TRACE_NOC_CTRL);
 73}
 74
 75static int trace_noc_enable(struct coresight_device *csdev, struct coresight_connection *inport,
 76			    struct coresight_connection *outport)
 77{
 78	struct trace_noc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 79
 80	scoped_guard(spinlock, &drvdata->spinlock) {
 81		if (csdev->refcnt == 0)
 82			trace_noc_enable_hw(drvdata);
 83
 84		csdev->refcnt++;
 85	}
 86
 87	dev_dbg(drvdata->dev, "Trace NOC is enabled\n");
 88	return 0;
 89}
 90
 91static void trace_noc_disable(struct coresight_device *csdev, struct coresight_connection *inport,
 92			      struct coresight_connection *outport)
 93{
 94	struct trace_noc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 95
 96	scoped_guard(spinlock, &drvdata->spinlock) {
 97		if (--csdev->refcnt == 0)
 98			writel(0x0, drvdata->base + TRACE_NOC_CTRL);
 99	}
100	dev_dbg(drvdata->dev, "Trace NOC is disabled\n");
101}
102
103static int trace_noc_id(struct coresight_device *csdev, __maybe_unused enum cs_mode mode,
104			__maybe_unused struct coresight_device *sink)
105{
106	struct trace_noc_drvdata *drvdata;
107
108	drvdata = dev_get_drvdata(csdev->dev.parent);
109
110	return drvdata->atid;
111}
112
113static const struct coresight_ops_link trace_noc_link_ops = {
114	.enable		= trace_noc_enable,
115	.disable	= trace_noc_disable,
116};
117
118static const struct coresight_ops trace_noc_cs_ops = {
119	.trace_id	= trace_noc_id,
120	.link_ops	= &trace_noc_link_ops,
121};
122
123static int trace_noc_init_default_data(struct trace_noc_drvdata *drvdata)
124{
125	int atid;
126
127	atid = coresight_trace_id_get_system_id();
128	if (atid < 0)
129		return atid;
130
131	drvdata->atid = atid;
132
133	return 0;
134}
135
136static ssize_t traceid_show(struct device *dev,
137			    struct device_attribute *attr, char *buf)
138{
139	unsigned long val;
140	struct trace_noc_drvdata *drvdata = dev_get_drvdata(dev->parent);
141
142	val = drvdata->atid;
143	return sprintf(buf, "%#lx\n", val);
144}
145static DEVICE_ATTR_RO(traceid);
146
147static struct attribute *coresight_tnoc_attrs[] = {
148	&dev_attr_traceid.attr,
149	NULL,
150};
151
152static const struct attribute_group coresight_tnoc_group = {
153	.attrs = coresight_tnoc_attrs,
154};
155
156static const struct attribute_group *coresight_tnoc_groups[] = {
157	&coresight_tnoc_group,
158	NULL,
159};
160
161static int trace_noc_probe(struct amba_device *adev, const struct amba_id *id)
162{
163	struct device *dev = &adev->dev;
164	struct coresight_platform_data *pdata;
165	struct trace_noc_drvdata *drvdata;
166	struct coresight_desc desc = { 0 };
167	int ret;
168
169	desc.name = coresight_alloc_device_name(&trace_noc_devs, dev);
170	if (!desc.name)
171		return -ENOMEM;
172
173	pdata = coresight_get_platform_data(dev);
174	if (IS_ERR(pdata))
175		return PTR_ERR(pdata);
176	adev->dev.platform_data = pdata;
177
178	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
179	if (!drvdata)
180		return -ENOMEM;
181
182	drvdata->dev = &adev->dev;
183	dev_set_drvdata(dev, drvdata);
184
185	drvdata->base = devm_ioremap_resource(dev, &adev->res);
186	if (IS_ERR(drvdata->base))
187		return PTR_ERR(drvdata->base);
188
189	spin_lock_init(&drvdata->spinlock);
190
191	ret = trace_noc_init_default_data(drvdata);
192	if (ret)
193		return ret;
194
195	desc.ops = &trace_noc_cs_ops;
196	desc.type = CORESIGHT_DEV_TYPE_LINK;
197	desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG;
198	desc.pdata = adev->dev.platform_data;
199	desc.dev = &adev->dev;
200	desc.access = CSDEV_ACCESS_IOMEM(drvdata->base);
201	desc.groups = coresight_tnoc_groups;
202	drvdata->csdev = coresight_register(&desc);
203	if (IS_ERR(drvdata->csdev)) {
204		coresight_trace_id_put_system_id(drvdata->atid);
205		return PTR_ERR(drvdata->csdev);
206	}
207	pm_runtime_put(&adev->dev);
208
209	return 0;
210}
211
212static void trace_noc_remove(struct amba_device *adev)
213{
214	struct trace_noc_drvdata *drvdata = dev_get_drvdata(&adev->dev);
215
216	coresight_unregister(drvdata->csdev);
217	coresight_trace_id_put_system_id(drvdata->atid);
218}
219
220static struct amba_id trace_noc_ids[] = {
221	{
222		.id     = 0x000f0c00,
223		.mask   = 0x00ffff00,
224	},
225	{
226		.id     = 0x001f0c00,
227		.mask   = 0x00ffff00,
228	},
229	{},
230};
231MODULE_DEVICE_TABLE(amba, trace_noc_ids);
232
233static struct amba_driver trace_noc_driver = {
234	.drv = {
235		.name   = "coresight-trace-noc",
236		.suppress_bind_attrs = true,
237	},
238	.probe          = trace_noc_probe,
239	.remove		= trace_noc_remove,
240	.id_table	= trace_noc_ids,
241};
242
243module_amba_driver(trace_noc_driver);
244
245MODULE_LICENSE("GPL");
246MODULE_DESCRIPTION("Trace NOC driver");
~/ Read-only file preview.