blob: 9c31f0f584e3b6e9ad4413e4cb677d527345b7e8 [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>
30
31#include "qdss.h"
32
Pratik Patel492b3012012-03-06 14:22:30 -080033#define etm_writel(etm, cpu, val, off) \
34 __raw_writel((val), etm.base + (SZ_4K * cpu) + off)
35#define etm_readl(etm, cpu, off) \
36 __raw_readl(etm.base + (SZ_4K * cpu) + off)
Pratik Patel7831c082011-06-08 21:44:37 -070037
38/*
39 * Device registers:
40 * 0x000 - 0x2FC: Trace registers
41 * 0x300 - 0x314: Management registers
42 * 0x318 - 0xEFC: Trace registers
43 *
44 * Coresight registers
45 * 0xF00 - 0xF9C: Management registers
46 * 0xFA0 - 0xFA4: Management registers in PFTv1.0
47 * Trace registers in PFTv1.1
48 * 0xFA8 - 0xFFC: Management registers
49 */
50
51/* Trace registers (0x000-0x2FC) */
52#define ETMCR (0x000)
53#define ETMCCR (0x004)
54#define ETMTRIGGER (0x008)
55#define ETMSR (0x010)
56#define ETMSCR (0x014)
57#define ETMTSSCR (0x018)
58#define ETMTEEVR (0x020)
59#define ETMTECR1 (0x024)
60#define ETMFFLR (0x02C)
61#define ETMACVRn(n) (0x040 + (n * 4))
62#define ETMACTRn(n) (0x080 + (n * 4))
63#define ETMCNTRLDVRn(n) (0x140 + (n * 4))
64#define ETMCNTENRn(n) (0x150 + (n * 4))
65#define ETMCNTRLDEVRn(n) (0x160 + (n * 4))
66#define ETMCNTVRn(n) (0x170 + (n * 4))
67#define ETMSQ12EVR (0x180)
68#define ETMSQ21EVR (0x184)
69#define ETMSQ23EVR (0x188)
Pratik Pateld5bbc762012-01-29 14:13:21 -080070#define ETMSQ31EVR (0x18C)
71#define ETMSQ32EVR (0x190)
72#define ETMSQ13EVR (0x194)
Pratik Patel7831c082011-06-08 21:44:37 -070073#define ETMSQR (0x19C)
74#define ETMEXTOUTEVRn(n) (0x1A0 + (n * 4))
75#define ETMCIDCVRn(n) (0x1B0 + (n * 4))
76#define ETMCIDCMR (0x1BC)
77#define ETMIMPSPEC0 (0x1C0)
78#define ETMIMPSPEC1 (0x1C4)
79#define ETMIMPSPEC2 (0x1C8)
80#define ETMIMPSPEC3 (0x1CC)
81#define ETMIMPSPEC4 (0x1D0)
82#define ETMIMPSPEC5 (0x1D4)
83#define ETMIMPSPEC6 (0x1D8)
84#define ETMIMPSPEC7 (0x1DC)
85#define ETMSYNCFR (0x1E0)
86#define ETMIDR (0x1E4)
87#define ETMCCER (0x1E8)
88#define ETMEXTINSELR (0x1EC)
89#define ETMTESSEICR (0x1F0)
90#define ETMEIBCR (0x1F4)
91#define ETMTSEVR (0x1F8)
92#define ETMAUXCR (0x1FC)
93#define ETMTRACEIDR (0x200)
Pratik Pateld5bbc762012-01-29 14:13:21 -080094#define ETMVMIDCVR (0x240)
Pratik Patel7831c082011-06-08 21:44:37 -070095/* Management registers (0x300-0x314) */
96#define ETMOSLAR (0x300)
97#define ETMOSLSR (0x304)
98#define ETMOSSRR (0x308)
99#define ETMPDCR (0x310)
100#define ETMPDSR (0x314)
101
Pratik Patel61de7302012-03-07 12:06:10 -0800102#define ETM_MAX_ADDR_CMP (16)
103#define ETM_MAX_CNTR (4)
104#define ETM_MAX_CTXID_CMP (3)
105
Pratik Patel492b3012012-03-06 14:22:30 -0800106#define ETM_LOCK(cpu) \
Pratik Patel7831c082011-06-08 21:44:37 -0700107do { \
108 mb(); \
Pratik Patel492b3012012-03-06 14:22:30 -0800109 etm_writel(etm, cpu, 0x0, CS_LAR); \
Pratik Patel7831c082011-06-08 21:44:37 -0700110} while (0)
Pratik Patel492b3012012-03-06 14:22:30 -0800111#define ETM_UNLOCK(cpu) \
Pratik Patel7831c082011-06-08 21:44:37 -0700112do { \
Pratik Patel492b3012012-03-06 14:22:30 -0800113 etm_writel(etm, cpu, CS_UNLOCK_MAGIC, CS_LAR); \
Pratik Patel7831c082011-06-08 21:44:37 -0700114 mb(); \
115} while (0)
116
Pratik Patel7831c082011-06-08 21:44:37 -0700117
Pratik Patel29cba152012-01-03 11:40:26 -0800118#ifdef CONFIG_MSM_QDSS_ETM_DEFAULT_ENABLE
Pratik Patel61de7302012-03-07 12:06:10 -0800119static int etm_boot_enable = 1;
Pratik Patel29cba152012-01-03 11:40:26 -0800120#else
Pratik Patel61de7302012-03-07 12:06:10 -0800121static int etm_boot_enable;
Pratik Patel29cba152012-01-03 11:40:26 -0800122#endif
Pratik Patel7831c082011-06-08 21:44:37 -0700123module_param_named(
Pratik Patel61de7302012-03-07 12:06:10 -0800124 etm_boot_enable, etm_boot_enable, int, S_IRUGO
Pratik Patel7831c082011-06-08 21:44:37 -0700125);
126
Pratik Patel492b3012012-03-06 14:22:30 -0800127struct etm_ctx {
Pratik Patel7831c082011-06-08 21:44:37 -0700128 void __iomem *base;
Pratik Patel61de7302012-03-07 12:06:10 -0800129 bool enabled;
Pratik Patel7831c082011-06-08 21:44:37 -0700130 struct wake_lock wake_lock;
131 struct pm_qos_request_list qos_req;
132 atomic_t in_use;
133 struct device *dev;
Pratik Patel61de7302012-03-07 12:06:10 -0800134 uint8_t arch;
135 uint8_t nr_addr_cmp;
136 uint8_t nr_cntr;
137 uint8_t nr_ext_inp;
138 uint8_t nr_ext_out;
139 uint8_t nr_ctxid_cmp;
140 uint32_t ctrl;
141 uint32_t trigger_event;
142 uint32_t startstop_ctrl;
143 uint32_t enable_event;
144 uint32_t enable_ctrl1;
145 uint32_t fifofull_level;
146 uint32_t addr_val[ETM_MAX_ADDR_CMP];
147 uint32_t addr_acctype[ETM_MAX_ADDR_CMP];
148 uint32_t cntr_rld_val[ETM_MAX_CNTR];
149 uint32_t cntr_event[ETM_MAX_CNTR];
150 uint32_t cntr_rld_event[ETM_MAX_CNTR];
151 uint32_t cntr_val[ETM_MAX_CNTR];
152 uint32_t seq_12_event;
153 uint32_t seq_21_event;
154 uint32_t seq_23_event;
155 uint32_t seq_31_event;
156 uint32_t seq_32_event;
157 uint32_t seq_13_event;
158 uint32_t seq_curr_state;
159 uint32_t ctxid_val[ETM_MAX_CTXID_CMP];
160 uint32_t ctxid_mask;
161 uint32_t sync_freq;
162 uint32_t timestamp_event;
Pratik Patel7831c082011-06-08 21:44:37 -0700163};
164
Pratik Patel61de7302012-03-07 12:06:10 -0800165static struct etm_ctx etm = {
166 .ctrl = 0x1000,
167 .trigger_event = 0x406F,
168 .enable_event = 0x6F,
169 .enable_ctrl1 = 0x1000000,
170 .fifofull_level = 0x28,
171 .cntr_event = {[0 ... (ETM_MAX_CNTR - 1)] = 0x406F},
172 .cntr_rld_event = {[0 ... (ETM_MAX_CNTR - 1)] = 0x406F},
173 .seq_12_event = 0x406F,
174 .seq_21_event = 0x406F,
175 .seq_23_event = 0x406F,
176 .seq_31_event = 0x406F,
177 .seq_32_event = 0x406F,
178 .seq_13_event = 0x406F,
179 .sync_freq = 0x80,
180 .timestamp_event = 0x406F,
181};
Pratik Patel7831c082011-06-08 21:44:37 -0700182
Pratik Patel7831c082011-06-08 21:44:37 -0700183
Pratik Patel17f3b822011-11-21 12:41:47 -0800184/* ETM clock is derived from the processor clock and gets enabled on a
185 * logical OR of below items on Krait (pass2 onwards):
186 * 1.CPMR[ETMCLKEN] is 1
187 * 2.ETMCR[PD] is 0
188 * 3.ETMPDCR[PU] is 1
189 * 4.Reset is asserted (core or debug)
190 * 5.APB memory mapped requests (eg. EDAP access)
191 *
192 * 1., 2. and 3. above are permanent enables whereas 4. and 5. are temporary
193 * enables
194 *
195 * We rely on 5. to be able to access ETMCR and then use 2. above for ETM
196 * clock vote in the driver and the save-restore code uses 1. above
197 * for its vote
198 */
Pratik Patel61de7302012-03-07 12:06:10 -0800199static void etm_set_pwrdwn(int cpu)
Pratik Patel7831c082011-06-08 21:44:37 -0700200{
201 uint32_t etmcr;
202
Pratik Patel492b3012012-03-06 14:22:30 -0800203 etmcr = etm_readl(etm, cpu, ETMCR);
Pratik Patel7831c082011-06-08 21:44:37 -0700204 etmcr |= BIT(0);
Pratik Patel492b3012012-03-06 14:22:30 -0800205 etm_writel(etm, cpu, etmcr, ETMCR);
Pratik Patel7831c082011-06-08 21:44:37 -0700206}
207
Pratik Patel61de7302012-03-07 12:06:10 -0800208static void etm_clr_pwrdwn(int cpu)
Pratik Patel7831c082011-06-08 21:44:37 -0700209{
210 uint32_t etmcr;
211
Pratik Patel492b3012012-03-06 14:22:30 -0800212 etmcr = etm_readl(etm, cpu, ETMCR);
Pratik Patel7831c082011-06-08 21:44:37 -0700213 etmcr &= ~BIT(0);
Pratik Patel492b3012012-03-06 14:22:30 -0800214 etm_writel(etm, cpu, etmcr, ETMCR);
Pratik Patel7831c082011-06-08 21:44:37 -0700215}
216
Pratik Patel492b3012012-03-06 14:22:30 -0800217static void etm_set_prog(int cpu)
Pratik Patel7831c082011-06-08 21:44:37 -0700218{
219 uint32_t etmcr;
220 int count;
221
Pratik Patel492b3012012-03-06 14:22:30 -0800222 etmcr = etm_readl(etm, cpu, ETMCR);
Pratik Patel7831c082011-06-08 21:44:37 -0700223 etmcr |= BIT(10);
Pratik Patel492b3012012-03-06 14:22:30 -0800224 etm_writel(etm, cpu, etmcr, ETMCR);
Pratik Patel7831c082011-06-08 21:44:37 -0700225
Pratik Patel492b3012012-03-06 14:22:30 -0800226 for (count = TIMEOUT_US; BVAL(etm_readl(etm, cpu, ETMSR), 1) != 1
Pratik Patel7831c082011-06-08 21:44:37 -0700227 && count > 0; count--)
228 udelay(1);
Pratik Patel61de7302012-03-07 12:06:10 -0800229 WARN(count == 0, "timeout while setting prog bit, ETMSR: %#x\n",
230 etm_readl(etm, cpu, ETMSR));
Pratik Patel7831c082011-06-08 21:44:37 -0700231}
232
Pratik Patel61de7302012-03-07 12:06:10 -0800233static void etm_clr_prog(int cpu)
Pratik Patel7831c082011-06-08 21:44:37 -0700234{
235 uint32_t etmcr;
236 int count;
237
Pratik Patel492b3012012-03-06 14:22:30 -0800238 etmcr = etm_readl(etm, cpu, ETMCR);
Pratik Patel7831c082011-06-08 21:44:37 -0700239 etmcr &= ~BIT(10);
Pratik Patel492b3012012-03-06 14:22:30 -0800240 etm_writel(etm, cpu, etmcr, ETMCR);
Pratik Patel7831c082011-06-08 21:44:37 -0700241
Pratik Patel492b3012012-03-06 14:22:30 -0800242 for (count = TIMEOUT_US; BVAL(etm_readl(etm, cpu, ETMSR), 1) != 0
Pratik Patel7831c082011-06-08 21:44:37 -0700243 && count > 0; count--)
244 udelay(1);
Pratik Patel61de7302012-03-07 12:06:10 -0800245 WARN(count == 0, "timeout while clearing prog bit, ETMSR: %#x\n",
246 etm_readl(etm, cpu, ETMSR));
Pratik Patel7831c082011-06-08 21:44:37 -0700247}
248
Pratik Patel61de7302012-03-07 12:06:10 -0800249static void __etm_enable(int cpu)
Pratik Patel7831c082011-06-08 21:44:37 -0700250{
Pratik Patel17f3b822011-11-21 12:41:47 -0800251 int i;
Pratik Patel7831c082011-06-08 21:44:37 -0700252
Pratik Patel492b3012012-03-06 14:22:30 -0800253 ETM_UNLOCK(cpu);
Pratik Patel17f3b822011-11-21 12:41:47 -0800254 /* Vote for ETM power/clock enable */
Pratik Patel61de7302012-03-07 12:06:10 -0800255 etm_clr_pwrdwn(cpu);
Pratik Patel492b3012012-03-06 14:22:30 -0800256 etm_set_prog(cpu);
Pratik Patel7831c082011-06-08 21:44:37 -0700257
Pratik Patel61de7302012-03-07 12:06:10 -0800258 etm_writel(etm, cpu, etm.ctrl | BIT(10), ETMCR);
259 etm_writel(etm, cpu, etm.trigger_event, ETMTRIGGER);
260 etm_writel(etm, cpu, etm.startstop_ctrl, ETMTSSCR);
261 etm_writel(etm, cpu, etm.enable_event, ETMTEEVR);
262 etm_writel(etm, cpu, etm.enable_ctrl1, ETMTECR1);
263 etm_writel(etm, cpu, etm.fifofull_level, ETMFFLR);
264 for (i = 0; i < etm.nr_addr_cmp; i++) {
265 etm_writel(etm, cpu, etm.addr_val[i], ETMACVRn(i));
266 etm_writel(etm, cpu, etm.addr_acctype[i], ETMACTRn(i));
Pratik Patel7831c082011-06-08 21:44:37 -0700267 }
Pratik Patel61de7302012-03-07 12:06:10 -0800268 for (i = 0; i < etm.nr_cntr; i++) {
269 etm_writel(etm, cpu, etm.cntr_rld_val[i], ETMCNTRLDVRn(i));
270 etm_writel(etm, cpu, etm.cntr_event[i], ETMCNTENRn(i));
271 etm_writel(etm, cpu, etm.cntr_rld_event[i], ETMCNTRLDEVRn(i));
272 etm_writel(etm, cpu, etm.cntr_val[i], ETMCNTVRn(i));
Pratik Patel17f3b822011-11-21 12:41:47 -0800273 }
Pratik Patel61de7302012-03-07 12:06:10 -0800274 etm_writel(etm, cpu, etm.seq_12_event, ETMSQ12EVR);
275 etm_writel(etm, cpu, etm.seq_21_event, ETMSQ21EVR);
276 etm_writel(etm, cpu, etm.seq_23_event, ETMSQ23EVR);
277 etm_writel(etm, cpu, etm.seq_31_event, ETMSQ31EVR);
278 etm_writel(etm, cpu, etm.seq_32_event, ETMSQ32EVR);
279 etm_writel(etm, cpu, etm.seq_13_event, ETMSQ13EVR);
280 etm_writel(etm, cpu, etm.seq_curr_state, ETMSQR);
281 for (i = 0; i < etm.nr_ext_out; i++)
282 etm_writel(etm, cpu, 0x0000406F, ETMEXTOUTEVRn(i));
283 for (i = 0; i < etm.nr_ctxid_cmp; i++)
284 etm_writel(etm, cpu, etm.ctxid_val[i], ETMCIDCVRn(i));
285 etm_writel(etm, cpu, etm.ctxid_mask, ETMCIDCMR);
286 etm_writel(etm, cpu, etm.sync_freq, ETMSYNCFR);
287 etm_writel(etm, cpu, 0x00000000, ETMEXTINSELR);
288 etm_writel(etm, cpu, etm.timestamp_event, ETMTSEVR);
289 etm_writel(etm, cpu, 0x00000000, ETMAUXCR);
Pratik Patel492b3012012-03-06 14:22:30 -0800290 etm_writel(etm, cpu, cpu+1, ETMTRACEIDR);
Pratik Patel61de7302012-03-07 12:06:10 -0800291 etm_writel(etm, cpu, 0x00000000, ETMVMIDCVR);
Pratik Patel17f3b822011-11-21 12:41:47 -0800292
Pratik Patel61de7302012-03-07 12:06:10 -0800293 etm_clr_prog(cpu);
Pratik Patel492b3012012-03-06 14:22:30 -0800294 ETM_LOCK(cpu);
Pratik Patel7831c082011-06-08 21:44:37 -0700295}
296
Pratik Patel61de7302012-03-07 12:06:10 -0800297static int etm_enable(void)
Pratik Patel7831c082011-06-08 21:44:37 -0700298{
Pratik Patel17f3b822011-11-21 12:41:47 -0800299 int ret, cpu;
Pratik Patel7831c082011-06-08 21:44:37 -0700300
Pratik Patel61de7302012-03-07 12:06:10 -0800301 if (etm.enabled) {
302 dev_err(etm.dev, "ETM tracing already enabled\n");
303 ret = -EPERM;
304 goto err;
305 }
306
Pratik Patelcc320a42011-12-22 10:48:14 -0800307 ret = qdss_clk_enable();
Pratik Patel7831c082011-06-08 21:44:37 -0700308 if (ret)
Pratik Patel61de7302012-03-07 12:06:10 -0800309 goto err;
Pratik Patel7831c082011-06-08 21:44:37 -0700310
Pratik Patel492b3012012-03-06 14:22:30 -0800311 wake_lock(&etm.wake_lock);
Pratik Patele5771792011-09-17 18:33:54 -0700312 /* 1. causes all online cpus to come out of idle PC
Pratik Patel7831c082011-06-08 21:44:37 -0700313 * 2. prevents idle PC until save restore flag is enabled atomically
Pratik Patele5771792011-09-17 18:33:54 -0700314 *
315 * we rely on the user to prevent hotplug on/off racing with this
316 * operation and to ensure cores where trace is expected to be turned
317 * on are already hotplugged on
Pratik Patel7831c082011-06-08 21:44:37 -0700318 */
Pratik Patel492b3012012-03-06 14:22:30 -0800319 pm_qos_update_request(&etm.qos_req, 0);
Pratik Patel7831c082011-06-08 21:44:37 -0700320
321 etb_disable();
322 tpiu_disable();
323 /* enable ETB first to avoid loosing any trace data */
324 etb_enable();
325 funnel_enable(0x0, 0x3);
Pratik Patel17f3b822011-11-21 12:41:47 -0800326 for_each_online_cpu(cpu)
Pratik Patel61de7302012-03-07 12:06:10 -0800327 __etm_enable(cpu);
Pratik Patel7831c082011-06-08 21:44:37 -0700328
Pratik Patel61de7302012-03-07 12:06:10 -0800329 etm.enabled = true;
Pratik Patel7831c082011-06-08 21:44:37 -0700330
Pratik Patel492b3012012-03-06 14:22:30 -0800331 pm_qos_update_request(&etm.qos_req, PM_QOS_DEFAULT_VALUE);
332 wake_unlock(&etm.wake_lock);
Pratik Patel7831c082011-06-08 21:44:37 -0700333
Pratik Patel61de7302012-03-07 12:06:10 -0800334 dev_info(etm.dev, "ETM tracing enabled\n");
Pratik Patel7831c082011-06-08 21:44:37 -0700335 return 0;
Pratik Patel61de7302012-03-07 12:06:10 -0800336err:
337 return ret;
Pratik Patel7831c082011-06-08 21:44:37 -0700338}
339
Pratik Patel61de7302012-03-07 12:06:10 -0800340static void __etm_disable(int cpu)
Pratik Patel7831c082011-06-08 21:44:37 -0700341{
Pratik Patel492b3012012-03-06 14:22:30 -0800342 ETM_UNLOCK(cpu);
343 etm_set_prog(cpu);
Pratik Patel7831c082011-06-08 21:44:37 -0700344
Pratik Patel17f3b822011-11-21 12:41:47 -0800345 /* program trace enable to low by using always false event */
Pratik Patel492b3012012-03-06 14:22:30 -0800346 etm_writel(etm, cpu, 0x6F | BIT(14), ETMTEEVR);
Pratik Patel7831c082011-06-08 21:44:37 -0700347
Pratik Patel17f3b822011-11-21 12:41:47 -0800348 /* Vote for ETM power/clock disable */
Pratik Patel61de7302012-03-07 12:06:10 -0800349 etm_set_pwrdwn(cpu);
Pratik Patel492b3012012-03-06 14:22:30 -0800350 ETM_LOCK(cpu);
Pratik Patel7831c082011-06-08 21:44:37 -0700351}
352
Pratik Patel61de7302012-03-07 12:06:10 -0800353static int etm_disable(void)
Pratik Patel7831c082011-06-08 21:44:37 -0700354{
Pratik Patel61de7302012-03-07 12:06:10 -0800355 int ret, cpu;
356
357 if (!etm.enabled) {
358 dev_err(etm.dev, "ETM tracing already disabled\n");
359 ret = -EPERM;
360 goto err;
361 }
Pratik Patel17f3b822011-11-21 12:41:47 -0800362
Pratik Patel492b3012012-03-06 14:22:30 -0800363 wake_lock(&etm.wake_lock);
Pratik Patele5771792011-09-17 18:33:54 -0700364 /* 1. causes all online cpus to come out of idle PC
Pratik Patel7831c082011-06-08 21:44:37 -0700365 * 2. prevents idle PC until save restore flag is disabled atomically
Pratik Patele5771792011-09-17 18:33:54 -0700366 *
367 * we rely on the user to prevent hotplug on/off racing with this
368 * operation and to ensure cores where trace is expected to be turned
369 * off are already hotplugged on
Pratik Patel7831c082011-06-08 21:44:37 -0700370 */
Pratik Patel492b3012012-03-06 14:22:30 -0800371 pm_qos_update_request(&etm.qos_req, 0);
Pratik Patel7831c082011-06-08 21:44:37 -0700372
Pratik Patel17f3b822011-11-21 12:41:47 -0800373 for_each_online_cpu(cpu)
Pratik Patel61de7302012-03-07 12:06:10 -0800374 __etm_disable(cpu);
Pratik Patel7831c082011-06-08 21:44:37 -0700375 etb_dump();
376 etb_disable();
377 funnel_disable(0x0, 0x3);
378
Pratik Patel61de7302012-03-07 12:06:10 -0800379 etm.enabled = false;
Pratik Patel7831c082011-06-08 21:44:37 -0700380
Pratik Patel492b3012012-03-06 14:22:30 -0800381 pm_qos_update_request(&etm.qos_req, PM_QOS_DEFAULT_VALUE);
382 wake_unlock(&etm.wake_lock);
Pratik Patel7831c082011-06-08 21:44:37 -0700383
Pratik Patelcc320a42011-12-22 10:48:14 -0800384 qdss_clk_disable();
Pratik Patel61de7302012-03-07 12:06:10 -0800385
386 dev_info(etm.dev, "ETM tracing disabled\n");
387 return 0;
388err:
389 return ret;
Pratik Patel7831c082011-06-08 21:44:37 -0700390}
391
Pratik Patel492b3012012-03-06 14:22:30 -0800392static int etm_open(struct inode *inode, struct file *file)
Pratik Patel7831c082011-06-08 21:44:37 -0700393{
Pratik Patel492b3012012-03-06 14:22:30 -0800394 if (atomic_cmpxchg(&etm.in_use, 0, 1))
Pratik Patel7831c082011-06-08 21:44:37 -0700395 return -EBUSY;
396
Pratik Patel492b3012012-03-06 14:22:30 -0800397 dev_dbg(etm.dev, "%s: successfully opened\n", __func__);
Pratik Patel7831c082011-06-08 21:44:37 -0700398 return 0;
399}
400
Pratik Patel492b3012012-03-06 14:22:30 -0800401static void etm_range_filter(char range, uint32_t reg1,
Pratik Patel7831c082011-06-08 21:44:37 -0700402 uint32_t addr1, uint32_t reg2, uint32_t addr2)
403{
Pratik Patel61de7302012-03-07 12:06:10 -0800404 etm.addr_val[reg1] = addr1;
405 etm.addr_val[reg2] = addr2;
Pratik Patel7831c082011-06-08 21:44:37 -0700406
Pratik Patel61de7302012-03-07 12:06:10 -0800407 etm.enable_ctrl1 |= (1 << (reg1/2));
Pratik Patel7831c082011-06-08 21:44:37 -0700408 if (range == 'i')
Pratik Patel61de7302012-03-07 12:06:10 -0800409 etm.enable_ctrl1 &= ~BIT(24);
Pratik Patel7831c082011-06-08 21:44:37 -0700410 else if (range == 'e')
Pratik Patel61de7302012-03-07 12:06:10 -0800411 etm.enable_ctrl1 |= BIT(24);
Pratik Patel7831c082011-06-08 21:44:37 -0700412}
413
Pratik Patel492b3012012-03-06 14:22:30 -0800414static void etm_start_stop_filter(char start_stop,
Pratik Patel7831c082011-06-08 21:44:37 -0700415 uint32_t reg, uint32_t addr)
416{
Pratik Patel61de7302012-03-07 12:06:10 -0800417 etm.addr_val[reg] = addr;
Pratik Patel7831c082011-06-08 21:44:37 -0700418
419 if (start_stop == 's')
Pratik Patel61de7302012-03-07 12:06:10 -0800420 etm.startstop_ctrl |= (1 << reg);
Pratik Patel7831c082011-06-08 21:44:37 -0700421 else if (start_stop == 't')
Pratik Patel61de7302012-03-07 12:06:10 -0800422 etm.startstop_ctrl |= (1 << (reg + 16));
Pratik Patel7831c082011-06-08 21:44:37 -0700423
Pratik Patel61de7302012-03-07 12:06:10 -0800424 etm.enable_ctrl1 |= BIT(25);
Pratik Patel7831c082011-06-08 21:44:37 -0700425}
426
427#define MAX_COMMAND_STRLEN 40
Pratik Patel492b3012012-03-06 14:22:30 -0800428static ssize_t etm_write(struct file *file, const char __user *data,
Pratik Patel7831c082011-06-08 21:44:37 -0700429 size_t len, loff_t *ppos)
430{
431 char command[MAX_COMMAND_STRLEN];
432 int str_len;
433 unsigned long reg1, reg2;
434 unsigned long addr1, addr2;
435
436 str_len = strnlen_user(data, MAX_COMMAND_STRLEN);
Pratik Patel492b3012012-03-06 14:22:30 -0800437 dev_dbg(etm.dev, "string length: %d", str_len);
Pratik Patel7831c082011-06-08 21:44:37 -0700438 if (str_len == 0 || str_len == (MAX_COMMAND_STRLEN+1)) {
Pratik Patel492b3012012-03-06 14:22:30 -0800439 dev_err(etm.dev, "error in str_len: %d", str_len);
Pratik Patel7831c082011-06-08 21:44:37 -0700440 return -EFAULT;
441 }
442 /* includes the null character */
443 if (copy_from_user(command, data, str_len)) {
Pratik Patel492b3012012-03-06 14:22:30 -0800444 dev_err(etm.dev, "error in copy_from_user: %d", str_len);
Pratik Patel7831c082011-06-08 21:44:37 -0700445 return -EFAULT;
446 }
447
Pratik Patel492b3012012-03-06 14:22:30 -0800448 dev_dbg(etm.dev, "input = %s", command);
Pratik Patel7831c082011-06-08 21:44:37 -0700449
450 switch (command[0]) {
451 case '0':
Pratik Patel61de7302012-03-07 12:06:10 -0800452 if (etm.enabled) {
453 etm_disable();
Pratik Patel492b3012012-03-06 14:22:30 -0800454 dev_info(etm.dev, "tracing disabled\n");
Pratik Patel7831c082011-06-08 21:44:37 -0700455 } else
Pratik Patel492b3012012-03-06 14:22:30 -0800456 dev_err(etm.dev, "trace already disabled\n");
Pratik Patel7831c082011-06-08 21:44:37 -0700457
458 break;
459 case '1':
Pratik Patel61de7302012-03-07 12:06:10 -0800460 if (!etm.enabled) {
461 if (!etm_enable())
Pratik Patel492b3012012-03-06 14:22:30 -0800462 dev_info(etm.dev, "tracing enabled\n");
Pratik Patel7831c082011-06-08 21:44:37 -0700463 else
Pratik Patel492b3012012-03-06 14:22:30 -0800464 dev_err(etm.dev, "error enabling trace\n");
Pratik Patel7831c082011-06-08 21:44:37 -0700465 } else
Pratik Patel492b3012012-03-06 14:22:30 -0800466 dev_err(etm.dev, "trace already enabled\n");
Pratik Patel7831c082011-06-08 21:44:37 -0700467 break;
468 case 'f':
469 switch (command[2]) {
470 case 'i':
471 switch (command[4]) {
472 case 'i':
473 if (sscanf(&command[6], "%lx:%lx:%lx:%lx\\0",
474 &reg1, &addr1, &reg2, &addr2) != 4)
475 goto err_out;
476 if (reg1 > 7 || reg2 > 7 || (reg1 % 2))
477 goto err_out;
Pratik Patel492b3012012-03-06 14:22:30 -0800478 etm_range_filter('i',
Pratik Patel7831c082011-06-08 21:44:37 -0700479 reg1, addr1, reg2, addr2);
480 break;
481 case 'e':
482 if (sscanf(&command[6], "%lx:%lx:%lx:%lx\\0",
483 &reg1, &addr1, &reg2, &addr2) != 4)
484 goto err_out;
485 if (reg1 > 7 || reg2 > 7 || (reg1 % 2)
486 || command[2] == 'd')
487 goto err_out;
Pratik Patel492b3012012-03-06 14:22:30 -0800488 etm_range_filter('e',
Pratik Patel7831c082011-06-08 21:44:37 -0700489 reg1, addr1, reg2, addr2);
490 break;
491 case 's':
492 if (sscanf(&command[6], "%lx:%lx\\0",
493 &reg1, &addr1) != 2)
494 goto err_out;
495 if (reg1 > 7)
496 goto err_out;
Pratik Patel492b3012012-03-06 14:22:30 -0800497 etm_start_stop_filter('s', reg1, addr1);
Pratik Patel7831c082011-06-08 21:44:37 -0700498 break;
499 case 't':
500 if (sscanf(&command[6], "%lx:%lx\\0",
501 &reg1, &addr1) != 2)
502 goto err_out;
503 if (reg1 > 7)
504 goto err_out;
Pratik Patel492b3012012-03-06 14:22:30 -0800505 etm_start_stop_filter('t', reg1, addr1);
Pratik Patel7831c082011-06-08 21:44:37 -0700506 break;
507 default:
508 goto err_out;
509 }
510 break;
Pratik Patel7831c082011-06-08 21:44:37 -0700511 default:
512 goto err_out;
513 }
514 break;
515 default:
516 goto err_out;
517 }
518
519 return len;
520
521err_out:
522 return -EFAULT;
523}
524
Pratik Patel492b3012012-03-06 14:22:30 -0800525static int etm_release(struct inode *inode, struct file *file)
Pratik Patel7831c082011-06-08 21:44:37 -0700526{
Pratik Patel492b3012012-03-06 14:22:30 -0800527 atomic_set(&etm.in_use, 0);
528 dev_dbg(etm.dev, "%s: released\n", __func__);
Pratik Patel7831c082011-06-08 21:44:37 -0700529 return 0;
530}
531
Pratik Patel492b3012012-03-06 14:22:30 -0800532static const struct file_operations etm_fops = {
Pratik Patel7831c082011-06-08 21:44:37 -0700533 .owner = THIS_MODULE,
Pratik Patel492b3012012-03-06 14:22:30 -0800534 .open = etm_open,
535 .write = etm_write,
536 .release = etm_release,
Pratik Patel7831c082011-06-08 21:44:37 -0700537};
538
Pratik Patel492b3012012-03-06 14:22:30 -0800539static struct miscdevice etm_misc = {
540 .name = "msm_etm",
Pratik Patel7831c082011-06-08 21:44:37 -0700541 .minor = MISC_DYNAMIC_MINOR,
Pratik Patel492b3012012-03-06 14:22:30 -0800542 .fops = &etm_fops,
Pratik Patel7831c082011-06-08 21:44:37 -0700543};
544
Pratik Patel17f3b822011-11-21 12:41:47 -0800545/* Memory mapped writes to clear os lock not supported */
Pratik Patel492b3012012-03-06 14:22:30 -0800546static void etm_os_unlock(void *unused)
Pratik Patel17f3b822011-11-21 12:41:47 -0800547{
548 unsigned long value = 0x0;
549
550 asm("mcr p14, 1, %0, c1, c0, 4\n\t" : : "r" (value));
551 asm("isb\n\t");
552}
553
Pratik Patel61de7302012-03-07 12:06:10 -0800554static bool etm_arch_supported(uint8_t arch)
Pratik Patel7831c082011-06-08 21:44:37 -0700555{
Pratik Patel61de7302012-03-07 12:06:10 -0800556 switch (arch) {
557 case PFT_ARCH_V1_1:
558 break;
559 default:
560 return false;
561 }
562 return true;
563}
564
565static int __init etm_arch_init(void)
566{
567 int ret;
Pratik Patel7831c082011-06-08 21:44:37 -0700568 /* use cpu 0 for setup */
569 int cpu = 0;
Pratik Patel61de7302012-03-07 12:06:10 -0800570 uint32_t etmidr;
571 uint32_t etmccr;
Pratik Patel7831c082011-06-08 21:44:37 -0700572
Pratik Patel17f3b822011-11-21 12:41:47 -0800573 /* Unlock OS lock first to allow memory mapped reads and writes */
Pratik Patel492b3012012-03-06 14:22:30 -0800574 etm_os_unlock(NULL);
575 smp_call_function(etm_os_unlock, NULL, 1);
576 ETM_UNLOCK(cpu);
Pratik Patel17f3b822011-11-21 12:41:47 -0800577 /* Vote for ETM power/clock enable */
Pratik Patel61de7302012-03-07 12:06:10 -0800578 etm_clr_pwrdwn(cpu);
579 /* Set prog bit. It will be set from reset but this is included to
580 * ensure it is set
581 */
Pratik Patel492b3012012-03-06 14:22:30 -0800582 etm_set_prog(cpu);
Pratik Patel7831c082011-06-08 21:44:37 -0700583
584 /* find all capabilities */
Pratik Patel61de7302012-03-07 12:06:10 -0800585 etmidr = etm_readl(etm, cpu, ETMIDR);
586 etm.arch = BMVAL(etmidr, 4, 11);
587 if (etm_arch_supported(etm.arch) == false) {
588 ret = -EINVAL;
589 goto err;
590 }
Pratik Patel7831c082011-06-08 21:44:37 -0700591
Pratik Patel61de7302012-03-07 12:06:10 -0800592 etmccr = etm_readl(etm, cpu, ETMCCR);
593 etm.nr_addr_cmp = BMVAL(etmccr, 0, 3) * 2;
594 etm.nr_cntr = BMVAL(etmccr, 13, 15);
595 etm.nr_ext_inp = BMVAL(etmccr, 17, 19);
596 etm.nr_ext_out = BMVAL(etmccr, 20, 22);
597 etm.nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
Pratik Patel7831c082011-06-08 21:44:37 -0700598
Pratik Patel17f3b822011-11-21 12:41:47 -0800599 /* Vote for ETM power/clock disable */
Pratik Patel61de7302012-03-07 12:06:10 -0800600 etm_set_pwrdwn(cpu);
Pratik Patel492b3012012-03-06 14:22:30 -0800601 ETM_LOCK(cpu);
Pratik Patel61de7302012-03-07 12:06:10 -0800602
603 return 0;
604err:
605 return ret;
Pratik Patel7831c082011-06-08 21:44:37 -0700606}
607
Pratik Patel492b3012012-03-06 14:22:30 -0800608static int __devinit etm_probe(struct platform_device *pdev)
Pratik Patel7831c082011-06-08 21:44:37 -0700609{
Pratik Patele5771792011-09-17 18:33:54 -0700610 int ret;
Pratik Patel7831c082011-06-08 21:44:37 -0700611 struct resource *res;
612
613 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
614 if (!res) {
615 ret = -EINVAL;
616 goto err_res;
617 }
618
Pratik Patel492b3012012-03-06 14:22:30 -0800619 etm.base = ioremap_nocache(res->start, resource_size(res));
620 if (!etm.base) {
Pratik Patel7831c082011-06-08 21:44:37 -0700621 ret = -EINVAL;
622 goto err_ioremap;
623 }
624
Pratik Patel492b3012012-03-06 14:22:30 -0800625 etm.dev = &pdev->dev;
Pratik Patel7831c082011-06-08 21:44:37 -0700626
Pratik Patel61de7302012-03-07 12:06:10 -0800627 wake_lock_init(&etm.wake_lock, WAKE_LOCK_SUSPEND, "msm_etm");
628 pm_qos_add_request(&etm.qos_req, PM_QOS_CPU_DMA_LATENCY,
629 PM_QOS_DEFAULT_VALUE);
630
Pratik Patel492b3012012-03-06 14:22:30 -0800631 ret = misc_register(&etm_misc);
Pratik Patel7831c082011-06-08 21:44:37 -0700632 if (ret)
633 goto err_misc;
634
Pratik Patelcc320a42011-12-22 10:48:14 -0800635 ret = qdss_clk_enable();
Pratik Patel7831c082011-06-08 21:44:37 -0700636 if (ret)
Pratik Patelcc320a42011-12-22 10:48:14 -0800637 goto err_clk;
Pratik Patel7831c082011-06-08 21:44:37 -0700638
Pratik Patel61de7302012-03-07 12:06:10 -0800639 ret = etm_arch_init();
640 if (ret)
641 goto err_arch;
Pratik Patel7831c082011-06-08 21:44:37 -0700642
Pratik Patel61de7302012-03-07 12:06:10 -0800643 etm.enabled = false;
Pratik Patel7831c082011-06-08 21:44:37 -0700644
Pratik Patelcc320a42011-12-22 10:48:14 -0800645 qdss_clk_disable();
Pratik Patel7831c082011-06-08 21:44:37 -0700646
Pratik Patel61de7302012-03-07 12:06:10 -0800647 dev_info(etm.dev, "ETM initialized\n");
Pratik Patel7831c082011-06-08 21:44:37 -0700648
Pratik Patel61de7302012-03-07 12:06:10 -0800649 if (etm_boot_enable)
650 etm_enable();
Pratik Patel7831c082011-06-08 21:44:37 -0700651
652 return 0;
653
Pratik Patel61de7302012-03-07 12:06:10 -0800654err_arch:
655 qdss_clk_disable();
Pratik Patelcc320a42011-12-22 10:48:14 -0800656err_clk:
Pratik Patel492b3012012-03-06 14:22:30 -0800657 misc_deregister(&etm_misc);
Pratik Patel7831c082011-06-08 21:44:37 -0700658err_misc:
Pratik Patel61de7302012-03-07 12:06:10 -0800659 pm_qos_remove_request(&etm.qos_req);
660 wake_lock_destroy(&etm.wake_lock);
Pratik Patel492b3012012-03-06 14:22:30 -0800661 iounmap(etm.base);
Pratik Patel7831c082011-06-08 21:44:37 -0700662err_ioremap:
663err_res:
Pratik Patel61de7302012-03-07 12:06:10 -0800664 dev_err(etm.dev, "ETM init failed\n");
Pratik Patel7831c082011-06-08 21:44:37 -0700665 return ret;
666}
667
Pratik Patel492b3012012-03-06 14:22:30 -0800668static int etm_remove(struct platform_device *pdev)
Pratik Patel7831c082011-06-08 21:44:37 -0700669{
Pratik Patel61de7302012-03-07 12:06:10 -0800670 if (etm.enabled)
671 etm_disable();
672 misc_deregister(&etm_misc);
Pratik Patel492b3012012-03-06 14:22:30 -0800673 pm_qos_remove_request(&etm.qos_req);
674 wake_lock_destroy(&etm.wake_lock);
Pratik Patel492b3012012-03-06 14:22:30 -0800675 iounmap(etm.base);
Pratik Patel7831c082011-06-08 21:44:37 -0700676
677 return 0;
678}
679
Pratik Patel492b3012012-03-06 14:22:30 -0800680static struct platform_driver etm_driver = {
681 .probe = etm_probe,
682 .remove = etm_remove,
Pratik Patel7831c082011-06-08 21:44:37 -0700683 .driver = {
Pratik Patel492b3012012-03-06 14:22:30 -0800684 .name = "msm_etm",
Pratik Patel7831c082011-06-08 21:44:37 -0700685 },
686};
687
Pratik Patel492b3012012-03-06 14:22:30 -0800688int __init etm_init(void)
Pratik Patel7831c082011-06-08 21:44:37 -0700689{
Pratik Patel492b3012012-03-06 14:22:30 -0800690 return platform_driver_register(&etm_driver);
Pratik Patel7831c082011-06-08 21:44:37 -0700691}
Pratik Patel7831c082011-06-08 21:44:37 -0700692
Pratik Patel492b3012012-03-06 14:22:30 -0800693void etm_exit(void)
Pratik Patel7831c082011-06-08 21:44:37 -0700694{
Pratik Patel492b3012012-03-06 14:22:30 -0800695 platform_driver_unregister(&etm_driver);
Pratik Patel7831c082011-06-08 21:44:37 -0700696}