blob: 7d4dabed10a3985c54b6c45fd10928407a585a92 [file] [log] [blame]
Pratik Patel4d5cb982013-02-11 11:56:34 -08001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Pratik Patel5ecf6a12012-04-25 18:34:59 -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>
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>
21#include <linux/fs.h>
22#include <linux/miscdevice.h>
23#include <linux/uaccess.h>
24#include <linux/slab.h>
Pratik Patel3b0ca882012-06-01 16:54:14 -070025#include <linux/delay.h>
Pratik Patelf17b1472012-05-25 22:23:52 -070026#include <linux/clk.h>
Pratik Patele7b35aa2012-10-24 17:34:43 -070027#include <linux/bitmap.h>
Pratik Patel4d5cb982013-02-11 11:56:34 -080028#include <linux/of.h>
Pratik Patel5f6d1af2012-06-13 15:48:13 -070029#include <linux/of_coresight.h>
Pratik Patel1746b8f2012-06-02 21:11:41 -070030#include <linux/coresight.h>
31#include <linux/coresight-stm.h>
Pratik Patel5ecf6a12012-04-25 18:34:59 -070032#include <asm/unaligned.h>
Pratik Patel5ecf6a12012-04-25 18:34:59 -070033
Pratik Patel1746b8f2012-06-02 21:11:41 -070034#include "coresight-priv.h"
Pratik Patel5ecf6a12012-04-25 18:34:59 -070035
Pratik Patel3b0ca882012-06-01 16:54:14 -070036#define stm_writel(drvdata, val, off) __raw_writel((val), drvdata->base + off)
37#define stm_readl(drvdata, off) __raw_readl(drvdata->base + off)
38
Pratik Patel4d5cb982013-02-11 11:56:34 -080039#define stm_data_writeb(val, addr) __raw_writeb_no_log(val, addr)
40#define stm_data_writew(val, addr) __raw_writew_no_log(val, addr)
41#define stm_data_writel(val, addr) __raw_writel_no_log(val, addr)
42
Pratik Patel3b0ca882012-06-01 16:54:14 -070043#define STM_LOCK(drvdata) \
44do { \
45 mb(); \
46 stm_writel(drvdata, 0x0, CORESIGHT_LAR); \
47} while (0)
48#define STM_UNLOCK(drvdata) \
49do { \
50 stm_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR); \
51 mb(); \
52} while (0)
53
Pratik Patele7b35aa2012-10-24 17:34:43 -070054#define STMDMASTARTR (0xC04)
55#define STMDMASTOPR (0xC08)
56#define STMDMASTATR (0xC0C)
57#define STMDMACTLR (0xC10)
58#define STMDMAIDR (0xCFC)
59#define STMHEER (0xD00)
60#define STMHETER (0xD20)
61#define STMHEMCR (0xD64)
62#define STMHEMASTR (0xDF4)
63#define STMHEFEAT1R (0xDF8)
64#define STMHEIDR (0xDFC)
65#define STMSPER (0xE00)
66#define STMSPTER (0xE20)
67#define STMSPSCR (0xE60)
68#define STMSPMSCR (0xE64)
69#define STMSPOVERRIDER (0xE68)
70#define STMSPMOVERRIDER (0xE6C)
71#define STMSPTRIGCSR (0xE70)
72#define STMTCSR (0xE80)
73#define STMTSSTIMR (0xE84)
74#define STMTSFREQR (0xE8C)
75#define STMSYNCR (0xE90)
76#define STMAUXCR (0xE94)
77#define STMSPFEAT1R (0xEA0)
78#define STMSPFEAT2R (0xEA4)
79#define STMSPFEAT3R (0xEA8)
80#define STMITTRIGGER (0xEE8)
81#define STMITATBDATA0 (0xEEC)
82#define STMITATBCTR2 (0xEF0)
83#define STMITATBID (0xEF4)
84#define STMITATBCTR0 (0xEF8)
Pratik Patel3b0ca882012-06-01 16:54:14 -070085
Pratik Patele7b35aa2012-10-24 17:34:43 -070086#define NR_STM_CHANNEL (32)
87#define BYTES_PER_CHANNEL (256)
88#define STM_TRACE_BUF_SIZE (4096)
89#define STM_USERSPACE_HEADER_SIZE (8)
90#define STM_USERSPACE_MAGIC1_VAL (0xf0)
91#define STM_USERSPACE_MAGIC2_VAL (0xf1)
Pratik Patel5ecf6a12012-04-25 18:34:59 -070092
Pratik Patel4d5cb982013-02-11 11:56:34 -080093#define OST_TOKEN_STARTSIMPLE (0x10)
94#define OST_TOKEN_STARTBASE (0x30)
95#define OST_VERSION_PROP (1)
96#define OST_VERSION_MIPI1 (16)
Pratik Patel3b0ca882012-06-01 16:54:14 -070097
98enum stm_pkt_type {
Pratik Patel5ecf6a12012-04-25 18:34:59 -070099 STM_PKT_TYPE_DATA = 0x98,
100 STM_PKT_TYPE_FLAG = 0xE8,
101 STM_PKT_TYPE_TRIG = 0xF8,
102};
103
104enum {
105 STM_OPTION_MARKED = 0x10,
106};
107
Pratik Patel3b0ca882012-06-01 16:54:14 -0700108#define stm_channel_addr(drvdata, ch) (drvdata->chs.base + \
109 (ch * BYTES_PER_CHANNEL))
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700110#define stm_channel_off(type, opts) (type & ~opts)
111
Pratik Patel61e91702013-01-27 20:30:42 -0800112#ifdef CONFIG_CORESIGHT_STM_DEFAULT_ENABLE
Pratik Patel3b0ca882012-06-01 16:54:14 -0700113static int boot_enable = 1;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700114#else
Pratik Patel3b0ca882012-06-01 16:54:14 -0700115static int boot_enable;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700116#endif
117
118module_param_named(
Pratik Patel3b0ca882012-06-01 16:54:14 -0700119 boot_enable, boot_enable, int, S_IRUGO
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700120);
121
Pratik Patel3b0ca882012-06-01 16:54:14 -0700122static int boot_nr_channel;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700123
124module_param_named(
Pratik Patel3b0ca882012-06-01 16:54:14 -0700125 boot_nr_channel, boot_nr_channel, int, S_IRUGO
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700126);
127
128struct channel_space {
129 void __iomem *base;
130 unsigned long *bitmap;
131};
132
Pratik Patel16aefdb2012-05-30 10:41:23 -0700133struct stm_drvdata {
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700134 void __iomem *base;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700135 struct device *dev;
Pratik Patel3b0ca882012-06-01 16:54:14 -0700136 struct coresight_device *csdev;
137 struct miscdevice miscdev;
Pratik Patelf17b1472012-05-25 22:23:52 -0700138 struct clk *clk;
Pratik Patel00120582012-07-13 11:33:39 -0700139 spinlock_t spinlock;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700140 struct channel_space chs;
Pratik Patel3b0ca882012-06-01 16:54:14 -0700141 bool enable;
Pratik Patele7b35aa2012-10-24 17:34:43 -0700142 DECLARE_BITMAP(entities, OST_ENTITY_MAX);
Pratik Patel4d5cb982013-02-11 11:56:34 -0800143 bool write_64bit;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700144};
145
Pratik Patel3b0ca882012-06-01 16:54:14 -0700146static struct stm_drvdata *stmdrvdata;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700147
Pratik Patel00120582012-07-13 11:33:39 -0700148static int stm_hwevent_isenable(struct stm_drvdata *drvdata)
149{
150 int ret = 0;
151
152 spin_lock(&drvdata->spinlock);
153 if (drvdata->enable)
154 if (BVAL(stm_readl(drvdata, STMHEMCR), 0))
155 ret = stm_readl(drvdata, STMHEER) == 0 ? 0 : 1;
156 spin_unlock(&drvdata->spinlock);
157
158 return ret;
159}
160
161static void __stm_hwevent_enable(struct stm_drvdata *drvdata)
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700162{
Pratik Patel3b0ca882012-06-01 16:54:14 -0700163 STM_UNLOCK(drvdata);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700164
Pratik Patel32a63482012-08-03 15:11:20 -0700165 /* Program STMHETER to ensure TRIGOUTHETE (fed to CTI) is asserted
166 for HW events.
167 */
168 stm_writel(drvdata, 0xFFFFFFFF, STMHETER);
Pratik Patel00120582012-07-13 11:33:39 -0700169 stm_writel(drvdata, 0xFFFFFFFF, STMHEER);
170 stm_writel(drvdata, 0x5, STMHEMCR);
171
172 STM_LOCK(drvdata);
173}
174
175static int stm_hwevent_enable(struct stm_drvdata *drvdata)
176{
177 int ret = 0;
178
179 spin_lock(&drvdata->spinlock);
180 if (drvdata->enable)
181 __stm_hwevent_enable(drvdata);
182 else
183 ret = -EINVAL;
184 spin_unlock(&drvdata->spinlock);
185
186 return ret;
187}
188
189static int stm_port_isenable(struct stm_drvdata *drvdata)
190{
191 int ret = 0;
192
193 spin_lock(&drvdata->spinlock);
194 if (drvdata->enable)
195 ret = stm_readl(drvdata, STMSPER) == 0 ? 0 : 1;
196 spin_unlock(&drvdata->spinlock);
197
198 return ret;
199}
200
201static void __stm_port_enable(struct stm_drvdata *drvdata)
202{
203 STM_UNLOCK(drvdata);
204
Pratik Patel32a63482012-08-03 15:11:20 -0700205 stm_writel(drvdata, 0x10, STMSPTRIGCSR);
Pratik Patel16aefdb2012-05-30 10:41:23 -0700206 stm_writel(drvdata, 0xFFFFFFFF, STMSPER);
Pratik Patel00120582012-07-13 11:33:39 -0700207
208 STM_LOCK(drvdata);
209}
210
211static int stm_port_enable(struct stm_drvdata *drvdata)
212{
213 int ret = 0;
214
215 spin_lock(&drvdata->spinlock);
216 if (drvdata->enable)
217 __stm_port_enable(drvdata);
218 else
219 ret = -EINVAL;
220 spin_unlock(&drvdata->spinlock);
221
222 return ret;
223}
224
225static void __stm_enable(struct stm_drvdata *drvdata)
226{
227 __stm_hwevent_enable(drvdata);
228 __stm_port_enable(drvdata);
229
230 STM_UNLOCK(drvdata);
231
Pratik Patel32a63482012-08-03 15:11:20 -0700232 stm_writel(drvdata, 0xFFF, STMSYNCR);
Pratik Patel00120582012-07-13 11:33:39 -0700233 /* SYNCEN is read-only and HWTEN is not implemented */
Pratik Patel3109a9b2012-09-06 17:51:25 -0700234 stm_writel(drvdata, 0x100003, STMTCSR);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700235
Pratik Patel3b0ca882012-06-01 16:54:14 -0700236 STM_LOCK(drvdata);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700237}
238
Pratik Patel3b0ca882012-06-01 16:54:14 -0700239static int stm_enable(struct coresight_device *csdev)
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700240{
Pratik Patel3b0ca882012-06-01 16:54:14 -0700241 struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700242 int ret;
243
Pratik Patel16aefdb2012-05-30 10:41:23 -0700244 ret = clk_prepare_enable(drvdata->clk);
Pratik Patelf17b1472012-05-25 22:23:52 -0700245 if (ret)
Pratik Patel3b0ca882012-06-01 16:54:14 -0700246 return ret;
Pratik Patelf17b1472012-05-25 22:23:52 -0700247
Pratik Patel00120582012-07-13 11:33:39 -0700248 spin_lock(&drvdata->spinlock);
Pratik Patel3b0ca882012-06-01 16:54:14 -0700249 __stm_enable(drvdata);
250 drvdata->enable = true;
Pratik Patel00120582012-07-13 11:33:39 -0700251 spin_unlock(&drvdata->spinlock);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700252
Pratik Patel16aefdb2012-05-30 10:41:23 -0700253 dev_info(drvdata->dev, "STM tracing enabled\n");
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700254 return 0;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700255}
256
Pratik Patel00120582012-07-13 11:33:39 -0700257static void __stm_hwevent_disable(struct stm_drvdata *drvdata)
258{
259 STM_UNLOCK(drvdata);
260
Pratik Patel00120582012-07-13 11:33:39 -0700261 stm_writel(drvdata, 0x0, STMHEMCR);
Pratik Patel32a63482012-08-03 15:11:20 -0700262 stm_writel(drvdata, 0x0, STMHEER);
263 stm_writel(drvdata, 0x0, STMHETER);
Pratik Patel00120582012-07-13 11:33:39 -0700264
265 STM_LOCK(drvdata);
266}
267
268static void stm_hwevent_disable(struct stm_drvdata *drvdata)
269{
270 spin_lock(&drvdata->spinlock);
271 if (drvdata->enable)
272 __stm_hwevent_disable(drvdata);
273 spin_unlock(&drvdata->spinlock);
274}
275
276static void __stm_port_disable(struct stm_drvdata *drvdata)
277{
278 STM_UNLOCK(drvdata);
279
280 stm_writel(drvdata, 0x0, STMSPER);
Pratik Patel32a63482012-08-03 15:11:20 -0700281 stm_writel(drvdata, 0x0, STMSPTRIGCSR);
Pratik Patel00120582012-07-13 11:33:39 -0700282
283 STM_LOCK(drvdata);
284}
285
286static void stm_port_disable(struct stm_drvdata *drvdata)
287{
288 spin_lock(&drvdata->spinlock);
289 if (drvdata->enable)
290 __stm_port_disable(drvdata);
291 spin_unlock(&drvdata->spinlock);
292}
293
Pratik Patel3b0ca882012-06-01 16:54:14 -0700294static void __stm_disable(struct stm_drvdata *drvdata)
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700295{
Pratik Patel3b0ca882012-06-01 16:54:14 -0700296 STM_UNLOCK(drvdata);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700297
Pratik Patel3109a9b2012-09-06 17:51:25 -0700298 stm_writel(drvdata, 0x100000, STMTCSR);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700299
Pratik Patel3b0ca882012-06-01 16:54:14 -0700300 STM_LOCK(drvdata);
Pratik Patel00120582012-07-13 11:33:39 -0700301
302 __stm_hwevent_disable(drvdata);
303 __stm_port_disable(drvdata);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700304}
305
Pratik Patel3b0ca882012-06-01 16:54:14 -0700306static void stm_disable(struct coresight_device *csdev)
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700307{
Pratik Patel3b0ca882012-06-01 16:54:14 -0700308 struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700309
Pratik Patel00120582012-07-13 11:33:39 -0700310 spin_lock(&drvdata->spinlock);
Pratik Patel3b0ca882012-06-01 16:54:14 -0700311 __stm_disable(drvdata);
312 drvdata->enable = false;
Pratik Patel00120582012-07-13 11:33:39 -0700313 spin_unlock(&drvdata->spinlock);
314
Pratik Patel3b0ca882012-06-01 16:54:14 -0700315 /* Wait for 100ms so that pending data has been written to HW */
316 msleep(100);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700317
Pratik Patel16aefdb2012-05-30 10:41:23 -0700318 clk_disable_unprepare(drvdata->clk);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700319
Pratik Patel16aefdb2012-05-30 10:41:23 -0700320 dev_info(drvdata->dev, "STM tracing disabled\n");
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700321}
322
Pratik Patel3b0ca882012-06-01 16:54:14 -0700323static const struct coresight_ops_source stm_source_ops = {
324 .enable = stm_enable,
325 .disable = stm_disable,
326};
327
328static const struct coresight_ops stm_cs_ops = {
329 .source_ops = &stm_source_ops,
330};
331
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700332static uint32_t stm_channel_alloc(uint32_t off)
333{
Pratik Patel3b0ca882012-06-01 16:54:14 -0700334 struct stm_drvdata *drvdata = stmdrvdata;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700335 uint32_t ch;
336
337 do {
Pratik Patel16aefdb2012-05-30 10:41:23 -0700338 ch = find_next_zero_bit(drvdata->chs.bitmap,
339 NR_STM_CHANNEL, off);
340 } while ((ch < NR_STM_CHANNEL) &&
341 test_and_set_bit(ch, drvdata->chs.bitmap));
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700342
343 return ch;
344}
345
346static void stm_channel_free(uint32_t ch)
347{
Pratik Patel3b0ca882012-06-01 16:54:14 -0700348 struct stm_drvdata *drvdata = stmdrvdata;
349
Pratik Patel16aefdb2012-05-30 10:41:23 -0700350 clear_bit(ch, drvdata->chs.bitmap);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700351}
352
Pratik Patel4d5cb982013-02-11 11:56:34 -0800353static int stm_send_64bit(void *addr, const void *data, uint32_t size)
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700354{
355 uint64_t prepad = 0;
356 uint64_t postpad = 0;
357 char *pad;
358 uint8_t off, endoff;
359 uint32_t len = size;
360
361 /* only 64bit writes are supported, we rely on the compiler to
362 * generate STRD instruction for the casted 64bit assignments
363 */
364
365 off = (unsigned long)data & 0x7;
366
367 if (off) {
368 endoff = 8 - off;
369 pad = (char *)&prepad;
370 pad += off;
371
372 while (endoff && size) {
373 *pad++ = *(char *)data++;
374 endoff--;
375 size--;
376 }
377 *(volatile uint64_t __force *)addr = prepad;
378 }
379
380 /* now we are 64bit aligned */
381 while (size >= 8) {
382 *(volatile uint64_t __force *)addr = *(uint64_t *)data;
383 data += 8;
384 size -= 8;
385 }
386
Pratik Patel4d5cb982013-02-11 11:56:34 -0800387 endoff = 0;
388
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700389 if (size) {
Pratik Patel4d5cb982013-02-11 11:56:34 -0800390 endoff = 8 - (uint8_t)size;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700391 pad = (char *)&postpad;
392
393 while (size) {
394 *pad++ = *(char *)data++;
395 size--;
396 }
397 *(volatile uint64_t __force *)addr = postpad;
398 }
399
Pratik Patel4d5cb982013-02-11 11:56:34 -0800400 return len + off + endoff;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700401}
402
Pratik Patel4d5cb982013-02-11 11:56:34 -0800403static int stm_trace_ost_header_64bit(unsigned long ch_addr, uint32_t options,
404 uint8_t entity_id, uint8_t proto_id,
405 const void *payload_data,
406 uint32_t payload_size)
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700407{
408 void *addr;
409 uint8_t prepad_size;
410 uint64_t header;
411 char *hdr;
412
413 hdr = (char *)&header;
414
Pratik Patel4d5cb982013-02-11 11:56:34 -0800415 hdr[0] = OST_TOKEN_STARTBASE;
416 hdr[1] = OST_VERSION_PROP;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700417 hdr[2] = entity_id;
418 hdr[3] = proto_id;
419 prepad_size = (unsigned long)payload_data & 0x7;
420 *(uint32_t *)(hdr + 4) = (prepad_size << 24) | payload_size;
421
Pratik Patel4d5cb982013-02-11 11:56:34 -0800422 /* for 64bit writes, header is expected to be D32M, D32M type */
423 options |= STM_OPTION_MARKED;
424 options &= ~STM_OPTION_TIMESTAMPED;
425 addr = (void *)(ch_addr | stm_channel_off(STM_PKT_TYPE_DATA, options));
426
427 return stm_send_64bit(addr, &header, sizeof(header));
428}
429
430static int stm_trace_data_64bit(unsigned long ch_addr, uint32_t options,
431 const void *data, uint32_t size)
432{
433 void *addr;
434
435 options &= ~STM_OPTION_TIMESTAMPED;
436 addr = (void *)(ch_addr | stm_channel_off(STM_PKT_TYPE_DATA, options));
437
438 return stm_send_64bit(addr, data, size);
439}
440
441static int stm_trace_ost_tail_64bit(unsigned long ch_addr, uint32_t options)
442{
443 void *addr;
444 uint64_t tail = 0x0;
445
446 addr = (void *)(ch_addr | stm_channel_off(STM_PKT_TYPE_FLAG, options));
447
448 return stm_send_64bit(addr, &tail, sizeof(tail));
449}
450
451static int stm_send(void *addr, const void *data, uint32_t size)
452{
453 if (((unsigned long)data & 0x1) && (size >= 1)) {
454 stm_data_writeb(*(uint8_t *)data, addr);
455 data++;
456 size--;
457 }
458 if (((unsigned long)data & 0x2) && (size >= 2)) {
459 stm_data_writew(*(uint16_t *)data, addr);
460 data += 2;
461 size -= 2;
462 }
463
464 /* now we are 32bit aligned */
465 while (size >= 4) {
466 stm_data_writel(*(uint32_t *)data, addr);
467 data += 4;
468 size -= 4;
469 }
470
471 if (size >= 2) {
472 stm_data_writew(*(uint16_t *)data, addr);
473 data += 2;
474 size -= 2;
475 }
476 if (size >= 1) {
477 stm_data_writeb(*(uint8_t *)data, addr);
478 data++;
479 size--;
480 }
481
482 return size;
483}
484
485static int stm_trace_ost_header(unsigned long ch_addr, uint32_t options,
486 uint8_t entity_id, uint8_t proto_id,
487 const void *payload_data, uint32_t payload_size)
488{
489 void *addr;
490 uint32_t header;
491 char *hdr;
492
493 hdr = (char *)&header;
494
495 hdr[0] = OST_TOKEN_STARTSIMPLE;
496 hdr[1] = OST_VERSION_MIPI1;
497 hdr[2] = entity_id;
498 hdr[3] = proto_id;
499
500 /* header is expected to be D32M type */
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700501 options |= STM_OPTION_MARKED;
502 options &= ~STM_OPTION_TIMESTAMPED;
503 addr = (void *)(ch_addr | stm_channel_off(STM_PKT_TYPE_DATA, options));
504
505 return stm_send(addr, &header, sizeof(header));
506}
507
508static int stm_trace_data(unsigned long ch_addr, uint32_t options,
509 const void *data, uint32_t size)
510{
511 void *addr;
512
513 options &= ~STM_OPTION_TIMESTAMPED;
514 addr = (void *)(ch_addr | stm_channel_off(STM_PKT_TYPE_DATA, options));
515
516 return stm_send(addr, data, size);
517}
518
519static int stm_trace_ost_tail(unsigned long ch_addr, uint32_t options)
520{
521 void *addr;
Pratik Patel4d5cb982013-02-11 11:56:34 -0800522 uint32_t tail = 0x0;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700523
524 addr = (void *)(ch_addr | stm_channel_off(STM_PKT_TYPE_FLAG, options));
525
526 return stm_send(addr, &tail, sizeof(tail));
527}
528
529static inline int __stm_trace(uint32_t options, uint8_t entity_id,
530 uint8_t proto_id, const void *data, uint32_t size)
531{
Pratik Patel3b0ca882012-06-01 16:54:14 -0700532 struct stm_drvdata *drvdata = stmdrvdata;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700533 int len = 0;
534 uint32_t ch;
535 unsigned long ch_addr;
536
537 /* allocate channel and get the channel address */
538 ch = stm_channel_alloc(0);
Pratik Patel3b0ca882012-06-01 16:54:14 -0700539 ch_addr = (unsigned long)stm_channel_addr(drvdata, ch);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700540
Pratik Patel4d5cb982013-02-11 11:56:34 -0800541 if (drvdata->write_64bit) {
542 /* send the ost header */
543 len += stm_trace_ost_header_64bit(ch_addr, options, entity_id,
544 proto_id, data, size);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700545
Pratik Patel4d5cb982013-02-11 11:56:34 -0800546 /* send the payload data */
547 len += stm_trace_data_64bit(ch_addr, options, data, size);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700548
Pratik Patel4d5cb982013-02-11 11:56:34 -0800549 /* send the ost tail */
550 len += stm_trace_ost_tail_64bit(ch_addr, options);
551 } else {
552 /* send the ost header */
553 len += stm_trace_ost_header(ch_addr, options, entity_id,
554 proto_id, data, size);
555
556 /* send the payload data */
557 len += stm_trace_data(ch_addr, options, data, size);
558
559 /* send the ost tail */
560 len += stm_trace_ost_tail(ch_addr, options);
561 }
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700562
563 /* we are done, free the channel */
564 stm_channel_free(ch);
565
566 return len;
567}
568
569/**
570 * stm_trace - trace the binary or string data through STM
571 * @options: tracing options - guaranteed, timestamped, etc
572 * @entity_id: entity representing the trace data
573 * @proto_id: protocol id to distinguish between different binary formats
574 * @data: pointer to binary or string data buffer
575 * @size: size of data to send
576 *
577 * Packetizes the data as the payload to an OST packet and sends it over STM
578 *
579 * CONTEXT:
580 * Can be called from any context.
581 *
582 * RETURNS:
583 * number of bytes transfered over STM
584 */
585int stm_trace(uint32_t options, uint8_t entity_id, uint8_t proto_id,
Pratik Patel6fb38342012-06-03 14:51:38 -0700586 const void *data, uint32_t size)
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700587{
Pratik Patel3b0ca882012-06-01 16:54:14 -0700588 struct stm_drvdata *drvdata = stmdrvdata;
589
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700590 /* we don't support sizes more than 24bits (0 to 23) */
Pratik Patele7b35aa2012-10-24 17:34:43 -0700591 if (!(drvdata && drvdata->enable &&
Pratik Patelfe155c82012-10-26 15:19:35 -0700592 test_bit(entity_id, drvdata->entities) && size &&
593 (size < 0x1000000)))
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700594 return 0;
595
596 return __stm_trace(options, entity_id, proto_id, data, size);
597}
Pratik Patel394783a2013-04-22 11:12:14 -0700598EXPORT_SYMBOL(stm_trace);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700599
600static ssize_t stm_write(struct file *file, const char __user *data,
601 size_t size, loff_t *ppos)
602{
Pratik Patel3b0ca882012-06-01 16:54:14 -0700603 struct stm_drvdata *drvdata = container_of(file->private_data,
604 struct stm_drvdata, miscdev);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700605 char *buf;
Pratik Patele7b35aa2012-10-24 17:34:43 -0700606 uint8_t entity_id, proto_id;
607 uint32_t options;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700608
Pratik Patelfe155c82012-10-26 15:19:35 -0700609 if (!drvdata->enable || !size)
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700610 return -EINVAL;
611
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700612 if (size > STM_TRACE_BUF_SIZE)
613 size = STM_TRACE_BUF_SIZE;
614
615 buf = kmalloc(size, GFP_KERNEL);
616 if (!buf)
617 return -ENOMEM;
618
619 if (copy_from_user(buf, data, size)) {
620 kfree(buf);
Pratik Patel16aefdb2012-05-30 10:41:23 -0700621 dev_dbg(drvdata->dev, "%s: copy_from_user failed\n", __func__);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700622 return -EFAULT;
623 }
624
Pratik Patele7b35aa2012-10-24 17:34:43 -0700625 if (size >= STM_USERSPACE_HEADER_SIZE &&
626 buf[0] == STM_USERSPACE_MAGIC1_VAL &&
627 buf[1] == STM_USERSPACE_MAGIC2_VAL) {
628
629 entity_id = buf[2];
630 proto_id = buf[3];
631 options = *(uint32_t *)(buf + 4);
632
Pratik Patelfe155c82012-10-26 15:19:35 -0700633 if (!test_bit(entity_id, drvdata->entities) ||
634 !(size - STM_USERSPACE_HEADER_SIZE)) {
Pratik Patele7b35aa2012-10-24 17:34:43 -0700635 kfree(buf);
636 return size;
637 }
638
639 __stm_trace(options, entity_id, proto_id,
640 buf + STM_USERSPACE_HEADER_SIZE,
641 size - STM_USERSPACE_HEADER_SIZE);
642 } else {
643 if (!test_bit(OST_ENTITY_DEV_NODE, drvdata->entities)) {
644 kfree(buf);
645 return size;
646 }
647
648 __stm_trace(STM_OPTION_TIMESTAMPED, OST_ENTITY_DEV_NODE, 0,
649 buf, size);
650 }
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700651
652 kfree(buf);
653
654 return size;
655}
656
657static const struct file_operations stm_fops = {
658 .owner = THIS_MODULE,
Pratik Patel3b0ca882012-06-01 16:54:14 -0700659 .open = nonseekable_open,
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700660 .write = stm_write,
661 .llseek = no_llseek,
662};
663
Pratik Patel00120582012-07-13 11:33:39 -0700664static ssize_t stm_show_hwevent_enable(struct device *dev,
665 struct device_attribute *attr, char *buf)
666{
667 struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
668 unsigned long val = stm_hwevent_isenable(drvdata);
669
670 return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
671}
672
673static ssize_t stm_store_hwevent_enable(struct device *dev,
674 struct device_attribute *attr,
675 const char *buf, size_t size)
676{
677 struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
678 unsigned long val;
679 int ret = 0;
680
681 if (sscanf(buf, "%lx", &val) != 1)
682 return -EINVAL;
683
684 if (val)
685 ret = stm_hwevent_enable(drvdata);
686 else
687 stm_hwevent_disable(drvdata);
688
689 if (ret)
690 return ret;
691 return size;
692}
693static DEVICE_ATTR(hwevent_enable, S_IRUGO | S_IWUSR, stm_show_hwevent_enable,
694 stm_store_hwevent_enable);
695
696static ssize_t stm_show_port_enable(struct device *dev,
697 struct device_attribute *attr, char *buf)
698{
699 struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
700 unsigned long val = stm_port_isenable(drvdata);
701
702 return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
703}
704
705static ssize_t stm_store_port_enable(struct device *dev,
706 struct device_attribute *attr,
707 const char *buf, size_t size)
708{
709 struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
710 unsigned long val;
711 int ret = 0;
712
713 if (sscanf(buf, "%lx", &val) != 1)
714 return -EINVAL;
715
716 if (val)
717 ret = stm_port_enable(drvdata);
718 else
719 stm_port_disable(drvdata);
720
721 if (ret)
722 return ret;
723 return size;
724}
725static DEVICE_ATTR(port_enable, S_IRUGO | S_IWUSR, stm_show_port_enable,
726 stm_store_port_enable);
727
Pratik Patele7b35aa2012-10-24 17:34:43 -0700728static ssize_t stm_show_entities(struct device *dev,
Pratik Patela9c0e062012-05-28 13:45:35 -0700729 struct device_attribute *attr, char *buf)
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700730{
Pratik Patel3b0ca882012-06-01 16:54:14 -0700731 struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
Pratik Patele7b35aa2012-10-24 17:34:43 -0700732 ssize_t len;
Pratik Patel3b0ca882012-06-01 16:54:14 -0700733
Pratik Patele7b35aa2012-10-24 17:34:43 -0700734 len = bitmap_scnprintf(buf, PAGE_SIZE, drvdata->entities,
735 OST_ENTITY_MAX);
736
737 if (PAGE_SIZE - len < 2)
738 len = -EINVAL;
739 else
740 len += scnprintf(buf + len, 2, "\n");
741
742 return len;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700743}
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700744
Pratik Patele7b35aa2012-10-24 17:34:43 -0700745static ssize_t stm_store_entities(struct device *dev,
Pratik Patela9c0e062012-05-28 13:45:35 -0700746 struct device_attribute *attr,
747 const char *buf, size_t size)
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700748{
Pratik Patel3b0ca882012-06-01 16:54:14 -0700749 struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
Pratik Patele7b35aa2012-10-24 17:34:43 -0700750 unsigned long val1, val2;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700751
Pratik Patele7b35aa2012-10-24 17:34:43 -0700752 if (sscanf(buf, "%lx %lx", &val1, &val2) != 2)
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700753 return -EINVAL;
754
Pratik Patele7b35aa2012-10-24 17:34:43 -0700755 if (val1 >= OST_ENTITY_MAX)
756 return -EINVAL;
757
758 if (val2)
759 __set_bit(val1, drvdata->entities);
760 else
761 __clear_bit(val1, drvdata->entities);
762
Pratik Patela9c0e062012-05-28 13:45:35 -0700763 return size;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700764}
Pratik Patele7b35aa2012-10-24 17:34:43 -0700765static DEVICE_ATTR(entities, S_IRUGO | S_IWUSR, stm_show_entities,
766 stm_store_entities);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700767
Pratik Patel3b0ca882012-06-01 16:54:14 -0700768static struct attribute *stm_attrs[] = {
Pratik Patel00120582012-07-13 11:33:39 -0700769 &dev_attr_hwevent_enable.attr,
770 &dev_attr_port_enable.attr,
Pratik Patele7b35aa2012-10-24 17:34:43 -0700771 &dev_attr_entities.attr,
Pratik Patel3b0ca882012-06-01 16:54:14 -0700772 NULL,
773};
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700774
Pratik Patel3b0ca882012-06-01 16:54:14 -0700775static struct attribute_group stm_attr_grp = {
776 .attrs = stm_attrs,
777};
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700778
Pratik Patel3b0ca882012-06-01 16:54:14 -0700779static const struct attribute_group *stm_attr_grps[] = {
780 &stm_attr_grp,
781 NULL,
782};
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700783
784static int __devinit stm_probe(struct platform_device *pdev)
785{
786 int ret;
Pratik Patel4a1b2522012-06-17 15:31:15 -0700787 struct device *dev = &pdev->dev;
Pratik Patel5f6d1af2012-06-13 15:48:13 -0700788 struct coresight_platform_data *pdata;
Pratik Patel3b0ca882012-06-01 16:54:14 -0700789 struct stm_drvdata *drvdata;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700790 struct resource *res;
791 size_t res_size, bitmap_size;
Pratik Patel3b0ca882012-06-01 16:54:14 -0700792 struct coresight_desc *desc;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700793
Pratik Patel5f6d1af2012-06-13 15:48:13 -0700794 if (pdev->dev.of_node) {
795 pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
796 if (IS_ERR(pdata))
797 return PTR_ERR(pdata);
798 pdev->dev.platform_data = pdata;
799 }
800
Pratik Patel4a1b2522012-06-17 15:31:15 -0700801 drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
802 if (!drvdata)
803 return -ENOMEM;
804 /* Store the driver data pointer for use in exported functions */
805 stmdrvdata = drvdata;
Pratik Patel3b0ca882012-06-01 16:54:14 -0700806 drvdata->dev = &pdev->dev;
807 platform_set_drvdata(pdev, drvdata);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700808
Aparna Dasc9907512013-03-08 10:20:52 -0800809 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "stm-base");
Pratik Patel4a1b2522012-06-17 15:31:15 -0700810 if (!res)
811 return -ENODEV;
Pratik Patel2c09b762012-07-21 15:54:54 -0700812
Pratik Patel4a1b2522012-06-17 15:31:15 -0700813 drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
814 if (!drvdata->base)
815 return -ENOMEM;
816
Aparna Dasc9907512013-03-08 10:20:52 -0800817 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
818 "stm-data-base");
Pratik Patel4a1b2522012-06-17 15:31:15 -0700819 if (!res)
820 return -ENODEV;
Pratik Patel2c09b762012-07-21 15:54:54 -0700821
Pratik Patel3b0ca882012-06-01 16:54:14 -0700822 if (boot_nr_channel) {
823 res_size = min((resource_size_t)(boot_nr_channel *
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700824 BYTES_PER_CHANNEL), resource_size(res));
Pratik Patel3b0ca882012-06-01 16:54:14 -0700825 bitmap_size = boot_nr_channel * sizeof(long);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700826 } else {
827 res_size = min((resource_size_t)(NR_STM_CHANNEL *
828 BYTES_PER_CHANNEL), resource_size(res));
829 bitmap_size = NR_STM_CHANNEL * sizeof(long);
830 }
Pratik Patel4a1b2522012-06-17 15:31:15 -0700831 drvdata->chs.base = devm_ioremap(dev, res->start, res_size);
832 if (!drvdata->chs.base)
833 return -ENOMEM;
834 drvdata->chs.bitmap = devm_kzalloc(dev, bitmap_size, GFP_KERNEL);
835 if (!drvdata->chs.bitmap)
836 return -ENOMEM;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700837
Pratik Patel00120582012-07-13 11:33:39 -0700838 spin_lock_init(&drvdata->spinlock);
839
Pratik Patel4a1b2522012-06-17 15:31:15 -0700840 drvdata->clk = devm_clk_get(dev, "core_clk");
841 if (IS_ERR(drvdata->clk))
842 return PTR_ERR(drvdata->clk);
Pratik Patel2c09b762012-07-21 15:54:54 -0700843
Pratik Patel6fb38342012-06-03 14:51:38 -0700844 ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
Pratik Patelf17b1472012-05-25 22:23:52 -0700845 if (ret)
Pratik Patel4a1b2522012-06-17 15:31:15 -0700846 return ret;
Pratik Patel3b0ca882012-06-01 16:54:14 -0700847
Pratik Patele7b35aa2012-10-24 17:34:43 -0700848 bitmap_fill(drvdata->entities, OST_ENTITY_MAX);
Pratik Patel16aefdb2012-05-30 10:41:23 -0700849
Pratik Patel4d5cb982013-02-11 11:56:34 -0800850 if (pdev->dev.of_node)
851 drvdata->write_64bit = of_property_read_bool(pdev->dev.of_node,
852 "qcom,write-64bit");
853
Pratik Patel4a1b2522012-06-17 15:31:15 -0700854 desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
855 if (!desc)
856 return -ENOMEM;
Pratik Patel3b0ca882012-06-01 16:54:14 -0700857 desc->type = CORESIGHT_DEV_TYPE_SOURCE;
858 desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE;
859 desc->ops = &stm_cs_ops;
860 desc->pdata = pdev->dev.platform_data;
861 desc->dev = &pdev->dev;
862 desc->groups = stm_attr_grps;
863 desc->owner = THIS_MODULE;
864 drvdata->csdev = coresight_register(desc);
Pratik Patel4a1b2522012-06-17 15:31:15 -0700865 if (IS_ERR(drvdata->csdev))
866 return PTR_ERR(drvdata->csdev);
867
868 drvdata->miscdev.name = ((struct coresight_platform_data *)
869 (pdev->dev.platform_data))->name;
870 drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
871 drvdata->miscdev.fops = &stm_fops;
872 ret = misc_register(&drvdata->miscdev);
873 if (ret)
874 goto err;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700875
Pratik Patel16aefdb2012-05-30 10:41:23 -0700876 dev_info(drvdata->dev, "STM initialized\n");
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700877
Pratik Patel3b0ca882012-06-01 16:54:14 -0700878 if (boot_enable)
879 coresight_enable(drvdata->csdev);
880
881 return 0;
Pratik Patel4a1b2522012-06-17 15:31:15 -0700882err:
883 coresight_unregister(drvdata->csdev);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700884 return ret;
885}
886
887static int __devexit stm_remove(struct platform_device *pdev)
888{
Pratik Patel3b0ca882012-06-01 16:54:14 -0700889 struct stm_drvdata *drvdata = platform_get_drvdata(pdev);
890
Pratik Patel3b0ca882012-06-01 16:54:14 -0700891 misc_deregister(&drvdata->miscdev);
Pratik Patel4a1b2522012-06-17 15:31:15 -0700892 coresight_unregister(drvdata->csdev);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700893 return 0;
894}
895
Pratik Patel9eae4822012-05-14 17:34:53 -0700896static struct of_device_id stm_match[] = {
Pratik Patel5f6d1af2012-06-13 15:48:13 -0700897 {.compatible = "arm,coresight-stm"},
Pratik Patel9eae4822012-05-14 17:34:53 -0700898 {}
899};
900
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700901static struct platform_driver stm_driver = {
902 .probe = stm_probe,
903 .remove = __devexit_p(stm_remove),
904 .driver = {
Pratik Patel3b0ca882012-06-01 16:54:14 -0700905 .name = "coresight-stm",
Pratik Patel9eae4822012-05-14 17:34:53 -0700906 .owner = THIS_MODULE,
907 .of_match_table = stm_match,
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700908 },
909};
910
911static int __init stm_init(void)
912{
913 return platform_driver_register(&stm_driver);
914}
915module_init(stm_init);
916
917static void __exit stm_exit(void)
918{
919 platform_driver_unregister(&stm_driver);
920}
921module_exit(stm_exit);
922
923MODULE_LICENSE("GPL v2");
924MODULE_DESCRIPTION("CoreSight System Trace Macrocell driver");