1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2023-2025 Qualcomm Innovation Center, Inc. All rights reserved.
4 */
5
6 #include <linux/amba/bus.h>
7 #include <linux/bitfield.h>
8 #include <linux/coresight.h>
9 #include <linux/device.h>
10 #include <linux/err.h>
11 #include <linux/fs.h>
12 #include <linux/io.h>
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/of.h>
16 #include <linux/platform_device.h>
17
18 #include "coresight-priv.h"
19 #include "coresight-tpda.h"
20 #include "coresight-trace-id.h"
21 #include "coresight-tpdm.h"
22
tpda_clear_element_size(struct coresight_device * csdev)23 static void tpda_clear_element_size(struct coresight_device *csdev)
24 {
25 struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
26
27 drvdata->dsb_esize = 0;
28 drvdata->cmb_esize = 0;
29 }
30
tpda_set_element_size(struct tpda_drvdata * drvdata,u32 * val)31 static void tpda_set_element_size(struct tpda_drvdata *drvdata, u32 *val)
32 {
33 /* Clear all relevant fields */
34 *val &= ~(TPDA_Pn_CR_DSBSIZE | TPDA_Pn_CR_CMBSIZE);
35
36 if (drvdata->dsb_esize == 64)
37 *val |= TPDA_Pn_CR_DSBSIZE;
38 else if (drvdata->dsb_esize == 32)
39 *val &= ~TPDA_Pn_CR_DSBSIZE;
40
41 if (drvdata->cmb_esize == 64)
42 *val |= FIELD_PREP(TPDA_Pn_CR_CMBSIZE, 0x2);
43 else if (drvdata->cmb_esize == 32)
44 *val |= FIELD_PREP(TPDA_Pn_CR_CMBSIZE, 0x1);
45 else if (drvdata->cmb_esize == 8)
46 *val &= ~TPDA_Pn_CR_CMBSIZE;
47 }
48
49 /*
50 * Read the element size from the TPDM device. One TPDM must have at least one of the
51 * element size property.
52 * Returns
53 * 0 - The element size property is read
54 * Others - Cannot read the property of the element size
55 */
tpdm_read_element_size(struct tpda_drvdata * drvdata,struct coresight_device * csdev)56 static int tpdm_read_element_size(struct tpda_drvdata *drvdata,
57 struct coresight_device *csdev)
58 {
59 int rc = -EINVAL;
60 struct tpdm_drvdata *tpdm_data = dev_get_drvdata(csdev->dev.parent);
61
62 if (tpdm_data->dsb) {
63 rc = fwnode_property_read_u32(dev_fwnode(csdev->dev.parent),
64 "qcom,dsb-element-bits", &drvdata->dsb_esize);
65 if (rc)
66 goto out;
67 }
68
69 if (tpdm_data->cmb) {
70 rc = fwnode_property_read_u32(dev_fwnode(csdev->dev.parent),
71 "qcom,cmb-element-bits", &drvdata->cmb_esize);
72 }
73
74 out:
75 if (rc)
76 dev_warn_once(&csdev->dev,
77 "Failed to read TPDM Element size: %d\n", rc);
78
79 return rc;
80 }
81
82 /*
83 * Search and read element data size from the TPDM node in
84 * the devicetree. Each input port of TPDA is connected to
85 * a TPDM. Different TPDM supports different types of dataset,
86 * and some may support more than one type of dataset.
87 * Parameter "inport" is used to pass in the input port number
88 * of TPDA, and it is set to -1 in the recursize call.
89 */
tpda_get_element_size(struct tpda_drvdata * drvdata,struct coresight_device * csdev,int inport)90 static int tpda_get_element_size(struct tpda_drvdata *drvdata,
91 struct coresight_device *csdev,
92 int inport)
93 {
94 int rc = 0;
95 int i;
96 struct coresight_device *in;
97
98 for (i = 0; i < csdev->pdata->nr_inconns; i++) {
99 in = csdev->pdata->in_conns[i]->src_dev;
100 if (!in)
101 continue;
102
103 /* Ignore the paths that do not match port */
104 if (inport >= 0 &&
105 csdev->pdata->in_conns[i]->dest_port != inport)
106 continue;
107
108 /*
109 * If this port has a hardcoded filter, use the source
110 * device directly.
111 */
112 if (csdev->pdata->in_conns[i]->filter_src_fwnode) {
113 in = csdev->pdata->in_conns[i]->filter_src_dev;
114 if (!in)
115 continue;
116 }
117
118 if (coresight_device_is_tpdm(in)) {
119 if (drvdata->dsb_esize || drvdata->cmb_esize)
120 return -EEXIST;
121 rc = tpdm_read_element_size(drvdata, in);
122 if (rc)
123 return rc;
124 } else {
125 /* Recurse down the path */
126 rc = tpda_get_element_size(drvdata, in, -1);
127 if (rc)
128 return rc;
129 }
130 }
131
132 return rc;
133 }
134
135 /* Settings pre enabling port control register */
tpda_enable_pre_port(struct tpda_drvdata * drvdata)136 static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
137 {
138 u32 val = 0;
139
140 val |= FIELD_PREP(TPDA_CR_ATID, drvdata->atid);
141 if (drvdata->trig_async)
142 val |= TPDA_CR_SRIE;
143
144 if (drvdata->trig_flag_ts)
145 val |= TPDA_CR_FLRIE;
146
147 if (drvdata->trig_freq)
148 val |= TPDA_CR_FRIE;
149
150 if (drvdata->freq_ts)
151 val |= TPDA_CR_FREQTS;
152
153 if (drvdata->cmbchan_mode)
154 val |= TPDA_CR_CMBCHANMODE;
155
156 writel_relaxed(val, drvdata->base + TPDA_CR);
157
158 /*
159 * If FLRIE bit is set, set the master and channel
160 * id as zero
161 */
162 if (drvdata->trig_flag_ts)
163 writel_relaxed(0x0, drvdata->base + TPDA_FPID_CR);
164
165 /* Initialize with a value of 0 */
166 val = 0;
167 if (drvdata->syncr_mode)
168 val |= TPDA_SYNCR_MODE_CTRL_MASK;
169
170 if (drvdata->syncr_count > 0 &&
171 drvdata->syncr_count < TPDA_SYNCR_COUNT_MASK)
172 val |= drvdata->syncr_count;
173 else
174 /* Program the count to its MAX value by default */
175 val |= TPDA_SYNCR_COUNT_MASK;
176
177 writel_relaxed(val, drvdata->base + TPDA_SYNCR);
178 }
179
tpda_enable_port(struct tpda_drvdata * drvdata,int port)180 static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
181 {
182 u32 val;
183 int rc;
184
185 val = readl_relaxed(drvdata->base + TPDA_Pn_CR(port));
186 tpda_clear_element_size(drvdata->csdev);
187 rc = tpda_get_element_size(drvdata, drvdata->csdev, port);
188 if (!rc && (drvdata->dsb_esize || drvdata->cmb_esize)) {
189 tpda_set_element_size(drvdata, &val);
190 /* Enable the port */
191 val |= TPDA_Pn_CR_ENA;
192 writel_relaxed(val, drvdata->base + TPDA_Pn_CR(port));
193 } else if (rc == -EEXIST)
194 dev_warn_once(&drvdata->csdev->dev,
195 "Detected multiple TPDMs on port %d", port);
196 else
197 dev_warn_once(&drvdata->csdev->dev,
198 "Didn't find TPDM element size");
199
200 return rc;
201 }
202
__tpda_enable(struct tpda_drvdata * drvdata,int port)203 static int __tpda_enable(struct tpda_drvdata *drvdata, int port)
204 {
205 int ret;
206
207 CS_UNLOCK(drvdata->base);
208
209 /*
210 * Only do pre-port enable for first port that calls enable when the
211 * device's main refcount is still 0
212 */
213 lockdep_assert_held(&drvdata->spinlock);
214 if (!drvdata->csdev->refcnt)
215 tpda_enable_pre_port(drvdata);
216
217 ret = tpda_enable_port(drvdata, port);
218 CS_LOCK(drvdata->base);
219
220 return ret;
221 }
222
tpda_enable(struct coresight_device * csdev,struct coresight_connection * in,struct coresight_connection * out)223 static int tpda_enable(struct coresight_device *csdev,
224 struct coresight_connection *in,
225 struct coresight_connection *out)
226 {
227 struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
228 int ret = 0;
229
230 spin_lock(&drvdata->spinlock);
231 if (in->dest_refcnt == 0) {
232 ret = __tpda_enable(drvdata, in->dest_port);
233 if (!ret) {
234 in->dest_refcnt++;
235 csdev->refcnt++;
236 dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port);
237 }
238 }
239
240 spin_unlock(&drvdata->spinlock);
241 return ret;
242 }
243
__tpda_disable(struct tpda_drvdata * drvdata,int port)244 static void __tpda_disable(struct tpda_drvdata *drvdata, int port)
245 {
246 u32 val;
247
248 CS_UNLOCK(drvdata->base);
249
250 val = readl_relaxed(drvdata->base + TPDA_Pn_CR(port));
251 val &= ~TPDA_Pn_CR_ENA;
252 writel_relaxed(val, drvdata->base + TPDA_Pn_CR(port));
253
254 CS_LOCK(drvdata->base);
255 }
256
tpda_disable(struct coresight_device * csdev,struct coresight_connection * in,struct coresight_connection * out)257 static void tpda_disable(struct coresight_device *csdev,
258 struct coresight_connection *in,
259 struct coresight_connection *out)
260 {
261 struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
262
263 spin_lock(&drvdata->spinlock);
264 if (--in->dest_refcnt == 0) {
265 __tpda_disable(drvdata, in->dest_port);
266 csdev->refcnt--;
267 }
268 spin_unlock(&drvdata->spinlock);
269
270 dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", in->dest_port);
271 }
272
tpda_trace_id(struct coresight_device * csdev,__maybe_unused enum cs_mode mode,__maybe_unused struct coresight_device * sink)273 static int tpda_trace_id(struct coresight_device *csdev, __maybe_unused enum cs_mode mode,
274 __maybe_unused struct coresight_device *sink)
275 {
276 struct tpda_drvdata *drvdata;
277
278 drvdata = dev_get_drvdata(csdev->dev.parent);
279
280 return drvdata->atid;
281 }
282
283 static const struct coresight_ops_link tpda_link_ops = {
284 .enable = tpda_enable,
285 .disable = tpda_disable,
286 };
287
288 static const struct coresight_ops tpda_cs_ops = {
289 .trace_id = tpda_trace_id,
290 .link_ops = &tpda_link_ops,
291 };
292
293 /* Read cross-trigger register member */
tpda_trig_sysfs_show(struct device * dev,struct device_attribute * attr,char * buf)294 static ssize_t tpda_trig_sysfs_show(struct device *dev,
295 struct device_attribute *attr,
296 char *buf)
297 {
298 struct tpda_trig_sysfs_attribute *tpda_attr =
299 container_of(attr, struct tpda_trig_sysfs_attribute, attr);
300 struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
301
302 guard(spinlock)(&drvdata->spinlock);
303 switch (tpda_attr->mem) {
304 case FREQTS:
305 return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->freq_ts);
306 case FRIE:
307 return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_freq);
308 case FLRIE:
309 return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_flag_ts);
310 case SRIE:
311 return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->trig_async);
312 case CMBCHANMODE:
313 return sysfs_emit(buf, "%u\n", (unsigned int)drvdata->cmbchan_mode);
314
315 }
316 return -EINVAL;
317 }
318
tpda_trig_sysfs_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)319 static ssize_t tpda_trig_sysfs_store(struct device *dev,
320 struct device_attribute *attr,
321 const char *buf,
322 size_t size)
323 {
324 struct tpda_trig_sysfs_attribute *tpda_attr =
325 container_of(attr, struct tpda_trig_sysfs_attribute, attr);
326 struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
327 unsigned long val;
328
329 if (kstrtoul(buf, 0, &val))
330 return -EINVAL;
331
332 guard(spinlock)(&drvdata->spinlock);
333 switch (tpda_attr->mem) {
334 case FREQTS:
335 drvdata->freq_ts = !!val;
336 break;
337 case FRIE:
338 drvdata->trig_freq = !!val;
339 break;
340 case FLRIE:
341 drvdata->trig_flag_ts = !!val;
342 break;
343 case SRIE:
344 drvdata->trig_async = !!val;
345 break;
346 case CMBCHANMODE:
347 drvdata->cmbchan_mode = !!val;
348 break;
349 default:
350 return -EINVAL;
351 }
352
353 return size;
354 }
355
global_flush_req_show(struct device * dev,struct device_attribute * attr,char * buf)356 static ssize_t global_flush_req_show(struct device *dev,
357 struct device_attribute *attr,
358 char *buf)
359 {
360 struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
361 unsigned long val;
362
363 if (!drvdata->csdev->refcnt)
364 return -EINVAL;
365
366 guard(spinlock)(&drvdata->spinlock);
367 val = readl_relaxed(drvdata->base + TPDA_CR);
368 /* read global_flush_req bit */
369 val &= TPDA_CR_FLREQ;
370
371 return sysfs_emit(buf, "%lu\n", val);
372 }
373
global_flush_req_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)374 static ssize_t global_flush_req_store(struct device *dev,
375 struct device_attribute *attr,
376 const char *buf,
377 size_t size)
378 {
379 struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
380 unsigned long val;
381
382 if (kstrtoul(buf, 0, &val))
383 return -EINVAL;
384
385 if (!drvdata->csdev->refcnt || !val)
386 return -EINVAL;
387
388 guard(spinlock)(&drvdata->spinlock);
389 val = readl_relaxed(drvdata->base + TPDA_CR);
390 /* set global_flush_req bit */
391 val |= TPDA_CR_FLREQ;
392 CS_UNLOCK(drvdata->base);
393 writel_relaxed(val, drvdata->base + TPDA_CR);
394 CS_LOCK(drvdata->base);
395
396 return size;
397 }
398 static DEVICE_ATTR_RW(global_flush_req);
399
syncr_mode_show(struct device * dev,struct device_attribute * attr,char * buf)400 static ssize_t syncr_mode_show(struct device *dev,
401 struct device_attribute *attr,
402 char *buf)
403 {
404 struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
405 unsigned long val, syncr_val;
406
407 if (!drvdata->csdev->refcnt)
408 return -EINVAL;
409
410 guard(spinlock)(&drvdata->spinlock);
411 syncr_val = readl_relaxed(drvdata->base + TPDA_SYNCR);
412 val = FIELD_GET(TPDA_SYNCR_MODE_CTRL_MASK, syncr_val);
413
414 return sysfs_emit(buf, "%lu\n", val);
415 }
416
syncr_mode_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)417 static ssize_t syncr_mode_store(struct device *dev,
418 struct device_attribute *attr,
419 const char *buf,
420 size_t size)
421 {
422 struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
423 unsigned long val;
424
425 if (kstrtoul(buf, 0, &val))
426 return -EINVAL;
427
428 guard(spinlock)(&drvdata->spinlock);
429 /* set the mode when first enabling the device */
430 drvdata->syncr_mode = !!val;
431
432 return size;
433 }
434 static DEVICE_ATTR_RW(syncr_mode);
435
syncr_count_show(struct device * dev,struct device_attribute * attr,char * buf)436 static ssize_t syncr_count_show(struct device *dev,
437 struct device_attribute *attr,
438 char *buf)
439 {
440 struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
441 unsigned long val;
442
443 if (!drvdata->csdev->refcnt)
444 return -EINVAL;
445
446 guard(spinlock)(&drvdata->spinlock);
447 val = readl_relaxed(drvdata->base + TPDA_SYNCR);
448 val &= TPDA_SYNCR_COUNT_MASK;
449
450 return sysfs_emit(buf, "%lu\n", val);
451 }
452
syncr_count_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)453 static ssize_t syncr_count_store(struct device *dev,
454 struct device_attribute *attr,
455 const char *buf,
456 size_t size)
457 {
458 struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
459 unsigned long val;
460
461 if (kstrtoul(buf, 0, &val))
462 return -EINVAL;
463
464 if (val > TPDA_SYNCR_COUNT_MASK)
465 return -EINVAL;
466
467 guard(spinlock)(&drvdata->spinlock);
468 drvdata->syncr_count = val;
469
470 return size;
471 }
472 static DEVICE_ATTR_RW(syncr_count);
473
port_flush_req_show(struct device * dev,struct device_attribute * attr,char * buf)474 static ssize_t port_flush_req_show(struct device *dev,
475 struct device_attribute *attr,
476 char *buf)
477 {
478 struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
479 unsigned long val;
480
481 if (!drvdata->csdev->refcnt)
482 return -EINVAL;
483
484 guard(spinlock)(&drvdata->spinlock);
485 val = readl_relaxed(drvdata->base + TPDA_FLUSH_CR);
486
487 return sysfs_emit(buf, "0x%lx\n", val);
488 }
489
port_flush_req_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)490 static ssize_t port_flush_req_store(struct device *dev,
491 struct device_attribute *attr,
492 const char *buf,
493 size_t size)
494 {
495 struct tpda_drvdata *drvdata = dev_get_drvdata(dev->parent);
496 u32 val;
497
498 if (kstrtou32(buf, 0, &val))
499 return -EINVAL;
500
501 if (!drvdata->csdev->refcnt || !val)
502 return -EINVAL;
503
504 guard(spinlock)(&drvdata->spinlock);
505 CS_UNLOCK(drvdata->base);
506 writel_relaxed(val, drvdata->base + TPDA_FLUSH_CR);
507 CS_LOCK(drvdata->base);
508
509 return size;
510 }
511 static DEVICE_ATTR_RW(port_flush_req);
512
513 static struct attribute *tpda_attrs[] = {
514 &dev_attr_global_flush_req.attr,
515 &dev_attr_syncr_mode.attr,
516 &dev_attr_syncr_count.attr,
517 &dev_attr_port_flush_req.attr,
518 tpda_trig_sysfs_rw(freq_ts_enable, FREQTS),
519 tpda_trig_sysfs_rw(trig_freq_enable, FRIE),
520 tpda_trig_sysfs_rw(trig_flag_ts_enable, FLRIE),
521 tpda_trig_sysfs_rw(trig_async_enable, SRIE),
522 tpda_trig_sysfs_rw(cmbchan_mode, CMBCHANMODE),
523 NULL,
524 };
525
526 static struct attribute_group tpda_attr_grp = {
527 .attrs = tpda_attrs,
528 };
529
530 static const struct attribute_group *tpda_attr_grps[] = {
531 &tpda_attr_grp,
532 NULL,
533 };
534
tpda_init_default_data(struct tpda_drvdata * drvdata)535 static int tpda_init_default_data(struct tpda_drvdata *drvdata)
536 {
537 int atid;
538 /*
539 * TPDA must has a unique atid. This atid can uniquely
540 * identify the TPDM trace source connected to the TPDA.
541 * The TPDMs which are connected to same TPDA share the
542 * same trace-id. When TPDA does packetization, different
543 * port will have unique channel number for decoding.
544 */
545 atid = coresight_trace_id_get_system_id();
546 if (atid < 0)
547 return atid;
548
549 drvdata->atid = atid;
550 drvdata->freq_ts = true;
551 return 0;
552 }
553
tpda_probe(struct amba_device * adev,const struct amba_id * id)554 static int tpda_probe(struct amba_device *adev, const struct amba_id *id)
555 {
556 int ret;
557 struct device *dev = &adev->dev;
558 struct coresight_platform_data *pdata;
559 struct tpda_drvdata *drvdata;
560 struct coresight_desc desc = { 0 };
561 void __iomem *base;
562
563 pdata = coresight_get_platform_data(dev);
564 if (IS_ERR(pdata))
565 return PTR_ERR(pdata);
566 adev->dev.platform_data = pdata;
567
568 drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
569 if (!drvdata)
570 return -ENOMEM;
571
572 drvdata->dev = &adev->dev;
573 dev_set_drvdata(dev, drvdata);
574
575 base = devm_ioremap_resource(dev, &adev->res);
576 if (IS_ERR(base))
577 return PTR_ERR(base);
578 drvdata->base = base;
579
580 spin_lock_init(&drvdata->spinlock);
581
582 ret = tpda_init_default_data(drvdata);
583 if (ret)
584 return ret;
585
586 desc.name = coresight_alloc_device_name("tpda", dev);
587 if (!desc.name)
588 return -ENOMEM;
589 desc.type = CORESIGHT_DEV_TYPE_LINK;
590 desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG;
591 desc.ops = &tpda_cs_ops;
592 desc.pdata = adev->dev.platform_data;
593 desc.dev = &adev->dev;
594 desc.groups = tpda_attr_grps;
595 desc.access = CSDEV_ACCESS_IOMEM(base);
596 drvdata->csdev = coresight_register(&desc);
597 if (IS_ERR(drvdata->csdev))
598 return PTR_ERR(drvdata->csdev);
599
600 pm_runtime_put(&adev->dev);
601
602 dev_dbg(drvdata->dev, "TPDA initialized\n");
603 return 0;
604 }
605
tpda_remove(struct amba_device * adev)606 static void tpda_remove(struct amba_device *adev)
607 {
608 struct tpda_drvdata *drvdata = dev_get_drvdata(&adev->dev);
609
610 coresight_trace_id_put_system_id(drvdata->atid);
611 coresight_unregister(drvdata->csdev);
612 }
613
614 /*
615 * Different TPDA has different periph id.
616 * The difference is 0-7 bits' value. So ignore 0-7 bits.
617 */
618 static const struct amba_id tpda_ids[] = {
619 {
620 .id = 0x000f0f00,
621 .mask = 0x000fff00,
622 },
623 { 0, 0, NULL },
624 };
625
626 static struct amba_driver tpda_driver = {
627 .drv = {
628 .name = "coresight-tpda",
629 .suppress_bind_attrs = true,
630 },
631 .probe = tpda_probe,
632 .remove = tpda_remove,
633 .id_table = tpda_ids,
634 };
635
636 module_amba_driver(tpda_driver);
637
638 MODULE_LICENSE("GPL");
639 MODULE_DESCRIPTION("Trace, Profiling & Diagnostic Aggregator driver");
640