blob: a17ac9a430c61db73ef1a5f6a944a0971f30e114 [file] [log] [blame]
Pratik Patel74929432011-12-26 12:03:41 -08001/* Copyright (c) 2012, Code Aurora Forum. 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/platform_device.h>
19#include <linux/io.h>
20#include <linux/err.h>
Pratik Patelbf3e77442012-03-18 18:30:43 -070021#include <linux/export.h>
Pratik Patelb84ef9d2012-05-24 14:01:43 -070022#include <linux/slab.h>
Pratik Patel0a7edd32012-06-08 09:31:55 -070023#include <linux/semaphore.h>
Pratik Patel27086d92012-05-17 23:21:43 -070024#include <linux/clk.h>
Pratik Patel1746b8f2012-06-02 21:11:41 -070025#include <linux/coresight.h>
Pratik Patel74929432011-12-26 12:03:41 -080026
Pratik Patel1746b8f2012-06-02 21:11:41 -070027#include "coresight-priv.h"
Pratik Patel74929432011-12-26 12:03:41 -080028
Pratik Patel0a7edd32012-06-08 09:31:55 -070029
30#define NO_SINK (-1)
Pratik Patel1403f2a2012-03-21 10:10:00 -070031#define MAX_STR_LEN (65535)
32
Pratik Patel74929432011-12-26 12:03:41 -080033
Pratik Patel0a7edd32012-06-08 09:31:55 -070034static int curr_sink = NO_SINK;
Pratik Patel6fb38342012-06-03 14:51:38 -070035static LIST_HEAD(coresight_orph_conns);
Pratik Patel6fb38342012-06-03 14:51:38 -070036static LIST_HEAD(coresight_devs);
Pratik Patel0a7edd32012-06-08 09:31:55 -070037static DEFINE_SEMAPHORE(coresight_mutex);
Pratik Patelb84ef9d2012-05-24 14:01:43 -070038
39
Pratik Patel0a7edd32012-06-08 09:31:55 -070040static int coresight_find_link_inport(struct coresight_device *csdev)
Pratik Patelb84ef9d2012-05-24 14:01:43 -070041{
42 int i;
Pratik Patel0a7edd32012-06-08 09:31:55 -070043 struct coresight_device *parent;
Pratik Patel6fb38342012-06-03 14:51:38 -070044 struct coresight_connection *conn;
Pratik Patelb84ef9d2012-05-24 14:01:43 -070045
Pratik Patel0a7edd32012-06-08 09:31:55 -070046 parent = container_of(csdev->path_link.next, struct coresight_device,
47 path_link);
48 for (i = 0; i < parent->nr_conns; i++) {
49 conn = &parent->conns[i];
50 if (conn->child_dev == csdev)
51 return conn->child_port;
Pratik Patelb84ef9d2012-05-24 14:01:43 -070052 }
Pratik Patel0a7edd32012-06-08 09:31:55 -070053
54 pr_err("coresight: couldn't find inport, parent: %d, child: %d\n",
55 parent->id, csdev->id);
Pratik Patelb84ef9d2012-05-24 14:01:43 -070056 return 0;
Pratik Patel0a7edd32012-06-08 09:31:55 -070057}
58
59static int coresight_find_link_outport(struct coresight_device *csdev)
60{
61 int i;
62 struct coresight_device *child;
63 struct coresight_connection *conn;
64
65 child = container_of(csdev->path_link.prev, struct coresight_device,
66 path_link);
67 for (i = 0; i < csdev->nr_conns; i++) {
68 conn = &csdev->conns[i];
69 if (conn->child_dev == child)
70 return conn->outport;
Pratik Patelb84ef9d2012-05-24 14:01:43 -070071 }
Pratik Patel0a7edd32012-06-08 09:31:55 -070072
73 pr_err("coresight: couldn't find outport, parent: %d, child: %d\n",
74 csdev->id, child->id);
75 return 0;
76}
77
78static int coresight_enable_sink(struct coresight_device *csdev)
79{
80 int ret;
81
82 if (csdev->refcnt.sink_refcnt == 0) {
83 if (csdev->ops->sink_ops->enable) {
84 ret = csdev->ops->sink_ops->enable(csdev);
85 if (ret)
86 goto err;
87 csdev->enable = true;
88 }
89 }
90 csdev->refcnt.sink_refcnt++;
91
92 return 0;
93err:
94 return ret;
95}
96
97static void coresight_disable_sink(struct coresight_device *csdev)
98{
99 if (csdev->refcnt.sink_refcnt == 1) {
100 if (csdev->ops->sink_ops->disable) {
101 csdev->ops->sink_ops->disable(csdev);
102 csdev->enable = false;
103 }
104 }
105 csdev->refcnt.sink_refcnt--;
106}
107
108static int coresight_enable_link(struct coresight_device *csdev)
109{
110 int ret;
111 int link_subtype;
112 int refport, inport, outport;
113
114 inport = coresight_find_link_inport(csdev);
115 outport = coresight_find_link_outport(csdev);
116
117 link_subtype = csdev->subtype.link_subtype;
118 if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
119 refport = inport;
120 else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
121 refport = outport;
122 else
123 refport = 0;
124
125 if (csdev->refcnt.link_refcnts[refport] == 0) {
126 if (csdev->ops->link_ops->enable) {
127 ret = csdev->ops->link_ops->enable(csdev, inport,
128 outport);
129 if (ret)
130 goto err;
131 csdev->enable = true;
132 }
133 }
134 csdev->refcnt.link_refcnts[refport]++;
135
136 return 0;
137err:
138 return ret;
139}
140
141static void coresight_disable_link(struct coresight_device *csdev)
142{
143 int link_subtype;
144 int refport, inport, outport;
145
146 inport = coresight_find_link_inport(csdev);
147 outport = coresight_find_link_outport(csdev);
148
149 link_subtype = csdev->subtype.link_subtype;
150 if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
151 refport = inport;
152 else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
153 refport = outport;
154 else
155 refport = 0;
156
157 if (csdev->refcnt.link_refcnts[refport] == 1) {
158 if (csdev->ops->link_ops->disable) {
159 csdev->ops->link_ops->disable(csdev, inport, outport);
160 csdev->enable = false;
161 }
162 }
163 csdev->refcnt.link_refcnts[refport]--;
164}
165
166static int coresight_enable_source(struct coresight_device *csdev)
167{
168 int ret;
169
170 if (csdev->refcnt.source_refcnt == 0) {
171 if (csdev->ops->source_ops->enable) {
172 ret = csdev->ops->source_ops->enable(csdev);
173 if (ret)
174 goto err;
175 csdev->enable = true;
176 }
177 }
178 csdev->refcnt.source_refcnt++;
179
180 return 0;
181err:
182 return ret;
183}
184
185static void coresight_disable_source(struct coresight_device *csdev)
186{
187 if (csdev->refcnt.source_refcnt == 1) {
188 if (csdev->ops->source_ops->disable) {
189 csdev->ops->source_ops->disable(csdev);
190 csdev->enable = false;
191 }
192 }
193 csdev->refcnt.source_refcnt--;
194}
195
196static struct list_head *coresight_build_path(struct coresight_device *csdev,
197 struct list_head *path)
198{
199 int i;
200 struct list_head *p;
201 struct coresight_connection *conn;
202
203 if (csdev->id == curr_sink) {
204 list_add_tail(&csdev->path_link, path);
205 return path;
206 }
207
208 for (i = 0; i < csdev->nr_conns; i++) {
209 conn = &csdev->conns[i];
210 p = coresight_build_path(conn->child_dev, path);
211 if (p) {
212 list_add_tail(&csdev->path_link, p);
213 return p;
214 }
215 }
216 return NULL;
217}
218
219static void coresight_release_path(struct list_head *path)
220{
221 struct coresight_device *cd, *temp;
222
223 list_for_each_entry_safe(cd, temp, path, path_link)
224 list_del(&cd->path_link);
225}
226
227static int coresight_enable_path(struct list_head *path, bool incl_source)
228{
229 int ret = 0;
230 struct coresight_device *cd;
231
232 list_for_each_entry(cd, path, path_link) {
233 if (cd == list_first_entry(path, struct coresight_device,
234 path_link)) {
235 ret = coresight_enable_sink(cd);
236 } else if (list_is_last(&cd->path_link, path)) {
237 if (incl_source)
238 ret = coresight_enable_source(cd);
239 } else {
240 ret = coresight_enable_link(cd);
241 }
242 if (ret)
243 goto err;
244 }
245 return 0;
246err:
247 list_for_each_entry_continue_reverse(cd, path, path_link) {
248 if (cd == list_first_entry(path, struct coresight_device,
249 path_link)) {
250 coresight_disable_sink(cd);
251 } else if (list_is_last(&cd->path_link, path)) {
252 if (incl_source)
253 coresight_disable_source(cd);
254 } else {
255 coresight_disable_link(cd);
256 }
257 }
258 return ret;
259}
260
261static void coresight_disable_path(struct list_head *path, bool incl_source)
262{
263 struct coresight_device *cd;
264
265 list_for_each_entry(cd, path, path_link) {
266 if (cd == list_first_entry(path, struct coresight_device,
267 path_link)) {
268 coresight_disable_sink(cd);
269 } else if (list_is_last(&cd->path_link, path)) {
270 if (incl_source)
271 coresight_disable_source(cd);
272 } else {
273 coresight_disable_link(cd);
274 }
275 }
276}
277
278static int coresight_switch_sink(struct coresight_device *csdev)
279{
280 int ret = 0;
281 LIST_HEAD(path);
282 struct coresight_device *cd;
283
284 if (IS_ERR_OR_NULL(csdev))
285 return -EINVAL;
286
287 down(&coresight_mutex);
288 if (csdev->id == curr_sink)
289 goto out;
290
291 list_for_each_entry(cd, &coresight_devs, dev_link) {
292 if (cd->type == CORESIGHT_DEV_TYPE_SOURCE && cd->enable) {
293 coresight_build_path(cd, &path);
294 coresight_disable_path(&path, false);
295 coresight_release_path(&path);
296 }
297 }
298 curr_sink = csdev->id;
299 list_for_each_entry(cd, &coresight_devs, dev_link) {
300 if (cd->type == CORESIGHT_DEV_TYPE_SOURCE && cd->enable) {
301 coresight_build_path(cd, &path);
302 ret = coresight_enable_path(&path, false);
303 coresight_release_path(&path);
304 if (ret)
305 goto err;
306 }
307 }
308out:
309 up(&coresight_mutex);
310 return 0;
311err:
312 list_for_each_entry(cd, &coresight_devs, dev_link) {
313 if (cd->type == CORESIGHT_DEV_TYPE_SOURCE && cd->enable)
314 coresight_disable_source(cd);
315 }
316 pr_err("coresight: sink switch failed, sources disabled; try again\n");
317 return ret;
318}
319
320int coresight_enable(struct coresight_device *csdev)
321{
322 int ret = 0;
323 LIST_HEAD(path);
324
325 if (IS_ERR_OR_NULL(csdev))
326 return -EINVAL;
327
328 down(&coresight_mutex);
329 if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE) {
330 ret = -EINVAL;
331 pr_err("coresight: wrong device type in %s\n", __func__);
332 goto out;
333 }
334 if (csdev->enable)
335 goto out;
336
337 coresight_build_path(csdev, &path);
338 ret = coresight_enable_path(&path, true);
339 coresight_release_path(&path);
340 if (ret)
341 pr_err("coresight: enable failed\n");
342out:
343 up(&coresight_mutex);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700344 return ret;
345}
Pratik Patel6fb38342012-06-03 14:51:38 -0700346EXPORT_SYMBOL(coresight_enable);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700347
Pratik Patel0a7edd32012-06-08 09:31:55 -0700348void coresight_disable(struct coresight_device *csdev)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700349{
Pratik Patel0a7edd32012-06-08 09:31:55 -0700350 LIST_HEAD(path);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700351
Pratik Patel0a7edd32012-06-08 09:31:55 -0700352 if (IS_ERR_OR_NULL(csdev))
353 return;
354
355 down(&coresight_mutex);
356 if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE) {
357 pr_err("coresight: wrong device type in %s\n", __func__);
358 goto out;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700359 }
Pratik Patel0a7edd32012-06-08 09:31:55 -0700360 if (!csdev->enable)
361 goto out;
362
363 coresight_build_path(csdev, &path);
364 coresight_disable_path(&path, true);
365 coresight_release_path(&path);
366out:
367 up(&coresight_mutex);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700368}
Pratik Patel6fb38342012-06-03 14:51:38 -0700369EXPORT_SYMBOL(coresight_disable);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700370
Pratik Patel6fb38342012-06-03 14:51:38 -0700371static ssize_t coresight_show_type(struct device *dev,
372 struct device_attribute *attr, char *buf)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700373{
374 return snprintf(buf, PAGE_SIZE, "%s\n", dev->type->name);
375}
376
Pratik Patel6fb38342012-06-03 14:51:38 -0700377static struct device_attribute coresight_dev_attrs[] = {
378 __ATTR(type, S_IRUGO, coresight_show_type, NULL),
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700379 { },
380};
381
Pratik Patel6fb38342012-06-03 14:51:38 -0700382struct bus_type coresight_bus_type = {
383 .name = "coresight",
384 .dev_attrs = coresight_dev_attrs,
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700385};
386
Pratik Patel0a7edd32012-06-08 09:31:55 -0700387static ssize_t coresight_show_curr_sink(struct device *dev,
388 struct device_attribute *attr,
389 char *buf)
390{
391 struct coresight_device *csdev = to_coresight_device(dev);
392
393 return scnprintf(buf, PAGE_SIZE, "%u\n",
394 csdev->id == curr_sink ? 1 : 0);
395}
396
397static ssize_t coresight_store_curr_sink(struct device *dev,
398 struct device_attribute *attr,
399 const char *buf, size_t size)
400{
401 int ret = 0;
402 unsigned long val;
403 struct coresight_device *csdev = to_coresight_device(dev);
404
405 if (sscanf(buf, "%lx", &val) != 1)
406 return -EINVAL;
407
408 if (val)
409 ret = coresight_switch_sink(csdev);
410 else
411 ret = -EINVAL;
412
413 if (ret)
414 return ret;
415 return size;
416}
417static DEVICE_ATTR(curr_sink, S_IRUGO | S_IWUSR, coresight_show_curr_sink,
418 coresight_store_curr_sink);
419
Pratik Patel6fb38342012-06-03 14:51:38 -0700420static ssize_t coresight_show_enable(struct device *dev,
421 struct device_attribute *attr, char *buf)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700422{
Pratik Patel6fb38342012-06-03 14:51:38 -0700423 struct coresight_device *csdev = to_coresight_device(dev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700424
425 return scnprintf(buf, PAGE_SIZE, "%u\n", (unsigned)csdev->enable);
426}
427
Pratik Patel6fb38342012-06-03 14:51:38 -0700428static ssize_t coresight_store_enable(struct device *dev,
429 struct device_attribute *attr,
430 const char *buf, size_t size)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700431{
432 int ret = 0;
433 unsigned long val;
Pratik Patel6fb38342012-06-03 14:51:38 -0700434 struct coresight_device *csdev = to_coresight_device(dev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700435
436 if (sscanf(buf, "%lx", &val) != 1)
437 return -EINVAL;
438
439 if (val)
Pratik Patel0a7edd32012-06-08 09:31:55 -0700440 ret = coresight_enable(csdev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700441 else
Pratik Patel0a7edd32012-06-08 09:31:55 -0700442 coresight_disable(csdev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700443
444 if (ret)
445 return ret;
446 return size;
447}
Pratik Patel6fb38342012-06-03 14:51:38 -0700448static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, coresight_show_enable,
449 coresight_store_enable);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700450
Pratik Patel0a7edd32012-06-08 09:31:55 -0700451static struct attribute *coresight_attrs_sink[] = {
452 &dev_attr_curr_sink.attr,
453 NULL,
454};
455
456static struct attribute_group coresight_attr_grp_sink = {
457 .attrs = coresight_attrs_sink,
458};
459
460static const struct attribute_group *coresight_attr_grps_sink[] = {
461 &coresight_attr_grp_sink,
462 NULL,
463};
464
465static struct attribute *coresight_attrs_source[] = {
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700466 &dev_attr_enable.attr,
467 NULL,
468};
469
Pratik Patel0a7edd32012-06-08 09:31:55 -0700470static struct attribute_group coresight_attr_grp_source = {
471 .attrs = coresight_attrs_source,
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700472};
473
Pratik Patel0a7edd32012-06-08 09:31:55 -0700474static const struct attribute_group *coresight_attr_grps_source[] = {
475 &coresight_attr_grp_source,
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700476 NULL,
477};
478
Pratik Patel0a7edd32012-06-08 09:31:55 -0700479static struct device_type coresight_dev_type[] = {
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700480 {
Pratik Patel0a7edd32012-06-08 09:31:55 -0700481 .name = "sink",
482 .groups = coresight_attr_grps_sink,
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700483 },
484 {
485 .name = "link",
486 },
487 {
Pratik Patel0a7edd32012-06-08 09:31:55 -0700488 .name = "linksink",
489 .groups = coresight_attr_grps_sink,
490 },
491 {
492 .name = "source",
493 .groups = coresight_attr_grps_source,
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700494 },
495};
496
Pratik Patel6fb38342012-06-03 14:51:38 -0700497static void coresight_device_release(struct device *dev)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700498{
Pratik Patel6fb38342012-06-03 14:51:38 -0700499 struct coresight_device *csdev = to_coresight_device(dev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700500 kfree(csdev);
501}
502
Pratik Patel6fb38342012-06-03 14:51:38 -0700503static void coresight_fixup_orphan_conns(struct coresight_device *csdev)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700504{
Pratik Patel6fb38342012-06-03 14:51:38 -0700505 struct coresight_connection *conn, *temp;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700506
Pratik Patel6fb38342012-06-03 14:51:38 -0700507 list_for_each_entry_safe(conn, temp, &coresight_orph_conns, link) {
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700508 if (conn->child_id == csdev->id) {
509 conn->child_dev = csdev;
510 list_del(&conn->link);
511 }
512 }
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700513}
514
Pratik Patel6fb38342012-06-03 14:51:38 -0700515static void coresight_fixup_device_conns(struct coresight_device *csdev)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700516{
517 int i;
Pratik Patel6fb38342012-06-03 14:51:38 -0700518 struct coresight_device *cd;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700519 bool found;
520
521 for (i = 0; i < csdev->nr_conns; i++) {
522 found = false;
Pratik Patel0a7edd32012-06-08 09:31:55 -0700523 list_for_each_entry(cd, &coresight_devs, dev_link) {
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700524 if (csdev->conns[i].child_id == cd->id) {
525 csdev->conns[i].child_dev = cd;
526 found = true;
527 break;
528 }
529 }
Pratik Patel0a7edd32012-06-08 09:31:55 -0700530 if (!found)
Pratik Patel6fb38342012-06-03 14:51:38 -0700531 list_add_tail(&csdev->conns[i].link,
532 &coresight_orph_conns);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700533 }
534}
535
Pratik Patel6fb38342012-06-03 14:51:38 -0700536struct coresight_device *coresight_register(struct coresight_desc *desc)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700537{
538 int i;
539 int ret;
Pratik Patel0a7edd32012-06-08 09:31:55 -0700540 int link_subtype;
541 int nr_refcnts;
542 int *refcnts = NULL;
Pratik Patel6fb38342012-06-03 14:51:38 -0700543 struct coresight_device *csdev;
544 struct coresight_connection *conns;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700545
546 csdev = kzalloc(sizeof(*csdev), GFP_KERNEL);
547 if (!csdev) {
548 ret = -ENOMEM;
549 goto err_kzalloc_csdev;
550 }
551
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700552 csdev->id = desc->pdata->id;
553
Pratik Patel0a7edd32012-06-08 09:31:55 -0700554 if (desc->type == CORESIGHT_DEV_TYPE_LINK ||
555 desc->type == CORESIGHT_DEV_TYPE_LINKSINK) {
556 link_subtype = desc->subtype.link_subtype;
557 if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
558 nr_refcnts = desc->pdata->nr_inports;
559 else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
560 nr_refcnts = desc->pdata->nr_outports;
561 else
562 nr_refcnts = 1;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700563
Pratik Patel0a7edd32012-06-08 09:31:55 -0700564 refcnts = kzalloc(sizeof(*refcnts) * nr_refcnts, GFP_KERNEL);
565 if (!refcnts) {
566 ret = -ENOMEM;
567 goto err_kzalloc_refcnts;
568 }
569 csdev->refcnt.link_refcnts = refcnts;
570 }
571
572 csdev->nr_conns = desc->pdata->nr_outports;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700573 conns = kzalloc(sizeof(*conns) * csdev->nr_conns, GFP_KERNEL);
574 if (!conns) {
575 ret = -ENOMEM;
576 goto err_kzalloc_conns;
577 }
578 for (i = 0; i < csdev->nr_conns; i++) {
Pratik Patel0a7edd32012-06-08 09:31:55 -0700579 conns[i].outport = desc->pdata->outports[i];
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700580 conns[i].child_id = desc->pdata->child_ids[i];
581 conns[i].child_port = desc->pdata->child_ports[i];
582 }
583 csdev->conns = conns;
584
Pratik Patel0a7edd32012-06-08 09:31:55 -0700585 csdev->type = desc->type;
586 csdev->subtype = desc->subtype;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700587 csdev->ops = desc->ops;
588 csdev->owner = desc->owner;
589
Pratik Patel6fb38342012-06-03 14:51:38 -0700590 csdev->dev.type = &coresight_dev_type[desc->type];
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700591 csdev->dev.groups = desc->groups;
592 csdev->dev.parent = desc->dev;
Pratik Patel6fb38342012-06-03 14:51:38 -0700593 csdev->dev.bus = &coresight_bus_type;
594 csdev->dev.release = coresight_device_release;
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700595 dev_set_name(&csdev->dev, "%s", desc->pdata->name);
596
Pratik Patel0a7edd32012-06-08 09:31:55 -0700597 down(&coresight_mutex);
598 if (desc->pdata->default_sink) {
599 if (curr_sink == NO_SINK) {
600 curr_sink = csdev->id;
601 } else {
602 ret = -EINVAL;
603 goto err_default_sink;
604 }
605 }
606
Pratik Patel6fb38342012-06-03 14:51:38 -0700607 coresight_fixup_device_conns(csdev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700608 ret = device_register(&csdev->dev);
609 if (ret)
610 goto err_dev_reg;
Pratik Patel6fb38342012-06-03 14:51:38 -0700611 coresight_fixup_orphan_conns(csdev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700612
Pratik Patel0a7edd32012-06-08 09:31:55 -0700613 list_add_tail(&csdev->dev_link, &coresight_devs);
614 up(&coresight_mutex);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700615
616 return csdev;
617err_dev_reg:
618 put_device(&csdev->dev);
Pratik Patel0a7edd32012-06-08 09:31:55 -0700619err_default_sink:
620 up(&coresight_mutex);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700621 kfree(conns);
622err_kzalloc_conns:
Pratik Patel0a7edd32012-06-08 09:31:55 -0700623 kfree(refcnts);
624err_kzalloc_refcnts:
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700625 kfree(csdev);
626err_kzalloc_csdev:
627 return ERR_PTR(ret);
628}
Pratik Patel6fb38342012-06-03 14:51:38 -0700629EXPORT_SYMBOL(coresight_register);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700630
Pratik Patel6fb38342012-06-03 14:51:38 -0700631void coresight_unregister(struct coresight_device *csdev)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700632{
633 if (IS_ERR_OR_NULL(csdev))
634 return;
635
636 if (get_device(&csdev->dev)) {
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700637 device_unregister(&csdev->dev);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700638 put_device(&csdev->dev);
639 }
640}
Pratik Patel6fb38342012-06-03 14:51:38 -0700641EXPORT_SYMBOL(coresight_unregister);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700642
Pratik Patel6fb38342012-06-03 14:51:38 -0700643static int __init coresight_init(void)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700644{
Pratik Patel6fb38342012-06-03 14:51:38 -0700645 return bus_register(&coresight_bus_type);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700646}
Pratik Patel6fb38342012-06-03 14:51:38 -0700647subsys_initcall(coresight_init);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700648
Pratik Patel6fb38342012-06-03 14:51:38 -0700649static void __exit coresight_exit(void)
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700650{
Pratik Patel6fb38342012-06-03 14:51:38 -0700651 bus_unregister(&coresight_bus_type);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700652}
Pratik Patel6fb38342012-06-03 14:51:38 -0700653module_exit(coresight_exit);
Pratik Patelb84ef9d2012-05-24 14:01:43 -0700654
655MODULE_LICENSE("GPL v2");
Pratik Patel1403f2a2012-03-21 10:10:00 -0700656/*
657 * Exclusion rules for structure fields.
658 *
659 * S: qdss.sources_mutex protected.
660 * I: qdss.sink_mutex protected.
661 * C: qdss.clk_mutex protected.
662 */
Pratik Patel6630ebe2012-03-06 16:44:22 -0800663struct qdss_ctx {
Pratik Patel1403f2a2012-03-21 10:10:00 -0700664 struct kobject *modulekobj;
Pratik Patel132d62b2012-05-14 17:37:23 -0700665 uint8_t afamily;
Pratik Patel1403f2a2012-03-21 10:10:00 -0700666 struct list_head sources; /* S: sources list */
667 struct mutex sources_mutex;
668 uint8_t sink_count; /* I: sink count */
669 struct mutex sink_mutex;
670 uint8_t max_clk;
Pratik Patel27086d92012-05-17 23:21:43 -0700671 struct clk *clk;
Pratik Patel6630ebe2012-03-06 16:44:22 -0800672};
673
674static struct qdss_ctx qdss;
675
Pratik Patel1403f2a2012-03-21 10:10:00 -0700676/**
677 * qdss_get - get the qdss source handle
678 * @name: name of the qdss source
679 *
680 * Searches the sources list to get the qdss source handle for this source.
681 *
682 * CONTEXT:
683 * Typically called from init or probe functions
684 *
685 * RETURNS:
686 * pointer to struct qdss_source on success, %NULL on failure
687 */
688struct qdss_source *qdss_get(const char *name)
Pratik Patel6630ebe2012-03-06 16:44:22 -0800689{
Pratik Patel1403f2a2012-03-21 10:10:00 -0700690 struct qdss_source *src, *source = NULL;
691
692 mutex_lock(&qdss.sources_mutex);
693 list_for_each_entry(src, &qdss.sources, link) {
694 if (src->name) {
695 if (strncmp(src->name, name, MAX_STR_LEN))
696 continue;
697 source = src;
698 break;
699 }
700 }
701 mutex_unlock(&qdss.sources_mutex);
702
703 return source ? source : ERR_PTR(-ENOENT);
Pratik Patel6630ebe2012-03-06 16:44:22 -0800704}
Pratik Patel1403f2a2012-03-21 10:10:00 -0700705EXPORT_SYMBOL(qdss_get);
706
707/**
708 * qdss_put - release the qdss source handle
709 * @name: name of the qdss source
710 *
711 * CONTEXT:
712 * Typically called from driver remove or exit functions
713 */
714void qdss_put(struct qdss_source *src)
715{
716}
717EXPORT_SYMBOL(qdss_put);
718
719/**
720 * qdss_enable - enable qdss for the source
721 * @src: handle for the source making the call
722 *
723 * Enables qdss block (relevant funnel ports and sink) if not already
724 * enabled, otherwise increments the reference count
725 *
726 * CONTEXT:
727 * Might sleep. Uses a mutex lock. Should be called from a non-atomic context.
728 *
729 * RETURNS:
730 * 0 on success, non-zero on failure
731 */
732int qdss_enable(struct qdss_source *src)
733{
Pratik Patel1403f2a2012-03-21 10:10:00 -0700734 if (!src)
735 return -EINVAL;
736
Pratik Patel132d62b2012-05-14 17:37:23 -0700737 if (qdss.afamily) {
Pratik Patel1403f2a2012-03-21 10:10:00 -0700738 mutex_lock(&qdss.sink_mutex);
739 if (qdss.sink_count == 0) {
Pratik Patel1403f2a2012-03-21 10:10:00 -0700740 tpiu_disable();
741 /* enable ETB first to avoid losing any trace data */
742 etb_enable();
743 }
744 qdss.sink_count++;
745 mutex_unlock(&qdss.sink_mutex);
746 }
747
748 funnel_enable(0x0, src->fport_mask);
749 return 0;
Pratik Patel1403f2a2012-03-21 10:10:00 -0700750}
751EXPORT_SYMBOL(qdss_enable);
752
753/**
754 * qdss_disable - disable qdss for the source
755 * @src: handle for the source making the call
756 *
757 * Disables qdss block (relevant funnel ports and sink) if the reference count
758 * is one, otherwise decrements the reference count
759 *
760 * CONTEXT:
761 * Might sleep. Uses a mutex lock. Should be called from a non-atomic context.
762 */
763void qdss_disable(struct qdss_source *src)
764{
765 if (!src)
766 return;
767
Pratik Patel132d62b2012-05-14 17:37:23 -0700768 if (qdss.afamily) {
Pratik Patel1403f2a2012-03-21 10:10:00 -0700769 mutex_lock(&qdss.sink_mutex);
770 if (WARN(qdss.sink_count == 0, "qdss is unbalanced\n"))
771 goto out;
772 if (qdss.sink_count == 1) {
773 etb_dump();
774 etb_disable();
775 }
776 qdss.sink_count--;
777 mutex_unlock(&qdss.sink_mutex);
778 }
779
780 funnel_disable(0x0, src->fport_mask);
Pratik Patel1403f2a2012-03-21 10:10:00 -0700781 return;
782out:
783 mutex_unlock(&qdss.sink_mutex);
784}
785EXPORT_SYMBOL(qdss_disable);
Pratik Patel74929432011-12-26 12:03:41 -0800786
Pratik Patelbf3e77442012-03-18 18:30:43 -0700787/**
Pratik Patelf3adf032012-05-03 12:50:21 -0700788 * qdss_disable_sink - force disable the current qdss sink(s)
789 *
790 * Force disable the current qdss sink(s) to stop the sink from accepting any
791 * trace generated subsequent to this call. This function should only be used
792 * as a way to stop the sink from getting polluted with trace data that is
793 * uninteresting after an event of interest has occured.
794 *
795 * CONTEXT:
796 * Can be called from atomic or non-atomic context.
797 */
798void qdss_disable_sink(void)
799{
Pratik Patel132d62b2012-05-14 17:37:23 -0700800 if (qdss.afamily) {
Pratik Patelf3adf032012-05-03 12:50:21 -0700801 etb_dump();
802 etb_disable();
803 }
804}
805EXPORT_SYMBOL(qdss_disable_sink);
806
Pratik Patel1403f2a2012-03-21 10:10:00 -0700807struct kobject *qdss_get_modulekobj(void)
808{
809 return qdss.modulekobj;
810}
811
Pratik Patel6630ebe2012-03-06 16:44:22 -0800812#define QDSS_ATTR(name) \
813static struct kobj_attribute name##_attr = \
814 __ATTR(name, S_IRUGO | S_IWUSR, name##_show, name##_store)
815
816static ssize_t max_clk_store(struct kobject *kobj,
817 struct kobj_attribute *attr,
818 const char *buf, size_t n)
819{
820 unsigned long val;
821
822 if (sscanf(buf, "%lx", &val) != 1)
823 return -EINVAL;
824
825 qdss.max_clk = val;
826 return n;
827}
828static ssize_t max_clk_show(struct kobject *kobj,
829 struct kobj_attribute *attr,
830 char *buf)
831{
832 unsigned long val = qdss.max_clk;
833 return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
834}
835QDSS_ATTR(max_clk);
836
Stephen Boyda9510502012-04-24 16:23:34 -0700837static void __devinit qdss_add_sources(struct qdss_source *srcs, size_t num)
Pratik Patel1403f2a2012-03-21 10:10:00 -0700838{
839 mutex_lock(&qdss.sources_mutex);
840 while (num--) {
841 list_add_tail(&srcs->link, &qdss.sources);
842 srcs++;
843 }
844 mutex_unlock(&qdss.sources_mutex);
845}
846
Pratik Patel6630ebe2012-03-06 16:44:22 -0800847static int __init qdss_sysfs_init(void)
848{
849 int ret;
850
851 qdss.modulekobj = kset_find_obj(module_kset, KBUILD_MODNAME);
852 if (!qdss.modulekobj) {
853 pr_err("failed to find QDSS sysfs module kobject\n");
854 ret = -ENOENT;
855 goto err;
856 }
857
858 ret = sysfs_create_file(qdss.modulekobj, &max_clk_attr.attr);
859 if (ret) {
860 pr_err("failed to create QDSS sysfs max_clk attribute\n");
861 goto err;
862 }
863
864 return 0;
865err:
866 return ret;
867}
868
Stephen Boyda9510502012-04-24 16:23:34 -0700869static void __devexit qdss_sysfs_exit(void)
Pratik Patel6630ebe2012-03-06 16:44:22 -0800870{
871 sysfs_remove_file(qdss.modulekobj, &max_clk_attr.attr);
872}
873
Pratik Patel1403f2a2012-03-21 10:10:00 -0700874static int __devinit qdss_probe(struct platform_device *pdev)
Pratik Patel59e29942011-12-27 10:31:33 -0800875{
Pratik Patel27086d92012-05-17 23:21:43 -0700876 int ret = 0;
Pratik Patel132d62b2012-05-14 17:37:23 -0700877 struct msm_qdss_platform_data *pdata;
Pratik Patel59e29942011-12-27 10:31:33 -0800878
Pratik Patel1403f2a2012-03-21 10:10:00 -0700879 mutex_init(&qdss.sources_mutex);
Pratik Patel1403f2a2012-03-21 10:10:00 -0700880 mutex_init(&qdss.sink_mutex);
881
Pratik Patel1403f2a2012-03-21 10:10:00 -0700882 INIT_LIST_HEAD(&qdss.sources);
Pratik Patel132d62b2012-05-14 17:37:23 -0700883
884 pdata = pdev->dev.platform_data;
885 if (!pdata)
886 goto err_pdata;
887
888 qdss.afamily = pdata->afamily;
889 qdss_add_sources(pdata->src_table, pdata->size);
Pratik Patel1403f2a2012-03-21 10:10:00 -0700890
891 pr_info("QDSS arch initialized\n");
892 return 0;
893err_pdata:
894 mutex_destroy(&qdss.sink_mutex);
Pratik Patel1403f2a2012-03-21 10:10:00 -0700895 mutex_destroy(&qdss.sources_mutex);
896 pr_err("QDSS init failed\n");
897 return ret;
898}
899
900static int __devexit qdss_remove(struct platform_device *pdev)
901{
902 qdss_sysfs_exit();
903 mutex_destroy(&qdss.sink_mutex);
Pratik Patel1403f2a2012-03-21 10:10:00 -0700904 mutex_destroy(&qdss.sources_mutex);
905
906 return 0;
907}
908
Pratik Patel9eae4822012-05-14 17:34:53 -0700909static struct of_device_id qdss_match[] = {
910 {.compatible = "qcom,msm-qdss"},
911 {}
912};
913
Pratik Patel1403f2a2012-03-21 10:10:00 -0700914static struct platform_driver qdss_driver = {
915 .probe = qdss_probe,
916 .remove = __devexit_p(qdss_remove),
917 .driver = {
918 .name = "msm_qdss",
Pratik Patel9eae4822012-05-14 17:34:53 -0700919 .owner = THIS_MODULE,
920 .of_match_table = qdss_match,
Pratik Patel1403f2a2012-03-21 10:10:00 -0700921 },
922};
923
924static int __init qdss_init(void)
925{
926 return platform_driver_register(&qdss_driver);
927}
928arch_initcall(qdss_init);
929
930static int __init qdss_module_init(void)
931{
932 int ret;
Pratik Patelbf3e77442012-03-18 18:30:43 -0700933
Pratik Patel6630ebe2012-03-06 16:44:22 -0800934 ret = qdss_sysfs_init();
935 if (ret)
936 goto err_sysfs;
Pratik Patel59e29942011-12-27 10:31:33 -0800937
Pratik Patel1403f2a2012-03-21 10:10:00 -0700938 pr_info("QDSS module initialized\n");
Pratik Patel59e29942011-12-27 10:31:33 -0800939 return 0;
Pratik Patel6630ebe2012-03-06 16:44:22 -0800940err_sysfs:
Pratik Patel59e29942011-12-27 10:31:33 -0800941 return ret;
942}
Pratik Patel1403f2a2012-03-21 10:10:00 -0700943module_init(qdss_module_init);
Pratik Patel59e29942011-12-27 10:31:33 -0800944
945static void __exit qdss_exit(void)
946{
Pratik Patel1403f2a2012-03-21 10:10:00 -0700947 platform_driver_unregister(&qdss_driver);
Pratik Patel59e29942011-12-27 10:31:33 -0800948}
949module_exit(qdss_exit);
950
951MODULE_LICENSE("GPL v2");
952MODULE_DESCRIPTION("Qualcomm Debug SubSystem Driver");