blob: cfe65ad6b3a87179ab9398a47854176ed155701c [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 Patel74929432011-12-26 12:03:41 -080022#include <mach/rpm.h>
23
24#include "rpm_resources.h"
Pratik Patelb27a9352012-03-17 22:37:21 -070025#include "qdss-priv.h"
Pratik Patel74929432011-12-26 12:03:41 -080026
Pratik Patel1403f2a2012-03-21 10:10:00 -070027#define MAX_STR_LEN (65535)
28
Pratik Patel74929432011-12-26 12:03:41 -080029enum {
30 QDSS_CLK_OFF,
31 QDSS_CLK_ON_DBG,
32 QDSS_CLK_ON_HSDBG,
33};
34
Pratik Patel1403f2a2012-03-21 10:10:00 -070035/*
36 * Exclusion rules for structure fields.
37 *
38 * S: qdss.sources_mutex protected.
39 * I: qdss.sink_mutex protected.
40 * C: qdss.clk_mutex protected.
41 */
Pratik Patel6630ebe2012-03-06 16:44:22 -080042struct qdss_ctx {
Pratik Patel1403f2a2012-03-21 10:10:00 -070043 struct kobject *modulekobj;
44 struct msm_qdss_platform_data *pdata;
45 struct list_head sources; /* S: sources list */
46 struct mutex sources_mutex;
47 uint8_t sink_count; /* I: sink count */
48 struct mutex sink_mutex;
49 uint8_t max_clk;
50 uint8_t clk_count; /* C: clk count */
51 struct mutex clk_mutex;
Pratik Patel6630ebe2012-03-06 16:44:22 -080052};
53
54static struct qdss_ctx qdss;
55
Pratik Patel1403f2a2012-03-21 10:10:00 -070056/**
57 * qdss_get - get the qdss source handle
58 * @name: name of the qdss source
59 *
60 * Searches the sources list to get the qdss source handle for this source.
61 *
62 * CONTEXT:
63 * Typically called from init or probe functions
64 *
65 * RETURNS:
66 * pointer to struct qdss_source on success, %NULL on failure
67 */
68struct qdss_source *qdss_get(const char *name)
Pratik Patel6630ebe2012-03-06 16:44:22 -080069{
Pratik Patel1403f2a2012-03-21 10:10:00 -070070 struct qdss_source *src, *source = NULL;
71
72 mutex_lock(&qdss.sources_mutex);
73 list_for_each_entry(src, &qdss.sources, link) {
74 if (src->name) {
75 if (strncmp(src->name, name, MAX_STR_LEN))
76 continue;
77 source = src;
78 break;
79 }
80 }
81 mutex_unlock(&qdss.sources_mutex);
82
83 return source ? source : ERR_PTR(-ENOENT);
Pratik Patel6630ebe2012-03-06 16:44:22 -080084}
Pratik Patel1403f2a2012-03-21 10:10:00 -070085EXPORT_SYMBOL(qdss_get);
86
87/**
88 * qdss_put - release the qdss source handle
89 * @name: name of the qdss source
90 *
91 * CONTEXT:
92 * Typically called from driver remove or exit functions
93 */
94void qdss_put(struct qdss_source *src)
95{
96}
97EXPORT_SYMBOL(qdss_put);
98
99/**
100 * qdss_enable - enable qdss for the source
101 * @src: handle for the source making the call
102 *
103 * Enables qdss block (relevant funnel ports and sink) if not already
104 * enabled, otherwise increments the reference count
105 *
106 * CONTEXT:
107 * Might sleep. Uses a mutex lock. Should be called from a non-atomic context.
108 *
109 * RETURNS:
110 * 0 on success, non-zero on failure
111 */
112int qdss_enable(struct qdss_source *src)
113{
114 int ret;
115
116 if (!src)
117 return -EINVAL;
118
119 ret = qdss_clk_enable();
120 if (ret)
121 goto err;
122
123 if ((qdss.pdata)->afamily) {
124 mutex_lock(&qdss.sink_mutex);
125 if (qdss.sink_count == 0) {
126 etb_disable();
127 tpiu_disable();
128 /* enable ETB first to avoid losing any trace data */
129 etb_enable();
130 }
131 qdss.sink_count++;
132 mutex_unlock(&qdss.sink_mutex);
133 }
134
135 funnel_enable(0x0, src->fport_mask);
136 return 0;
137err:
138 return ret;
139}
140EXPORT_SYMBOL(qdss_enable);
141
142/**
143 * qdss_disable - disable qdss for the source
144 * @src: handle for the source making the call
145 *
146 * Disables qdss block (relevant funnel ports and sink) if the reference count
147 * is one, otherwise decrements the reference count
148 *
149 * CONTEXT:
150 * Might sleep. Uses a mutex lock. Should be called from a non-atomic context.
151 */
152void qdss_disable(struct qdss_source *src)
153{
154 if (!src)
155 return;
156
157 if ((qdss.pdata)->afamily) {
158 mutex_lock(&qdss.sink_mutex);
159 if (WARN(qdss.sink_count == 0, "qdss is unbalanced\n"))
160 goto out;
161 if (qdss.sink_count == 1) {
162 etb_dump();
163 etb_disable();
164 }
165 qdss.sink_count--;
166 mutex_unlock(&qdss.sink_mutex);
167 }
168
169 funnel_disable(0x0, src->fport_mask);
170 qdss_clk_disable();
171 return;
172out:
173 mutex_unlock(&qdss.sink_mutex);
174}
175EXPORT_SYMBOL(qdss_disable);
Pratik Patel74929432011-12-26 12:03:41 -0800176
Pratik Patelbf3e77442012-03-18 18:30:43 -0700177/**
178 * qdss_clk_enable - enable qdss clocks
179 *
180 * Enables qdss clocks via RPM if they aren't already enabled, otherwise
181 * increments the reference count.
182 *
183 * CONTEXT:
184 * Might sleep. Uses a mutex lock. Should be called from a non-atomic context.
185 *
186 * RETURNS:
187 * 0 on success, non-zero on failure
188 */
Pratik Patel74929432011-12-26 12:03:41 -0800189int qdss_clk_enable(void)
190{
191 int ret;
Pratik Patel74929432011-12-26 12:03:41 -0800192 struct msm_rpm_iv_pair iv;
Pratik Patel74929432011-12-26 12:03:41 -0800193
Pratik Patelbf3e77442012-03-18 18:30:43 -0700194 mutex_lock(&qdss.clk_mutex);
195 if (qdss.clk_count == 0) {
196 iv.id = MSM_RPM_ID_QDSS_CLK;
197 if (qdss.max_clk)
198 iv.value = QDSS_CLK_ON_HSDBG;
199 else
200 iv.value = QDSS_CLK_ON_DBG;
201 ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, &iv, 1);
202 if (WARN(ret, "qdss clks not enabled (%d)\n", ret))
203 goto err_clk;
204 }
205 qdss.clk_count++;
206 mutex_unlock(&qdss.clk_mutex);
Pratik Patel74929432011-12-26 12:03:41 -0800207 return 0;
Pratik Patel74929432011-12-26 12:03:41 -0800208err_clk:
Pratik Patelbf3e77442012-03-18 18:30:43 -0700209 mutex_unlock(&qdss.clk_mutex);
Pratik Patel74929432011-12-26 12:03:41 -0800210 return ret;
211}
Pratik Patelbf3e77442012-03-18 18:30:43 -0700212EXPORT_SYMBOL(qdss_clk_enable);
Pratik Patel74929432011-12-26 12:03:41 -0800213
Pratik Patelbf3e77442012-03-18 18:30:43 -0700214/**
215 * qdss_clk_disable - disable qdss clocks
216 *
217 * Disables qdss clocks via RPM if the reference count is one, otherwise
218 * decrements the reference count.
219 *
220 * CONTEXT:
221 * Might sleep. Uses a mutex lock. Should be called from a non-atomic context.
222 */
Pratik Patel74929432011-12-26 12:03:41 -0800223void qdss_clk_disable(void)
224{
225 int ret;
226 struct msm_rpm_iv_pair iv;
227
Pratik Patelbf3e77442012-03-18 18:30:43 -0700228 mutex_lock(&qdss.clk_mutex);
229 if (WARN(qdss.clk_count == 0, "qdss clks are unbalanced\n"))
230 goto out;
231 if (qdss.clk_count == 1) {
232 iv.id = MSM_RPM_ID_QDSS_CLK;
233 iv.value = QDSS_CLK_OFF;
234 ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, &iv, 1);
235 WARN(ret, "qdss clks not disabled (%d)\n", ret);
236 }
237 qdss.clk_count--;
238out:
239 mutex_unlock(&qdss.clk_mutex);
Pratik Patel74929432011-12-26 12:03:41 -0800240}
Pratik Patelbf3e77442012-03-18 18:30:43 -0700241EXPORT_SYMBOL(qdss_clk_disable);
Pratik Patel59e29942011-12-27 10:31:33 -0800242
Pratik Patel1403f2a2012-03-21 10:10:00 -0700243struct kobject *qdss_get_modulekobj(void)
244{
245 return qdss.modulekobj;
246}
247
Pratik Patel6630ebe2012-03-06 16:44:22 -0800248#define QDSS_ATTR(name) \
249static struct kobj_attribute name##_attr = \
250 __ATTR(name, S_IRUGO | S_IWUSR, name##_show, name##_store)
251
252static ssize_t max_clk_store(struct kobject *kobj,
253 struct kobj_attribute *attr,
254 const char *buf, size_t n)
255{
256 unsigned long val;
257
258 if (sscanf(buf, "%lx", &val) != 1)
259 return -EINVAL;
260
261 qdss.max_clk = val;
262 return n;
263}
264static ssize_t max_clk_show(struct kobject *kobj,
265 struct kobj_attribute *attr,
266 char *buf)
267{
268 unsigned long val = qdss.max_clk;
269 return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
270}
271QDSS_ATTR(max_clk);
272
Pratik Patel1403f2a2012-03-21 10:10:00 -0700273static void __init qdss_add_sources(struct qdss_source *srcs, size_t num)
274{
275 mutex_lock(&qdss.sources_mutex);
276 while (num--) {
277 list_add_tail(&srcs->link, &qdss.sources);
278 srcs++;
279 }
280 mutex_unlock(&qdss.sources_mutex);
281}
282
Pratik Patel6630ebe2012-03-06 16:44:22 -0800283static int __init qdss_sysfs_init(void)
284{
285 int ret;
286
287 qdss.modulekobj = kset_find_obj(module_kset, KBUILD_MODNAME);
288 if (!qdss.modulekobj) {
289 pr_err("failed to find QDSS sysfs module kobject\n");
290 ret = -ENOENT;
291 goto err;
292 }
293
294 ret = sysfs_create_file(qdss.modulekobj, &max_clk_attr.attr);
295 if (ret) {
296 pr_err("failed to create QDSS sysfs max_clk attribute\n");
297 goto err;
298 }
299
300 return 0;
301err:
302 return ret;
303}
304
Pratik Patelf6fe9182012-03-20 14:04:18 -0700305static void __exit qdss_sysfs_exit(void)
Pratik Patel6630ebe2012-03-06 16:44:22 -0800306{
307 sysfs_remove_file(qdss.modulekobj, &max_clk_attr.attr);
308}
309
Pratik Patel1403f2a2012-03-21 10:10:00 -0700310static int __devinit qdss_probe(struct platform_device *pdev)
Pratik Patel59e29942011-12-27 10:31:33 -0800311{
312 int ret;
Pratik Patel1403f2a2012-03-21 10:10:00 -0700313 struct qdss_source *src_table;
314 size_t num_srcs;
Pratik Patel59e29942011-12-27 10:31:33 -0800315
Pratik Patel1403f2a2012-03-21 10:10:00 -0700316 mutex_init(&qdss.sources_mutex);
Pratik Patelbf3e77442012-03-18 18:30:43 -0700317 mutex_init(&qdss.clk_mutex);
Pratik Patel1403f2a2012-03-21 10:10:00 -0700318 mutex_init(&qdss.sink_mutex);
319
320 if (pdev->dev.platform_data == NULL) {
321 pr_err("%s: platform data is NULL\n", __func__);
322 ret = -ENODEV;
323 goto err_pdata;
324 }
325 qdss.pdata = pdev->dev.platform_data;
326
327 INIT_LIST_HEAD(&qdss.sources);
328 src_table = (qdss.pdata)->src_table;
329 num_srcs = (qdss.pdata)->size;
330 qdss_add_sources(src_table, num_srcs);
331
332 pr_info("QDSS arch initialized\n");
333 return 0;
334err_pdata:
335 mutex_destroy(&qdss.sink_mutex);
336 mutex_destroy(&qdss.clk_mutex);
337 mutex_destroy(&qdss.sources_mutex);
338 pr_err("QDSS init failed\n");
339 return ret;
340}
341
342static int __devexit qdss_remove(struct platform_device *pdev)
343{
344 qdss_sysfs_exit();
345 mutex_destroy(&qdss.sink_mutex);
346 mutex_destroy(&qdss.clk_mutex);
347 mutex_destroy(&qdss.sources_mutex);
348
349 return 0;
350}
351
352static struct platform_driver qdss_driver = {
353 .probe = qdss_probe,
354 .remove = __devexit_p(qdss_remove),
355 .driver = {
356 .name = "msm_qdss",
357 },
358};
359
360static int __init qdss_init(void)
361{
362 return platform_driver_register(&qdss_driver);
363}
364arch_initcall(qdss_init);
365
366static int __init qdss_module_init(void)
367{
368 int ret;
Pratik Patelbf3e77442012-03-18 18:30:43 -0700369
Pratik Patel6630ebe2012-03-06 16:44:22 -0800370 ret = qdss_sysfs_init();
371 if (ret)
372 goto err_sysfs;
Pratik Patel59e29942011-12-27 10:31:33 -0800373
Pratik Patel1403f2a2012-03-21 10:10:00 -0700374 pr_info("QDSS module initialized\n");
Pratik Patel59e29942011-12-27 10:31:33 -0800375 return 0;
Pratik Patel6630ebe2012-03-06 16:44:22 -0800376err_sysfs:
Pratik Patel59e29942011-12-27 10:31:33 -0800377 return ret;
378}
Pratik Patel1403f2a2012-03-21 10:10:00 -0700379module_init(qdss_module_init);
Pratik Patel59e29942011-12-27 10:31:33 -0800380
381static void __exit qdss_exit(void)
382{
Pratik Patel1403f2a2012-03-21 10:10:00 -0700383 platform_driver_unregister(&qdss_driver);
Pratik Patel59e29942011-12-27 10:31:33 -0800384}
385module_exit(qdss_exit);
386
387MODULE_LICENSE("GPL v2");
388MODULE_DESCRIPTION("Qualcomm Debug SubSystem Driver");