xref: /linux/drivers/hwtracing/coresight/coresight-tpda.c (revision cb4eb6771c0f8fd1c52a8f6fdec7762fb087380a)
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