blob: ce61b1d778e7ddac3a06dd8a960fe4c4630ad37c [file] [log] [blame]
Pratik Patel17f3b822011-11-21 12:41:47 -08001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Pratik Patel7831c082011-06-08 21:44:37 -07002 *
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>
Pratik Patelcf418622011-09-22 11:15:11 -070015#include <linux/init.h>
16#include <linux/types.h>
17#include <linux/device.h>
Pratik Patel7831c082011-06-08 21:44:37 -070018#include <linux/platform_device.h>
19#include <linux/io.h>
20#include <linux/err.h>
21#include <linux/fs.h>
22#include <linux/miscdevice.h>
23#include <linux/uaccess.h>
24#include <linux/slab.h>
25#include <linux/delay.h>
26#include <linux/smp.h>
Pratik Patel7831c082011-06-08 21:44:37 -070027#include <linux/wakelock.h>
28#include <linux/pm_qos_params.h>
29#include <linux/clk.h>
30#include <asm/atomic.h>
31
32#include "qdss.h"
33
34#define ptm_writel(ptm, cpu, val, off) \
35 __raw_writel((val), ptm.base + (SZ_4K * cpu) + off)
36#define ptm_readl(ptm, cpu, off) \
37 __raw_readl(ptm.base + (SZ_4K * cpu) + off)
38
39/*
40 * Device registers:
41 * 0x000 - 0x2FC: Trace registers
42 * 0x300 - 0x314: Management registers
43 * 0x318 - 0xEFC: Trace registers
44 *
45 * Coresight registers
46 * 0xF00 - 0xF9C: Management registers
47 * 0xFA0 - 0xFA4: Management registers in PFTv1.0
48 * Trace registers in PFTv1.1
49 * 0xFA8 - 0xFFC: Management registers
50 */
51
52/* Trace registers (0x000-0x2FC) */
53#define ETMCR (0x000)
54#define ETMCCR (0x004)
55#define ETMTRIGGER (0x008)
56#define ETMSR (0x010)
57#define ETMSCR (0x014)
58#define ETMTSSCR (0x018)
59#define ETMTEEVR (0x020)
60#define ETMTECR1 (0x024)
61#define ETMFFLR (0x02C)
62#define ETMACVRn(n) (0x040 + (n * 4))
63#define ETMACTRn(n) (0x080 + (n * 4))
64#define ETMCNTRLDVRn(n) (0x140 + (n * 4))
65#define ETMCNTENRn(n) (0x150 + (n * 4))
66#define ETMCNTRLDEVRn(n) (0x160 + (n * 4))
67#define ETMCNTVRn(n) (0x170 + (n * 4))
68#define ETMSQ12EVR (0x180)
69#define ETMSQ21EVR (0x184)
70#define ETMSQ23EVR (0x188)
71#define ETMSQ32EVR (0x18C)
72#define ETMSQ13EVR (0x190)
73#define ETMSQ31EVR (0x194)
74#define ETMSQR (0x19C)
75#define ETMEXTOUTEVRn(n) (0x1A0 + (n * 4))
76#define ETMCIDCVRn(n) (0x1B0 + (n * 4))
77#define ETMCIDCMR (0x1BC)
78#define ETMIMPSPEC0 (0x1C0)
79#define ETMIMPSPEC1 (0x1C4)
80#define ETMIMPSPEC2 (0x1C8)
81#define ETMIMPSPEC3 (0x1CC)
82#define ETMIMPSPEC4 (0x1D0)
83#define ETMIMPSPEC5 (0x1D4)
84#define ETMIMPSPEC6 (0x1D8)
85#define ETMIMPSPEC7 (0x1DC)
86#define ETMSYNCFR (0x1E0)
87#define ETMIDR (0x1E4)
88#define ETMCCER (0x1E8)
89#define ETMEXTINSELR (0x1EC)
90#define ETMTESSEICR (0x1F0)
91#define ETMEIBCR (0x1F4)
92#define ETMTSEVR (0x1F8)
93#define ETMAUXCR (0x1FC)
94#define ETMTRACEIDR (0x200)
95#define ETMVMIDCVR (0x204)
96/* Management registers (0x300-0x314) */
97#define ETMOSLAR (0x300)
98#define ETMOSLSR (0x304)
99#define ETMOSSRR (0x308)
100#define ETMPDCR (0x310)
101#define ETMPDSR (0x314)
102
Pratik Patel7831c082011-06-08 21:44:37 -0700103#define PTM_LOCK(cpu) \
104do { \
105 mb(); \
Pratik Patel17f3b822011-11-21 12:41:47 -0800106 ptm_writel(ptm, cpu, 0x0, CS_LAR); \
Pratik Patel7831c082011-06-08 21:44:37 -0700107} while (0)
108#define PTM_UNLOCK(cpu) \
109do { \
Pratik Patel17f3b822011-11-21 12:41:47 -0800110 ptm_writel(ptm, cpu, CS_UNLOCK_MAGIC, CS_LAR); \
Pratik Patel7831c082011-06-08 21:44:37 -0700111 mb(); \
112} while (0)
113
Pratik Patel7831c082011-06-08 21:44:37 -0700114
115/* Forward declarations */
116static void ptm_cfg_rw_init(void);
117
118static int trace_on_boot;
119module_param_named(
120 trace_on_boot, trace_on_boot, int, S_IRUGO
121);
122
123struct ptm_config {
124 /* read only config registers */
125 uint32_t config_code;
126 /* derived values */
127 uint8_t nr_addr_comp;
128 uint8_t nr_cntr;
129 uint8_t nr_ext_input;
130 uint8_t nr_ext_output;
131 uint8_t nr_context_id_comp;
132
133 uint32_t config_code_extn;
134 /* derived values */
135 uint8_t nr_extnd_ext_input_sel;
136 uint8_t nr_instr_resources;
137
138 uint32_t system_config;
139 /* derived values */
140 uint8_t fifofull_supported;
141 uint8_t nr_procs_supported;
142
143 /* read-write registers */
144 uint32_t main_control;
145 uint32_t trigger_event;
146 uint32_t te_start_stop_control;
147 uint32_t te_event;
148 uint32_t te_control;
149 uint32_t fifofull_level;
150 uint32_t addr_comp_value[16];
151 uint32_t addr_comp_access_type[16];
152 uint32_t cntr_reload_value[4];
153 uint32_t cntr_enable_event[4];
154 uint32_t cntr_reload_event[4];
155 uint32_t cntr_value[4];
156 uint32_t seq_state_12_event;
157 uint32_t seq_state_21_event;
158 uint32_t seq_state_23_event;
159 uint32_t seq_state_32_event;
160 uint32_t seq_state_13_event;
161 uint32_t seq_state_31_event;
162 uint32_t current_seq_state;
163 uint32_t ext_output_event[4];
164 uint32_t context_id_comp_value[3];
165 uint32_t context_id_comp_mask;
166 uint32_t sync_freq;
167 uint32_t extnd_ext_input_sel;
168 uint32_t ts_event;
169 uint32_t aux_control;
170 uint32_t coresight_trace_id;
171 uint32_t vmid_comp_value;
172};
173
174struct ptm_ctx {
175 struct ptm_config cfg;
176 void __iomem *base;
Pratik Patel7831c082011-06-08 21:44:37 -0700177 bool trace_enabled;
Pratik Patel7831c082011-06-08 21:44:37 -0700178 struct wake_lock wake_lock;
179 struct pm_qos_request_list qos_req;
180 atomic_t in_use;
181 struct device *dev;
182 struct clk *qdss_at_clk;
183 struct clk *qdss_pclkdbg_clk;
184 struct clk *qdss_pclk;
185 struct clk *qdss_traceclkin_clk;
186 struct clk *qdss_tsctr_clk;
187};
188
189static struct ptm_ctx ptm;
190
Pratik Patel7831c082011-06-08 21:44:37 -0700191
192static int ptm_clock_enable(void)
193{
194 int ret;
195
196 ret = clk_enable(ptm.qdss_at_clk);
197 if (WARN(ret, "qdss_at_clk not enabled (%d)\n", ret))
198 goto err;
199
200 ret = clk_enable(ptm.qdss_pclkdbg_clk);
201 if (WARN(ret, "qdss_pclkdbg_clk not enabled (%d)\n", ret))
202 goto err_pclkdbg;
203
204 ret = clk_enable(ptm.qdss_pclk);
205 if (WARN(ret, "qdss_pclk not enabled (%d)\n", ret))
206 goto err_pclk;
207
208 ret = clk_enable(ptm.qdss_traceclkin_clk);
209 if (WARN(ret, "qdss_traceclkin_clk not enabled (%d)\n", ret))
210 goto err_traceclkin;
211
212 ret = clk_enable(ptm.qdss_tsctr_clk);
213 if (WARN(ret, "qdss_tsctr_clk not enabled (%d)\n", ret))
214 goto err_tsctr;
215
216 return 0;
217
218err_tsctr:
219 clk_disable(ptm.qdss_traceclkin_clk);
220err_traceclkin:
221 clk_disable(ptm.qdss_pclk);
222err_pclk:
223 clk_disable(ptm.qdss_pclkdbg_clk);
224err_pclkdbg:
225 clk_disable(ptm.qdss_at_clk);
226err:
227 return ret;
228}
229
230static void ptm_clock_disable(void)
231{
232 clk_disable(ptm.qdss_tsctr_clk);
233 clk_disable(ptm.qdss_traceclkin_clk);
234 clk_disable(ptm.qdss_pclk);
235 clk_disable(ptm.qdss_pclkdbg_clk);
236 clk_disable(ptm.qdss_at_clk);
237}
238
Pratik Patel17f3b822011-11-21 12:41:47 -0800239/* ETM clock is derived from the processor clock and gets enabled on a
240 * logical OR of below items on Krait (pass2 onwards):
241 * 1.CPMR[ETMCLKEN] is 1
242 * 2.ETMCR[PD] is 0
243 * 3.ETMPDCR[PU] is 1
244 * 4.Reset is asserted (core or debug)
245 * 5.APB memory mapped requests (eg. EDAP access)
246 *
247 * 1., 2. and 3. above are permanent enables whereas 4. and 5. are temporary
248 * enables
249 *
250 * We rely on 5. to be able to access ETMCR and then use 2. above for ETM
251 * clock vote in the driver and the save-restore code uses 1. above
252 * for its vote
253 */
Pratik Patel7831c082011-06-08 21:44:37 -0700254static void ptm_set_powerdown(int cpu)
255{
256 uint32_t etmcr;
257
258 etmcr = ptm_readl(ptm, cpu, ETMCR);
259 etmcr |= BIT(0);
260 ptm_writel(ptm, cpu, etmcr, ETMCR);
261}
262
263static void ptm_clear_powerdown(int cpu)
264{
265 uint32_t etmcr;
266
267 etmcr = ptm_readl(ptm, cpu, ETMCR);
268 etmcr &= ~BIT(0);
269 ptm_writel(ptm, cpu, etmcr, ETMCR);
270}
271
272static void ptm_set_prog(int cpu)
273{
274 uint32_t etmcr;
275 int count;
276
277 etmcr = ptm_readl(ptm, cpu, ETMCR);
278 etmcr |= BIT(10);
279 ptm_writel(ptm, cpu, etmcr, ETMCR);
280
281 for (count = TIMEOUT_US; BVAL(ptm_readl(ptm, cpu, ETMSR), 1) != 1
282 && count > 0; count--)
283 udelay(1);
284 WARN(count == 0, "timeout while setting prog bit\n");
285}
286
287static void ptm_clear_prog(int cpu)
288{
289 uint32_t etmcr;
290 int count;
291
292 etmcr = ptm_readl(ptm, cpu, ETMCR);
293 etmcr &= ~BIT(10);
294 ptm_writel(ptm, cpu, etmcr, ETMCR);
295
296 for (count = TIMEOUT_US; BVAL(ptm_readl(ptm, cpu, ETMSR), 1) != 0
297 && count > 0; count--)
298 udelay(1);
299 WARN(count == 0, "timeout while clearing prog bit\n");
300}
301
Pratik Patel17f3b822011-11-21 12:41:47 -0800302static void __ptm_trace_enable(int cpu)
Pratik Patel7831c082011-06-08 21:44:37 -0700303{
Pratik Patel17f3b822011-11-21 12:41:47 -0800304 int i;
Pratik Patel7831c082011-06-08 21:44:37 -0700305
Pratik Patel17f3b822011-11-21 12:41:47 -0800306 PTM_UNLOCK(cpu);
307 /* Vote for ETM power/clock enable */
308 ptm_clear_powerdown(cpu);
309 ptm_set_prog(cpu);
Pratik Patel7831c082011-06-08 21:44:37 -0700310
Pratik Patel17f3b822011-11-21 12:41:47 -0800311 ptm_writel(ptm, cpu, ptm.cfg.main_control | BIT(10), ETMCR);
312 ptm_writel(ptm, cpu, ptm.cfg.trigger_event, ETMTRIGGER);
313 ptm_writel(ptm, cpu, ptm.cfg.te_start_stop_control, ETMTSSCR);
314 ptm_writel(ptm, cpu, ptm.cfg.te_event, ETMTEEVR);
315 ptm_writel(ptm, cpu, ptm.cfg.te_control, ETMTECR1);
316 ptm_writel(ptm, cpu, ptm.cfg.fifofull_level, ETMFFLR);
317 for (i = 0; i < ptm.cfg.nr_addr_comp; i++) {
318 ptm_writel(ptm, cpu, ptm.cfg.addr_comp_value[i], ETMACVRn(i));
319 ptm_writel(ptm, cpu, ptm.cfg.addr_comp_access_type[i],
Pratik Patel7831c082011-06-08 21:44:37 -0700320 ETMACTRn(i));
Pratik Patel7831c082011-06-08 21:44:37 -0700321 }
Pratik Patel17f3b822011-11-21 12:41:47 -0800322 for (i = 0; i < ptm.cfg.nr_cntr; i++) {
323 ptm_writel(ptm, cpu, ptm.cfg.cntr_reload_value[i],
324 ETMCNTRLDVRn(i));
325 ptm_writel(ptm, cpu, ptm.cfg.cntr_enable_event[i],
326 ETMCNTENRn(i));
327 ptm_writel(ptm, cpu, ptm.cfg.cntr_reload_event[i],
328 ETMCNTRLDEVRn(i));
329 ptm_writel(ptm, cpu, ptm.cfg.cntr_value[i], ETMCNTVRn(i));
330 }
331 ptm_writel(ptm, cpu, ptm.cfg.seq_state_12_event, ETMSQ12EVR);
332 ptm_writel(ptm, cpu, ptm.cfg.seq_state_21_event, ETMSQ21EVR);
333 ptm_writel(ptm, cpu, ptm.cfg.seq_state_23_event, ETMSQ23EVR);
334 ptm_writel(ptm, cpu, ptm.cfg.seq_state_32_event, ETMSQ32EVR);
335 ptm_writel(ptm, cpu, ptm.cfg.seq_state_13_event, ETMSQ13EVR);
336 ptm_writel(ptm, cpu, ptm.cfg.seq_state_31_event, ETMSQ31EVR);
337 ptm_writel(ptm, cpu, ptm.cfg.current_seq_state, ETMSQR);
338 for (i = 0; i < ptm.cfg.nr_ext_output; i++)
339 ptm_writel(ptm, cpu, ptm.cfg.ext_output_event[i],
340 ETMEXTOUTEVRn(i));
341 for (i = 0; i < ptm.cfg.nr_context_id_comp; i++)
342 ptm_writel(ptm, cpu, ptm.cfg.context_id_comp_value[i],
343 ETMCIDCVRn(i));
344 ptm_writel(ptm, cpu, ptm.cfg.context_id_comp_mask, ETMCIDCMR);
345 ptm_writel(ptm, cpu, ptm.cfg.sync_freq, ETMSYNCFR);
346 ptm_writel(ptm, cpu, ptm.cfg.extnd_ext_input_sel, ETMEXTINSELR);
347 ptm_writel(ptm, cpu, ptm.cfg.ts_event, ETMTSEVR);
348 ptm_writel(ptm, cpu, ptm.cfg.aux_control, ETMAUXCR);
349 ptm_writel(ptm, cpu, cpu+1, ETMTRACEIDR);
350 ptm_writel(ptm, cpu, ptm.cfg.vmid_comp_value, ETMVMIDCVR);
351
352 ptm_clear_prog(cpu);
353 PTM_LOCK(cpu);
Pratik Patel7831c082011-06-08 21:44:37 -0700354}
355
356static int ptm_trace_enable(void)
357{
Pratik Patel17f3b822011-11-21 12:41:47 -0800358 int ret, cpu;
Pratik Patel7831c082011-06-08 21:44:37 -0700359
360 ret = ptm_clock_enable();
361 if (ret)
362 return ret;
363
364 wake_lock(&ptm.wake_lock);
Pratik Patele5771792011-09-17 18:33:54 -0700365 /* 1. causes all online cpus to come out of idle PC
Pratik Patel7831c082011-06-08 21:44:37 -0700366 * 2. prevents idle PC until save restore flag is enabled atomically
Pratik Patele5771792011-09-17 18:33:54 -0700367 *
368 * we rely on the user to prevent hotplug on/off racing with this
369 * operation and to ensure cores where trace is expected to be turned
370 * on are already hotplugged on
Pratik Patel7831c082011-06-08 21:44:37 -0700371 */
372 pm_qos_update_request(&ptm.qos_req, 0);
373
374 etb_disable();
375 tpiu_disable();
376 /* enable ETB first to avoid loosing any trace data */
377 etb_enable();
378 funnel_enable(0x0, 0x3);
Pratik Patel17f3b822011-11-21 12:41:47 -0800379 for_each_online_cpu(cpu)
380 __ptm_trace_enable(cpu);
Pratik Patel7831c082011-06-08 21:44:37 -0700381
382 ptm.trace_enabled = true;
383
384 pm_qos_update_request(&ptm.qos_req, PM_QOS_DEFAULT_VALUE);
385 wake_unlock(&ptm.wake_lock);
386
387 return 0;
388}
389
Pratik Patel17f3b822011-11-21 12:41:47 -0800390static void __ptm_trace_disable(int cpu)
Pratik Patel7831c082011-06-08 21:44:37 -0700391{
Pratik Patel17f3b822011-11-21 12:41:47 -0800392 PTM_UNLOCK(cpu);
393 ptm_set_prog(cpu);
Pratik Patel7831c082011-06-08 21:44:37 -0700394
Pratik Patel17f3b822011-11-21 12:41:47 -0800395 /* program trace enable to low by using always false event */
396 ptm_writel(ptm, cpu, 0x6F | BIT(14), ETMTEEVR);
Pratik Patel7831c082011-06-08 21:44:37 -0700397
Pratik Patel17f3b822011-11-21 12:41:47 -0800398 /* Vote for ETM power/clock disable */
399 ptm_set_powerdown(cpu);
400 PTM_LOCK(cpu);
Pratik Patel7831c082011-06-08 21:44:37 -0700401}
402
403static void ptm_trace_disable(void)
404{
Pratik Patel17f3b822011-11-21 12:41:47 -0800405 int cpu;
406
Pratik Patel7831c082011-06-08 21:44:37 -0700407 wake_lock(&ptm.wake_lock);
Pratik Patele5771792011-09-17 18:33:54 -0700408 /* 1. causes all online cpus to come out of idle PC
Pratik Patel7831c082011-06-08 21:44:37 -0700409 * 2. prevents idle PC until save restore flag is disabled atomically
Pratik Patele5771792011-09-17 18:33:54 -0700410 *
411 * we rely on the user to prevent hotplug on/off racing with this
412 * operation and to ensure cores where trace is expected to be turned
413 * off are already hotplugged on
Pratik Patel7831c082011-06-08 21:44:37 -0700414 */
415 pm_qos_update_request(&ptm.qos_req, 0);
416
Pratik Patel17f3b822011-11-21 12:41:47 -0800417 for_each_online_cpu(cpu)
418 __ptm_trace_disable(cpu);
Pratik Patel7831c082011-06-08 21:44:37 -0700419 etb_dump();
420 etb_disable();
421 funnel_disable(0x0, 0x3);
422
423 ptm.trace_enabled = false;
424
Pratik Patel7831c082011-06-08 21:44:37 -0700425 pm_qos_update_request(&ptm.qos_req, PM_QOS_DEFAULT_VALUE);
426 wake_unlock(&ptm.wake_lock);
427
428 ptm_clock_disable();
429}
430
431static int ptm_open(struct inode *inode, struct file *file)
432{
433 if (atomic_cmpxchg(&ptm.in_use, 0, 1))
434 return -EBUSY;
435
436 dev_dbg(ptm.dev, "%s: successfully opened\n", __func__);
437 return 0;
438}
439
440static void ptm_range_filter(char range, uint32_t reg1,
441 uint32_t addr1, uint32_t reg2, uint32_t addr2)
442{
443 ptm.cfg.addr_comp_value[reg1] = addr1;
444 ptm.cfg.addr_comp_value[reg2] = addr2;
445
446 ptm.cfg.te_control |= (1 << (reg1/2));
447 if (range == 'i')
448 ptm.cfg.te_control &= ~BIT(24);
449 else if (range == 'e')
450 ptm.cfg.te_control |= BIT(24);
451}
452
453static void ptm_start_stop_filter(char start_stop,
454 uint32_t reg, uint32_t addr)
455{
456 ptm.cfg.addr_comp_value[reg] = addr;
457
458 if (start_stop == 's')
459 ptm.cfg.te_start_stop_control |= (1 << reg);
460 else if (start_stop == 't')
461 ptm.cfg.te_start_stop_control |= (1 << (reg + 16));
462
463 ptm.cfg.te_control |= BIT(25);
464}
465
466#define MAX_COMMAND_STRLEN 40
467static ssize_t ptm_write(struct file *file, const char __user *data,
468 size_t len, loff_t *ppos)
469{
470 char command[MAX_COMMAND_STRLEN];
471 int str_len;
472 unsigned long reg1, reg2;
473 unsigned long addr1, addr2;
474
475 str_len = strnlen_user(data, MAX_COMMAND_STRLEN);
476 dev_dbg(ptm.dev, "string length: %d", str_len);
477 if (str_len == 0 || str_len == (MAX_COMMAND_STRLEN+1)) {
478 dev_err(ptm.dev, "error in str_len: %d", str_len);
479 return -EFAULT;
480 }
481 /* includes the null character */
482 if (copy_from_user(command, data, str_len)) {
483 dev_err(ptm.dev, "error in copy_from_user: %d", str_len);
484 return -EFAULT;
485 }
486
487 dev_dbg(ptm.dev, "input = %s", command);
488
489 switch (command[0]) {
490 case '0':
491 if (ptm.trace_enabled) {
492 ptm_trace_disable();
493 dev_info(ptm.dev, "tracing disabled\n");
494 } else
495 dev_err(ptm.dev, "trace already disabled\n");
496
497 break;
498 case '1':
499 if (!ptm.trace_enabled) {
500 if (!ptm_trace_enable())
501 dev_info(ptm.dev, "tracing enabled\n");
502 else
503 dev_err(ptm.dev, "error enabling trace\n");
504 } else
505 dev_err(ptm.dev, "trace already enabled\n");
506 break;
507 case 'f':
508 switch (command[2]) {
509 case 'i':
510 switch (command[4]) {
511 case 'i':
512 if (sscanf(&command[6], "%lx:%lx:%lx:%lx\\0",
513 &reg1, &addr1, &reg2, &addr2) != 4)
514 goto err_out;
515 if (reg1 > 7 || reg2 > 7 || (reg1 % 2))
516 goto err_out;
517 ptm_range_filter('i',
518 reg1, addr1, reg2, addr2);
519 break;
520 case 'e':
521 if (sscanf(&command[6], "%lx:%lx:%lx:%lx\\0",
522 &reg1, &addr1, &reg2, &addr2) != 4)
523 goto err_out;
524 if (reg1 > 7 || reg2 > 7 || (reg1 % 2)
525 || command[2] == 'd')
526 goto err_out;
527 ptm_range_filter('e',
528 reg1, addr1, reg2, addr2);
529 break;
530 case 's':
531 if (sscanf(&command[6], "%lx:%lx\\0",
532 &reg1, &addr1) != 2)
533 goto err_out;
534 if (reg1 > 7)
535 goto err_out;
536 ptm_start_stop_filter('s', reg1, addr1);
537 break;
538 case 't':
539 if (sscanf(&command[6], "%lx:%lx\\0",
540 &reg1, &addr1) != 2)
541 goto err_out;
542 if (reg1 > 7)
543 goto err_out;
544 ptm_start_stop_filter('t', reg1, addr1);
545 break;
546 default:
547 goto err_out;
548 }
549 break;
550 case 'r':
551 ptm_cfg_rw_init();
552 break;
553 default:
554 goto err_out;
555 }
556 break;
557 default:
558 goto err_out;
559 }
560
561 return len;
562
563err_out:
564 return -EFAULT;
565}
566
567static int ptm_release(struct inode *inode, struct file *file)
568{
569 atomic_set(&ptm.in_use, 0);
570 dev_dbg(ptm.dev, "%s: released\n", __func__);
571 return 0;
572}
573
574static const struct file_operations ptm_fops = {
575 .owner = THIS_MODULE,
576 .open = ptm_open,
577 .write = ptm_write,
578 .release = ptm_release,
579};
580
581static struct miscdevice ptm_misc = {
582 .name = "msm_ptm",
583 .minor = MISC_DYNAMIC_MINOR,
584 .fops = &ptm_fops,
585};
586
Pratik Patel7831c082011-06-08 21:44:37 -0700587static void ptm_cfg_rw_init(void)
588{
589 int i;
590
591 ptm.cfg.main_control = 0x00001000;
592 ptm.cfg.trigger_event = 0x0000406F;
593 ptm.cfg.te_start_stop_control = 0x00000000;
594 ptm.cfg.te_event = 0x0000006F;
595 ptm.cfg.te_control = 0x01000000;
596 ptm.cfg.fifofull_level = 0x00000028;
597 for (i = 0; i < ptm.cfg.nr_addr_comp; i++) {
598 ptm.cfg.addr_comp_value[i] = 0x00000000;
599 ptm.cfg.addr_comp_access_type[i] = 0x00000000;
600 }
601 for (i = 0; i < ptm.cfg.nr_cntr; i++) {
602 ptm.cfg.cntr_reload_value[i] = 0x00000000;
603 ptm.cfg.cntr_enable_event[i] = 0x0000406F;
604 ptm.cfg.cntr_reload_event[i] = 0x0000406F;
605 ptm.cfg.cntr_value[i] = 0x00000000;
606 }
607 ptm.cfg.seq_state_12_event = 0x0000406F;
608 ptm.cfg.seq_state_21_event = 0x0000406F;
609 ptm.cfg.seq_state_23_event = 0x0000406F;
610 ptm.cfg.seq_state_32_event = 0x0000406F;
611 ptm.cfg.seq_state_13_event = 0x0000406F;
612 ptm.cfg.seq_state_31_event = 0x0000406F;
613 ptm.cfg.current_seq_state = 0x00000000;
614 for (i = 0; i < ptm.cfg.nr_ext_output; i++)
615 ptm.cfg.ext_output_event[i] = 0x0000406F;
616 for (i = 0; i < ptm.cfg.nr_context_id_comp; i++)
617 ptm.cfg.context_id_comp_value[i] = 0x00000000;
618 ptm.cfg.context_id_comp_mask = 0x00000000;
619 ptm.cfg.sync_freq = 0x00000080;
620 ptm.cfg.extnd_ext_input_sel = 0x00000000;
621 ptm.cfg.ts_event = 0x0000406F;
622 ptm.cfg.aux_control = 0x00000000;
623 ptm.cfg.vmid_comp_value = 0x00000000;
624}
625
Pratik Patel17f3b822011-11-21 12:41:47 -0800626/* Memory mapped writes to clear os lock not supported */
627static void ptm_os_unlock(void *unused)
628{
629 unsigned long value = 0x0;
630
631 asm("mcr p14, 1, %0, c1, c0, 4\n\t" : : "r" (value));
632 asm("isb\n\t");
633}
634
Pratik Patel7831c082011-06-08 21:44:37 -0700635static void ptm_cfg_ro_init(void)
636{
637 /* use cpu 0 for setup */
638 int cpu = 0;
639
Pratik Patel17f3b822011-11-21 12:41:47 -0800640 /* Unlock OS lock first to allow memory mapped reads and writes */
Pratik Patel7831c082011-06-08 21:44:37 -0700641 ptm_os_unlock(NULL);
642 smp_call_function(ptm_os_unlock, NULL, 1);
643 PTM_UNLOCK(cpu);
Pratik Patel17f3b822011-11-21 12:41:47 -0800644 /* Vote for ETM power/clock enable */
Pratik Patel7831c082011-06-08 21:44:37 -0700645 ptm_clear_powerdown(cpu);
646 ptm_set_prog(cpu);
647
648 /* find all capabilities */
649 ptm.cfg.config_code = ptm_readl(ptm, cpu, ETMCCR);
650 ptm.cfg.nr_addr_comp = BMVAL(ptm.cfg.config_code, 0, 3) * 2;
651 ptm.cfg.nr_cntr = BMVAL(ptm.cfg.config_code, 13, 15);
652 ptm.cfg.nr_ext_input = BMVAL(ptm.cfg.config_code, 17, 19);
653 ptm.cfg.nr_ext_output = BMVAL(ptm.cfg.config_code, 20, 22);
654 ptm.cfg.nr_context_id_comp = BMVAL(ptm.cfg.config_code, 24, 25);
655
656 ptm.cfg.config_code_extn = ptm_readl(ptm, cpu, ETMCCER);
657 ptm.cfg.nr_extnd_ext_input_sel =
658 BMVAL(ptm.cfg.config_code_extn, 0, 2);
659 ptm.cfg.nr_instr_resources = BMVAL(ptm.cfg.config_code_extn, 13, 15);
660
661 ptm.cfg.system_config = ptm_readl(ptm, cpu, ETMSCR);
662 ptm.cfg.fifofull_supported = BVAL(ptm.cfg.system_config, 8);
663 ptm.cfg.nr_procs_supported = BMVAL(ptm.cfg.system_config, 12, 14);
664
Pratik Patel17f3b822011-11-21 12:41:47 -0800665 /* Vote for ETM power/clock disable */
Pratik Patel7831c082011-06-08 21:44:37 -0700666 ptm_set_powerdown(cpu);
667 PTM_LOCK(cpu);
668}
669
670static int __devinit ptm_probe(struct platform_device *pdev)
671{
Pratik Patele5771792011-09-17 18:33:54 -0700672 int ret;
Pratik Patel7831c082011-06-08 21:44:37 -0700673 struct resource *res;
674
675 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
676 if (!res) {
677 ret = -EINVAL;
678 goto err_res;
679 }
680
681 ptm.base = ioremap_nocache(res->start, resource_size(res));
682 if (!ptm.base) {
683 ret = -EINVAL;
684 goto err_ioremap;
685 }
686
687 ptm.dev = &pdev->dev;
688
Pratik Patel7831c082011-06-08 21:44:37 -0700689 ret = misc_register(&ptm_misc);
690 if (ret)
691 goto err_misc;
692
693 ptm.qdss_at_clk = clk_get(NULL, "qdss_at_clk");
694 if (IS_ERR(ptm.qdss_at_clk)) {
695 ret = PTR_ERR(ptm.qdss_at_clk);
696 goto err_at;
697 }
698 ret = clk_set_rate(ptm.qdss_at_clk, 300000000);
699 if (ret)
700 goto err_at_rate;
701 ret = clk_enable(ptm.qdss_at_clk);
702 if (ret)
703 goto err_at_enable;
704
705 ptm.qdss_pclkdbg_clk = clk_get(NULL, "qdss_pclkdbg_clk");
706 if (IS_ERR(ptm.qdss_pclkdbg_clk)) {
707 ret = PTR_ERR(ptm.qdss_pclkdbg_clk);
708 goto err_pclkdbg;
709 }
710 ret = clk_enable(ptm.qdss_pclkdbg_clk);
711 if (ret)
712 goto err_pclkdbg_enable;
713
714 ptm.qdss_pclk = clk_get(NULL, "qdss_pclk");
715 if (IS_ERR(ptm.qdss_pclk)) {
716 ret = PTR_ERR(ptm.qdss_pclk);
717 goto err_pclk;
718 }
719
720 ret = clk_enable(ptm.qdss_pclk);
721 if (ret)
722 goto err_pclk_enable;
723
724 ptm.qdss_traceclkin_clk = clk_get(NULL, "qdss_traceclkin_clk");
725 if (IS_ERR(ptm.qdss_traceclkin_clk)) {
726 ret = PTR_ERR(ptm.qdss_traceclkin_clk);
727 goto err_traceclkin;
728 }
729 ret = clk_set_rate(ptm.qdss_traceclkin_clk, 300000000);
730 if (ret)
731 goto err_traceclkin_rate;
732 ret = clk_enable(ptm.qdss_traceclkin_clk);
733 if (ret)
734 goto err_traceclkin_enable;
735
736 ptm.qdss_tsctr_clk = clk_get(NULL, "qdss_tsctr_clk");
737 if (IS_ERR(ptm.qdss_tsctr_clk)) {
738 ret = PTR_ERR(ptm.qdss_tsctr_clk);
739 goto err_tsctr;
740 }
741 ret = clk_set_rate(ptm.qdss_tsctr_clk, 400000000);
742 if (ret)
743 goto err_tsctr_rate;
744
745 ret = clk_enable(ptm.qdss_tsctr_clk);
746 if (ret)
747 goto err_tsctr_enable;
748
749 ptm_cfg_ro_init();
750 ptm_cfg_rw_init();
751
752 ptm.trace_enabled = false;
753
Pratik Patel7831c082011-06-08 21:44:37 -0700754 wake_lock_init(&ptm.wake_lock, WAKE_LOCK_SUSPEND, "msm_ptm");
755 pm_qos_add_request(&ptm.qos_req, PM_QOS_CPU_DMA_LATENCY,
756 PM_QOS_DEFAULT_VALUE);
757 atomic_set(&ptm.in_use, 0);
758
759 clk_disable(ptm.qdss_tsctr_clk);
760 clk_disable(ptm.qdss_traceclkin_clk);
761 clk_disable(ptm.qdss_pclk);
762 clk_disable(ptm.qdss_pclkdbg_clk);
763 clk_disable(ptm.qdss_at_clk);
764
765 dev_info(ptm.dev, "PTM intialized.\n");
766
767 if (trace_on_boot) {
768 if (!ptm_trace_enable())
769 dev_info(ptm.dev, "tracing enabled\n");
770 else
771 dev_err(ptm.dev, "error enabling trace\n");
772 }
773
774 return 0;
775
Pratik Patel7831c082011-06-08 21:44:37 -0700776err_tsctr_enable:
777err_tsctr_rate:
778 clk_put(ptm.qdss_tsctr_clk);
779err_tsctr:
780 clk_disable(ptm.qdss_traceclkin_clk);
781err_traceclkin_enable:
782err_traceclkin_rate:
783 clk_put(ptm.qdss_traceclkin_clk);
784err_traceclkin:
785 clk_disable(ptm.qdss_pclk);
786err_pclk_enable:
787 clk_put(ptm.qdss_pclk);
788err_pclk:
789 clk_disable(ptm.qdss_pclkdbg_clk);
790err_pclkdbg_enable:
791 clk_put(ptm.qdss_pclkdbg_clk);
792err_pclkdbg:
793 clk_disable(ptm.qdss_at_clk);
794err_at_enable:
795err_at_rate:
796 clk_put(ptm.qdss_at_clk);
797err_at:
798 misc_deregister(&ptm_misc);
799err_misc:
Pratik Patel7831c082011-06-08 21:44:37 -0700800 iounmap(ptm.base);
801err_ioremap:
802err_res:
803 return ret;
804}
805
806static int __devexit ptm_remove(struct platform_device *pdev)
807{
808 if (ptm.trace_enabled)
809 ptm_trace_disable();
810 pm_qos_remove_request(&ptm.qos_req);
811 wake_lock_destroy(&ptm.wake_lock);
Pratik Patel7831c082011-06-08 21:44:37 -0700812 clk_put(ptm.qdss_tsctr_clk);
813 clk_put(ptm.qdss_traceclkin_clk);
814 clk_put(ptm.qdss_pclk);
815 clk_put(ptm.qdss_pclkdbg_clk);
816 clk_put(ptm.qdss_at_clk);
817 misc_deregister(&ptm_misc);
Pratik Patel7831c082011-06-08 21:44:37 -0700818 iounmap(ptm.base);
819
820 return 0;
821}
822
823static struct platform_driver ptm_driver = {
824 .probe = ptm_probe,
825 .remove = __devexit_p(ptm_remove),
826 .driver = {
827 .name = "msm_ptm",
828 },
829};
830
831static int __init ptm_init(void)
832{
833 return platform_driver_register(&ptm_driver);
834}
835module_init(ptm_init);
836
837static void __exit ptm_exit(void)
838{
839 platform_driver_unregister(&ptm_driver);
840}
841module_exit(ptm_exit);
842
843MODULE_LICENSE("GPL v2");
844MODULE_DESCRIPTION("Coresight Program Flow Trace driver");