blob: 00d46ee3217c163a3518c959e0d1fff1b5a735f1 [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>
Pratik Patel7831c082011-06-08 21:44:37 -070029#include <asm/atomic.h>
Pratik Patelcc320a42011-12-22 10:48:14 -080030#include <mach/rpm.h>
Pratik Patel7831c082011-06-08 21:44:37 -070031
Pratik Patelcc320a42011-12-22 10:48:14 -080032#include "rpm_resources.h"
Pratik Patel7831c082011-06-08 21:44:37 -070033#include "qdss.h"
34
Pratik Patelcc320a42011-12-22 10:48:14 -080035#define QDSS_CLK_ON_DBG 0x1
36#define QDSS_CLK_ON_HSDBG 0x2
37#define QDSS_CLK_OFF 0x0
38
Pratik Patel7831c082011-06-08 21:44:37 -070039#define ptm_writel(ptm, cpu, val, off) \
40 __raw_writel((val), ptm.base + (SZ_4K * cpu) + off)
41#define ptm_readl(ptm, cpu, off) \
42 __raw_readl(ptm.base + (SZ_4K * cpu) + off)
43
44/*
45 * Device registers:
46 * 0x000 - 0x2FC: Trace registers
47 * 0x300 - 0x314: Management registers
48 * 0x318 - 0xEFC: Trace registers
49 *
50 * Coresight registers
51 * 0xF00 - 0xF9C: Management registers
52 * 0xFA0 - 0xFA4: Management registers in PFTv1.0
53 * Trace registers in PFTv1.1
54 * 0xFA8 - 0xFFC: Management registers
55 */
56
57/* Trace registers (0x000-0x2FC) */
58#define ETMCR (0x000)
59#define ETMCCR (0x004)
60#define ETMTRIGGER (0x008)
61#define ETMSR (0x010)
62#define ETMSCR (0x014)
63#define ETMTSSCR (0x018)
64#define ETMTEEVR (0x020)
65#define ETMTECR1 (0x024)
66#define ETMFFLR (0x02C)
67#define ETMACVRn(n) (0x040 + (n * 4))
68#define ETMACTRn(n) (0x080 + (n * 4))
69#define ETMCNTRLDVRn(n) (0x140 + (n * 4))
70#define ETMCNTENRn(n) (0x150 + (n * 4))
71#define ETMCNTRLDEVRn(n) (0x160 + (n * 4))
72#define ETMCNTVRn(n) (0x170 + (n * 4))
73#define ETMSQ12EVR (0x180)
74#define ETMSQ21EVR (0x184)
75#define ETMSQ23EVR (0x188)
76#define ETMSQ32EVR (0x18C)
77#define ETMSQ13EVR (0x190)
78#define ETMSQ31EVR (0x194)
79#define ETMSQR (0x19C)
80#define ETMEXTOUTEVRn(n) (0x1A0 + (n * 4))
81#define ETMCIDCVRn(n) (0x1B0 + (n * 4))
82#define ETMCIDCMR (0x1BC)
83#define ETMIMPSPEC0 (0x1C0)
84#define ETMIMPSPEC1 (0x1C4)
85#define ETMIMPSPEC2 (0x1C8)
86#define ETMIMPSPEC3 (0x1CC)
87#define ETMIMPSPEC4 (0x1D0)
88#define ETMIMPSPEC5 (0x1D4)
89#define ETMIMPSPEC6 (0x1D8)
90#define ETMIMPSPEC7 (0x1DC)
91#define ETMSYNCFR (0x1E0)
92#define ETMIDR (0x1E4)
93#define ETMCCER (0x1E8)
94#define ETMEXTINSELR (0x1EC)
95#define ETMTESSEICR (0x1F0)
96#define ETMEIBCR (0x1F4)
97#define ETMTSEVR (0x1F8)
98#define ETMAUXCR (0x1FC)
99#define ETMTRACEIDR (0x200)
100#define ETMVMIDCVR (0x204)
101/* Management registers (0x300-0x314) */
102#define ETMOSLAR (0x300)
103#define ETMOSLSR (0x304)
104#define ETMOSSRR (0x308)
105#define ETMPDCR (0x310)
106#define ETMPDSR (0x314)
107
Pratik Patel7831c082011-06-08 21:44:37 -0700108#define PTM_LOCK(cpu) \
109do { \
110 mb(); \
Pratik Patel17f3b822011-11-21 12:41:47 -0800111 ptm_writel(ptm, cpu, 0x0, CS_LAR); \
Pratik Patel7831c082011-06-08 21:44:37 -0700112} while (0)
113#define PTM_UNLOCK(cpu) \
114do { \
Pratik Patel17f3b822011-11-21 12:41:47 -0800115 ptm_writel(ptm, cpu, CS_UNLOCK_MAGIC, CS_LAR); \
Pratik Patel7831c082011-06-08 21:44:37 -0700116 mb(); \
117} while (0)
118
Pratik Patel7831c082011-06-08 21:44:37 -0700119
120/* Forward declarations */
121static void ptm_cfg_rw_init(void);
122
123static int trace_on_boot;
124module_param_named(
125 trace_on_boot, trace_on_boot, int, S_IRUGO
126);
127
128struct ptm_config {
129 /* read only config registers */
130 uint32_t config_code;
131 /* derived values */
132 uint8_t nr_addr_comp;
133 uint8_t nr_cntr;
134 uint8_t nr_ext_input;
135 uint8_t nr_ext_output;
136 uint8_t nr_context_id_comp;
137
138 uint32_t config_code_extn;
139 /* derived values */
140 uint8_t nr_extnd_ext_input_sel;
141 uint8_t nr_instr_resources;
142
143 uint32_t system_config;
144 /* derived values */
145 uint8_t fifofull_supported;
146 uint8_t nr_procs_supported;
147
148 /* read-write registers */
149 uint32_t main_control;
150 uint32_t trigger_event;
151 uint32_t te_start_stop_control;
152 uint32_t te_event;
153 uint32_t te_control;
154 uint32_t fifofull_level;
155 uint32_t addr_comp_value[16];
156 uint32_t addr_comp_access_type[16];
157 uint32_t cntr_reload_value[4];
158 uint32_t cntr_enable_event[4];
159 uint32_t cntr_reload_event[4];
160 uint32_t cntr_value[4];
161 uint32_t seq_state_12_event;
162 uint32_t seq_state_21_event;
163 uint32_t seq_state_23_event;
164 uint32_t seq_state_32_event;
165 uint32_t seq_state_13_event;
166 uint32_t seq_state_31_event;
167 uint32_t current_seq_state;
168 uint32_t ext_output_event[4];
169 uint32_t context_id_comp_value[3];
170 uint32_t context_id_comp_mask;
171 uint32_t sync_freq;
172 uint32_t extnd_ext_input_sel;
173 uint32_t ts_event;
174 uint32_t aux_control;
175 uint32_t coresight_trace_id;
176 uint32_t vmid_comp_value;
177};
178
179struct ptm_ctx {
180 struct ptm_config cfg;
181 void __iomem *base;
Pratik Patel7831c082011-06-08 21:44:37 -0700182 bool trace_enabled;
Pratik Patel7831c082011-06-08 21:44:37 -0700183 struct wake_lock wake_lock;
184 struct pm_qos_request_list qos_req;
185 atomic_t in_use;
186 struct device *dev;
Pratik Patel7831c082011-06-08 21:44:37 -0700187};
188
189static struct ptm_ctx ptm;
190
Pratik Patel7831c082011-06-08 21:44:37 -0700191
Pratik Patelcc320a42011-12-22 10:48:14 -0800192int qdss_clk_enable(void)
Pratik Patel7831c082011-06-08 21:44:37 -0700193{
194 int ret;
195
Pratik Patelcc320a42011-12-22 10:48:14 -0800196 struct msm_rpm_iv_pair iv;
197 iv.id = MSM_RPM_ID_QDSS_CLK;
198 iv.value = QDSS_CLK_ON_DBG;
199 ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, &iv, 1);
200 if (WARN(ret, "qdss clks not enabled (%d)\n", ret))
201 goto err_clk;
Pratik Patel7831c082011-06-08 21:44:37 -0700202
203 return 0;
204
Pratik Patelcc320a42011-12-22 10:48:14 -0800205err_clk:
Pratik Patel7831c082011-06-08 21:44:37 -0700206 return ret;
207}
208
Pratik Patelcc320a42011-12-22 10:48:14 -0800209void qdss_clk_disable(void)
Pratik Patel7831c082011-06-08 21:44:37 -0700210{
Pratik Patelcc320a42011-12-22 10:48:14 -0800211 int ret;
212 struct msm_rpm_iv_pair iv;
213
214 iv.id = MSM_RPM_ID_QDSS_CLK;
215 iv.value = QDSS_CLK_OFF;
216 ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, &iv, 1);
217 WARN(ret, "qdss clks not disabled (%d)\n", ret);
Pratik Patel7831c082011-06-08 21:44:37 -0700218}
219
Pratik Patel17f3b822011-11-21 12:41:47 -0800220/* ETM clock is derived from the processor clock and gets enabled on a
221 * logical OR of below items on Krait (pass2 onwards):
222 * 1.CPMR[ETMCLKEN] is 1
223 * 2.ETMCR[PD] is 0
224 * 3.ETMPDCR[PU] is 1
225 * 4.Reset is asserted (core or debug)
226 * 5.APB memory mapped requests (eg. EDAP access)
227 *
228 * 1., 2. and 3. above are permanent enables whereas 4. and 5. are temporary
229 * enables
230 *
231 * We rely on 5. to be able to access ETMCR and then use 2. above for ETM
232 * clock vote in the driver and the save-restore code uses 1. above
233 * for its vote
234 */
Pratik Patel7831c082011-06-08 21:44:37 -0700235static void ptm_set_powerdown(int cpu)
236{
237 uint32_t etmcr;
238
239 etmcr = ptm_readl(ptm, cpu, ETMCR);
240 etmcr |= BIT(0);
241 ptm_writel(ptm, cpu, etmcr, ETMCR);
242}
243
244static void ptm_clear_powerdown(int cpu)
245{
246 uint32_t etmcr;
247
248 etmcr = ptm_readl(ptm, cpu, ETMCR);
249 etmcr &= ~BIT(0);
250 ptm_writel(ptm, cpu, etmcr, ETMCR);
251}
252
253static void ptm_set_prog(int cpu)
254{
255 uint32_t etmcr;
256 int count;
257
258 etmcr = ptm_readl(ptm, cpu, ETMCR);
259 etmcr |= BIT(10);
260 ptm_writel(ptm, cpu, etmcr, ETMCR);
261
262 for (count = TIMEOUT_US; BVAL(ptm_readl(ptm, cpu, ETMSR), 1) != 1
263 && count > 0; count--)
264 udelay(1);
265 WARN(count == 0, "timeout while setting prog bit\n");
266}
267
268static void ptm_clear_prog(int cpu)
269{
270 uint32_t etmcr;
271 int count;
272
273 etmcr = ptm_readl(ptm, cpu, ETMCR);
274 etmcr &= ~BIT(10);
275 ptm_writel(ptm, cpu, etmcr, ETMCR);
276
277 for (count = TIMEOUT_US; BVAL(ptm_readl(ptm, cpu, ETMSR), 1) != 0
278 && count > 0; count--)
279 udelay(1);
280 WARN(count == 0, "timeout while clearing prog bit\n");
281}
282
Pratik Patel17f3b822011-11-21 12:41:47 -0800283static void __ptm_trace_enable(int cpu)
Pratik Patel7831c082011-06-08 21:44:37 -0700284{
Pratik Patel17f3b822011-11-21 12:41:47 -0800285 int i;
Pratik Patel7831c082011-06-08 21:44:37 -0700286
Pratik Patel17f3b822011-11-21 12:41:47 -0800287 PTM_UNLOCK(cpu);
288 /* Vote for ETM power/clock enable */
289 ptm_clear_powerdown(cpu);
290 ptm_set_prog(cpu);
Pratik Patel7831c082011-06-08 21:44:37 -0700291
Pratik Patel17f3b822011-11-21 12:41:47 -0800292 ptm_writel(ptm, cpu, ptm.cfg.main_control | BIT(10), ETMCR);
293 ptm_writel(ptm, cpu, ptm.cfg.trigger_event, ETMTRIGGER);
294 ptm_writel(ptm, cpu, ptm.cfg.te_start_stop_control, ETMTSSCR);
295 ptm_writel(ptm, cpu, ptm.cfg.te_event, ETMTEEVR);
296 ptm_writel(ptm, cpu, ptm.cfg.te_control, ETMTECR1);
297 ptm_writel(ptm, cpu, ptm.cfg.fifofull_level, ETMFFLR);
298 for (i = 0; i < ptm.cfg.nr_addr_comp; i++) {
299 ptm_writel(ptm, cpu, ptm.cfg.addr_comp_value[i], ETMACVRn(i));
300 ptm_writel(ptm, cpu, ptm.cfg.addr_comp_access_type[i],
Pratik Patel7831c082011-06-08 21:44:37 -0700301 ETMACTRn(i));
Pratik Patel7831c082011-06-08 21:44:37 -0700302 }
Pratik Patel17f3b822011-11-21 12:41:47 -0800303 for (i = 0; i < ptm.cfg.nr_cntr; i++) {
304 ptm_writel(ptm, cpu, ptm.cfg.cntr_reload_value[i],
305 ETMCNTRLDVRn(i));
306 ptm_writel(ptm, cpu, ptm.cfg.cntr_enable_event[i],
307 ETMCNTENRn(i));
308 ptm_writel(ptm, cpu, ptm.cfg.cntr_reload_event[i],
309 ETMCNTRLDEVRn(i));
310 ptm_writel(ptm, cpu, ptm.cfg.cntr_value[i], ETMCNTVRn(i));
311 }
312 ptm_writel(ptm, cpu, ptm.cfg.seq_state_12_event, ETMSQ12EVR);
313 ptm_writel(ptm, cpu, ptm.cfg.seq_state_21_event, ETMSQ21EVR);
314 ptm_writel(ptm, cpu, ptm.cfg.seq_state_23_event, ETMSQ23EVR);
315 ptm_writel(ptm, cpu, ptm.cfg.seq_state_32_event, ETMSQ32EVR);
316 ptm_writel(ptm, cpu, ptm.cfg.seq_state_13_event, ETMSQ13EVR);
317 ptm_writel(ptm, cpu, ptm.cfg.seq_state_31_event, ETMSQ31EVR);
318 ptm_writel(ptm, cpu, ptm.cfg.current_seq_state, ETMSQR);
319 for (i = 0; i < ptm.cfg.nr_ext_output; i++)
320 ptm_writel(ptm, cpu, ptm.cfg.ext_output_event[i],
321 ETMEXTOUTEVRn(i));
322 for (i = 0; i < ptm.cfg.nr_context_id_comp; i++)
323 ptm_writel(ptm, cpu, ptm.cfg.context_id_comp_value[i],
324 ETMCIDCVRn(i));
325 ptm_writel(ptm, cpu, ptm.cfg.context_id_comp_mask, ETMCIDCMR);
326 ptm_writel(ptm, cpu, ptm.cfg.sync_freq, ETMSYNCFR);
327 ptm_writel(ptm, cpu, ptm.cfg.extnd_ext_input_sel, ETMEXTINSELR);
328 ptm_writel(ptm, cpu, ptm.cfg.ts_event, ETMTSEVR);
329 ptm_writel(ptm, cpu, ptm.cfg.aux_control, ETMAUXCR);
330 ptm_writel(ptm, cpu, cpu+1, ETMTRACEIDR);
331 ptm_writel(ptm, cpu, ptm.cfg.vmid_comp_value, ETMVMIDCVR);
332
333 ptm_clear_prog(cpu);
334 PTM_LOCK(cpu);
Pratik Patel7831c082011-06-08 21:44:37 -0700335}
336
337static int ptm_trace_enable(void)
338{
Pratik Patel17f3b822011-11-21 12:41:47 -0800339 int ret, cpu;
Pratik Patel7831c082011-06-08 21:44:37 -0700340
Pratik Patelcc320a42011-12-22 10:48:14 -0800341 ret = qdss_clk_enable();
Pratik Patel7831c082011-06-08 21:44:37 -0700342 if (ret)
343 return ret;
344
345 wake_lock(&ptm.wake_lock);
Pratik Patele5771792011-09-17 18:33:54 -0700346 /* 1. causes all online cpus to come out of idle PC
Pratik Patel7831c082011-06-08 21:44:37 -0700347 * 2. prevents idle PC until save restore flag is enabled atomically
Pratik Patele5771792011-09-17 18:33:54 -0700348 *
349 * we rely on the user to prevent hotplug on/off racing with this
350 * operation and to ensure cores where trace is expected to be turned
351 * on are already hotplugged on
Pratik Patel7831c082011-06-08 21:44:37 -0700352 */
353 pm_qos_update_request(&ptm.qos_req, 0);
354
355 etb_disable();
356 tpiu_disable();
357 /* enable ETB first to avoid loosing any trace data */
358 etb_enable();
359 funnel_enable(0x0, 0x3);
Pratik Patel17f3b822011-11-21 12:41:47 -0800360 for_each_online_cpu(cpu)
361 __ptm_trace_enable(cpu);
Pratik Patel7831c082011-06-08 21:44:37 -0700362
363 ptm.trace_enabled = true;
364
365 pm_qos_update_request(&ptm.qos_req, PM_QOS_DEFAULT_VALUE);
366 wake_unlock(&ptm.wake_lock);
367
368 return 0;
369}
370
Pratik Patel17f3b822011-11-21 12:41:47 -0800371static void __ptm_trace_disable(int cpu)
Pratik Patel7831c082011-06-08 21:44:37 -0700372{
Pratik Patel17f3b822011-11-21 12:41:47 -0800373 PTM_UNLOCK(cpu);
374 ptm_set_prog(cpu);
Pratik Patel7831c082011-06-08 21:44:37 -0700375
Pratik Patel17f3b822011-11-21 12:41:47 -0800376 /* program trace enable to low by using always false event */
377 ptm_writel(ptm, cpu, 0x6F | BIT(14), ETMTEEVR);
Pratik Patel7831c082011-06-08 21:44:37 -0700378
Pratik Patel17f3b822011-11-21 12:41:47 -0800379 /* Vote for ETM power/clock disable */
380 ptm_set_powerdown(cpu);
381 PTM_LOCK(cpu);
Pratik Patel7831c082011-06-08 21:44:37 -0700382}
383
384static void ptm_trace_disable(void)
385{
Pratik Patel17f3b822011-11-21 12:41:47 -0800386 int cpu;
387
Pratik Patel7831c082011-06-08 21:44:37 -0700388 wake_lock(&ptm.wake_lock);
Pratik Patele5771792011-09-17 18:33:54 -0700389 /* 1. causes all online cpus to come out of idle PC
Pratik Patel7831c082011-06-08 21:44:37 -0700390 * 2. prevents idle PC until save restore flag is disabled atomically
Pratik Patele5771792011-09-17 18:33:54 -0700391 *
392 * we rely on the user to prevent hotplug on/off racing with this
393 * operation and to ensure cores where trace is expected to be turned
394 * off are already hotplugged on
Pratik Patel7831c082011-06-08 21:44:37 -0700395 */
396 pm_qos_update_request(&ptm.qos_req, 0);
397
Pratik Patel17f3b822011-11-21 12:41:47 -0800398 for_each_online_cpu(cpu)
399 __ptm_trace_disable(cpu);
Pratik Patel7831c082011-06-08 21:44:37 -0700400 etb_dump();
401 etb_disable();
402 funnel_disable(0x0, 0x3);
403
404 ptm.trace_enabled = false;
405
Pratik Patel7831c082011-06-08 21:44:37 -0700406 pm_qos_update_request(&ptm.qos_req, PM_QOS_DEFAULT_VALUE);
407 wake_unlock(&ptm.wake_lock);
408
Pratik Patelcc320a42011-12-22 10:48:14 -0800409 qdss_clk_disable();
Pratik Patel7831c082011-06-08 21:44:37 -0700410}
411
412static int ptm_open(struct inode *inode, struct file *file)
413{
414 if (atomic_cmpxchg(&ptm.in_use, 0, 1))
415 return -EBUSY;
416
417 dev_dbg(ptm.dev, "%s: successfully opened\n", __func__);
418 return 0;
419}
420
421static void ptm_range_filter(char range, uint32_t reg1,
422 uint32_t addr1, uint32_t reg2, uint32_t addr2)
423{
424 ptm.cfg.addr_comp_value[reg1] = addr1;
425 ptm.cfg.addr_comp_value[reg2] = addr2;
426
427 ptm.cfg.te_control |= (1 << (reg1/2));
428 if (range == 'i')
429 ptm.cfg.te_control &= ~BIT(24);
430 else if (range == 'e')
431 ptm.cfg.te_control |= BIT(24);
432}
433
434static void ptm_start_stop_filter(char start_stop,
435 uint32_t reg, uint32_t addr)
436{
437 ptm.cfg.addr_comp_value[reg] = addr;
438
439 if (start_stop == 's')
440 ptm.cfg.te_start_stop_control |= (1 << reg);
441 else if (start_stop == 't')
442 ptm.cfg.te_start_stop_control |= (1 << (reg + 16));
443
444 ptm.cfg.te_control |= BIT(25);
445}
446
447#define MAX_COMMAND_STRLEN 40
448static ssize_t ptm_write(struct file *file, const char __user *data,
449 size_t len, loff_t *ppos)
450{
451 char command[MAX_COMMAND_STRLEN];
452 int str_len;
453 unsigned long reg1, reg2;
454 unsigned long addr1, addr2;
455
456 str_len = strnlen_user(data, MAX_COMMAND_STRLEN);
457 dev_dbg(ptm.dev, "string length: %d", str_len);
458 if (str_len == 0 || str_len == (MAX_COMMAND_STRLEN+1)) {
459 dev_err(ptm.dev, "error in str_len: %d", str_len);
460 return -EFAULT;
461 }
462 /* includes the null character */
463 if (copy_from_user(command, data, str_len)) {
464 dev_err(ptm.dev, "error in copy_from_user: %d", str_len);
465 return -EFAULT;
466 }
467
468 dev_dbg(ptm.dev, "input = %s", command);
469
470 switch (command[0]) {
471 case '0':
472 if (ptm.trace_enabled) {
473 ptm_trace_disable();
474 dev_info(ptm.dev, "tracing disabled\n");
475 } else
476 dev_err(ptm.dev, "trace already disabled\n");
477
478 break;
479 case '1':
480 if (!ptm.trace_enabled) {
481 if (!ptm_trace_enable())
482 dev_info(ptm.dev, "tracing enabled\n");
483 else
484 dev_err(ptm.dev, "error enabling trace\n");
485 } else
486 dev_err(ptm.dev, "trace already enabled\n");
487 break;
488 case 'f':
489 switch (command[2]) {
490 case 'i':
491 switch (command[4]) {
492 case 'i':
493 if (sscanf(&command[6], "%lx:%lx:%lx:%lx\\0",
494 &reg1, &addr1, &reg2, &addr2) != 4)
495 goto err_out;
496 if (reg1 > 7 || reg2 > 7 || (reg1 % 2))
497 goto err_out;
498 ptm_range_filter('i',
499 reg1, addr1, reg2, addr2);
500 break;
501 case 'e':
502 if (sscanf(&command[6], "%lx:%lx:%lx:%lx\\0",
503 &reg1, &addr1, &reg2, &addr2) != 4)
504 goto err_out;
505 if (reg1 > 7 || reg2 > 7 || (reg1 % 2)
506 || command[2] == 'd')
507 goto err_out;
508 ptm_range_filter('e',
509 reg1, addr1, reg2, addr2);
510 break;
511 case 's':
512 if (sscanf(&command[6], "%lx:%lx\\0",
513 &reg1, &addr1) != 2)
514 goto err_out;
515 if (reg1 > 7)
516 goto err_out;
517 ptm_start_stop_filter('s', reg1, addr1);
518 break;
519 case 't':
520 if (sscanf(&command[6], "%lx:%lx\\0",
521 &reg1, &addr1) != 2)
522 goto err_out;
523 if (reg1 > 7)
524 goto err_out;
525 ptm_start_stop_filter('t', reg1, addr1);
526 break;
527 default:
528 goto err_out;
529 }
530 break;
531 case 'r':
532 ptm_cfg_rw_init();
533 break;
534 default:
535 goto err_out;
536 }
537 break;
538 default:
539 goto err_out;
540 }
541
542 return len;
543
544err_out:
545 return -EFAULT;
546}
547
548static int ptm_release(struct inode *inode, struct file *file)
549{
550 atomic_set(&ptm.in_use, 0);
551 dev_dbg(ptm.dev, "%s: released\n", __func__);
552 return 0;
553}
554
555static const struct file_operations ptm_fops = {
556 .owner = THIS_MODULE,
557 .open = ptm_open,
558 .write = ptm_write,
559 .release = ptm_release,
560};
561
562static struct miscdevice ptm_misc = {
563 .name = "msm_ptm",
564 .minor = MISC_DYNAMIC_MINOR,
565 .fops = &ptm_fops,
566};
567
Pratik Patel7831c082011-06-08 21:44:37 -0700568static void ptm_cfg_rw_init(void)
569{
570 int i;
571
572 ptm.cfg.main_control = 0x00001000;
573 ptm.cfg.trigger_event = 0x0000406F;
574 ptm.cfg.te_start_stop_control = 0x00000000;
575 ptm.cfg.te_event = 0x0000006F;
576 ptm.cfg.te_control = 0x01000000;
577 ptm.cfg.fifofull_level = 0x00000028;
578 for (i = 0; i < ptm.cfg.nr_addr_comp; i++) {
579 ptm.cfg.addr_comp_value[i] = 0x00000000;
580 ptm.cfg.addr_comp_access_type[i] = 0x00000000;
581 }
582 for (i = 0; i < ptm.cfg.nr_cntr; i++) {
583 ptm.cfg.cntr_reload_value[i] = 0x00000000;
584 ptm.cfg.cntr_enable_event[i] = 0x0000406F;
585 ptm.cfg.cntr_reload_event[i] = 0x0000406F;
586 ptm.cfg.cntr_value[i] = 0x00000000;
587 }
588 ptm.cfg.seq_state_12_event = 0x0000406F;
589 ptm.cfg.seq_state_21_event = 0x0000406F;
590 ptm.cfg.seq_state_23_event = 0x0000406F;
591 ptm.cfg.seq_state_32_event = 0x0000406F;
592 ptm.cfg.seq_state_13_event = 0x0000406F;
593 ptm.cfg.seq_state_31_event = 0x0000406F;
594 ptm.cfg.current_seq_state = 0x00000000;
595 for (i = 0; i < ptm.cfg.nr_ext_output; i++)
596 ptm.cfg.ext_output_event[i] = 0x0000406F;
597 for (i = 0; i < ptm.cfg.nr_context_id_comp; i++)
598 ptm.cfg.context_id_comp_value[i] = 0x00000000;
599 ptm.cfg.context_id_comp_mask = 0x00000000;
600 ptm.cfg.sync_freq = 0x00000080;
601 ptm.cfg.extnd_ext_input_sel = 0x00000000;
602 ptm.cfg.ts_event = 0x0000406F;
603 ptm.cfg.aux_control = 0x00000000;
604 ptm.cfg.vmid_comp_value = 0x00000000;
605}
606
Pratik Patel17f3b822011-11-21 12:41:47 -0800607/* Memory mapped writes to clear os lock not supported */
608static void ptm_os_unlock(void *unused)
609{
610 unsigned long value = 0x0;
611
612 asm("mcr p14, 1, %0, c1, c0, 4\n\t" : : "r" (value));
613 asm("isb\n\t");
614}
615
Pratik Patel7831c082011-06-08 21:44:37 -0700616static void ptm_cfg_ro_init(void)
617{
618 /* use cpu 0 for setup */
619 int cpu = 0;
620
Pratik Patel17f3b822011-11-21 12:41:47 -0800621 /* Unlock OS lock first to allow memory mapped reads and writes */
Pratik Patel7831c082011-06-08 21:44:37 -0700622 ptm_os_unlock(NULL);
623 smp_call_function(ptm_os_unlock, NULL, 1);
624 PTM_UNLOCK(cpu);
Pratik Patel17f3b822011-11-21 12:41:47 -0800625 /* Vote for ETM power/clock enable */
Pratik Patel7831c082011-06-08 21:44:37 -0700626 ptm_clear_powerdown(cpu);
627 ptm_set_prog(cpu);
628
629 /* find all capabilities */
630 ptm.cfg.config_code = ptm_readl(ptm, cpu, ETMCCR);
631 ptm.cfg.nr_addr_comp = BMVAL(ptm.cfg.config_code, 0, 3) * 2;
632 ptm.cfg.nr_cntr = BMVAL(ptm.cfg.config_code, 13, 15);
633 ptm.cfg.nr_ext_input = BMVAL(ptm.cfg.config_code, 17, 19);
634 ptm.cfg.nr_ext_output = BMVAL(ptm.cfg.config_code, 20, 22);
635 ptm.cfg.nr_context_id_comp = BMVAL(ptm.cfg.config_code, 24, 25);
636
637 ptm.cfg.config_code_extn = ptm_readl(ptm, cpu, ETMCCER);
638 ptm.cfg.nr_extnd_ext_input_sel =
639 BMVAL(ptm.cfg.config_code_extn, 0, 2);
640 ptm.cfg.nr_instr_resources = BMVAL(ptm.cfg.config_code_extn, 13, 15);
641
642 ptm.cfg.system_config = ptm_readl(ptm, cpu, ETMSCR);
643 ptm.cfg.fifofull_supported = BVAL(ptm.cfg.system_config, 8);
644 ptm.cfg.nr_procs_supported = BMVAL(ptm.cfg.system_config, 12, 14);
645
Pratik Patel17f3b822011-11-21 12:41:47 -0800646 /* Vote for ETM power/clock disable */
Pratik Patel7831c082011-06-08 21:44:37 -0700647 ptm_set_powerdown(cpu);
648 PTM_LOCK(cpu);
649}
650
651static int __devinit ptm_probe(struct platform_device *pdev)
652{
Pratik Patele5771792011-09-17 18:33:54 -0700653 int ret;
Pratik Patel7831c082011-06-08 21:44:37 -0700654 struct resource *res;
655
656 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
657 if (!res) {
658 ret = -EINVAL;
659 goto err_res;
660 }
661
662 ptm.base = ioremap_nocache(res->start, resource_size(res));
663 if (!ptm.base) {
664 ret = -EINVAL;
665 goto err_ioremap;
666 }
667
668 ptm.dev = &pdev->dev;
669
Pratik Patel7831c082011-06-08 21:44:37 -0700670 ret = misc_register(&ptm_misc);
671 if (ret)
672 goto err_misc;
673
Pratik Patelcc320a42011-12-22 10:48:14 -0800674 ret = qdss_clk_enable();
Pratik Patel7831c082011-06-08 21:44:37 -0700675 if (ret)
Pratik Patelcc320a42011-12-22 10:48:14 -0800676 goto err_clk;
Pratik Patel7831c082011-06-08 21:44:37 -0700677
678 ptm_cfg_ro_init();
679 ptm_cfg_rw_init();
680
681 ptm.trace_enabled = false;
682
Pratik Patel7831c082011-06-08 21:44:37 -0700683 wake_lock_init(&ptm.wake_lock, WAKE_LOCK_SUSPEND, "msm_ptm");
684 pm_qos_add_request(&ptm.qos_req, PM_QOS_CPU_DMA_LATENCY,
685 PM_QOS_DEFAULT_VALUE);
686 atomic_set(&ptm.in_use, 0);
687
Pratik Patelcc320a42011-12-22 10:48:14 -0800688 qdss_clk_disable();
Pratik Patel7831c082011-06-08 21:44:37 -0700689
690 dev_info(ptm.dev, "PTM intialized.\n");
691
692 if (trace_on_boot) {
693 if (!ptm_trace_enable())
694 dev_info(ptm.dev, "tracing enabled\n");
695 else
696 dev_err(ptm.dev, "error enabling trace\n");
697 }
698
699 return 0;
700
Pratik Patelcc320a42011-12-22 10:48:14 -0800701err_clk:
Pratik Patel7831c082011-06-08 21:44:37 -0700702 misc_deregister(&ptm_misc);
703err_misc:
Pratik Patel7831c082011-06-08 21:44:37 -0700704 iounmap(ptm.base);
705err_ioremap:
706err_res:
707 return ret;
708}
709
710static int __devexit ptm_remove(struct platform_device *pdev)
711{
712 if (ptm.trace_enabled)
713 ptm_trace_disable();
714 pm_qos_remove_request(&ptm.qos_req);
715 wake_lock_destroy(&ptm.wake_lock);
Pratik Patel7831c082011-06-08 21:44:37 -0700716 misc_deregister(&ptm_misc);
Pratik Patel7831c082011-06-08 21:44:37 -0700717 iounmap(ptm.base);
718
719 return 0;
720}
721
722static struct platform_driver ptm_driver = {
723 .probe = ptm_probe,
724 .remove = __devexit_p(ptm_remove),
725 .driver = {
726 .name = "msm_ptm",
727 },
728};
729
730static int __init ptm_init(void)
731{
732 return platform_driver_register(&ptm_driver);
733}
734module_init(ptm_init);
735
736static void __exit ptm_exit(void)
737{
738 platform_driver_unregister(&ptm_driver);
739}
740module_exit(ptm_exit);
741
742MODULE_LICENSE("GPL v2");
743MODULE_DESCRIPTION("Coresight Program Flow Trace driver");