blob: 81672ea576f852aadc2505c3568916034b42d519 [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{
Pratik Patel0be1fca2013-06-14 15:27:37 -0700453 uint32_t len = size;
454
Pratik Patel4d5cb982013-02-11 11:56:34 -0800455 if (((unsigned long)data & 0x1) && (size >= 1)) {
456 stm_data_writeb(*(uint8_t *)data, addr);
457 data++;
458 size--;
459 }
460 if (((unsigned long)data & 0x2) && (size >= 2)) {
461 stm_data_writew(*(uint16_t *)data, addr);
462 data += 2;
463 size -= 2;
464 }
465
466 /* now we are 32bit aligned */
467 while (size >= 4) {
468 stm_data_writel(*(uint32_t *)data, addr);
469 data += 4;
470 size -= 4;
471 }
472
473 if (size >= 2) {
474 stm_data_writew(*(uint16_t *)data, addr);
475 data += 2;
476 size -= 2;
477 }
478 if (size >= 1) {
479 stm_data_writeb(*(uint8_t *)data, addr);
480 data++;
481 size--;
482 }
483
Pratik Patel0be1fca2013-06-14 15:27:37 -0700484 return len;
Pratik Patel4d5cb982013-02-11 11:56:34 -0800485}
486
487static int stm_trace_ost_header(unsigned long ch_addr, uint32_t options,
488 uint8_t entity_id, uint8_t proto_id,
489 const void *payload_data, uint32_t payload_size)
490{
491 void *addr;
492 uint32_t header;
493 char *hdr;
494
495 hdr = (char *)&header;
496
497 hdr[0] = OST_TOKEN_STARTSIMPLE;
498 hdr[1] = OST_VERSION_MIPI1;
499 hdr[2] = entity_id;
500 hdr[3] = proto_id;
501
502 /* header is expected to be D32M type */
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700503 options |= STM_OPTION_MARKED;
504 options &= ~STM_OPTION_TIMESTAMPED;
505 addr = (void *)(ch_addr | stm_channel_off(STM_PKT_TYPE_DATA, options));
506
507 return stm_send(addr, &header, sizeof(header));
508}
509
510static int stm_trace_data(unsigned long ch_addr, uint32_t options,
511 const void *data, uint32_t size)
512{
513 void *addr;
514
515 options &= ~STM_OPTION_TIMESTAMPED;
516 addr = (void *)(ch_addr | stm_channel_off(STM_PKT_TYPE_DATA, options));
517
518 return stm_send(addr, data, size);
519}
520
521static int stm_trace_ost_tail(unsigned long ch_addr, uint32_t options)
522{
523 void *addr;
Pratik Patel4d5cb982013-02-11 11:56:34 -0800524 uint32_t tail = 0x0;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700525
526 addr = (void *)(ch_addr | stm_channel_off(STM_PKT_TYPE_FLAG, options));
527
528 return stm_send(addr, &tail, sizeof(tail));
529}
530
531static inline int __stm_trace(uint32_t options, uint8_t entity_id,
532 uint8_t proto_id, const void *data, uint32_t size)
533{
Pratik Patel3b0ca882012-06-01 16:54:14 -0700534 struct stm_drvdata *drvdata = stmdrvdata;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700535 int len = 0;
536 uint32_t ch;
537 unsigned long ch_addr;
538
539 /* allocate channel and get the channel address */
540 ch = stm_channel_alloc(0);
Pratik Patel3b0ca882012-06-01 16:54:14 -0700541 ch_addr = (unsigned long)stm_channel_addr(drvdata, ch);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700542
Pratik Patel4d5cb982013-02-11 11:56:34 -0800543 if (drvdata->write_64bit) {
544 /* send the ost header */
545 len += stm_trace_ost_header_64bit(ch_addr, options, entity_id,
546 proto_id, data, size);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700547
Pratik Patel4d5cb982013-02-11 11:56:34 -0800548 /* send the payload data */
549 len += stm_trace_data_64bit(ch_addr, options, data, size);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700550
Pratik Patel4d5cb982013-02-11 11:56:34 -0800551 /* send the ost tail */
552 len += stm_trace_ost_tail_64bit(ch_addr, options);
553 } else {
554 /* send the ost header */
555 len += stm_trace_ost_header(ch_addr, options, entity_id,
556 proto_id, data, size);
557
558 /* send the payload data */
559 len += stm_trace_data(ch_addr, options, data, size);
560
561 /* send the ost tail */
562 len += stm_trace_ost_tail(ch_addr, options);
563 }
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700564
565 /* we are done, free the channel */
566 stm_channel_free(ch);
567
568 return len;
569}
570
571/**
572 * stm_trace - trace the binary or string data through STM
573 * @options: tracing options - guaranteed, timestamped, etc
574 * @entity_id: entity representing the trace data
575 * @proto_id: protocol id to distinguish between different binary formats
576 * @data: pointer to binary or string data buffer
577 * @size: size of data to send
578 *
579 * Packetizes the data as the payload to an OST packet and sends it over STM
580 *
581 * CONTEXT:
582 * Can be called from any context.
583 *
584 * RETURNS:
585 * number of bytes transfered over STM
586 */
587int stm_trace(uint32_t options, uint8_t entity_id, uint8_t proto_id,
Pratik Patel6fb38342012-06-03 14:51:38 -0700588 const void *data, uint32_t size)
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700589{
Pratik Patel3b0ca882012-06-01 16:54:14 -0700590 struct stm_drvdata *drvdata = stmdrvdata;
591
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700592 /* we don't support sizes more than 24bits (0 to 23) */
Pratik Patele7b35aa2012-10-24 17:34:43 -0700593 if (!(drvdata && drvdata->enable &&
Pratik Patelfe155c82012-10-26 15:19:35 -0700594 test_bit(entity_id, drvdata->entities) && size &&
595 (size < 0x1000000)))
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700596 return 0;
597
598 return __stm_trace(options, entity_id, proto_id, data, size);
599}
Pratik Patel394783a2013-04-22 11:12:14 -0700600EXPORT_SYMBOL(stm_trace);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700601
602static ssize_t stm_write(struct file *file, const char __user *data,
603 size_t size, loff_t *ppos)
604{
Pratik Patel3b0ca882012-06-01 16:54:14 -0700605 struct stm_drvdata *drvdata = container_of(file->private_data,
606 struct stm_drvdata, miscdev);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700607 char *buf;
Pratik Patele7b35aa2012-10-24 17:34:43 -0700608 uint8_t entity_id, proto_id;
609 uint32_t options;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700610
Pratik Patelfe155c82012-10-26 15:19:35 -0700611 if (!drvdata->enable || !size)
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700612 return -EINVAL;
613
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700614 if (size > STM_TRACE_BUF_SIZE)
615 size = STM_TRACE_BUF_SIZE;
616
617 buf = kmalloc(size, GFP_KERNEL);
618 if (!buf)
619 return -ENOMEM;
620
621 if (copy_from_user(buf, data, size)) {
622 kfree(buf);
Pratik Patel16aefdb2012-05-30 10:41:23 -0700623 dev_dbg(drvdata->dev, "%s: copy_from_user failed\n", __func__);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700624 return -EFAULT;
625 }
626
Pratik Patele7b35aa2012-10-24 17:34:43 -0700627 if (size >= STM_USERSPACE_HEADER_SIZE &&
628 buf[0] == STM_USERSPACE_MAGIC1_VAL &&
629 buf[1] == STM_USERSPACE_MAGIC2_VAL) {
630
631 entity_id = buf[2];
632 proto_id = buf[3];
633 options = *(uint32_t *)(buf + 4);
634
Pratik Patelfe155c82012-10-26 15:19:35 -0700635 if (!test_bit(entity_id, drvdata->entities) ||
636 !(size - STM_USERSPACE_HEADER_SIZE)) {
Pratik Patele7b35aa2012-10-24 17:34:43 -0700637 kfree(buf);
638 return size;
639 }
640
641 __stm_trace(options, entity_id, proto_id,
642 buf + STM_USERSPACE_HEADER_SIZE,
643 size - STM_USERSPACE_HEADER_SIZE);
644 } else {
645 if (!test_bit(OST_ENTITY_DEV_NODE, drvdata->entities)) {
646 kfree(buf);
647 return size;
648 }
649
650 __stm_trace(STM_OPTION_TIMESTAMPED, OST_ENTITY_DEV_NODE, 0,
651 buf, size);
652 }
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700653
654 kfree(buf);
655
656 return size;
657}
658
659static const struct file_operations stm_fops = {
660 .owner = THIS_MODULE,
Pratik Patel3b0ca882012-06-01 16:54:14 -0700661 .open = nonseekable_open,
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700662 .write = stm_write,
663 .llseek = no_llseek,
664};
665
Pratik Patel00120582012-07-13 11:33:39 -0700666static ssize_t stm_show_hwevent_enable(struct device *dev,
667 struct device_attribute *attr, char *buf)
668{
669 struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
670 unsigned long val = stm_hwevent_isenable(drvdata);
671
672 return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
673}
674
675static ssize_t stm_store_hwevent_enable(struct device *dev,
676 struct device_attribute *attr,
677 const char *buf, size_t size)
678{
679 struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
680 unsigned long val;
681 int ret = 0;
682
683 if (sscanf(buf, "%lx", &val) != 1)
684 return -EINVAL;
685
686 if (val)
687 ret = stm_hwevent_enable(drvdata);
688 else
689 stm_hwevent_disable(drvdata);
690
691 if (ret)
692 return ret;
693 return size;
694}
695static DEVICE_ATTR(hwevent_enable, S_IRUGO | S_IWUSR, stm_show_hwevent_enable,
696 stm_store_hwevent_enable);
697
698static ssize_t stm_show_port_enable(struct device *dev,
699 struct device_attribute *attr, char *buf)
700{
701 struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
702 unsigned long val = stm_port_isenable(drvdata);
703
704 return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
705}
706
707static ssize_t stm_store_port_enable(struct device *dev,
708 struct device_attribute *attr,
709 const char *buf, size_t size)
710{
711 struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
712 unsigned long val;
713 int ret = 0;
714
715 if (sscanf(buf, "%lx", &val) != 1)
716 return -EINVAL;
717
718 if (val)
719 ret = stm_port_enable(drvdata);
720 else
721 stm_port_disable(drvdata);
722
723 if (ret)
724 return ret;
725 return size;
726}
727static DEVICE_ATTR(port_enable, S_IRUGO | S_IWUSR, stm_show_port_enable,
728 stm_store_port_enable);
729
Pratik Patele7b35aa2012-10-24 17:34:43 -0700730static ssize_t stm_show_entities(struct device *dev,
Pratik Patela9c0e062012-05-28 13:45:35 -0700731 struct device_attribute *attr, char *buf)
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700732{
Pratik Patel3b0ca882012-06-01 16:54:14 -0700733 struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
Pratik Patele7b35aa2012-10-24 17:34:43 -0700734 ssize_t len;
Pratik Patel3b0ca882012-06-01 16:54:14 -0700735
Pratik Patele7b35aa2012-10-24 17:34:43 -0700736 len = bitmap_scnprintf(buf, PAGE_SIZE, drvdata->entities,
737 OST_ENTITY_MAX);
738
739 if (PAGE_SIZE - len < 2)
740 len = -EINVAL;
741 else
742 len += scnprintf(buf + len, 2, "\n");
743
744 return len;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700745}
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700746
Pratik Patele7b35aa2012-10-24 17:34:43 -0700747static ssize_t stm_store_entities(struct device *dev,
Pratik Patela9c0e062012-05-28 13:45:35 -0700748 struct device_attribute *attr,
749 const char *buf, size_t size)
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700750{
Pratik Patel3b0ca882012-06-01 16:54:14 -0700751 struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
Pratik Patele7b35aa2012-10-24 17:34:43 -0700752 unsigned long val1, val2;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700753
Pratik Patele7b35aa2012-10-24 17:34:43 -0700754 if (sscanf(buf, "%lx %lx", &val1, &val2) != 2)
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700755 return -EINVAL;
756
Pratik Patele7b35aa2012-10-24 17:34:43 -0700757 if (val1 >= OST_ENTITY_MAX)
758 return -EINVAL;
759
760 if (val2)
761 __set_bit(val1, drvdata->entities);
762 else
763 __clear_bit(val1, drvdata->entities);
764
Pratik Patela9c0e062012-05-28 13:45:35 -0700765 return size;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700766}
Pratik Patele7b35aa2012-10-24 17:34:43 -0700767static DEVICE_ATTR(entities, S_IRUGO | S_IWUSR, stm_show_entities,
768 stm_store_entities);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700769
Pratik Patel3b0ca882012-06-01 16:54:14 -0700770static struct attribute *stm_attrs[] = {
Pratik Patel00120582012-07-13 11:33:39 -0700771 &dev_attr_hwevent_enable.attr,
772 &dev_attr_port_enable.attr,
Pratik Patele7b35aa2012-10-24 17:34:43 -0700773 &dev_attr_entities.attr,
Pratik Patel3b0ca882012-06-01 16:54:14 -0700774 NULL,
775};
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700776
Pratik Patel3b0ca882012-06-01 16:54:14 -0700777static struct attribute_group stm_attr_grp = {
778 .attrs = stm_attrs,
779};
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700780
Pratik Patel3b0ca882012-06-01 16:54:14 -0700781static const struct attribute_group *stm_attr_grps[] = {
782 &stm_attr_grp,
783 NULL,
784};
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700785
786static int __devinit stm_probe(struct platform_device *pdev)
787{
788 int ret;
Pratik Patel4a1b2522012-06-17 15:31:15 -0700789 struct device *dev = &pdev->dev;
Pratik Patel5f6d1af2012-06-13 15:48:13 -0700790 struct coresight_platform_data *pdata;
Pratik Patel3b0ca882012-06-01 16:54:14 -0700791 struct stm_drvdata *drvdata;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700792 struct resource *res;
793 size_t res_size, bitmap_size;
Pratik Patel3b0ca882012-06-01 16:54:14 -0700794 struct coresight_desc *desc;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700795
Pratik Patel49306402013-06-14 01:02:08 -0700796 if (coresight_fuse_access_disabled())
797 return -EPERM;
798
Pratik Patel5f6d1af2012-06-13 15:48:13 -0700799 if (pdev->dev.of_node) {
800 pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
801 if (IS_ERR(pdata))
802 return PTR_ERR(pdata);
803 pdev->dev.platform_data = pdata;
804 }
805
Pratik Patel4a1b2522012-06-17 15:31:15 -0700806 drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
807 if (!drvdata)
808 return -ENOMEM;
809 /* Store the driver data pointer for use in exported functions */
810 stmdrvdata = drvdata;
Pratik Patel3b0ca882012-06-01 16:54:14 -0700811 drvdata->dev = &pdev->dev;
812 platform_set_drvdata(pdev, drvdata);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700813
Aparna Dasc9907512013-03-08 10:20:52 -0800814 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "stm-base");
Pratik Patel4a1b2522012-06-17 15:31:15 -0700815 if (!res)
816 return -ENODEV;
Pratik Patel2c09b762012-07-21 15:54:54 -0700817
Pratik Patel4a1b2522012-06-17 15:31:15 -0700818 drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
819 if (!drvdata->base)
820 return -ENOMEM;
821
Aparna Dasc9907512013-03-08 10:20:52 -0800822 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
823 "stm-data-base");
Pratik Patel4a1b2522012-06-17 15:31:15 -0700824 if (!res)
825 return -ENODEV;
Pratik Patel2c09b762012-07-21 15:54:54 -0700826
Pratik Patel3b0ca882012-06-01 16:54:14 -0700827 if (boot_nr_channel) {
828 res_size = min((resource_size_t)(boot_nr_channel *
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700829 BYTES_PER_CHANNEL), resource_size(res));
Pratik Patel3b0ca882012-06-01 16:54:14 -0700830 bitmap_size = boot_nr_channel * sizeof(long);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700831 } else {
832 res_size = min((resource_size_t)(NR_STM_CHANNEL *
833 BYTES_PER_CHANNEL), resource_size(res));
834 bitmap_size = NR_STM_CHANNEL * sizeof(long);
835 }
Pratik Patel4a1b2522012-06-17 15:31:15 -0700836 drvdata->chs.base = devm_ioremap(dev, res->start, res_size);
837 if (!drvdata->chs.base)
838 return -ENOMEM;
839 drvdata->chs.bitmap = devm_kzalloc(dev, bitmap_size, GFP_KERNEL);
840 if (!drvdata->chs.bitmap)
841 return -ENOMEM;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700842
Pratik Patel00120582012-07-13 11:33:39 -0700843 spin_lock_init(&drvdata->spinlock);
844
Pratik Patel4a1b2522012-06-17 15:31:15 -0700845 drvdata->clk = devm_clk_get(dev, "core_clk");
846 if (IS_ERR(drvdata->clk))
847 return PTR_ERR(drvdata->clk);
Pratik Patel2c09b762012-07-21 15:54:54 -0700848
Pratik Patel6fb38342012-06-03 14:51:38 -0700849 ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
Pratik Patelf17b1472012-05-25 22:23:52 -0700850 if (ret)
Pratik Patel4a1b2522012-06-17 15:31:15 -0700851 return ret;
Pratik Patel3b0ca882012-06-01 16:54:14 -0700852
Pratik Patele7b35aa2012-10-24 17:34:43 -0700853 bitmap_fill(drvdata->entities, OST_ENTITY_MAX);
Pratik Patel16aefdb2012-05-30 10:41:23 -0700854
Pratik Patel4d5cb982013-02-11 11:56:34 -0800855 if (pdev->dev.of_node)
856 drvdata->write_64bit = of_property_read_bool(pdev->dev.of_node,
857 "qcom,write-64bit");
858
Pratik Patel4a1b2522012-06-17 15:31:15 -0700859 desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
860 if (!desc)
861 return -ENOMEM;
Pratik Patel3b0ca882012-06-01 16:54:14 -0700862 desc->type = CORESIGHT_DEV_TYPE_SOURCE;
863 desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE;
864 desc->ops = &stm_cs_ops;
865 desc->pdata = pdev->dev.platform_data;
866 desc->dev = &pdev->dev;
867 desc->groups = stm_attr_grps;
868 desc->owner = THIS_MODULE;
869 drvdata->csdev = coresight_register(desc);
Pratik Patel4a1b2522012-06-17 15:31:15 -0700870 if (IS_ERR(drvdata->csdev))
871 return PTR_ERR(drvdata->csdev);
872
873 drvdata->miscdev.name = ((struct coresight_platform_data *)
874 (pdev->dev.platform_data))->name;
875 drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
876 drvdata->miscdev.fops = &stm_fops;
877 ret = misc_register(&drvdata->miscdev);
878 if (ret)
879 goto err;
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700880
Pratik Patel16aefdb2012-05-30 10:41:23 -0700881 dev_info(drvdata->dev, "STM initialized\n");
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700882
Pratik Patel3b0ca882012-06-01 16:54:14 -0700883 if (boot_enable)
884 coresight_enable(drvdata->csdev);
885
886 return 0;
Pratik Patel4a1b2522012-06-17 15:31:15 -0700887err:
888 coresight_unregister(drvdata->csdev);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700889 return ret;
890}
891
892static int __devexit stm_remove(struct platform_device *pdev)
893{
Pratik Patel3b0ca882012-06-01 16:54:14 -0700894 struct stm_drvdata *drvdata = platform_get_drvdata(pdev);
895
Pratik Patel3b0ca882012-06-01 16:54:14 -0700896 misc_deregister(&drvdata->miscdev);
Pratik Patel4a1b2522012-06-17 15:31:15 -0700897 coresight_unregister(drvdata->csdev);
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700898 return 0;
899}
900
Pratik Patel9eae4822012-05-14 17:34:53 -0700901static struct of_device_id stm_match[] = {
Pratik Patel5f6d1af2012-06-13 15:48:13 -0700902 {.compatible = "arm,coresight-stm"},
Pratik Patel9eae4822012-05-14 17:34:53 -0700903 {}
904};
905
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700906static struct platform_driver stm_driver = {
907 .probe = stm_probe,
908 .remove = __devexit_p(stm_remove),
909 .driver = {
Pratik Patel3b0ca882012-06-01 16:54:14 -0700910 .name = "coresight-stm",
Pratik Patel9eae4822012-05-14 17:34:53 -0700911 .owner = THIS_MODULE,
912 .of_match_table = stm_match,
Pratik Patel5ecf6a12012-04-25 18:34:59 -0700913 },
914};
915
916static int __init stm_init(void)
917{
918 return platform_driver_register(&stm_driver);
919}
920module_init(stm_init);
921
922static void __exit stm_exit(void)
923{
924 platform_driver_unregister(&stm_driver);
925}
926module_exit(stm_exit);
927
928MODULE_LICENSE("GPL v2");
929MODULE_DESCRIPTION("CoreSight System Trace Macrocell driver");