blob: eb01fca8801ee5af209adaa97111eed5ac0fa84e [file] [log] [blame]
Mukesh Ojha4949cde2018-02-21 19:17:54 +05301/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
Mukesh Ojha4350ecb2017-11-30 19:24:55 +05302 *
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/slab.h>
22#include <linux/delay.h>
23#include <linux/clk.h>
24#include <linux/of.h>
25#include <linux/mutex.h>
26#include <linux/coresight.h>
27#include <soc/qcom/memory_dump.h>
28
29#include "coresight-priv.h"
30
31#define dbgui_writel(drvdata, val, off) \
32 __raw_writel((val), drvdata->base + off)
33#define dbgui_readl(drvdata, off) __raw_readl(drvdata->base + off)
34
35#define DBGUI_LOCK(drvdata) \
36do { \
37 mb(); /* ensure configuration take effect before we lock it */ \
38 dbgui_writel(drvdata, 0x0, CORESIGHT_LAR); \
39} while (0)
40
41#define DBGUI_UNLOCK(drvdata) \
42do { \
43 dbgui_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR); \
44 mb(); /* ensure unlock take effect before we configure */ \
45} while (0)
46
47/* DBGUI registers */
48#define DBGUI_SECURE (0x000)
49#define DBGUI_CTL (0x004)
50#define DBGUI_CTL_MASK (0x008)
51#define DBGUI_SWTRIG (0x00C)
52#define DBGUI_STATUS (0x010)
53#define DBGUI_HWE_MASK (0x014)
54#define DBGUI_CTR_VAL (0x018)
55#define DBGUI_CTR_EN (0x01C)
56#define DBGUI_NUM_REGS_RD (0x020)
57#define DBGUI_ATB_REG (0x024)
58
59#define DBGUI_ADDRn(drvdata, n) (drvdata->addr_offset + 4*n)
60#define DBGUI_DATAn(drvdata, n) (drvdata->data_offset + 4*n)
61
62#define DBGUI_TRIG_MASK 0xF0001
63#define DBGUI_MAX_ADDR_VAL 64
64#define DBGUI_TS_VALID BIT(15)
65#define DBGUI_ATB_TRACE_EN BIT(0)
66#define DBGUI_TIMER_CTR_OVERRIDE BIT(1)
67#define DBGUI_TIMER_CTR_EN BIT(0)
68
69/* ATID for DBGUI */
70#define APB_ATID 50
71#define AHB_ATID 52
72
73enum dbgui_trig_type {
74 DBGUI_TRIG_SW = BIT(0),
75 DBGUI_TRIG_TIMER = BIT(16),
76 DBGUI_TRIG_HWE = BIT(17),
77 DBGUI_TRIG_WDOG = BIT(18),
78 DBGUI_TRIG_CTI = BIT(19),
79};
80
81struct dbgui_drvdata {
82 void __iomem *base;
83 bool enable;
84 uint32_t addr_offset;
85 uint32_t data_offset;
86 uint32_t size;
87 struct device *dev;
88 struct coresight_device *csdev;
89 struct clk *clk;
90 struct mutex mutex;
91 uint32_t trig_mask;
92 bool capture_enable;
93 bool ts_enable;
94 bool timer_override_enable;
95 bool handoff_enable;
96 uint32_t nr_apb_regs;
97 uint32_t nr_ahb_regs;
98 uint32_t hwe_mask;
99 uint32_t addr_idx;
100 uint32_t timeout_val;
101 uint32_t addr_val[DBGUI_MAX_ADDR_VAL];
102 uint32_t data_val[DBGUI_MAX_ADDR_VAL];
103 struct msm_dump_data reg_data;
104};
105
106static struct dbgui_drvdata *dbgui_drvdata;
107
108static void dbgui_enable_atb_trace(struct dbgui_drvdata *drvdata)
109{
110 uint32_t reg;
111
112 reg = dbgui_readl(drvdata, DBGUI_ATB_REG);
113 reg |= DBGUI_ATB_TRACE_EN | APB_ATID << 8 | AHB_ATID << 1;
114 dbgui_writel(drvdata, reg, DBGUI_ATB_REG);
115}
116
117static void dbgui_disable_atb_trace(struct dbgui_drvdata *drvdata)
118{
119 uint32_t reg;
120
121 reg = dbgui_readl(drvdata, DBGUI_ATB_REG);
122 reg &= ~DBGUI_ATB_TRACE_EN;
123 dbgui_writel(drvdata, reg, DBGUI_ATB_REG);
124}
125
126static void dbgui_enable_timestamp(struct dbgui_drvdata *drvdata)
127{
128 uint32_t reg;
129
130 reg = dbgui_readl(drvdata, DBGUI_ATB_REG);
131 reg |= DBGUI_TS_VALID;
132 dbgui_writel(drvdata, reg, DBGUI_ATB_REG);
133}
134
135static void dbgui_disable_timestamp(struct dbgui_drvdata *drvdata)
136{
137 uint32_t reg;
138
139 reg = dbgui_readl(drvdata, DBGUI_ATB_REG);
140 reg &= ~DBGUI_TS_VALID;
141 dbgui_writel(drvdata, reg, DBGUI_ATB_REG);
142}
143
144static void dbgui_wait_for_pending_actions(struct dbgui_drvdata *drvdata)
145{
146 int count;
147 uint32_t reg_val;
148
149 for (count = TIMEOUT_US; reg_val =
150 dbgui_readl(drvdata, DBGUI_STATUS),
151 BMVAL(reg_val, 4, 7) != 0
152 && BVAL(reg_val, 0) != 0 && count > 0; count--)
153 udelay(1);
154
155 WARN(count == 0,
156 "timeout while waiting for pending action: STATUS %#x\n",
157 dbgui_readl(drvdata, DBGUI_STATUS));
158}
159
160static void __dbgui_capture_enable(struct dbgui_drvdata *drvdata)
161{
162 int i;
163 uint32_t reg_val;
164
165 DBGUI_UNLOCK(drvdata);
166
167 dbgui_wait_for_pending_actions(drvdata);
168 dbgui_writel(drvdata, 0x1, DBGUI_SECURE);
169 dbgui_writel(drvdata, 0x1, DBGUI_CTL);
170
171 reg_val = dbgui_readl(drvdata, DBGUI_NUM_REGS_RD);
172 reg_val &= ~0xFF;
173 reg_val |= (drvdata->nr_apb_regs | drvdata->nr_ahb_regs << 8);
174 dbgui_writel(drvdata, reg_val, DBGUI_NUM_REGS_RD);
175
176 for (i = 0; i < drvdata->size; i++) {
177 if (drvdata->addr_val[i])
178 dbgui_writel(drvdata, drvdata->addr_val[i],
179 DBGUI_ADDRn(drvdata, i));
180 }
181
182 if (!(drvdata->trig_mask & DBGUI_TRIG_TIMER) && drvdata->timeout_val) {
183 dbgui_writel(drvdata, drvdata->timeout_val, DBGUI_CTR_VAL);
184
185 reg_val = dbgui_readl(drvdata, DBGUI_CTR_EN);
186 if (drvdata->timer_override_enable)
187 reg_val |= DBGUI_TIMER_CTR_OVERRIDE;
188
189 reg_val |= DBGUI_TIMER_CTR_EN;
190 dbgui_writel(drvdata, reg_val, DBGUI_CTR_EN);
191 }
192
193 if (!(drvdata->trig_mask & DBGUI_TRIG_HWE))
194 dbgui_writel(drvdata, drvdata->hwe_mask, DBGUI_HWE_MASK);
195
196 dbgui_writel(drvdata, drvdata->trig_mask, DBGUI_CTL_MASK);
197
198 DBGUI_LOCK(drvdata);
199};
200
201static int dbgui_capture_enable(struct dbgui_drvdata *drvdata)
202{
203 int ret = 0;
204
205 mutex_lock(&drvdata->mutex);
206 if (drvdata->capture_enable)
207 goto out;
208
209 if (drvdata->trig_mask == DBGUI_TRIG_MASK) {
210 ret = -EINVAL;
211 goto out;
212 }
213
214 ret = clk_prepare_enable(drvdata->clk);
215 if (ret)
216 goto out;
217
218 if (!drvdata->handoff_enable)
219 __dbgui_capture_enable(drvdata);
220 drvdata->capture_enable = true;
221 mutex_unlock(&drvdata->mutex);
222
223 dev_info(drvdata->dev, "DebugUI capture enabled\n");
224 return 0;
225out:
226 mutex_unlock(&drvdata->mutex);
227 return ret;
228}
229
230static void __dbgui_capture_disable(struct dbgui_drvdata *drvdata)
231{
232 DBGUI_UNLOCK(drvdata);
233
234 dbgui_wait_for_pending_actions(drvdata);
235
236 /* mask all the triggers */
237 dbgui_writel(drvdata, DBGUI_TRIG_MASK, DBGUI_CTL_MASK);
238
239 DBGUI_LOCK(drvdata);
240}
241
242static int dbgui_capture_disable(struct dbgui_drvdata *drvdata)
243{
244 int ret = 0;
245
246 mutex_lock(&drvdata->mutex);
247 if (!drvdata->capture_enable)
248 goto out;
249
250 /* don't allow capture disable while its enabled as a trace source */
251 if (drvdata->enable) {
252 ret = -EPERM;
253 goto out;
254 }
255
256 __dbgui_capture_disable(drvdata);
257 clk_disable_unprepare(drvdata->clk);
258 drvdata->capture_enable = false;
259 mutex_unlock(&drvdata->mutex);
260
261 dev_info(drvdata->dev, "DebugUI capture disabled\n");
262 return 0;
263out:
264 mutex_unlock(&drvdata->mutex);
265 return ret;
266}
267
268static int __dbgui_enable(struct dbgui_drvdata *drvdata)
269{
270 DBGUI_UNLOCK(drvdata);
271
272 dbgui_enable_atb_trace(drvdata);
273 if (drvdata->ts_enable)
274 dbgui_enable_timestamp(drvdata);
275
276 DBGUI_LOCK(drvdata);
277 return 0;
278}
279
280static int dbgui_enable(struct coresight_device *csdev,
281 struct perf_event *event, u32 mode)
282{
283 struct dbgui_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
284
285 mutex_lock(&drvdata->mutex);
286
287 if (!drvdata->capture_enable) {
288 mutex_unlock(&drvdata->mutex);
289 return -EPERM;
290 }
291
292 __dbgui_enable(drvdata);
293 drvdata->enable = true;
294 mutex_unlock(&drvdata->mutex);
295
296 dev_info(drvdata->dev, "DebugUI tracing enabled\n");
297 return 0;
298}
299
300static void __dbgui_disable(struct dbgui_drvdata *drvdata)
301{
302 DBGUI_UNLOCK(drvdata);
303
304 dbgui_disable_atb_trace(drvdata);
305 if (drvdata->ts_enable)
306 dbgui_disable_timestamp(drvdata);
307
308 DBGUI_LOCK(drvdata);
309}
310
311static void dbgui_disable(struct coresight_device *csdev,
312 struct perf_event *event)
313{
314 struct dbgui_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
315
316 mutex_lock(&drvdata->mutex);
317 __dbgui_disable(drvdata);
318 drvdata->enable = false;
319 mutex_unlock(&drvdata->mutex);
320
321 dev_info(drvdata->dev, "DebugUI tracing disabled\n");
322}
323
324static int dbgui_trace_id(struct coresight_device *csdev)
325{
326 return 0;
327}
328
329static const struct coresight_ops_source dbgui_source_ops = {
330 .trace_id = dbgui_trace_id,
331 .enable = dbgui_enable,
332 .disable = dbgui_disable,
333};
334
335/* DebugUI may already be configured for capture, so retrieve current state */
336static void dbgui_handoff(struct dbgui_drvdata *drvdata)
337{
338 uint32_t val;
339 int i;
340
341 drvdata->handoff_enable = true;
342
343 drvdata->trig_mask = dbgui_readl(drvdata, DBGUI_CTL_MASK);
344 drvdata->hwe_mask = dbgui_readl(drvdata, DBGUI_HWE_MASK);
345 drvdata->timeout_val = dbgui_readl(drvdata, DBGUI_CTR_VAL);
346
347 val = dbgui_readl(drvdata, DBGUI_NUM_REGS_RD);
348 drvdata->nr_ahb_regs = (val >> 8) & 0xF;
349 drvdata->nr_apb_regs = val & 0xF;
350
351 val = dbgui_readl(drvdata, DBGUI_ATB_REG);
352 if (val & DBGUI_TS_VALID)
353 drvdata->ts_enable = true;
354
355 val = dbgui_readl(drvdata, DBGUI_CTR_EN);
356 if (val & DBGUI_TIMER_CTR_OVERRIDE)
357 drvdata->timer_override_enable = true;
358
359 for (i = 0; i < drvdata->size; i++)
360 drvdata->addr_val[i] = dbgui_readl(drvdata,
361 DBGUI_ADDRn(drvdata, i));
362
363 if (drvdata->trig_mask != DBGUI_TRIG_MASK)
364 dbgui_capture_enable(drvdata);
365
366 drvdata->handoff_enable = false;
367}
368
369static const struct coresight_ops dbgui_cs_ops = {
370 .source_ops = &dbgui_source_ops,
371};
372
373static ssize_t dbgui_store_trig_mask(struct device *dev,
374 struct device_attribute *attr,
375 const char *buf,
376 size_t size)
377{
Mukesh Ojha4949cde2018-02-21 19:17:54 +0530378 unsigned long val;
Mukesh Ojha4350ecb2017-11-30 19:24:55 +0530379 struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
380
Mukesh Ojha4949cde2018-02-21 19:17:54 +0530381 if (kstrtoul(buf, 16, &val))
Mukesh Ojha4350ecb2017-11-30 19:24:55 +0530382 return -EINVAL;
383
384 mutex_lock(&drvdata->mutex);
385 drvdata->trig_mask = val & DBGUI_TRIG_MASK;
386 mutex_unlock(&drvdata->mutex);
387
388 return size;
389}
390
391static ssize_t dbgui_show_trig_mask(struct device *dev,
392 struct device_attribute *attr, char *buf)
393{
394 struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
395
396 return scnprintf(buf, PAGE_SIZE, "0x%x\n", drvdata->trig_mask);
397};
398static DEVICE_ATTR(trig_mask, 0644,
399 dbgui_show_trig_mask, dbgui_store_trig_mask);
400
401static ssize_t dbgui_store_timer_override_enable(struct device *dev,
402 struct device_attribute *attr,
403 const char *buf,
404 size_t size)
405{
Mukesh Ojha4949cde2018-02-21 19:17:54 +0530406 unsigned long val;
Mukesh Ojha4350ecb2017-11-30 19:24:55 +0530407 struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
408
Mukesh Ojha4949cde2018-02-21 19:17:54 +0530409 if (kstrtoul(buf, 16, &val))
Mukesh Ojha4350ecb2017-11-30 19:24:55 +0530410 return -EINVAL;
411
412 mutex_lock(&drvdata->mutex);
413 drvdata->timer_override_enable = val ? true : false;
414 mutex_unlock(&drvdata->mutex);
415
416 return size;
417}
418
419static ssize_t dbgui_show_timer_override_enable(struct device *dev,
420 struct device_attribute *attr,
421 char *buf)
422{
423 struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
424
425 return scnprintf(buf, PAGE_SIZE, "0x%x\n",
426 drvdata->timer_override_enable);
427};
428static DEVICE_ATTR(timer_override_enable, 0644,
429 dbgui_show_timer_override_enable,
430 dbgui_store_timer_override_enable);
431
432static ssize_t dbgui_store_ts_enable(struct device *dev,
433 struct device_attribute *attr,
434 const char *buf,
435 size_t size)
436{
Mukesh Ojha4949cde2018-02-21 19:17:54 +0530437 unsigned long val;
Mukesh Ojha4350ecb2017-11-30 19:24:55 +0530438 struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
439
Mukesh Ojha4949cde2018-02-21 19:17:54 +0530440 if (kstrtoul(buf, 16, &val))
Mukesh Ojha4350ecb2017-11-30 19:24:55 +0530441 return -EINVAL;
442
443 mutex_lock(&drvdata->mutex);
444 drvdata->ts_enable = val ? true : false;
445 mutex_unlock(&drvdata->mutex);
446
447 return size;
448}
449
450static ssize_t dbgui_show_ts_enable(struct device *dev,
451 struct device_attribute *attr,
452 char *buf)
453{
454 struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
455
456 return scnprintf(buf, PAGE_SIZE, "0x%x\n", drvdata->ts_enable);
457};
458static DEVICE_ATTR(ts_enable, 0644,
459 dbgui_show_ts_enable, dbgui_store_ts_enable);
460
461static ssize_t dbgui_store_hwe_mask(struct device *dev,
462 struct device_attribute *attr,
463 const char *buf,
464 size_t size)
465{
Mukesh Ojha4949cde2018-02-21 19:17:54 +0530466 unsigned long val;
Mukesh Ojha4350ecb2017-11-30 19:24:55 +0530467 struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
468
Mukesh Ojha4949cde2018-02-21 19:17:54 +0530469 if (kstrtoul(buf, 16, &val))
Mukesh Ojha4350ecb2017-11-30 19:24:55 +0530470 return -EINVAL;
471
472 mutex_lock(&drvdata->mutex);
473 drvdata->hwe_mask = val;
474 mutex_unlock(&drvdata->mutex);
475
476 return size;
477}
478
479static ssize_t dbgui_show_hwe_mask(struct device *dev,
480 struct device_attribute *attr,
481 char *buf)
482{
483 struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
484
485 return scnprintf(buf, PAGE_SIZE, "0x%x\n", drvdata->hwe_mask);
486};
487static DEVICE_ATTR(hwe_mask, 0644,
488 dbgui_show_hwe_mask, dbgui_store_hwe_mask);
489
490static ssize_t dbgui_store_sw_trig(struct device *dev,
491 struct device_attribute *attr,
492 const char *buf,
493 size_t size)
494{
Mukesh Ojha4949cde2018-02-21 19:17:54 +0530495 unsigned long val;
Mukesh Ojha4350ecb2017-11-30 19:24:55 +0530496 struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
497
Mukesh Ojha4949cde2018-02-21 19:17:54 +0530498 if (kstrtoul(buf, 16, &val))
Mukesh Ojha4350ecb2017-11-30 19:24:55 +0530499 return -EINVAL;
500
501 if (!val)
502 return 0;
503
504 mutex_lock(&drvdata->mutex);
505 if (!drvdata->capture_enable) {
506 mutex_unlock(&drvdata->mutex);
507 return -EINVAL;
508 }
509
510 dbgui_wait_for_pending_actions(drvdata);
511 DBGUI_UNLOCK(drvdata);
512
513 /* clear status register and free the sequencer */
514 dbgui_writel(drvdata, 0x1, DBGUI_CTL);
515
516 /* fire a software trigger */
517 dbgui_writel(drvdata, 0x1, DBGUI_SWTRIG);
518
519 DBGUI_LOCK(drvdata);
520 mutex_unlock(&drvdata->mutex);
521
522 return size;
523}
524static DEVICE_ATTR(sw_trig, 0200, NULL, dbgui_store_sw_trig);
525
526static ssize_t dbgui_store_nr_ahb_regs(struct device *dev,
527 struct device_attribute *attr,
528 const char *buf,
529 size_t size)
530{
Mukesh Ojha4949cde2018-02-21 19:17:54 +0530531 unsigned long val;
Mukesh Ojha4350ecb2017-11-30 19:24:55 +0530532 struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
533
Mukesh Ojha4949cde2018-02-21 19:17:54 +0530534 if (kstrtoul(buf, 16, &val))
Mukesh Ojha4350ecb2017-11-30 19:24:55 +0530535 return -EINVAL;
536
537 if (val > drvdata->size)
538 return -EINVAL;
539
540 mutex_lock(&drvdata->mutex);
541 drvdata->nr_ahb_regs = val;
542
543 /*
544 * Please make sure nr_ahb_regs + nr_apb_regs isn't greater than
545 * drvdata->size. If sum is greater than size, The last setting
546 * of nr_ahb_regs or nr_apb_regs takes high priority.
547 */
548 if (drvdata->nr_apb_regs + drvdata->nr_ahb_regs > drvdata->size)
549 drvdata->nr_apb_regs = drvdata->size -
550 drvdata->nr_ahb_regs;
551
552 mutex_unlock(&drvdata->mutex);
553
554 return size;
555}
556
557static ssize_t dbgui_show_nr_ahb_regs(struct device *dev,
558 struct device_attribute *attr, char *buf)
559{
560 struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
561
562 return scnprintf(buf, PAGE_SIZE, "0x%x\n", drvdata->nr_ahb_regs);
563};
564static DEVICE_ATTR(nr_ahb_regs, 0644, dbgui_show_nr_ahb_regs,
565 dbgui_store_nr_ahb_regs);
566
567static ssize_t dbgui_store_nr_apb_regs(struct device *dev,
568 struct device_attribute *attr,
569 const char *buf,
570 size_t size)
571{
Mukesh Ojha4949cde2018-02-21 19:17:54 +0530572 unsigned long val;
Mukesh Ojha4350ecb2017-11-30 19:24:55 +0530573 struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
574
Mukesh Ojha4949cde2018-02-21 19:17:54 +0530575 if (kstrtoul(buf, 16, &val))
Mukesh Ojha4350ecb2017-11-30 19:24:55 +0530576 return -EINVAL;
577
578 if (val > drvdata->size)
579 return -EINVAL;
580
581 mutex_lock(&drvdata->mutex);
582 drvdata->nr_apb_regs = val;
583
584 if (drvdata->nr_apb_regs + drvdata->nr_ahb_regs > drvdata->size)
585 drvdata->nr_ahb_regs = drvdata->size -
586 drvdata->nr_apb_regs;
587
588 mutex_unlock(&drvdata->mutex);
589
590 return size;
591}
592
593static ssize_t dbgui_show_nr_apb_regs(struct device *dev,
594 struct device_attribute *attr,
595 char *buf)
596{
597 struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
598
599 return scnprintf(buf, PAGE_SIZE, "0x%x\n", drvdata->nr_apb_regs);
600};
601static DEVICE_ATTR(nr_apb_regs, 0644, dbgui_show_nr_apb_regs,
602 dbgui_store_nr_apb_regs);
603
604static ssize_t dbgui_show_size(struct device *dev,
605 struct device_attribute *attr, char *buf)
606{
607 struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
608
609 return scnprintf(buf, PAGE_SIZE, "0x%x\n", drvdata->size);
610};
611static DEVICE_ATTR(size, 0644, dbgui_show_size, NULL);
612
613static ssize_t dbgui_store_timeout_val(struct device *dev,
614 struct device_attribute *attr,
615 const char *buf,
616 size_t size)
617{
Mukesh Ojha4949cde2018-02-21 19:17:54 +0530618 unsigned long val;
Mukesh Ojha4350ecb2017-11-30 19:24:55 +0530619 struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
620
Mukesh Ojha4949cde2018-02-21 19:17:54 +0530621 if (kstrtoul(buf, 16, &val))
Mukesh Ojha4350ecb2017-11-30 19:24:55 +0530622 return -EINVAL;
623
624 mutex_lock(&drvdata->mutex);
625 drvdata->timeout_val = val;
626 mutex_unlock(&drvdata->mutex);
627
628 return size;
629}
630
631static ssize_t dbgui_show_timeout_val(struct device *dev,
632 struct device_attribute *attr, char *buf)
633{
634 struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
635
636 return scnprintf(buf, PAGE_SIZE, "0x%x\n", drvdata->timeout_val);
637};
638static DEVICE_ATTR(timeout_val, 0644, dbgui_show_timeout_val,
639 dbgui_store_timeout_val);
640
641static ssize_t dbgui_store_addr_idx(struct device *dev,
642 struct device_attribute *attr,
643 const char *buf,
644 size_t size)
645{
Mukesh Ojha4949cde2018-02-21 19:17:54 +0530646 unsigned long val;
Mukesh Ojha4350ecb2017-11-30 19:24:55 +0530647 struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
648
Mukesh Ojha4949cde2018-02-21 19:17:54 +0530649 if (kstrtoul(buf, 16, &val))
Mukesh Ojha4350ecb2017-11-30 19:24:55 +0530650 return -EINVAL;
651
652 if (val >= drvdata->size)
653 return -EINVAL;
654
655 mutex_lock(&drvdata->mutex);
656 drvdata->addr_idx = val;
657 mutex_unlock(&drvdata->mutex);
658
659 return size;
660}
661
662static ssize_t dbgui_show_addr_idx(struct device *dev,
663 struct device_attribute *attr, char *buf)
664{
665 struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
666
667 return scnprintf(buf, PAGE_SIZE, "0x%x\n", drvdata->addr_idx);
668};
669static DEVICE_ATTR(addr_idx, 0644, dbgui_show_addr_idx,
670 dbgui_store_addr_idx);
671
672static ssize_t dbgui_store_addr_val(struct device *dev,
673 struct device_attribute *attr,
674 const char *buf,
675 size_t size)
676{
Mukesh Ojha4949cde2018-02-21 19:17:54 +0530677 unsigned long val;
Mukesh Ojha4350ecb2017-11-30 19:24:55 +0530678 struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
679
Mukesh Ojha4949cde2018-02-21 19:17:54 +0530680 if (kstrtoul(buf, 16, &val))
Mukesh Ojha4350ecb2017-11-30 19:24:55 +0530681 return -EINVAL;
682
683 mutex_lock(&drvdata->mutex);
684 drvdata->addr_val[drvdata->addr_idx] = val;
685 mutex_unlock(&drvdata->mutex);
686
687 return size;
688}
689
690static ssize_t dbgui_show_addr_val(struct device *dev,
691 struct device_attribute *attr, char *buf)
692{
693 struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
694 ssize_t len = 0;
695 int i;
696
697 mutex_lock(&drvdata->mutex);
698 for (i = 0; i < drvdata->size; i++)
699 len += scnprintf(buf + len, PAGE_SIZE - len,
700 "[%02d]:0x%08x%s\n",
701 i, drvdata->addr_val[i],
702 drvdata->addr_idx == i ?
703 " *" : "");
704 mutex_unlock(&drvdata->mutex);
705
706 return len;
707};
708static DEVICE_ATTR(addr_val, 0644, dbgui_show_addr_val,
709 dbgui_store_addr_val);
710
711static ssize_t dbgui_show_data_val(struct device *dev,
712 struct device_attribute *attr, char *buf)
713{
714 struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
715 ssize_t len = 0;
716 int i;
717 uint32_t val, trig_mask;
718
719 if (!drvdata->capture_enable)
720 return 0;
721
722 dbgui_wait_for_pending_actions(drvdata);
723
724 mutex_lock(&drvdata->mutex);
725
726 DBGUI_UNLOCK(drvdata);
727
728 /*
729 * If the timer trigger is enabled, data might change while we read it.
730 * We mask all the trggers here to avoid this.
731 */
732 trig_mask = dbgui_readl(drvdata, DBGUI_CTL_MASK);
733 dbgui_writel(drvdata, DBGUI_TRIG_MASK, DBGUI_CTL_MASK);
734
735 for (i = 0; i < drvdata->size; i++) {
736 val = dbgui_readl(drvdata, DBGUI_DATAn(drvdata, i));
737 drvdata->data_val[i] = val;
738 len += scnprintf(buf + len, PAGE_SIZE - len,
739 "[%02d]:0x%08x\n",
740 i, drvdata->data_val[i]);
741 }
742 dbgui_writel(drvdata, trig_mask, DBGUI_CTL_MASK);
743
744 DBGUI_LOCK(drvdata);
745
746 mutex_unlock(&drvdata->mutex);
747
748 return len;
749};
750static DEVICE_ATTR(data_val, 0444, dbgui_show_data_val, NULL);
751
752static ssize_t dbgui_store_capture_enable(struct device *dev,
753 struct device_attribute *attr,
754 const char *buf,
755 size_t size)
756{
757 struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
Mukesh Ojha4949cde2018-02-21 19:17:54 +0530758 uint32_t ret;
759 unsigned long val;
Mukesh Ojha4350ecb2017-11-30 19:24:55 +0530760
Mukesh Ojha4949cde2018-02-21 19:17:54 +0530761 if (kstrtoul(buf, 16, &val))
Mukesh Ojha4350ecb2017-11-30 19:24:55 +0530762 return -EINVAL;
763
764 if (val)
765 ret = dbgui_capture_enable(drvdata);
766 else
767 ret = dbgui_capture_disable(drvdata);
768
769 if (ret)
770 return ret;
771 return size;
772}
773
774static ssize_t dbgui_show_capture_enable(struct device *dev,
775 struct device_attribute *attr, char *buf)
776{
777 struct dbgui_drvdata *drvdata = dev_get_drvdata(dev->parent);
778
779 return scnprintf(buf, PAGE_SIZE, "0x%x\n", drvdata->capture_enable);
780};
781static DEVICE_ATTR(capture_enable, 0644,
782 dbgui_show_capture_enable,
783 dbgui_store_capture_enable);
784
785static struct attribute *dbgui_attrs[] = {
786 &dev_attr_sw_trig.attr,
787 &dev_attr_trig_mask.attr,
788 &dev_attr_capture_enable.attr,
789 &dev_attr_ts_enable.attr,
790 &dev_attr_hwe_mask.attr,
791 &dev_attr_timer_override_enable.attr,
792 &dev_attr_size.attr,
793 &dev_attr_nr_ahb_regs.attr,
794 &dev_attr_nr_apb_regs.attr,
795 &dev_attr_timeout_val.attr,
796 &dev_attr_addr_idx.attr,
797 &dev_attr_addr_val.attr,
798 &dev_attr_data_val.attr,
799 NULL,
800};
801
802static struct attribute_group dbgui_attr_grp = {
803 .attrs = dbgui_attrs,
804};
805
806static const struct attribute_group *dbgui_attr_grps[] = {
807 &dbgui_attr_grp,
808 NULL,
809};
810
811static int dbgui_probe(struct platform_device *pdev)
812{
813 int ret;
814 struct device *dev = &pdev->dev;
815 struct coresight_platform_data *pdata;
816 struct dbgui_drvdata *drvdata;
817 struct resource *res;
818 struct coresight_desc *desc;
819 struct msm_dump_entry dump_entry;
820 void *baddr;
821
822 pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
823 if (IS_ERR(pdata))
824 return PTR_ERR(pdata);
825 pdev->dev.platform_data = pdata;
826
827 drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
828 if (!drvdata)
829 return -ENOMEM;
830
831 drvdata->dev = &pdev->dev;
832 platform_set_drvdata(pdev, drvdata);
833 mutex_init(&drvdata->mutex);
834
835 drvdata->clk = devm_clk_get(dev, "apb_pclk");
836 if (IS_ERR(drvdata->clk))
837 return PTR_ERR(drvdata->clk);
838
839 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbgui-base");
840 if (!res) {
841 dev_info(dev, "DBGUI base not specified\n");
842 return -ENODEV;
843 }
844
845 drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
846 if (!drvdata->base)
847 return -ENOMEM;
848
849 ret = clk_prepare_enable(drvdata->clk);
850 if (ret)
851 return ret;
852
853 if (!coresight_authstatus_enabled(drvdata->base))
854 goto err;
855
856 clk_disable_unprepare(drvdata->clk);
857
858 baddr = devm_kzalloc(dev, resource_size(res), GFP_KERNEL);
859 if (baddr) {
860 drvdata->reg_data.addr = virt_to_phys(baddr);
861 drvdata->reg_data.len = resource_size(res);
862 dump_entry.id = MSM_DUMP_DATA_DBGUI_REG;
863 dump_entry.addr = virt_to_phys(&drvdata->reg_data);
864 ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS,
865 &dump_entry);
866 if (ret) {
867 devm_kfree(dev, baddr);
868 dev_err(dev, "DBGUI REG dump setup failed\n");
869 }
870 } else {
871 dev_err(dev, "DBGUI REG dump allocation failed\n");
872 }
873
874 ret = of_property_read_u32(pdev->dev.of_node,
875 "qcom,dbgui-addr-offset",
876 &drvdata->addr_offset);
877 if (ret)
878 return -EINVAL;
879
880 ret = of_property_read_u32(pdev->dev.of_node,
881 "qcom,dbgui-data-offset",
882 &drvdata->data_offset);
883 if (ret)
884 return -EINVAL;
885
886 if (drvdata->addr_offset >= resource_size(res)
887 || drvdata->data_offset >= resource_size(res)) {
888 dev_err(dev, "Invalid address or data offset\n");
889 return -EINVAL;
890 }
891
892 ret = of_property_read_u32(pdev->dev.of_node,
893 "qcom,dbgui-size",
894 &drvdata->size);
895 if (ret || drvdata->size > DBGUI_MAX_ADDR_VAL)
896 return -EINVAL;
897
898 ret = clk_prepare_enable(drvdata->clk);
899 if (ret)
900 return ret;
901
902 dbgui_handoff(drvdata);
903 clk_disable_unprepare(drvdata->clk);
904 /*
905 * To provide addr_offset, data_offset and size via a global variable.
906 * NOTE: Only single dbgui device is supported now.
907 */
908 dbgui_drvdata = drvdata;
909
910 desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
911 if (!desc)
912 return -ENOMEM;
913 desc->type = CORESIGHT_DEV_TYPE_SOURCE;
914 desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
915 desc->ops = &dbgui_cs_ops;
916 desc->pdata = pdev->dev.platform_data;
917 desc->dev = &pdev->dev;
918 desc->groups = dbgui_attr_grps;
919 drvdata->csdev = coresight_register(desc);
920 if (IS_ERR(drvdata->csdev))
921 return PTR_ERR(drvdata->csdev);
922
923 dev_info(dev, "DebugUI initializaed\n");
924 return 0;
925err:
926 clk_disable_unprepare(drvdata->clk);
927 return -EPERM;
928}
929
930static int dbgui_remove(struct platform_device *pdev)
931{
932 struct dbgui_drvdata *drvdata = platform_get_drvdata(pdev);
933
934 coresight_unregister(drvdata->csdev);
935 return 0;
936}
937
938static const struct of_device_id dbgui_match[] = {
939 {.compatible = "qcom,coresight-dbgui"},
940 {}
941};
942
943static struct platform_driver dbgui_driver = {
944 .probe = dbgui_probe,
945 .remove = dbgui_remove,
946 .driver = {
947 .name = "coresight-dbgui",
948 .owner = THIS_MODULE,
949 .of_match_table = dbgui_match,
950 },
951};
952
953static int __init dbgui_init(void)
954{
955 return platform_driver_register(&dbgui_driver);
956}
957module_init(dbgui_init);
958
959static void __exit dbgui_exit(void)
960{
961 return platform_driver_unregister(&dbgui_driver);
962}
963module_exit(dbgui_exit);
964
965MODULE_LICENSE("GPL v2");
966MODULE_DESCRIPTION("CoreSight DebugUI driver");