blob: 3e686e95fd2bdd1024597bb8ca03fef4119fd3e6 [file] [log] [blame]
Benjamin Chan59a06052017-01-12 18:06:03 -05001/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12#define pr_fmt(fmt) "%s: " fmt, __func__
13
14#include <linux/types.h>
15#include <linux/kernel.h>
16#include <linux/slab.h>
17#include <linux/uaccess.h>
18#include <linux/debugfs.h>
19
20#include "sde_rotator_debug.h"
21#include "sde_rotator_base.h"
22#include "sde_rotator_core.h"
23#include "sde_rotator_dev.h"
24
Benjamin Chan53e3bce2016-08-31 14:43:29 -040025#ifdef CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG
26#define SDE_EVTLOG_DEFAULT_ENABLE 1
27#else
28#define SDE_EVTLOG_DEFAULT_ENABLE 0
29#endif
30#define SDE_EVTLOG_DEFAULT_PANIC 1
31#define SDE_EVTLOG_DEFAULT_REGDUMP SDE_ROT_DBG_DUMP_IN_MEM
32#define SDE_EVTLOG_DEFAULT_VBIF_DBGBUSDUMP SDE_ROT_DBG_DUMP_IN_MEM
Benjamin Chan2d6411a2017-03-28 18:01:53 -040033#define SDE_EVTLOG_DEFAULT_ROT_DBGBUSDUMP SDE_ROT_DBG_DUMP_IN_MEM
Benjamin Chan53e3bce2016-08-31 14:43:29 -040034
35/*
36 * evtlog will print this number of entries when it is called through
37 * sysfs node or panic. This prevents kernel log from evtlog message
38 * flood.
39 */
40#define SDE_ROT_EVTLOG_PRINT_ENTRY 256
41
42/*
43 * evtlog keeps this number of entries in memory for debug purpose. This
44 * number must be greater than print entry to prevent out of bound evtlog
45 * entry array access.
46 */
47#define SDE_ROT_EVTLOG_ENTRY (SDE_ROT_EVTLOG_PRINT_ENTRY * 4)
48#define SDE_ROT_EVTLOG_MAX_DATA 15
49#define SDE_ROT_EVTLOG_BUF_MAX 512
50#define SDE_ROT_EVTLOG_BUF_ALIGN 32
51#define SDE_ROT_DEBUG_BASE_MAX 10
52
Benjamin Chan6a0d2412016-10-27 17:47:46 -040053#define SDE_ROT_DEFAULT_BASE_REG_CNT 0x100
54#define GROUP_BYTES 4
55#define ROW_BYTES 16
56
Benjamin Chan2d6411a2017-03-28 18:01:53 -040057#define SDE_ROT_TEST_MASK(id, tp) ((id << 4) | (tp << 1) | BIT(0))
58
Benjamin Chan53e3bce2016-08-31 14:43:29 -040059static DEFINE_SPINLOCK(sde_rot_xlock);
60
61/*
62 * tlog - EVTLOG entry structure
63 * @counter - EVTLOG entriy counter
64 * @time - timestamp of EVTLOG entry
65 * @name - function name of EVTLOG entry
66 * @line - line number of EVTLOG entry
67 * @data - EVTLOG data contents
68 * @data_cnt - number of data contents
69 * @pid - pid of current calling thread
70 */
71struct tlog {
72 u32 counter;
73 s64 time;
74 const char *name;
75 int line;
76 u32 data[SDE_ROT_EVTLOG_MAX_DATA];
77 u32 data_cnt;
78 int pid;
79};
80
81/*
82 * sde_rot_dbg_evtlog - EVTLOG debug data structure
83 * @logs - EVTLOG entries
84 * @first - first entry index in the EVTLOG
85 * @last - last entry index in the EVTLOG
86 * @curr - curr entry index in the EVTLOG
87 * @evtlog - EVTLOG debugfs handle
88 * @evtlog_enable - boolean indicates EVTLOG enable/disable
89 * @panic_on_err - boolean indicates issue panic after EVTLOG dump
90 * @enable_reg_dump - control in-log/memory dump for rotator registers
91 * @enable_vbif_dbgbus_dump - control in-log/memory dump for VBIF debug bus
Benjamin Chan2d6411a2017-03-28 18:01:53 -040092 * @enable_rot_dbgbus_dump - control in-log/memroy dump for rotator debug bus
Benjamin Chan53e3bce2016-08-31 14:43:29 -040093 * @evtlog_dump_work - schedule work strucutre for timeout handler
94 * @work_dump_reg - storage for register dump control in schedule work
95 * @work_panic - storage for panic control in schedule work
96 * @work_vbif_dbgbus - storage for VBIF debug bus control in schedule work
Benjamin Chan2d6411a2017-03-28 18:01:53 -040097 * @work_rot_dbgbus - storage for rotator debug bus control in schedule work
Benjamin Chan53e3bce2016-08-31 14:43:29 -040098 * @nrt_vbif_dbgbus_dump - memory buffer for VBIF debug bus dumping
Benjamin Chan2d6411a2017-03-28 18:01:53 -040099 * @rot_dbgbus_dump - memory buffer for rotator debug bus dumping
Benjamin Chan53e3bce2016-08-31 14:43:29 -0400100 * @reg_dump_array - memory buffer for rotator registers dumping
101 */
102struct sde_rot_dbg_evtlog {
103 struct tlog logs[SDE_ROT_EVTLOG_ENTRY];
104 u32 first;
105 u32 last;
106 u32 curr;
107 struct dentry *evtlog;
108 u32 evtlog_enable;
109 u32 panic_on_err;
110 u32 enable_reg_dump;
111 u32 enable_vbif_dbgbus_dump;
Benjamin Chan2d6411a2017-03-28 18:01:53 -0400112 u32 enable_rot_dbgbus_dump;
Benjamin Chan53e3bce2016-08-31 14:43:29 -0400113 struct work_struct evtlog_dump_work;
114 bool work_dump_reg;
115 bool work_panic;
116 bool work_vbif_dbgbus;
Benjamin Chan2d6411a2017-03-28 18:01:53 -0400117 bool work_rot_dbgbus;
Benjamin Chan53e3bce2016-08-31 14:43:29 -0400118 u32 *nrt_vbif_dbgbus_dump; /* address for the nrt vbif debug bus dump */
Benjamin Chan2d6411a2017-03-28 18:01:53 -0400119 u32 *rot_dbgbus_dump;
Benjamin Chan53e3bce2016-08-31 14:43:29 -0400120 u32 *reg_dump_array[SDE_ROT_DEBUG_BASE_MAX];
121} sde_rot_dbg_evtlog;
122
Benjamin Chan2d6411a2017-03-28 18:01:53 -0400123static void sde_rot_dump_debug_bus(u32 bus_dump_flag, u32 **dump_mem)
124{
125 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
126 bool in_log, in_mem;
127 u32 *dump_addr = NULL;
128 u32 status = 0;
129 struct sde_rot_debug_bus *head;
130 phys_addr_t phys = 0;
131 int i;
132 u32 offset;
133 void __iomem *base;
134
135 in_log = (bus_dump_flag & SDE_ROT_DBG_DUMP_IN_LOG);
136 in_mem = (bus_dump_flag & SDE_ROT_DBG_DUMP_IN_MEM);
137 base = mdata->sde_io.base;
138
139 if (!base || !mdata->rot_dbg_bus || !mdata->rot_dbg_bus_size)
140 return;
141
142 pr_info("======== SDE Rotator Debug bus DUMP =========\n");
143
144 if (in_mem) {
145 if (!(*dump_mem))
146 *dump_mem = dma_alloc_coherent(&mdata->pdev->dev,
147 mdata->rot_dbg_bus_size * 4 * sizeof(u32),
148 &phys, GFP_KERNEL);
149
150 if (*dump_mem) {
151 dump_addr = *dump_mem;
152 pr_info("%s: start_addr:0x%pK end_addr:0x%pK\n",
153 __func__, dump_addr,
154 dump_addr + (u32)mdata->rot_dbg_bus_size * 16);
155 } else {
156 in_mem = false;
157 pr_err("dump_mem: allocation fails\n");
158 }
159 }
160
161 sde_smmu_ctrl(1);
162
163 for (i = 0; i < mdata->rot_dbg_bus_size; i++) {
164 head = mdata->rot_dbg_bus + i;
165 writel_relaxed(SDE_ROT_TEST_MASK(head->block_id, head->test_id),
166 base + head->wr_addr);
167 wmb(); /* make sure test bits were written */
168
169 offset = head->wr_addr + 0x4;
170
171 status = readl_relaxed(base + offset);
172
173 if (in_log)
174 pr_err("waddr=0x%x blk=%d tst=%d val=0x%x\n",
175 head->wr_addr, head->block_id, head->test_id,
176 status);
177
178 if (dump_addr && in_mem) {
179 dump_addr[i*4] = head->wr_addr;
180 dump_addr[i*4 + 1] = head->block_id;
181 dump_addr[i*4 + 2] = head->test_id;
182 dump_addr[i*4 + 3] = status;
183 }
184
185 /* Disable debug bus once we are done */
186 writel_relaxed(0, base + head->wr_addr);
187 }
188
189 sde_smmu_ctrl(0);
190
191 pr_info("========End Debug bus=========\n");
192}
193
Benjamin Chan53e3bce2016-08-31 14:43:29 -0400194/*
195 * sde_rot_evtlog_is_enabled - helper function for checking EVTLOG
196 * enable/disable
197 * @flag - EVTLOG option flag
198 */
199static inline bool sde_rot_evtlog_is_enabled(u32 flag)
200{
201 return (flag & sde_rot_dbg_evtlog.evtlog_enable) ||
202 (flag == SDE_ROT_EVTLOG_ALL &&
203 sde_rot_dbg_evtlog.evtlog_enable);
204}
205
206/*
207 * __vbif_debug_bus - helper function for VBIF debug bus dump
208 * @head - VBIF debug bus data structure
209 * @vbif_base - VBIF IO mapped address
210 * @dump_addr - output buffer for memory dump option
211 * @in_log - boolean indicates in-log dump option
212 */
213static void __vbif_debug_bus(struct sde_rot_vbif_debug_bus *head,
214 void __iomem *vbif_base, u32 *dump_addr, bool in_log)
215{
216 int i, j;
217 u32 val;
218
219 if (!dump_addr && !in_log)
220 return;
221
222 for (i = 0; i < head->block_cnt; i++) {
223 writel_relaxed(1 << (i + head->bit_offset),
224 vbif_base + head->block_bus_addr);
225 /* make sure that current bus blcok enable */
226 wmb();
227 for (j = 0; j < head->test_pnt_cnt; j++) {
228 writel_relaxed(j, vbif_base + head->block_bus_addr + 4);
229 /* make sure that test point is enabled */
230 wmb();
231 val = readl_relaxed(vbif_base + MMSS_VBIF_TEST_BUS_OUT);
232 if (dump_addr) {
233 *dump_addr++ = head->block_bus_addr;
234 *dump_addr++ = i;
235 *dump_addr++ = j;
236 *dump_addr++ = val;
237 }
238 if (in_log)
239 pr_err("testpoint:%x arb/xin id=%d index=%d val=0x%x\n",
240 head->block_bus_addr, i, j, val);
241 }
242 }
243}
244
245/*
246 * sde_rot_dump_vbif_debug_bus - VBIF debug bus dump
247 * @bus_dump_flag - dump flag controlling in-log/memory dump option
248 * @dump_mem - output buffer for memory dump location
249 */
250static void sde_rot_dump_vbif_debug_bus(u32 bus_dump_flag,
251 u32 **dump_mem)
252{
253 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
254 bool in_log, in_mem;
255 u32 *dump_addr = NULL;
256 u32 value;
257 struct sde_rot_vbif_debug_bus *head;
258 phys_addr_t phys = 0;
259 int i, list_size = 0;
260 void __iomem *vbif_base;
261 struct sde_rot_vbif_debug_bus *dbg_bus;
262 u32 bus_size;
263
264 pr_info("======== NRT VBIF Debug bus DUMP =========\n");
265 vbif_base = mdata->vbif_nrt_io.base;
266 dbg_bus = mdata->nrt_vbif_dbg_bus;
267 bus_size = mdata->nrt_vbif_dbg_bus_size;
268
269 if (!vbif_base || !dbg_bus || !bus_size)
270 return;
271
272 /* allocate memory for each test point */
273 for (i = 0; i < bus_size; i++) {
274 head = dbg_bus + i;
275 list_size += (head->block_cnt * head->test_pnt_cnt);
276 }
277
278 /* 4 bytes * 4 entries for each test point*/
279 list_size *= 16;
280
281 in_log = (bus_dump_flag & SDE_ROT_DBG_DUMP_IN_LOG);
282 in_mem = (bus_dump_flag & SDE_ROT_DBG_DUMP_IN_MEM);
283
284 if (in_mem) {
285 if (!(*dump_mem))
286 *dump_mem = dma_alloc_coherent(&mdata->pdev->dev,
287 list_size, &phys, GFP_KERNEL);
288
289 if (*dump_mem) {
290 dump_addr = *dump_mem;
291 pr_info("%s: start_addr:0x%pK end_addr:0x%pK\n",
292 __func__, dump_addr, dump_addr + list_size);
293 } else {
294 in_mem = false;
295 pr_err("dump_mem: allocation fails\n");
296 }
297 }
298
299 sde_smmu_ctrl(1);
300
301 value = readl_relaxed(vbif_base + MMSS_VBIF_CLKON);
302 writel_relaxed(value | BIT(1), vbif_base + MMSS_VBIF_CLKON);
303
304 /* make sure that vbif core is on */
305 wmb();
306
307 for (i = 0; i < bus_size; i++) {
308 head = dbg_bus + i;
309
310 writel_relaxed(0, vbif_base + head->disable_bus_addr);
311 writel_relaxed(BIT(0), vbif_base + MMSS_VBIF_TEST_BUS_OUT_CTRL);
312 /* make sure that other bus is off */
313 wmb();
314
315 __vbif_debug_bus(head, vbif_base, dump_addr, in_log);
316 if (dump_addr)
317 dump_addr += (head->block_cnt * head->test_pnt_cnt * 4);
318 }
319
320 sde_smmu_ctrl(0);
321
322 pr_info("========End VBIF Debug bus=========\n");
323}
324
325/*
326 * sde_rot_dump_reg - helper function for dumping rotator register set content
327 * @dump_name - register set name
328 * @reg_dump_flag - dumping flag controlling in-log/memory dump location
Benjamin Chan59a06052017-01-12 18:06:03 -0500329 * @access - access type, sde registers or vbif registers
Benjamin Chan53e3bce2016-08-31 14:43:29 -0400330 * @addr - starting address offset for dumping
331 * @len - range of the register set
332 * @dump_mem - output buffer for memory dump location option
333 */
Benjamin Chan59a06052017-01-12 18:06:03 -0500334void sde_rot_dump_reg(const char *dump_name, u32 reg_dump_flag,
335 enum sde_rot_regdump_access access, u32 addr,
Benjamin Chan53e3bce2016-08-31 14:43:29 -0400336 int len, u32 **dump_mem)
337{
338 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
339 bool in_log, in_mem;
340 u32 *dump_addr = NULL;
341 phys_addr_t phys = 0;
342 int i;
Benjamin Chan59a06052017-01-12 18:06:03 -0500343 void __iomem *base;
Benjamin Chan53e3bce2016-08-31 14:43:29 -0400344
345 in_log = (reg_dump_flag & SDE_ROT_DBG_DUMP_IN_LOG);
346 in_mem = (reg_dump_flag & SDE_ROT_DBG_DUMP_IN_MEM);
347
348 pr_debug("reg_dump_flag=%d in_log=%d in_mem=%d\n",
349 reg_dump_flag, in_log, in_mem);
350
351 if (len % 16)
352 len += 16;
353 len /= 16;
354
355 if (in_mem) {
356 if (!(*dump_mem))
357 *dump_mem = dma_alloc_coherent(&mdata->pdev->dev,
358 len * 16, &phys, GFP_KERNEL);
359
360 if (*dump_mem) {
361 dump_addr = *dump_mem;
362 pr_info("%s: start_addr:0x%p end_addr:0x%p reg_addr=0x%X\n",
363 dump_name, dump_addr, dump_addr + (u32)len * 16,
364 addr);
365 } else {
366 in_mem = false;
367 pr_err("dump_mem: kzalloc fails!\n");
368 }
369 }
370
Benjamin Chan59a06052017-01-12 18:06:03 -0500371 base = mdata->sde_io.base;
372 /*
373 * VBIF NRT base handling
374 */
375 if (access == SDE_ROT_REGDUMP_VBIF)
376 base = mdata->vbif_nrt_io.base;
Benjamin Chan53e3bce2016-08-31 14:43:29 -0400377
378 for (i = 0; i < len; i++) {
379 u32 x0, x4, x8, xc;
380
Benjamin Chan59a06052017-01-12 18:06:03 -0500381 x0 = readl_relaxed(base + addr+0x0);
382 x4 = readl_relaxed(base + addr+0x4);
383 x8 = readl_relaxed(base + addr+0x8);
384 xc = readl_relaxed(base + addr+0xc);
Benjamin Chan53e3bce2016-08-31 14:43:29 -0400385
386 if (in_log)
387 pr_info("0x%08X : %08x %08x %08x %08x\n",
388 addr, x0, x4, x8, xc);
389
390 if (dump_addr && in_mem) {
391 dump_addr[i*4] = x0;
392 dump_addr[i*4 + 1] = x4;
393 dump_addr[i*4 + 2] = x8;
394 dump_addr[i*4 + 3] = xc;
395 }
396
397 addr += 16;
398 }
399}
400
401/*
402 * sde_rot_dump_reg_all - dumping all SDE rotator registers
403 */
404static void sde_rot_dump_reg_all(void)
405{
406 struct sde_rot_data_type *mdata = sde_rot_get_mdata();
407 struct sde_rot_regdump *head, *regdump;
408 u32 regdump_size;
409 int i;
410
411 regdump = mdata->regdump;
412 regdump_size = mdata->regdump_size;
413
414 if (!regdump || !regdump_size)
415 return;
416
417 /* Enable clock to rotator if not yet enabled */
418 sde_smmu_ctrl(1);
419
420 for (i = 0; (i < regdump_size) && (i < SDE_ROT_DEBUG_BASE_MAX); i++) {
421 head = &regdump[i];
422
423 if (head->access == SDE_ROT_REGDUMP_WRITE) {
424 writel_relaxed(1, mdata->sde_io.base + head->offset);
425 /* Make sure write go through */
426 wmb();
427 } else {
428 sde_rot_dump_reg(head->name,
429 sde_rot_dbg_evtlog.enable_reg_dump,
Benjamin Chan59a06052017-01-12 18:06:03 -0500430 head->access,
Benjamin Chan53e3bce2016-08-31 14:43:29 -0400431 head->offset, head->len,
432 &sde_rot_dbg_evtlog.reg_dump_array[i]);
433 }
434 }
435
436 /* Disable rotator clock */
437 sde_smmu_ctrl(0);
438}
439
440/*
441 * __sde_rot_evtlog_dump_calc_range - calculate dump range for EVTLOG
442 */
443static bool __sde_rot_evtlog_dump_calc_range(void)
444{
445 static u32 next;
446 bool need_dump = true;
447 unsigned long flags;
448 struct sde_rot_dbg_evtlog *evtlog = &sde_rot_dbg_evtlog;
449
450 spin_lock_irqsave(&sde_rot_xlock, flags);
451
452 evtlog->first = next;
453
454 if (evtlog->last == evtlog->first) {
455 need_dump = false;
456 goto dump_exit;
457 }
458
459 if (evtlog->last < evtlog->first) {
460 evtlog->first %= SDE_ROT_EVTLOG_ENTRY;
461 if (evtlog->last < evtlog->first)
462 evtlog->last += SDE_ROT_EVTLOG_ENTRY;
463 }
464
465 if ((evtlog->last - evtlog->first) > SDE_ROT_EVTLOG_PRINT_ENTRY) {
466 pr_warn("evtlog buffer overflow before dump: %d\n",
467 evtlog->last - evtlog->first);
468 evtlog->first = evtlog->last - SDE_ROT_EVTLOG_PRINT_ENTRY;
469 }
470 next = evtlog->first + 1;
471
472dump_exit:
473 spin_unlock_irqrestore(&sde_rot_xlock, flags);
474
475 return need_dump;
476}
477
478/*
479 * sde_rot_evtlog_dump_entry - helper function for EVTLOG content dumping
480 * @evtlog_buf: EVTLOG dump output buffer
481 * @evtlog_buf_size: EVTLOG output buffer size
482 */
483static ssize_t sde_rot_evtlog_dump_entry(char *evtlog_buf,
484 ssize_t evtlog_buf_size)
485{
486 int i;
487 ssize_t off = 0;
488 struct tlog *log, *prev_log;
489 unsigned long flags;
490
491 spin_lock_irqsave(&sde_rot_xlock, flags);
492
493 log = &sde_rot_dbg_evtlog.logs[sde_rot_dbg_evtlog.first %
494 SDE_ROT_EVTLOG_ENTRY];
495
496 prev_log = &sde_rot_dbg_evtlog.logs[(sde_rot_dbg_evtlog.first - 1) %
497 SDE_ROT_EVTLOG_ENTRY];
498
499 off = snprintf((evtlog_buf + off), (evtlog_buf_size - off), "%s:%-4d",
500 log->name, log->line);
501
502 if (off < SDE_ROT_EVTLOG_BUF_ALIGN) {
503 memset((evtlog_buf + off), 0x20,
504 (SDE_ROT_EVTLOG_BUF_ALIGN - off));
505 off = SDE_ROT_EVTLOG_BUF_ALIGN;
506 }
507
508 off += snprintf((evtlog_buf + off), (evtlog_buf_size - off),
509 "=>[%-8d:%-11llu:%9llu][%-4d]:", sde_rot_dbg_evtlog.first,
510 log->time, (log->time - prev_log->time), log->pid);
511
512 for (i = 0; i < log->data_cnt; i++)
513 off += snprintf((evtlog_buf + off), (evtlog_buf_size - off),
514 "%x ", log->data[i]);
515
516 off += snprintf((evtlog_buf + off), (evtlog_buf_size - off), "\n");
517
518 spin_unlock_irqrestore(&sde_rot_xlock, flags);
519
520 return off;
521}
522
523/*
524 * sde_rot_evtlog_dump_all - Dumping all content in EVTLOG buffer
525 */
526static void sde_rot_evtlog_dump_all(void)
527{
528 char evtlog_buf[SDE_ROT_EVTLOG_BUF_MAX];
529
530 while (__sde_rot_evtlog_dump_calc_range()) {
531 sde_rot_evtlog_dump_entry(evtlog_buf, SDE_ROT_EVTLOG_BUF_MAX);
532 pr_info("%s", evtlog_buf);
533 }
534}
535
536/*
537 * sde_rot_evtlog_dump_open - debugfs open handler for evtlog dump
538 * @inode: debugfs inode
539 * @file: file handler
540 */
541static int sde_rot_evtlog_dump_open(struct inode *inode, struct file *file)
542{
543 /* non-seekable */
544 file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
545 file->private_data = inode->i_private;
546 return 0;
547}
548
549/*
550 * sde_rot_evtlog_dump_read - debugfs read handler for evtlog dump
551 * @file: file handler
552 * @buff: user buffer content for debugfs
553 * @count: size of user buffer
554 * @ppos: position offset of user buffer
555 */
556static ssize_t sde_rot_evtlog_dump_read(struct file *file, char __user *buff,
557 size_t count, loff_t *ppos)
558{
559 ssize_t len = 0;
560 char evtlog_buf[SDE_ROT_EVTLOG_BUF_MAX];
561
562 if (__sde_rot_evtlog_dump_calc_range()) {
563 len = sde_rot_evtlog_dump_entry(evtlog_buf,
564 SDE_ROT_EVTLOG_BUF_MAX);
565 if (copy_to_user(buff, evtlog_buf, len))
566 return -EFAULT;
567 *ppos += len;
568 }
569
570 return len;
571}
572
573/*
574 * sde_rot_evtlog_dump_write - debugfs write handler for evtlog dump
575 * @file: file handler
576 * @user_buf: user buffer content from debugfs
577 * @count: size of user buffer
578 * @ppos: position offset of user buffer
579 */
580static ssize_t sde_rot_evtlog_dump_write(struct file *file,
581 const char __user *user_buf, size_t count, loff_t *ppos)
582{
583 sde_rot_evtlog_dump_all();
584
585 sde_rot_dump_reg_all();
586
587 if (sde_rot_dbg_evtlog.panic_on_err)
588 panic("evtlog_dump_write");
589
590 return count;
591}
592
593/*
594 * sde_rot_evtlog_dump_helper - helper function for evtlog dump
595 * @dead: boolean indicates panic after dump
596 * @panic_name: Panic signature name show up in log
597 * @dump_rot: boolean indicates rotator register dump
598 * @dump_vbif_debug_bus: boolean indicates VBIF debug bus dump
599 */
600static void sde_rot_evtlog_dump_helper(bool dead, const char *panic_name,
Benjamin Chan2d6411a2017-03-28 18:01:53 -0400601 bool dump_rot, bool dump_vbif_debug_bus, bool dump_rot_debug_bus)
Benjamin Chan53e3bce2016-08-31 14:43:29 -0400602{
603 sde_rot_evtlog_dump_all();
604
Benjamin Chan2d6411a2017-03-28 18:01:53 -0400605 if (dump_rot_debug_bus)
606 sde_rot_dump_debug_bus(
607 sde_rot_dbg_evtlog.enable_rot_dbgbus_dump,
608 &sde_rot_dbg_evtlog.rot_dbgbus_dump);
Benjamin Chan53e3bce2016-08-31 14:43:29 -0400609
610 if (dump_vbif_debug_bus)
611 sde_rot_dump_vbif_debug_bus(
612 sde_rot_dbg_evtlog.enable_vbif_dbgbus_dump,
613 &sde_rot_dbg_evtlog.nrt_vbif_dbgbus_dump);
614
Benjamin Chan2d6411a2017-03-28 18:01:53 -0400615 /*
616 * Rotator registers always dump last
617 */
618 if (dump_rot)
619 sde_rot_dump_reg_all();
620
Benjamin Chan53e3bce2016-08-31 14:43:29 -0400621 if (dead)
622 panic(panic_name);
623}
624
625/*
626 * sde_rot_evtlog_debug_work - schedule work function for evtlog dump
627 * @work: schedule work structure
628 */
629static void sde_rot_evtlog_debug_work(struct work_struct *work)
630{
631 sde_rot_evtlog_dump_helper(
632 sde_rot_dbg_evtlog.work_panic,
633 "evtlog_workitem",
634 sde_rot_dbg_evtlog.work_dump_reg,
Benjamin Chan2d6411a2017-03-28 18:01:53 -0400635 sde_rot_dbg_evtlog.work_vbif_dbgbus,
636 sde_rot_dbg_evtlog.work_rot_dbgbus);
Benjamin Chan53e3bce2016-08-31 14:43:29 -0400637}
638
639/*
640 * sde_rot_dump_panic - Issue evtlog dump and generic panic
641 */
642void sde_rot_dump_panic(void)
643{
644 sde_rot_evtlog_dump_all();
645 sde_rot_dump_reg_all();
646
647 panic("sde_rotator");
648}
649
650/*
651 * sde_rot_evtlog_tout_handler - log dump timeout handler
652 * @queue: boolean indicate putting log dump into queue
653 * @name: function name having timeout
654 */
655void sde_rot_evtlog_tout_handler(bool queue, const char *name, ...)
656{
657 int i;
658 bool dead = false;
659 bool dump_rot = false;
660 bool dump_vbif_dbgbus = false;
Benjamin Chan2d6411a2017-03-28 18:01:53 -0400661 bool dump_rot_dbgbus = false;
Benjamin Chan53e3bce2016-08-31 14:43:29 -0400662 char *blk_name = NULL;
663 va_list args;
664
665 if (!sde_rot_evtlog_is_enabled(SDE_ROT_EVTLOG_DEFAULT))
666 return;
667
668 if (queue && work_pending(&sde_rot_dbg_evtlog.evtlog_dump_work))
669 return;
670
671 va_start(args, name);
672 for (i = 0; i < SDE_ROT_EVTLOG_MAX_DATA; i++) {
673 blk_name = va_arg(args, char*);
674 if (IS_ERR_OR_NULL(blk_name))
675 break;
676
677 if (!strcmp(blk_name, "rot"))
678 dump_rot = true;
679
680 if (!strcmp(blk_name, "vbif_dbg_bus"))
681 dump_vbif_dbgbus = true;
682
Benjamin Chan2d6411a2017-03-28 18:01:53 -0400683 if (!strcmp(blk_name, "rot_dbg_bus"))
684 dump_rot_dbgbus = true;
685
Benjamin Chan53e3bce2016-08-31 14:43:29 -0400686 if (!strcmp(blk_name, "panic"))
687 dead = true;
688 }
689 va_end(args);
690
691 if (queue) {
692 /* schedule work to dump later */
693 sde_rot_dbg_evtlog.work_panic = dead;
694 sde_rot_dbg_evtlog.work_dump_reg = dump_rot;
695 sde_rot_dbg_evtlog.work_vbif_dbgbus = dump_vbif_dbgbus;
Benjamin Chan2d6411a2017-03-28 18:01:53 -0400696 sde_rot_dbg_evtlog.work_rot_dbgbus = dump_rot_dbgbus;
Benjamin Chan53e3bce2016-08-31 14:43:29 -0400697 schedule_work(&sde_rot_dbg_evtlog.evtlog_dump_work);
698 } else {
699 sde_rot_evtlog_dump_helper(dead, name, dump_rot,
Benjamin Chan2d6411a2017-03-28 18:01:53 -0400700 dump_vbif_dbgbus, dump_rot_dbgbus);
Benjamin Chan53e3bce2016-08-31 14:43:29 -0400701 }
702}
703
704/*
705 * sde_rot_evtlog - log contents into memory for dump analysis
706 * @name: Name of function calling evtlog
707 * @line: line number of calling function
708 * @flag: Log control flag
709 */
710void sde_rot_evtlog(const char *name, int line, int flag, ...)
711{
712 unsigned long flags;
713 int i, val = 0;
714 va_list args;
715 struct tlog *log;
716
717 if (!sde_rot_evtlog_is_enabled(flag))
718 return;
719
720 spin_lock_irqsave(&sde_rot_xlock, flags);
721 log = &sde_rot_dbg_evtlog.logs[sde_rot_dbg_evtlog.curr];
722 log->time = ktime_to_us(ktime_get());
723 log->name = name;
724 log->line = line;
725 log->data_cnt = 0;
726 log->pid = current->pid;
727
728 va_start(args, flag);
729 for (i = 0; i < SDE_ROT_EVTLOG_MAX_DATA; i++) {
730
731 val = va_arg(args, int);
732 if (val == SDE_ROT_DATA_LIMITER)
733 break;
734
735 log->data[i] = val;
736 }
737 va_end(args);
738 log->data_cnt = i;
739 sde_rot_dbg_evtlog.curr =
740 (sde_rot_dbg_evtlog.curr + 1) % SDE_ROT_EVTLOG_ENTRY;
741 sde_rot_dbg_evtlog.last++;
742
743 spin_unlock_irqrestore(&sde_rot_xlock, flags);
744}
745
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700746/*
747 * sde_rotator_stat_show - Show statistics on read to this debugfs file
748 * @s: Pointer to sequence file structure
749 * @data: Pointer to private data structure
750 */
751static int sde_rotator_stat_show(struct seq_file *s, void *data)
752{
753 int i, offset;
754 struct sde_rotator_device *rot_dev = s->private;
755 struct sde_rotator_statistics *stats = &rot_dev->stats;
756 u64 count = stats->count;
757 int num_events;
758 s64 proc_max, proc_min, proc_avg;
Benjamin Chan4a4c0e22016-08-10 16:10:59 -0400759 s64 swoh_max, swoh_min, swoh_avg;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700760
761 proc_max = 0;
762 proc_min = S64_MAX;
763 proc_avg = 0;
Benjamin Chan4a4c0e22016-08-10 16:10:59 -0400764 swoh_max = 0;
765 swoh_min = S64_MAX;
766 swoh_avg = 0;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700767
768 if (count > SDE_ROTATOR_NUM_EVENTS) {
769 num_events = SDE_ROTATOR_NUM_EVENTS;
770 offset = count % SDE_ROTATOR_NUM_EVENTS;
771 } else {
772 num_events = count;
773 offset = 0;
774 }
775
776 for (i = 0; i < num_events; i++) {
777 int k = (offset + i) % SDE_ROTATOR_NUM_EVENTS;
778 ktime_t *ts = stats->ts[k];
779 ktime_t start_time =
780 ktime_before(ts[SDE_ROTATOR_TS_SRCQB],
781 ts[SDE_ROTATOR_TS_DSTQB]) ?
782 ts[SDE_ROTATOR_TS_SRCQB] :
783 ts[SDE_ROTATOR_TS_DSTQB];
784 s64 proc_time =
785 ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_RETIRE],
786 start_time));
Benjamin Chan4a4c0e22016-08-10 16:10:59 -0400787 s64 sw_overhead_time =
788 ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_FLUSH],
789 start_time));
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700790
791 seq_printf(s,
Clarence Ipb25c65c2017-05-17 12:09:23 -0400792 "s:%d sq:%lld dq:%lld fe:%lld q:%lld c:%lld fl:%lld st:%lld d:%lld sdq:%lld ddq:%lld t:%lld oht:%lld\n",
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700793 i,
794 ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_FENCE],
795 ts[SDE_ROTATOR_TS_SRCQB])),
796 ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_FENCE],
797 ts[SDE_ROTATOR_TS_DSTQB])),
798 ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_QUEUE],
799 ts[SDE_ROTATOR_TS_FENCE])),
800 ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_COMMIT],
801 ts[SDE_ROTATOR_TS_QUEUE])),
802 ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_FLUSH],
803 ts[SDE_ROTATOR_TS_COMMIT])),
Clarence Ipb25c65c2017-05-17 12:09:23 -0400804 ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_START],
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700805 ts[SDE_ROTATOR_TS_FLUSH])),
Clarence Ipb25c65c2017-05-17 12:09:23 -0400806 ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_DONE],
807 ts[SDE_ROTATOR_TS_START])),
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700808 ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_RETIRE],
809 ts[SDE_ROTATOR_TS_DONE])),
810 ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_SRCDQB],
811 ts[SDE_ROTATOR_TS_RETIRE])),
812 ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_DSTDQB],
813 ts[SDE_ROTATOR_TS_RETIRE])),
Benjamin Chan4a4c0e22016-08-10 16:10:59 -0400814 proc_time, sw_overhead_time);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700815
816 proc_max = max(proc_max, proc_time);
817 proc_min = min(proc_min, proc_time);
818 proc_avg += proc_time;
Benjamin Chan4a4c0e22016-08-10 16:10:59 -0400819
820 swoh_max = max(swoh_max, sw_overhead_time);
821 swoh_min = min(swoh_min, sw_overhead_time);
822 swoh_avg += sw_overhead_time;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700823 }
824
825 proc_avg = (num_events) ?
826 DIV_ROUND_CLOSEST_ULL(proc_avg, num_events) : 0;
Benjamin Chan4a4c0e22016-08-10 16:10:59 -0400827 swoh_avg = (num_events) ?
828 DIV_ROUND_CLOSEST_ULL(swoh_avg, num_events) : 0;
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700829
830 seq_printf(s, "count:%llu\n", count);
831 seq_printf(s, "fai1:%llu\n", stats->fail_count);
832 seq_printf(s, "t_max:%lld\n", proc_max);
833 seq_printf(s, "t_min:%lld\n", proc_min);
834 seq_printf(s, "t_avg:%lld\n", proc_avg);
Benjamin Chan4a4c0e22016-08-10 16:10:59 -0400835 seq_printf(s, "swoh_max:%lld\n", swoh_max);
836 seq_printf(s, "swoh_min:%lld\n", swoh_min);
837 seq_printf(s, "swoh_avg:%lld\n", swoh_avg);
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700838
839 return 0;
840}
841
842/*
843 * sde_rotator_stat_write - Clear statistics on write to this debugfs file.
844 * @t_file:
845 * @t_char:
846 * @t_size_t:
847 * @t_lof_t:
848 */
849static ssize_t sde_rotator_stat_write(struct file *t_file,
850 const char *t_char, size_t t_size_t, loff_t *t_loff_t)
851{
852 struct seq_file *s = t_file->private_data;
853 struct sde_rotator_device *rot_dev = s->private;
854 struct sde_rotator_statistics *stats = &rot_dev->stats;
855 char buf[128];
856
857 mutex_lock(&rot_dev->lock);
858 sde_rot_mgr_lock(rot_dev->mgr);
859 memset(stats, 0, sizeof(struct sde_rotator_statistics));
860 sde_rot_mgr_unlock(rot_dev->mgr);
861 mutex_unlock(&rot_dev->lock);
862 return simple_write_to_buffer(buf, sizeof(buf),
863 t_loff_t, t_char, t_size_t);
864}
865
866/*
867 * sde_rotator_raw_show - Show raw statistics on read from this debugfs file
868 * @s: Pointer to sequence file structure
869 * @data: Pointer to private data structure
870 */
871static int sde_rotator_raw_show(struct seq_file *s, void *data)
872{
873 int i, j, offset;
874 struct sde_rotator_device *rot_dev = s->private;
875 struct sde_rotator_statistics *stats = &rot_dev->stats;
876 u64 count = stats->count;
877 int num_events;
878
879 if (count > SDE_ROTATOR_NUM_EVENTS) {
880 num_events = SDE_ROTATOR_NUM_EVENTS;
881 offset = count % SDE_ROTATOR_NUM_EVENTS;
882 } else {
883 num_events = count;
884 offset = 0;
885 }
886
887 for (i = 0; i < num_events; i++) {
888 int k = (offset + i) % SDE_ROTATOR_NUM_EVENTS;
889 ktime_t *ts = stats->ts[k];
890
891 seq_printf(s, "%d ", i);
892 for (j = 0; j < SDE_ROTATOR_NUM_TIMESTAMPS; j++)
893 seq_printf(s, "%lld ", ktime_to_us(ts[j]));
894 seq_puts(s, "\n");
895 }
896
897 return 0;
898}
899
900/*
901 * sde_rotator_dbg_open - Processed statistics debugfs file open function
902 * @inode:
903 * @file:
904 */
905static int sde_rotator_stat_open(struct inode *inode, struct file *file)
906{
907 return single_open(file, sde_rotator_stat_show, inode->i_private);
908}
909
910/*
911 * sde_rotator_dbg_open - Raw statistics debugfs file open function
912 * @inode:
913 * @file:
914 */
915static int sde_rotator_raw_open(struct inode *inode, struct file *file)
916{
917 return single_open(file, sde_rotator_raw_show, inode->i_private);
918}
919
920/*
921 * sde_rotator_dbg_open - Raw statistics debugfs file open function
922 * @mdata: Pointer to rotator global data
923 * @debugfs_root: Pointer to parent debugfs node
924 */
925static int sde_rotator_base_create_debugfs(
926 struct sde_rot_data_type *mdata,
927 struct dentry *debugfs_root)
928{
929 if (!debugfs_create_u32("iommu_ref_cnt", 0444,
930 debugfs_root, &mdata->iommu_ref_cnt)) {
931 SDEROT_WARN("failed to create debugfs iommu ref cnt\n");
932 return -EINVAL;
933 }
934
Benjamin Chan2d6411a2017-03-28 18:01:53 -0400935 mdata->clk_always_on = false;
936 if (!debugfs_create_bool("clk_always_on", 0644,
937 debugfs_root, &mdata->clk_always_on)) {
938 SDEROT_WARN("failed to create debugfs clk_always_on\n");
939 return -EINVAL;
940 }
941
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700942 return 0;
943}
944
945/*
946 * sde_rotator_dbg_open - Raw statistics debugfs file open function
947 * @mgr: Pointer to rotator manager structure
948 * @debugfs_root: Pointer to parent debugfs node
949 */
950static int sde_rotator_core_create_debugfs(
951 struct sde_rot_mgr *mgr,
952 struct dentry *debugfs_root)
953{
954 int ret;
955
956 if (!debugfs_create_u32("hwacquire_timeout", 0644,
957 debugfs_root, &mgr->hwacquire_timeout)) {
958 SDEROT_WARN("failed to create debugfs hw acquire timeout\n");
959 return -EINVAL;
960 }
961
962 if (!debugfs_create_u32("ppc_numer", 0644,
963 debugfs_root, &mgr->pixel_per_clk.numer)) {
964 SDEROT_WARN("failed to create debugfs ppc numerator\n");
965 return -EINVAL;
966 }
967
968 if (!debugfs_create_u32("ppc_denom", 0644,
969 debugfs_root, &mgr->pixel_per_clk.denom)) {
970 SDEROT_WARN("failed to create debugfs ppc denominator\n");
971 return -EINVAL;
972 }
973
Alan Kwong30ab1ce2017-03-03 12:09:32 -0800974 if (!debugfs_create_u64("enable_bw_vote", 0644,
975 debugfs_root, &mgr->enable_bw_vote)) {
976 SDEROT_WARN("failed to create enable_bw_vote\n");
977 return -EINVAL;
978 }
979
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -0700980 if (mgr->ops_hw_create_debugfs) {
981 ret = mgr->ops_hw_create_debugfs(mgr, debugfs_root);
982 if (ret)
983 return ret;
984 }
985 return 0;
986}
987
Benjamin Chan53e3bce2016-08-31 14:43:29 -0400988static const struct file_operations sde_rot_evtlog_fops = {
989 .open = sde_rot_evtlog_dump_open,
990 .read = sde_rot_evtlog_dump_read,
991 .write = sde_rot_evtlog_dump_write,
992};
993
994static int sde_rotator_evtlog_create_debugfs(
995 struct sde_rot_mgr *mgr,
996 struct dentry *debugfs_root)
997{
998 int i;
999
1000 sde_rot_dbg_evtlog.evtlog = debugfs_create_dir("evtlog", debugfs_root);
1001 if (IS_ERR_OR_NULL(sde_rot_dbg_evtlog.evtlog)) {
1002 pr_err("debugfs_create_dir fail, error %ld\n",
1003 PTR_ERR(sde_rot_dbg_evtlog.evtlog));
1004 sde_rot_dbg_evtlog.evtlog = NULL;
1005 return -ENODEV;
1006 }
1007
1008 INIT_WORK(&sde_rot_dbg_evtlog.evtlog_dump_work,
1009 sde_rot_evtlog_debug_work);
1010 sde_rot_dbg_evtlog.work_panic = false;
1011
1012 for (i = 0; i < SDE_ROT_EVTLOG_ENTRY; i++)
1013 sde_rot_dbg_evtlog.logs[i].counter = i;
1014
1015 debugfs_create_file("dump", 0644, sde_rot_dbg_evtlog.evtlog, NULL,
1016 &sde_rot_evtlog_fops);
1017 debugfs_create_u32("enable", 0644, sde_rot_dbg_evtlog.evtlog,
1018 &sde_rot_dbg_evtlog.evtlog_enable);
1019 debugfs_create_u32("panic", 0644, sde_rot_dbg_evtlog.evtlog,
1020 &sde_rot_dbg_evtlog.panic_on_err);
1021 debugfs_create_u32("reg_dump", 0644, sde_rot_dbg_evtlog.evtlog,
1022 &sde_rot_dbg_evtlog.enable_reg_dump);
1023 debugfs_create_u32("vbif_dbgbus_dump", 0644, sde_rot_dbg_evtlog.evtlog,
1024 &sde_rot_dbg_evtlog.enable_vbif_dbgbus_dump);
Benjamin Chan2d6411a2017-03-28 18:01:53 -04001025 debugfs_create_u32("rot_dbgbus_dump", 0644, sde_rot_dbg_evtlog.evtlog,
1026 &sde_rot_dbg_evtlog.enable_rot_dbgbus_dump);
Benjamin Chan53e3bce2016-08-31 14:43:29 -04001027
1028 sde_rot_dbg_evtlog.evtlog_enable = SDE_EVTLOG_DEFAULT_ENABLE;
1029 sde_rot_dbg_evtlog.panic_on_err = SDE_EVTLOG_DEFAULT_PANIC;
1030 sde_rot_dbg_evtlog.enable_reg_dump = SDE_EVTLOG_DEFAULT_REGDUMP;
1031 sde_rot_dbg_evtlog.enable_vbif_dbgbus_dump =
1032 SDE_EVTLOG_DEFAULT_VBIF_DBGBUSDUMP;
Benjamin Chan2d6411a2017-03-28 18:01:53 -04001033 sde_rot_dbg_evtlog.enable_rot_dbgbus_dump =
1034 SDE_EVTLOG_DEFAULT_ROT_DBGBUSDUMP;
Benjamin Chan53e3bce2016-08-31 14:43:29 -04001035
1036 pr_info("evtlog_status: enable:%d, panic:%d, dump:%d\n",
1037 sde_rot_dbg_evtlog.evtlog_enable,
1038 sde_rot_dbg_evtlog.panic_on_err,
1039 sde_rot_dbg_evtlog.enable_reg_dump);
1040
1041 return 0;
1042}
1043
Benjamin Chandbe13112016-09-26 12:10:06 -04001044
1045static int sde_rotator_perf_create_debugfs(
1046 struct sde_rotator_device *rot_dev,
1047 struct dentry *debugfs_root)
1048{
1049 rot_dev->perf_root = debugfs_create_dir("perf", debugfs_root);
1050 if (IS_ERR_OR_NULL(rot_dev->perf_root)) {
1051 pr_err("debugfs_create_dir for perf failed, error %ld\n",
1052 PTR_ERR(rot_dev->perf_root));
1053 rot_dev->perf_root = NULL;
1054 return -ENODEV;
1055 }
1056
1057 rot_dev->min_rot_clk = 0;
1058 debugfs_create_u32("min_rot_clk", 0644,
1059 rot_dev->perf_root, &rot_dev->min_rot_clk);
1060
1061 rot_dev->min_bw = 0;
1062 debugfs_create_u32("min_bw", 0644,
1063 rot_dev->perf_root, &rot_dev->min_bw);
1064
1065 rot_dev->min_overhead_us = 0;
1066 debugfs_create_u32("min_overhead_us", 0644,
1067 rot_dev->perf_root, &rot_dev->min_overhead_us);
1068
1069 return 0;
1070}
1071
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001072/*
1073 * struct sde_rotator_stat_ops - processed statistics file operations
1074 */
1075static const struct file_operations sde_rotator_stat_ops = {
1076 .open = sde_rotator_stat_open,
1077 .read = seq_read,
1078 .write = sde_rotator_stat_write,
1079 .llseek = seq_lseek,
1080 .release = single_release
1081};
1082
1083/*
1084 * struct sde_rotator_raw_ops - raw statistics file operations
1085 */
1086static const struct file_operations sde_rotator_raw_ops = {
1087 .open = sde_rotator_raw_open,
1088 .read = seq_read,
1089 .llseek = seq_lseek,
1090 .release = single_release
1091};
1092
Benjamin Chan6a0d2412016-10-27 17:47:46 -04001093static int sde_rotator_debug_base_open(struct inode *inode, struct file *file)
1094{
1095 /* non-seekable */
1096 file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
1097 file->private_data = inode->i_private;
1098 return 0;
1099}
1100
1101static int sde_rotator_debug_base_release(struct inode *inode,
1102 struct file *file)
1103{
1104 struct sde_rotator_debug_base *dbg = file->private_data;
1105
Benjamin Chan6db7eb52017-02-17 14:49:45 -05001106 if (dbg) {
1107 mutex_lock(&dbg->buflock);
Benjamin Chan6a0d2412016-10-27 17:47:46 -04001108 kfree(dbg->buf);
1109 dbg->buf_len = 0;
1110 dbg->buf = NULL;
Benjamin Chan6db7eb52017-02-17 14:49:45 -05001111 mutex_unlock(&dbg->buflock);
Benjamin Chan6a0d2412016-10-27 17:47:46 -04001112 }
Benjamin Chan6db7eb52017-02-17 14:49:45 -05001113
Benjamin Chan6a0d2412016-10-27 17:47:46 -04001114 return 0;
1115}
1116
1117static ssize_t sde_rotator_debug_base_offset_write(struct file *file,
1118 const char __user *user_buf, size_t count, loff_t *ppos)
1119{
1120 struct sde_rotator_debug_base *dbg = file->private_data;
1121 u32 off = 0;
1122 u32 cnt = SDE_ROT_DEFAULT_BASE_REG_CNT;
1123 char buf[24];
1124
1125 if (!dbg)
1126 return -ENODEV;
1127
1128 if (count >= sizeof(buf))
1129 return -EFAULT;
1130
1131 if (copy_from_user(buf, user_buf, count))
1132 return -EFAULT;
1133
1134 buf[count] = 0;
1135
1136 if (sscanf(buf, "%5x %x", &off, &cnt) < 2)
1137 return -EINVAL;
1138
1139 if (off > dbg->max_offset)
1140 return -EINVAL;
1141
1142 if (cnt > (dbg->max_offset - off))
1143 cnt = dbg->max_offset - off;
1144
Benjamin Chan6db7eb52017-02-17 14:49:45 -05001145 mutex_lock(&dbg->buflock);
Benjamin Chan6a0d2412016-10-27 17:47:46 -04001146 dbg->off = off;
1147 dbg->cnt = cnt;
Benjamin Chan6db7eb52017-02-17 14:49:45 -05001148 mutex_unlock(&dbg->buflock);
Benjamin Chan6a0d2412016-10-27 17:47:46 -04001149
1150 SDEROT_DBG("offset=%x cnt=%x\n", off, cnt);
1151
1152 return count;
1153}
1154
1155static ssize_t sde_rotator_debug_base_offset_read(struct file *file,
1156 char __user *buff, size_t count, loff_t *ppos)
1157{
1158 struct sde_rotator_debug_base *dbg = file->private_data;
1159 int len = 0;
1160 char buf[24] = {'\0'};
1161
1162 if (!dbg)
1163 return -ENODEV;
1164
1165 if (*ppos)
1166 return 0; /* the end */
1167
Benjamin Chan6db7eb52017-02-17 14:49:45 -05001168 mutex_lock(&dbg->buflock);
Benjamin Chan6a0d2412016-10-27 17:47:46 -04001169 len = snprintf(buf, sizeof(buf), "0x%08zx %zx\n", dbg->off, dbg->cnt);
Benjamin Chan6db7eb52017-02-17 14:49:45 -05001170 mutex_unlock(&dbg->buflock);
1171
Benjamin Chan6a0d2412016-10-27 17:47:46 -04001172 if (len < 0 || len >= sizeof(buf))
1173 return 0;
1174
1175 if ((count < sizeof(buf)) || copy_to_user(buff, buf, len))
1176 return -EFAULT;
1177
1178 *ppos += len; /* increase offset */
1179
1180 return len;
1181}
1182
1183static ssize_t sde_rotator_debug_base_reg_write(struct file *file,
1184 const char __user *user_buf, size_t count, loff_t *ppos)
1185{
1186 struct sde_rotator_debug_base *dbg = file->private_data;
1187 size_t off;
1188 u32 data, cnt;
1189 char buf[24];
1190
1191 if (!dbg)
1192 return -ENODEV;
1193
1194 if (count >= sizeof(buf))
1195 return -EFAULT;
1196
1197 if (copy_from_user(buf, user_buf, count))
1198 return -EFAULT;
1199
1200 buf[count] = 0;
1201
1202 cnt = sscanf(buf, "%zx %x", &off, &data);
1203
1204 if (cnt < 2)
1205 return -EFAULT;
1206
1207 if (off >= dbg->max_offset)
1208 return -EFAULT;
1209
Benjamin Chan6db7eb52017-02-17 14:49:45 -05001210 mutex_lock(&dbg->buflock);
1211
Benjamin Chan6a0d2412016-10-27 17:47:46 -04001212 /* Enable Clock for register access */
1213 sde_rotator_clk_ctrl(dbg->mgr, true);
1214
1215 writel_relaxed(data, dbg->base + off);
1216
1217 /* Disable Clock after register access */
1218 sde_rotator_clk_ctrl(dbg->mgr, false);
1219
Benjamin Chan6db7eb52017-02-17 14:49:45 -05001220 mutex_unlock(&dbg->buflock);
1221
Benjamin Chan6a0d2412016-10-27 17:47:46 -04001222 SDEROT_DBG("addr=%zx data=%x\n", off, data);
1223
1224 return count;
1225}
1226
1227static ssize_t sde_rotator_debug_base_reg_read(struct file *file,
1228 char __user *user_buf, size_t count, loff_t *ppos)
1229{
1230 struct sde_rotator_debug_base *dbg = file->private_data;
1231 size_t len;
Benjamin Chan6db7eb52017-02-17 14:49:45 -05001232 int rc = 0;
Benjamin Chan6a0d2412016-10-27 17:47:46 -04001233
1234 if (!dbg) {
1235 SDEROT_ERR("invalid handle\n");
1236 return -ENODEV;
1237 }
1238
Benjamin Chan6db7eb52017-02-17 14:49:45 -05001239 mutex_lock(&dbg->buflock);
Benjamin Chan6a0d2412016-10-27 17:47:46 -04001240 if (!dbg->buf) {
1241 char dump_buf[64];
1242 char *ptr;
1243 int cnt, tot;
1244
1245 dbg->buf_len = sizeof(dump_buf) *
1246 DIV_ROUND_UP(dbg->cnt, ROW_BYTES);
1247 dbg->buf = kzalloc(dbg->buf_len, GFP_KERNEL);
1248
1249 if (!dbg->buf) {
1250 SDEROT_ERR("not enough memory to hold reg dump\n");
Benjamin Chan6db7eb52017-02-17 14:49:45 -05001251 rc = -ENOMEM;
1252 goto debug_read_error;
Benjamin Chan6a0d2412016-10-27 17:47:46 -04001253 }
1254
1255 ptr = dbg->base + dbg->off;
1256 tot = 0;
1257
1258 /* Enable clock for register access */
1259 sde_rotator_clk_ctrl(dbg->mgr, true);
1260
1261 for (cnt = dbg->cnt; cnt > 0; cnt -= ROW_BYTES) {
1262 hex_dump_to_buffer(ptr, min(cnt, ROW_BYTES),
1263 ROW_BYTES, GROUP_BYTES, dump_buf,
1264 sizeof(dump_buf), false);
1265 len = scnprintf(dbg->buf + tot, dbg->buf_len - tot,
1266 "0x%08x: %s\n",
1267 ((int) (unsigned long) ptr) -
1268 ((int) (unsigned long) dbg->base),
1269 dump_buf);
1270
1271 ptr += ROW_BYTES;
1272 tot += len;
1273 if (tot >= dbg->buf_len)
1274 break;
1275 }
1276 /* Disable clock after register access */
1277 sde_rotator_clk_ctrl(dbg->mgr, false);
1278
1279 dbg->buf_len = tot;
1280 }
1281
Benjamin Chan6db7eb52017-02-17 14:49:45 -05001282 if (*ppos >= dbg->buf_len) {
1283 rc = 0; /* done reading */
1284 goto debug_read_error;
1285 }
Benjamin Chan6a0d2412016-10-27 17:47:46 -04001286
1287 len = min(count, dbg->buf_len - (size_t) *ppos);
1288 if (copy_to_user(user_buf, dbg->buf + *ppos, len)) {
1289 SDEROT_ERR("failed to copy to user\n");
Benjamin Chan6db7eb52017-02-17 14:49:45 -05001290 rc = -EFAULT;
1291 goto debug_read_error;
Benjamin Chan6a0d2412016-10-27 17:47:46 -04001292 }
1293
1294 *ppos += len; /* increase offset */
1295
Benjamin Chan6db7eb52017-02-17 14:49:45 -05001296 mutex_unlock(&dbg->buflock);
Benjamin Chan6a0d2412016-10-27 17:47:46 -04001297 return len;
Benjamin Chan6db7eb52017-02-17 14:49:45 -05001298
1299debug_read_error:
1300 mutex_unlock(&dbg->buflock);
1301 return rc;
Benjamin Chan6a0d2412016-10-27 17:47:46 -04001302}
1303
1304static const struct file_operations sde_rotator_off_fops = {
1305 .open = sde_rotator_debug_base_open,
1306 .release = sde_rotator_debug_base_release,
1307 .read = sde_rotator_debug_base_offset_read,
1308 .write = sde_rotator_debug_base_offset_write,
1309};
1310
1311static const struct file_operations sde_rotator_reg_fops = {
1312 .open = sde_rotator_debug_base_open,
1313 .release = sde_rotator_debug_base_release,
1314 .read = sde_rotator_debug_base_reg_read,
1315 .write = sde_rotator_debug_base_reg_write,
1316};
1317
1318int sde_rotator_debug_register_base(struct sde_rotator_device *rot_dev,
1319 struct dentry *debugfs_root,
1320 const char *name,
1321 struct sde_io_data *io_data)
1322{
1323 struct sde_rotator_debug_base *dbg;
1324 struct dentry *ent_off, *ent_reg;
1325 char dbgname[80] = "";
1326 int prefix_len = 0;
1327
1328 if (!io_data)
1329 return -EINVAL;
1330
1331 dbg = kzalloc(sizeof(*dbg), GFP_KERNEL);
1332 if (!dbg)
1333 return -ENOMEM;
1334
Benjamin Chan6db7eb52017-02-17 14:49:45 -05001335 mutex_init(&dbg->buflock);
1336 mutex_lock(&dbg->buflock);
1337
Benjamin Chan6a0d2412016-10-27 17:47:46 -04001338 if (name)
1339 strlcpy(dbg->name, name, sizeof(dbg->name));
1340 dbg->base = io_data->base;
1341 dbg->max_offset = io_data->len;
1342 dbg->off = 0;
1343 dbg->cnt = SDE_ROT_DEFAULT_BASE_REG_CNT;
1344
1345 if (name) {
1346 if (strcmp(name, "sde"))
1347 prefix_len = snprintf(dbgname, sizeof(dbgname), "%s_",
1348 name);
1349 else
1350 /*
1351 * For SDE Rotator registers block, the IO base address
1352 * is based on MDP IO address base. It is necessary to
1353 * apply the initial offset to it from the first
1354 * regdump setting.
1355 */
1356 dbg->base += rot_dev->mdata->regdump ?
1357 rot_dev->mdata->regdump[0].offset : 0;
1358 }
Benjamin Chan6db7eb52017-02-17 14:49:45 -05001359 mutex_unlock(&dbg->buflock);
Benjamin Chan6a0d2412016-10-27 17:47:46 -04001360
1361 strlcpy(dbgname + prefix_len, "off", sizeof(dbgname) - prefix_len);
1362 ent_off = debugfs_create_file(dbgname, 0644, debugfs_root, dbg,
1363 &sde_rotator_off_fops);
1364 if (IS_ERR_OR_NULL(ent_off)) {
1365 SDEROT_ERR("debugfs_create_file: offset fail\n");
1366 goto off_fail;
1367 }
1368
1369 strlcpy(dbgname + prefix_len, "reg", sizeof(dbgname) - prefix_len);
1370 ent_reg = debugfs_create_file(dbgname, 0644, debugfs_root, dbg,
1371 &sde_rotator_reg_fops);
1372 if (IS_ERR_OR_NULL(ent_reg)) {
1373 SDEROT_ERR("debugfs_create_file: reg fail\n");
1374 goto reg_fail;
1375 }
1376
Benjamin Chan6db7eb52017-02-17 14:49:45 -05001377 mutex_lock(&dbg->buflock);
Benjamin Chan6a0d2412016-10-27 17:47:46 -04001378 dbg->mgr = rot_dev->mgr;
Benjamin Chan6db7eb52017-02-17 14:49:45 -05001379 mutex_unlock(&dbg->buflock);
Benjamin Chan6a0d2412016-10-27 17:47:46 -04001380
1381 return 0;
1382reg_fail:
1383 debugfs_remove(ent_off);
1384off_fail:
1385 kfree(dbg);
1386 return -ENODEV;
1387}
1388
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001389/*
1390 * sde_rotator_create_debugfs - Setup rotator debugfs directory structure.
1391 * @rot_dev: Pointer to rotator device
1392 */
1393struct dentry *sde_rotator_create_debugfs(
1394 struct sde_rotator_device *rot_dev)
1395{
1396 struct dentry *debugfs_root;
1397 char dirname[32] = {0};
1398
1399 snprintf(dirname, sizeof(dirname), "%s%d",
1400 SDE_ROTATOR_DRV_NAME, rot_dev->dev->id);
1401 debugfs_root = debugfs_create_dir(dirname, NULL);
1402 if (!debugfs_root) {
1403 SDEROT_ERR("fail create debugfs root\n");
1404 return NULL;
1405 }
1406
1407 if (!debugfs_create_file("stats", 0644,
1408 debugfs_root, rot_dev, &sde_rotator_stat_ops)) {
1409 SDEROT_ERR("fail create debugfs stats\n");
1410 debugfs_remove_recursive(debugfs_root);
1411 return NULL;
1412 }
1413
1414 if (!debugfs_create_file("raw", 0644,
1415 debugfs_root, rot_dev, &sde_rotator_raw_ops)) {
1416 SDEROT_ERR("fail create debugfs raw\n");
1417 debugfs_remove_recursive(debugfs_root);
1418 return NULL;
1419 }
1420
1421 if (!debugfs_create_u32("fence_timeout", 0644,
1422 debugfs_root, &rot_dev->fence_timeout)) {
1423 SDEROT_ERR("fail create fence_timeout\n");
1424 debugfs_remove_recursive(debugfs_root);
1425 return NULL;
1426 }
1427
Alan Kwong6bc64622017-02-04 17:36:03 -08001428 if (!debugfs_create_u32("disable_syscache", 0644,
1429 debugfs_root, &rot_dev->disable_syscache)) {
1430 SDEROT_ERR("fail create disable_syscache\n");
1431 debugfs_remove_recursive(debugfs_root);
1432 return NULL;
1433 }
1434
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001435 if (!debugfs_create_u32("streamoff_timeout", 0644,
1436 debugfs_root, &rot_dev->streamoff_timeout)) {
1437 SDEROT_ERR("fail create streamoff_timeout\n");
1438 debugfs_remove_recursive(debugfs_root);
1439 return NULL;
1440 }
1441
1442 if (!debugfs_create_u32("early_submit", 0644,
1443 debugfs_root, &rot_dev->early_submit)) {
1444 SDEROT_ERR("fail create early_submit\n");
1445 debugfs_remove_recursive(debugfs_root);
1446 return NULL;
1447 }
1448
1449 if (sde_rotator_base_create_debugfs(rot_dev->mdata, debugfs_root)) {
1450 SDEROT_ERR("fail create base debugfs\n");
1451 debugfs_remove_recursive(debugfs_root);
1452 return NULL;
1453 }
1454
1455 if (sde_rotator_core_create_debugfs(rot_dev->mgr, debugfs_root)) {
1456 SDEROT_ERR("fail create core debugfs\n");
1457 debugfs_remove_recursive(debugfs_root);
1458 return NULL;
1459 }
1460
Benjamin Chan53e3bce2016-08-31 14:43:29 -04001461 if (sde_rotator_evtlog_create_debugfs(rot_dev->mgr, debugfs_root)) {
1462 SDEROT_ERR("fail create evtlog debugfs\n");
1463 debugfs_remove_recursive(debugfs_root);
1464 return NULL;
1465 }
1466
Benjamin Chandbe13112016-09-26 12:10:06 -04001467 if (sde_rotator_perf_create_debugfs(rot_dev, debugfs_root)) {
1468 SDEROT_ERR("fail create perf debugfs\n");
1469 debugfs_remove_recursive(debugfs_root);
1470 return NULL;
1471 }
1472
Benjamin Chan6a0d2412016-10-27 17:47:46 -04001473 if (sde_rotator_debug_register_base(rot_dev, debugfs_root,
1474 "sde", &rot_dev->mdata->sde_io)) {
1475 SDEROT_ERR("fail create debug register for sde rotator\n");
1476 debugfs_remove_recursive(debugfs_root);
1477 return NULL;
1478 }
1479
1480 if (sde_rotator_debug_register_base(rot_dev, debugfs_root,
1481 "vbif_nrt", &rot_dev->mdata->vbif_nrt_io)) {
1482 SDEROT_ERR("fail create debug register for sderot vbif_nrt\n");
1483 debugfs_remove_recursive(debugfs_root);
1484 return NULL;
1485 }
1486
Adrian Salido-Moreno5c150382016-04-06 09:29:37 -07001487 return debugfs_root;
1488}
1489
1490/*
1491 * sde_rotator_destroy_debugfs - Destroy rotator debugfs directory structure.
1492 * @rot_dev: Pointer to rotator debugfs
1493 */
1494void sde_rotator_destroy_debugfs(struct dentry *debugfs)
1495{
1496 debugfs_remove_recursive(debugfs);
1497}