aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/coresight
diff options
context:
space:
mode:
authorPratik Patel <pratikp@codeaurora.org>2014-11-03 13:07:35 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-11-07 18:19:32 -0500
commita06ae8609b3dd06b957a6e4e965772a8a14d3af5 (patch)
tree7fb5339deabb245bce1803f1e9628b8dc5b20ab2 /drivers/coresight
parentf4c9485f9f5d816bb21333b517d0e3d2746dd285 (diff)
coresight: add CoreSight core layer framework
CoreSight components are compliant with the ARM CoreSight architecture specification and can be connected in various topologies to suit a particular SoC tracing needs. These trace components can generally be classified as sources, links and sinks. Trace data produced by one or more sources flows through the intermediate links connecting the source to the currently selected sink. The CoreSight framework provides an interface for the CoreSight trace drivers to register themselves with. It's intended to build up a topological view of the CoreSight components and configure the correct serie of components on user input via sysfs. For eg., when enabling a source, the framework builds up a path consisting of all the components connecting the source to the currently selected sink(s) and enables all of them. The framework also supports switching between available sinks and provides status information to user space applications through the debugfs interface. Signed-off-by: Pratik Patel <pratikp@codeaurora.org> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/coresight')
-rw-r--r--drivers/coresight/Makefile5
-rw-r--r--drivers/coresight/coresight-priv.h63
-rw-r--r--drivers/coresight/coresight.c717
-rw-r--r--drivers/coresight/of_coresight.c204
4 files changed, 989 insertions, 0 deletions
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
new file mode 100644
index 000000000000..218e3b589f93
--- /dev/null
+++ b/drivers/coresight/Makefile
@@ -0,0 +1,5 @@
1#
2# Makefile for CoreSight drivers.
3#
4obj-$(CONFIG_CORESIGHT) += coresight.o
5obj-$(CONFIG_OF) += of_coresight.o
diff --git a/drivers/coresight/coresight-priv.h b/drivers/coresight/coresight-priv.h
new file mode 100644
index 000000000000..8d1180c47c0b
--- /dev/null
+++ b/drivers/coresight/coresight-priv.h
@@ -0,0 +1,63 @@
1/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#ifndef _CORESIGHT_PRIV_H
14#define _CORESIGHT_PRIV_H
15
16#include <linux/bitops.h>
17#include <linux/io.h>
18#include <linux/coresight.h>
19
20/*
21 * Coresight management registers (0xf00-0xfcc)
22 * 0xfa0 - 0xfa4: Management registers in PFTv1.0
23 * Trace registers in PFTv1.1
24 */
25#define CORESIGHT_ITCTRL 0xf00
26#define CORESIGHT_CLAIMSET 0xfa0
27#define CORESIGHT_CLAIMCLR 0xfa4
28#define CORESIGHT_LAR 0xfb0
29#define CORESIGHT_LSR 0xfb4
30#define CORESIGHT_AUTHSTATUS 0xfb8
31#define CORESIGHT_DEVID 0xfc8
32#define CORESIGHT_DEVTYPE 0xfcc
33
34#define TIMEOUT_US 100
35#define BMVAL(val, lsb, msb) ((val & GENMASK(msb, lsb)) >> lsb)
36
37static inline void CS_LOCK(void __iomem *addr)
38{
39 do {
40 /* Wait for things to settle */
41 mb();
42 writel_relaxed(0x0, addr + CORESIGHT_LAR);
43 } while (0);
44}
45
46static inline void CS_UNLOCK(void __iomem *addr)
47{
48 do {
49 writel_relaxed(CORESIGHT_UNLOCK, addr + CORESIGHT_LAR);
50 /* Make sure eveyone has seen this */
51 mb();
52 } while (0);
53}
54
55#ifdef CONFIG_CORESIGHT_SOURCE_ETM3X
56extern int etm_readl_cp14(u32 off, unsigned int *val);
57extern int etm_writel_cp14(u32 off, u32 val);
58#else
59static inline int etm_readl_cp14(u32 off, unsigned int *val) { return 0; }
60static inline int etm_writel_cp14(u32 val, u32 off) { return 0; }
61#endif
62
63#endif
diff --git a/drivers/coresight/coresight.c b/drivers/coresight/coresight.c
new file mode 100644
index 000000000000..6e0181f84425
--- /dev/null
+++ b/drivers/coresight/coresight.c
@@ -0,0 +1,717 @@
1/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/types.h>
17#include <linux/device.h>
18#include <linux/io.h>
19#include <linux/err.h>
20#include <linux/export.h>
21#include <linux/slab.h>
22#include <linux/mutex.h>
23#include <linux/clk.h>
24#include <linux/coresight.h>
25#include <linux/of_platform.h>
26#include <linux/delay.h>
27
28#include "coresight-priv.h"
29
30static DEFINE_MUTEX(coresight_mutex);
31
32static int coresight_id_match(struct device *dev, void *data)
33{
34 int trace_id, i_trace_id;
35 struct coresight_device *csdev, *i_csdev;
36
37 csdev = data;
38 i_csdev = to_coresight_device(dev);
39
40 /*
41 * No need to care about oneself and components that are not
42 * sources or not enabled
43 */
44 if (i_csdev == csdev || !i_csdev->enable ||
45 i_csdev->type != CORESIGHT_DEV_TYPE_SOURCE)
46 return 0;
47
48 /* Get the source ID for both compoment */
49 trace_id = source_ops(csdev)->trace_id(csdev);
50 i_trace_id = source_ops(i_csdev)->trace_id(i_csdev);
51
52 /* All you need is one */
53 if (trace_id == i_trace_id)
54 return 1;
55
56 return 0;
57}
58
59static int coresight_source_is_unique(struct coresight_device *csdev)
60{
61 int trace_id = source_ops(csdev)->trace_id(csdev);
62
63 /* this shouldn't happen */
64 if (trace_id < 0)
65 return 0;
66
67 return !bus_for_each_dev(&coresight_bustype, NULL,
68 csdev, coresight_id_match);
69}
70
71static int coresight_find_link_inport(struct coresight_device *csdev)
72{
73 int i;
74 struct coresight_device *parent;
75 struct coresight_connection *conn;
76
77 parent = container_of(csdev->path_link.next,
78 struct coresight_device, path_link);
79
80 for (i = 0; i < parent->nr_outport; i++) {
81 conn = &parent->conns[i];
82 if (conn->child_dev == csdev)
83 return conn->child_port;
84 }
85
86 dev_err(&csdev->dev, "couldn't find inport, parent: %s, child: %s\n",
87 dev_name(&parent->dev), dev_name(&csdev->dev));
88
89 return 0;
90}
91
92static int coresight_find_link_outport(struct coresight_device *csdev)
93{
94 int i;
95 struct coresight_device *child;
96 struct coresight_connection *conn;
97
98 child = container_of(csdev->path_link.prev,
99 struct coresight_device, path_link);
100
101 for (i = 0; i < csdev->nr_outport; i++) {
102 conn = &csdev->conns[i];
103 if (conn->child_dev == child)
104 return conn->outport;
105 }
106
107 dev_err(&csdev->dev, "couldn't find outport, parent: %s, child: %s\n",
108 dev_name(&csdev->dev), dev_name(&child->dev));
109
110 return 0;
111}
112
113static int coresight_enable_sink(struct coresight_device *csdev)
114{
115 int ret;
116
117 if (!csdev->enable) {
118 if (sink_ops(csdev)->enable) {
119 ret = sink_ops(csdev)->enable(csdev);
120 if (ret)
121 return ret;
122 }
123 csdev->enable = true;
124 }
125
126 atomic_inc(csdev->refcnt);
127
128 return 0;
129}
130
131static void coresight_disable_sink(struct coresight_device *csdev)
132{
133 if (atomic_dec_return(csdev->refcnt) == 0) {
134 if (sink_ops(csdev)->disable) {
135 sink_ops(csdev)->disable(csdev);
136 csdev->enable = false;
137 }
138 }
139}
140
141static int coresight_enable_link(struct coresight_device *csdev)
142{
143 int ret;
144 int link_subtype;
145 int refport, inport, outport;
146
147 inport = coresight_find_link_inport(csdev);
148 outport = coresight_find_link_outport(csdev);
149 link_subtype = csdev->subtype.link_subtype;
150
151 if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
152 refport = inport;
153 else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
154 refport = outport;
155 else
156 refport = 0;
157
158 if (atomic_inc_return(&csdev->refcnt[refport]) == 1) {
159 if (link_ops(csdev)->enable) {
160 ret = link_ops(csdev)->enable(csdev, inport, outport);
161 if (ret)
162 return ret;
163 }
164 }
165
166 csdev->enable = true;
167
168 return 0;
169}
170
171static void coresight_disable_link(struct coresight_device *csdev)
172{
173 int i, nr_conns;
174 int link_subtype;
175 int refport, inport, outport;
176
177 inport = coresight_find_link_inport(csdev);
178 outport = coresight_find_link_outport(csdev);
179 link_subtype = csdev->subtype.link_subtype;
180
181 if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
182 refport = inport;
183 nr_conns = csdev->nr_inport;
184 } else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) {
185 refport = outport;
186 nr_conns = csdev->nr_outport;
187 } else {
188 refport = 0;
189 nr_conns = 1;
190 }
191
192 if (atomic_dec_return(&csdev->refcnt[refport]) == 0) {
193 if (link_ops(csdev)->disable)
194 link_ops(csdev)->disable(csdev, inport, outport);
195 }
196
197 for (i = 0; i < nr_conns; i++)
198 if (atomic_read(&csdev->refcnt[i]) != 0)
199 return;
200
201 csdev->enable = false;
202}
203
204static int coresight_enable_source(struct coresight_device *csdev)
205{
206 int ret;
207
208 if (!coresight_source_is_unique(csdev)) {
209 dev_warn(&csdev->dev, "traceID %d not unique\n",
210 source_ops(csdev)->trace_id(csdev));
211 return -EINVAL;
212 }
213
214 if (!csdev->enable) {
215 if (source_ops(csdev)->enable) {
216 ret = source_ops(csdev)->enable(csdev);
217 if (ret)
218 return ret;
219 }
220 csdev->enable = true;
221 }
222
223 atomic_inc(csdev->refcnt);
224
225 return 0;
226}
227
228static void coresight_disable_source(struct coresight_device *csdev)
229{
230 if (atomic_dec_return(csdev->refcnt) == 0) {
231 if (source_ops(csdev)->disable) {
232 source_ops(csdev)->disable(csdev);
233 csdev->enable = false;
234 }
235 }
236}
237
238static int coresight_enable_path(struct list_head *path)
239{
240 int ret = 0;
241 struct coresight_device *cd;
242
243 list_for_each_entry(cd, path, path_link) {
244 if (cd == list_first_entry(path, struct coresight_device,
245 path_link)) {
246 ret = coresight_enable_sink(cd);
247 } else if (list_is_last(&cd->path_link, path)) {
248 /*
249 * Don't enable the source just yet - this needs to
250 * happen at the very end when all links and sink
251 * along the path have been configured properly.
252 */
253 ;
254 } else {
255 ret = coresight_enable_link(cd);
256 }
257 if (ret)
258 goto err;
259 }
260
261 return 0;
262err:
263 list_for_each_entry_continue_reverse(cd, path, path_link) {
264 if (cd == list_first_entry(path, struct coresight_device,
265 path_link)) {
266 coresight_disable_sink(cd);
267 } else if (list_is_last(&cd->path_link, path)) {
268 ;
269 } else {
270 coresight_disable_link(cd);
271 }
272 }
273
274 return ret;
275}
276
277static int coresight_disable_path(struct list_head *path)
278{
279 struct coresight_device *cd;
280
281 list_for_each_entry_reverse(cd, path, path_link) {
282 if (cd == list_first_entry(path, struct coresight_device,
283 path_link)) {
284 coresight_disable_sink(cd);
285 } else if (list_is_last(&cd->path_link, path)) {
286 /*
287 * The source has already been stopped, no need
288 * to do it again here.
289 */
290 ;
291 } else {
292 coresight_disable_link(cd);
293 }
294 }
295
296 return 0;
297}
298
299static int coresight_build_paths(struct coresight_device *csdev,
300 struct list_head *path,
301 bool enable)
302{
303 int i, ret = -EINVAL;
304 struct coresight_connection *conn;
305
306 list_add(&csdev->path_link, path);
307
308 if (csdev->type == CORESIGHT_DEV_TYPE_SINK && csdev->activated) {
309 if (enable)
310 ret = coresight_enable_path(path);
311 else
312 ret = coresight_disable_path(path);
313 } else {
314 for (i = 0; i < csdev->nr_outport; i++) {
315 conn = &csdev->conns[i];
316 if (coresight_build_paths(conn->child_dev,
317 path, enable) == 0)
318 ret = 0;
319 }
320 }
321
322 if (list_first_entry(path, struct coresight_device, path_link) != csdev)
323 dev_err(&csdev->dev, "wrong device in %s\n", __func__);
324
325 list_del(&csdev->path_link);
326
327 return ret;
328}
329
330int coresight_enable(struct coresight_device *csdev)
331{
332 int ret = 0;
333 LIST_HEAD(path);
334
335 mutex_lock(&coresight_mutex);
336 if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE) {
337 ret = -EINVAL;
338 dev_err(&csdev->dev, "wrong device type in %s\n", __func__);
339 goto out;
340 }
341 if (csdev->enable)
342 goto out;
343
344 if (coresight_build_paths(csdev, &path, true)) {
345 dev_err(&csdev->dev, "building path(s) failed\n");
346 goto out;
347 }
348
349 if (coresight_enable_source(csdev))
350 dev_err(&csdev->dev, "source enable failed\n");
351out:
352 mutex_unlock(&coresight_mutex);
353 return ret;
354}
355EXPORT_SYMBOL_GPL(coresight_enable);
356
357void coresight_disable(struct coresight_device *csdev)
358{
359 LIST_HEAD(path);
360
361 mutex_lock(&coresight_mutex);
362 if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE) {
363 dev_err(&csdev->dev, "wrong device type in %s\n", __func__);
364 goto out;
365 }
366 if (!csdev->enable)
367 goto out;
368
369 coresight_disable_source(csdev);
370 if (coresight_build_paths(csdev, &path, false))
371 dev_err(&csdev->dev, "releasing path(s) failed\n");
372
373out:
374 mutex_unlock(&coresight_mutex);
375}
376EXPORT_SYMBOL_GPL(coresight_disable);
377
378static ssize_t enable_sink_show(struct device *dev,
379 struct device_attribute *attr, char *buf)
380{
381 struct coresight_device *csdev = to_coresight_device(dev);
382
383 return scnprintf(buf, PAGE_SIZE, "%u\n", (unsigned)csdev->activated);
384}
385
386static ssize_t enable_sink_store(struct device *dev,
387 struct device_attribute *attr,
388 const char *buf, size_t size)
389{
390 int ret;
391 unsigned long val;
392 struct coresight_device *csdev = to_coresight_device(dev);
393
394 ret = kstrtoul(buf, 10, &val);
395 if (ret)
396 return ret;
397
398 if (val)
399 csdev->activated = true;
400 else
401 csdev->activated = false;
402
403 return size;
404
405}
406static DEVICE_ATTR_RW(enable_sink);
407
408static ssize_t enable_source_show(struct device *dev,
409 struct device_attribute *attr, char *buf)
410{
411 struct coresight_device *csdev = to_coresight_device(dev);
412
413 return scnprintf(buf, PAGE_SIZE, "%u\n", (unsigned)csdev->enable);
414}
415
416static ssize_t enable_source_store(struct device *dev,
417 struct device_attribute *attr,
418 const char *buf, size_t size)
419{
420 int ret = 0;
421 unsigned long val;
422 struct coresight_device *csdev = to_coresight_device(dev);
423
424 ret = kstrtoul(buf, 10, &val);
425 if (ret)
426 return ret;
427
428 if (val) {
429 ret = coresight_enable(csdev);
430 if (ret)
431 return ret;
432 } else {
433 coresight_disable(csdev);
434 }
435
436 return size;
437}
438static DEVICE_ATTR_RW(enable_source);
439
440static struct attribute *coresight_sink_attrs[] = {
441 &dev_attr_enable_sink.attr,
442 NULL,
443};
444ATTRIBUTE_GROUPS(coresight_sink);
445
446static struct attribute *coresight_source_attrs[] = {
447 &dev_attr_enable_source.attr,
448 NULL,
449};
450ATTRIBUTE_GROUPS(coresight_source);
451
452static struct device_type coresight_dev_type[] = {
453 {
454 .name = "none",
455 },
456 {
457 .name = "sink",
458 .groups = coresight_sink_groups,
459 },
460 {
461 .name = "link",
462 },
463 {
464 .name = "linksink",
465 .groups = coresight_sink_groups,
466 },
467 {
468 .name = "source",
469 .groups = coresight_source_groups,
470 },
471};
472
473static void coresight_device_release(struct device *dev)
474{
475 struct coresight_device *csdev = to_coresight_device(dev);
476
477 kfree(csdev);
478}
479
480static int coresight_orphan_match(struct device *dev, void *data)
481{
482 int i;
483 bool still_orphan = false;
484 struct coresight_device *csdev, *i_csdev;
485 struct coresight_connection *conn;
486
487 csdev = data;
488 i_csdev = to_coresight_device(dev);
489
490 /* No need to check oneself */
491 if (csdev == i_csdev)
492 return 0;
493
494 /* Move on to another component if no connection is orphan */
495 if (!i_csdev->orphan)
496 return 0;
497 /*
498 * Circle throuch all the connection of that component. If we find
499 * an orphan connection whose name matches @csdev, link it.
500 */
501 for (i = 0; i < i_csdev->nr_outport; i++) {
502 conn = &i_csdev->conns[i];
503
504 /* We have found at least one orphan connection */
505 if (conn->child_dev == NULL) {
506 /* Does it match this newly added device? */
507 if (!strcmp(dev_name(&csdev->dev), conn->child_name))
508 conn->child_dev = csdev;
509 } else {
510 /* Too bad, this component still has an orphan */
511 still_orphan = true;
512 }
513 }
514
515 i_csdev->orphan = still_orphan;
516
517 /*
518 * Returning '0' ensures that all known component on the
519 * bus will be checked.
520 */
521 return 0;
522}
523
524static void coresight_fixup_orphan_conns(struct coresight_device *csdev)
525{
526 /*
527 * No need to check for a return value as orphan connection(s)
528 * are hooked-up with each newly added component.
529 */
530 bus_for_each_dev(&coresight_bustype, NULL,
531 csdev, coresight_orphan_match);
532}
533
534
535static int coresight_name_match(struct device *dev, void *data)
536{
537 char *to_match;
538 struct coresight_device *i_csdev;
539
540 to_match = data;
541 i_csdev = to_coresight_device(dev);
542
543 if (!strcmp(to_match, dev_name(&i_csdev->dev)))
544 return 1;
545
546 return 0;
547}
548
549static void coresight_fixup_device_conns(struct coresight_device *csdev)
550{
551 int i;
552 struct device *dev = NULL;
553 struct coresight_connection *conn;
554
555 for (i = 0; i < csdev->nr_outport; i++) {
556 conn = &csdev->conns[i];
557 dev = bus_find_device(&coresight_bustype, NULL,
558 (void *)conn->child_name,
559 coresight_name_match);
560
561 if (dev) {
562 conn->child_dev = to_coresight_device(dev);
563 } else {
564 csdev->orphan = true;
565 conn->child_dev = NULL;
566 }
567 }
568}
569
570/**
571 * coresight_timeout - loop until a bit has changed to a specific state.
572 * @addr: base address of the area of interest.
573 * @offset: address of a register, starting from @addr.
574 * @position: the position of the bit of interest.
575 * @value: the value the bit should have.
576 *
577 * Return: 0 as soon as the bit has taken the desired state or -EAGAIN if
578 * TIMEOUT_US has elapsed, which ever happens first.
579 */
580
581int coresight_timeout(void __iomem *addr, u32 offset, int position, int value)
582{
583 int i;
584 u32 val;
585
586 for (i = TIMEOUT_US; i > 0; i--) {
587 val = __raw_readl(addr + offset);
588 /* waiting on the bit to go from 0 to 1 */
589 if (value) {
590 if (val & BIT(position))
591 return 0;
592 /* waiting on the bit to go from 1 to 0 */
593 } else {
594 if (!(val & BIT(position)))
595 return 0;
596 }
597
598 /*
599 * Delay is arbitrary - the specification doesn't say how long
600 * we are expected to wait. Extra check required to make sure
601 * we don't wait needlessly on the last iteration.
602 */
603 if (i - 1)
604 udelay(1);
605 }
606
607 return -EAGAIN;
608}
609
610struct bus_type coresight_bustype = {
611 .name = "coresight",
612};
613
614static int __init coresight_init(void)
615{
616 return bus_register(&coresight_bustype);
617}
618postcore_initcall(coresight_init);
619
620struct coresight_device *coresight_register(struct coresight_desc *desc)
621{
622 int i;
623 int ret;
624 int link_subtype;
625 int nr_refcnts = 1;
626 atomic_t *refcnts = NULL;
627 struct coresight_device *csdev;
628 struct coresight_connection *conns;
629
630 csdev = kzalloc(sizeof(*csdev), GFP_KERNEL);
631 if (!csdev) {
632 ret = -ENOMEM;
633 goto err_kzalloc_csdev;
634 }
635
636 if (desc->type == CORESIGHT_DEV_TYPE_LINK ||
637 desc->type == CORESIGHT_DEV_TYPE_LINKSINK) {
638 link_subtype = desc->subtype.link_subtype;
639
640 if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
641 nr_refcnts = desc->pdata->nr_inport;
642 else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
643 nr_refcnts = desc->pdata->nr_outport;
644 }
645
646 refcnts = kcalloc(nr_refcnts, sizeof(*refcnts), GFP_KERNEL);
647 if (!refcnts) {
648 ret = -ENOMEM;
649 goto err_kzalloc_refcnts;
650 }
651
652 csdev->refcnt = refcnts;
653
654 csdev->nr_inport = desc->pdata->nr_inport;
655 csdev->nr_outport = desc->pdata->nr_outport;
656 conns = kcalloc(csdev->nr_outport, sizeof(*conns), GFP_KERNEL);
657 if (!conns) {
658 ret = -ENOMEM;
659 goto err_kzalloc_conns;
660 }
661
662 for (i = 0; i < csdev->nr_outport; i++) {
663 conns[i].outport = desc->pdata->outports[i];
664 conns[i].child_name = desc->pdata->child_names[i];
665 conns[i].child_port = desc->pdata->child_ports[i];
666 }
667
668 csdev->conns = conns;
669
670 csdev->type = desc->type;
671 csdev->subtype = desc->subtype;
672 csdev->ops = desc->ops;
673 csdev->orphan = false;
674
675 csdev->dev.type = &coresight_dev_type[desc->type];
676 csdev->dev.groups = desc->groups;
677 csdev->dev.parent = desc->dev;
678 csdev->dev.release = coresight_device_release;
679 csdev->dev.bus = &coresight_bustype;
680 dev_set_name(&csdev->dev, "%s", desc->pdata->name);
681
682 ret = device_register(&csdev->dev);
683 if (ret)
684 goto err_device_register;
685
686 mutex_lock(&coresight_mutex);
687
688 coresight_fixup_device_conns(csdev);
689 coresight_fixup_orphan_conns(csdev);
690
691 mutex_unlock(&coresight_mutex);
692
693 return csdev;
694
695err_device_register:
696 kfree(conns);
697err_kzalloc_conns:
698 kfree(refcnts);
699err_kzalloc_refcnts:
700 kfree(csdev);
701err_kzalloc_csdev:
702 return ERR_PTR(ret);
703}
704EXPORT_SYMBOL_GPL(coresight_register);
705
706void coresight_unregister(struct coresight_device *csdev)
707{
708 mutex_lock(&coresight_mutex);
709
710 kfree(csdev->conns);
711 device_unregister(&csdev->dev);
712
713 mutex_unlock(&coresight_mutex);
714}
715EXPORT_SYMBOL_GPL(coresight_unregister);
716
717MODULE_LICENSE("GPL v2");
diff --git a/drivers/coresight/of_coresight.c b/drivers/coresight/of_coresight.c
new file mode 100644
index 000000000000..5030c0734508
--- /dev/null
+++ b/drivers/coresight/of_coresight.c
@@ -0,0 +1,204 @@
1/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/module.h>
14#include <linux/types.h>
15#include <linux/err.h>
16#include <linux/slab.h>
17#include <linux/clk.h>
18#include <linux/of.h>
19#include <linux/of_address.h>
20#include <linux/of_graph.h>
21#include <linux/of_platform.h>
22#include <linux/platform_device.h>
23#include <linux/amba/bus.h>
24#include <linux/coresight.h>
25#include <asm/smp_plat.h>
26
27
28static int of_dev_node_match(struct device *dev, void *data)
29{
30 return dev->of_node == data;
31}
32
33static struct device *
34of_coresight_get_endpoint_device(struct device_node *endpoint)
35{
36 struct device *dev = NULL;
37
38 /*
39 * If we have a non-configuable replicator, it will be found on the
40 * platform bus.
41 */
42 dev = bus_find_device(&platform_bus_type, NULL,
43 endpoint, of_dev_node_match);
44 if (dev)
45 return dev;
46
47 /*
48 * We have a configurable component - circle through the AMBA bus
49 * looking for the device that matches the endpoint node.
50 */
51 return bus_find_device(&amba_bustype, NULL,
52 endpoint, of_dev_node_match);
53}
54
55static struct device_node *of_get_coresight_endpoint(
56 const struct device_node *parent, struct device_node *prev)
57{
58 struct device_node *node = of_graph_get_next_endpoint(parent, prev);
59
60 of_node_put(prev);
61 return node;
62}
63
64static void of_coresight_get_ports(struct device_node *node,
65 int *nr_inport, int *nr_outport)
66{
67 struct device_node *ep = NULL;
68 int in = 0, out = 0;
69
70 do {
71 ep = of_get_coresight_endpoint(node, ep);
72 if (!ep)
73 break;
74
75 if (of_property_read_bool(ep, "slave-mode"))
76 in++;
77 else
78 out++;
79
80 } while (ep);
81
82 *nr_inport = in;
83 *nr_outport = out;
84}
85
86static int of_coresight_alloc_memory(struct device *dev,
87 struct coresight_platform_data *pdata)
88{
89 /* List of output port on this component */
90 pdata->outports = devm_kzalloc(dev, pdata->nr_outport *
91 sizeof(*pdata->outports),
92 GFP_KERNEL);
93 if (!pdata->outports)
94 return -ENOMEM;
95
96 /* Children connected to this component via @outport */
97 pdata->child_names = devm_kzalloc(dev, pdata->nr_outport *
98 sizeof(*pdata->child_names),
99 GFP_KERNEL);
100 if (!pdata->child_names)
101 return -ENOMEM;
102
103 /* Port number on the child this component is connected to */
104 pdata->child_ports = devm_kzalloc(dev, pdata->nr_outport *
105 sizeof(*pdata->child_ports),
106 GFP_KERNEL);
107 if (!pdata->child_ports)
108 return -ENOMEM;
109
110 return 0;
111}
112
113struct coresight_platform_data *of_get_coresight_platform_data(
114 struct device *dev, struct device_node *node)
115{
116 int i = 0, ret = 0;
117 struct coresight_platform_data *pdata;
118 struct of_endpoint endpoint, rendpoint;
119 struct device *rdev;
120 struct device_node *cpu;
121 struct device_node *ep = NULL;
122 struct device_node *rparent = NULL;
123 struct device_node *rport = NULL;
124
125 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
126 if (!pdata)
127 return ERR_PTR(-ENOMEM);
128
129 /* Use device name as debugfs handle */
130 pdata->name = dev_name(dev);
131
132 /* Get the number of input and output port for this component */
133 of_coresight_get_ports(node, &pdata->nr_inport, &pdata->nr_outport);
134
135 if (pdata->nr_outport) {
136 ret = of_coresight_alloc_memory(dev, pdata);
137 if (ret)
138 return ERR_PTR(ret);
139
140 /* Iterate through each port to discover topology */
141 do {
142 /* Get a handle on a port */
143 ep = of_get_coresight_endpoint(node, ep);
144 if (!ep)
145 break;
146
147 /*
148 * No need to deal with input ports, processing for as
149 * processing for output ports will deal with them.
150 */
151 if (of_find_property(ep, "slave-mode", NULL))
152 continue;
153
154 /* Get a handle on the local endpoint */
155 ret = of_graph_parse_endpoint(ep, &endpoint);
156
157 if (ret)
158 continue;
159
160 /* The local out port number */
161 pdata->outports[i] = endpoint.id;
162
163 /*
164 * Get a handle on the remote port and parent
165 * attached to it.
166 */
167 rparent = of_graph_get_remote_port_parent(ep);
168 rport = of_graph_get_remote_port(ep);
169
170 if (!rparent || !rport)
171 continue;
172
173 if (of_graph_parse_endpoint(rport, &rendpoint))
174 continue;
175
176 rdev = of_coresight_get_endpoint_device(rparent);
177 if (!dev)
178 continue;
179
180 pdata->child_names[i] = dev_name(rdev);
181 pdata->child_ports[i] = rendpoint.id;
182
183 i++;
184 } while (ep);
185 }
186
187 /* Affinity defaults to CPU0 */
188 pdata->cpu = 0;
189 cpu = of_parse_phandle(node, "cpu", 0);
190 if (cpu) {
191 const u32 *mpidr;
192 int len, index;
193
194 mpidr = of_get_property(cpu, "reg", &len);
195 if (mpidr && len == 4) {
196 index = get_logical_index(be32_to_cpup(mpidr));
197 if (index != -EINVAL)
198 pdata->cpu = index;
199 }
200 }
201
202 return pdata;
203}
204EXPORT_SYMBOL_GPL(of_get_coresight_platform_data);