blob: b897e1091013422abafb52afe8b9fcc1a6c12a55 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2002,2008-2011, Code Aurora Forum. All rights reserved.
2 *
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
14#include <linux/delay.h>
15#include <linux/debugfs.h>
16#include <linux/uaccess.h>
17#include <linux/io.h>
18
19#include "kgsl.h"
20#include "adreno_postmortem.h"
21#include "adreno.h"
22
23#include "a200_reg.h"
24
25unsigned int kgsl_cff_dump_enable;
26int kgsl_pm_regs_enabled;
27
28static uint32_t kgsl_ib_base;
29static uint32_t kgsl_ib_size;
30
31static struct dentry *pm_d_debugfs;
32
33static int pm_dump_set(void *data, u64 val)
34{
35 struct kgsl_device *device = data;
36
37 if (val) {
38 mutex_lock(&device->mutex);
39 adreno_postmortem_dump(device, 1);
40 mutex_unlock(&device->mutex);
41 }
42
43 return 0;
44}
45
46DEFINE_SIMPLE_ATTRIBUTE(pm_dump_fops,
47 NULL,
48 pm_dump_set, "%llu\n");
49
50static int pm_regs_enabled_set(void *data, u64 val)
51{
52 kgsl_pm_regs_enabled = val ? 1 : 0;
53 return 0;
54}
55
56static int pm_regs_enabled_get(void *data, u64 *val)
57{
58 *val = kgsl_pm_regs_enabled;
59 return 0;
60}
61
62DEFINE_SIMPLE_ATTRIBUTE(pm_regs_enabled_fops,
63 pm_regs_enabled_get,
64 pm_regs_enabled_set, "%llu\n");
65
66
67static int kgsl_cff_dump_enable_set(void *data, u64 val)
68{
69#ifdef CONFIG_MSM_KGSL_CFF_DUMP
70 kgsl_cff_dump_enable = (val != 0);
71 return 0;
72#else
73 return -EINVAL;
74#endif
75}
76
77static int kgsl_cff_dump_enable_get(void *data, u64 *val)
78{
79 *val = kgsl_cff_dump_enable;
80 return 0;
81}
82
83DEFINE_SIMPLE_ATTRIBUTE(kgsl_cff_dump_enable_fops, kgsl_cff_dump_enable_get,
84 kgsl_cff_dump_enable_set, "%llu\n");
85
86static int kgsl_dbgfs_open(struct inode *inode, struct file *file)
87{
88 file->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
89 file->private_data = inode->i_private;
90 return 0;
91}
92
93static int kgsl_dbgfs_release(struct inode *inode, struct file *file)
94{
95 return 0;
96}
97
98static int kgsl_hex_dump(const char *prefix, int c, uint8_t *data,
99 int rowc, int linec, char __user *buff)
100{
101 int ss;
102 /* Prefix of 20 chars max, 32 bytes per row, in groups of four - that's
103 * 8 groups at 8 chars per group plus a space, plus new-line, plus
104 * ending character */
105 char linebuf[20 + 64 + 1 + 1];
106
107 ss = snprintf(linebuf, sizeof(linebuf), prefix, c);
108 hex_dump_to_buffer(data, linec, rowc, 4, linebuf+ss,
109 sizeof(linebuf)-ss, 0);
110 strncat(linebuf, "\n", sizeof(linebuf));
111 linebuf[sizeof(linebuf)-1] = 0;
112 ss = strlen(linebuf);
113 if (copy_to_user(buff, linebuf, ss+1))
114 return -EFAULT;
115 return ss;
116}
117
118static ssize_t kgsl_ib_dump_read(
119 struct file *file,
120 char __user *buff,
121 size_t buff_count,
122 loff_t *ppos)
123{
124 int i, count = kgsl_ib_size, remaining, pos = 0, tot = 0, ss;
125 struct kgsl_device *device = file->private_data;
126 const int rowc = 32;
127 unsigned int pt_base, ib_memsize;
128 uint8_t *base_addr;
129 char linebuf[80];
130
131 if (!ppos || !device || !kgsl_ib_base)
132 return 0;
133
134 kgsl_regread(device, MH_MMU_PT_BASE, &pt_base);
135 base_addr = kgsl_sharedmem_convertaddr(device, pt_base, kgsl_ib_base,
136 &ib_memsize);
137
138 if (!base_addr)
139 return 0;
140
141 pr_info("%s ppos=%ld, buff_count=%d, count=%d\n", __func__, (long)*ppos,
142 buff_count, count);
143 ss = snprintf(linebuf, sizeof(linebuf), "IB: base=%08x(%08x"
144 "), size=%d, memsize=%d\n", kgsl_ib_base,
145 (uint32_t)base_addr, kgsl_ib_size, ib_memsize);
146 if (*ppos == 0) {
147 if (copy_to_user(buff, linebuf, ss+1))
148 return -EFAULT;
149 tot += ss;
150 buff += ss;
151 *ppos += ss;
152 }
153 pos += ss;
154 remaining = count;
155 for (i = 0; i < count; i += rowc) {
156 int linec = min(remaining, rowc);
157
158 remaining -= rowc;
159 ss = kgsl_hex_dump("IB: %05x: ", i, base_addr, rowc, linec,
160 buff);
161 if (ss < 0)
162 return ss;
163
164 if (pos >= *ppos) {
165 if (tot+ss >= buff_count) {
166 ss = copy_to_user(buff, "", 1);
167 return tot;
168 }
169 tot += ss;
170 buff += ss;
171 *ppos += ss;
172 }
173 pos += ss;
174 base_addr += linec;
175 }
176
177 return tot;
178}
179
180static ssize_t kgsl_ib_dump_write(
181 struct file *file,
182 const char __user *buff,
183 size_t count,
184 loff_t *ppos)
185{
186 char local_buff[64];
187
188 if (count >= sizeof(local_buff))
189 return -EFAULT;
190
191 if (copy_from_user(local_buff, buff, count))
192 return -EFAULT;
193
194 local_buff[count] = 0; /* end of string */
195 sscanf(local_buff, "%x %d", &kgsl_ib_base, &kgsl_ib_size);
196
197 pr_info("%s: base=%08X size=%d\n", __func__, kgsl_ib_base,
198 kgsl_ib_size);
199
200 return count;
201}
202
203static const struct file_operations kgsl_ib_dump_fops = {
204 .open = kgsl_dbgfs_open,
205 .release = kgsl_dbgfs_release,
206 .read = kgsl_ib_dump_read,
207 .write = kgsl_ib_dump_write,
208};
209
210static int kgsl_regread_nolock(struct kgsl_device *device,
211 unsigned int offsetwords, unsigned int *value)
212{
213 unsigned int *reg;
214
215 if (offsetwords*sizeof(uint32_t) >= device->regspace.sizebytes) {
216 KGSL_DRV_ERR(device, "invalid offset %d\n", offsetwords);
217 return -ERANGE;
218 }
219
220 reg = (unsigned int *)(device->regspace.mmio_virt_base
221 + (offsetwords << 2));
222 *value = __raw_readl(reg);
223 return 0;
224}
225
226#define KGSL_ISTORE_START 0x5000
227#define KGSL_ISTORE_LENGTH 0x600
228static ssize_t kgsl_istore_read(
229 struct file *file,
230 char __user *buff,
231 size_t buff_count,
232 loff_t *ppos)
233{
234 int i, count = KGSL_ISTORE_LENGTH, remaining, pos = 0, tot = 0;
235 struct kgsl_device *device = file->private_data;
236 const int rowc = 8;
237
238 if (!ppos || !device)
239 return 0;
240
241 remaining = count;
242 for (i = 0; i < count; i += rowc) {
243 unsigned int vals[rowc];
244 int j, ss;
245 int linec = min(remaining, rowc);
246 remaining -= rowc;
247
248 if (pos >= *ppos) {
249 for (j = 0; j < linec; ++j)
250 kgsl_regread_nolock(device,
251 KGSL_ISTORE_START+i+j, vals+j);
252 } else
253 memset(vals, 0, sizeof(vals));
254
255 ss = kgsl_hex_dump("IS: %04x: ", i, (uint8_t *)vals, rowc*4,
256 linec*4, buff);
257 if (ss < 0)
258 return ss;
259
260 if (pos >= *ppos) {
261 if (tot+ss >= buff_count)
262 return tot;
263 tot += ss;
264 buff += ss;
265 *ppos += ss;
266 }
267 pos += ss;
268 }
269
270 return tot;
271}
272
273static const struct file_operations kgsl_istore_fops = {
274 .open = kgsl_dbgfs_open,
275 .release = kgsl_dbgfs_release,
276 .read = kgsl_istore_read,
277 .llseek = default_llseek,
278};
279
280typedef void (*reg_read_init_t)(struct kgsl_device *device);
281typedef void (*reg_read_fill_t)(struct kgsl_device *device, int i,
282 unsigned int *vals, int linec);
283static ssize_t kgsl_reg_read(struct kgsl_device *device, int count,
284 reg_read_init_t reg_read_init,
285 reg_read_fill_t reg_read_fill, const char *prefix, char __user *buff,
286 loff_t *ppos)
287{
288 int i, remaining;
289 const int rowc = 8;
290
291 if (!ppos || *ppos || !device)
292 return 0;
293
294 mutex_lock(&device->mutex);
295 reg_read_init(device);
296 remaining = count;
297 for (i = 0; i < count; i += rowc) {
298 unsigned int vals[rowc];
299 int ss;
300 int linec = min(remaining, rowc);
301 remaining -= rowc;
302
303 reg_read_fill(device, i, vals, linec);
304 ss = kgsl_hex_dump(prefix, i, (uint8_t *)vals, rowc*4, linec*4,
305 buff);
306 if (ss < 0) {
307 mutex_unlock(&device->mutex);
308 return ss;
309 }
310 buff += ss;
311 *ppos += ss;
312 }
313 mutex_unlock(&device->mutex);
314
315 return *ppos;
316}
317
318
319static void kgsl_sx_reg_read_init(struct kgsl_device *device)
320{
321 kgsl_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0xFF);
322 kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
323}
324
325static void kgsl_sx_reg_read_fill(struct kgsl_device *device, int i,
326 unsigned int *vals, int linec)
327{
328 int j;
329
330 for (j = 0; j < linec; ++j) {
331 kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1B00 | i);
332 kgsl_regread(device, REG_RBBM_DEBUG_OUT, vals+j);
333 }
334}
335
336static ssize_t kgsl_sx_debug_read(
337 struct file *file,
338 char __user *buff,
339 size_t buff_count,
340 loff_t *ppos)
341{
342 struct kgsl_device *device = file->private_data;
343 return kgsl_reg_read(device, 0x1B, kgsl_sx_reg_read_init,
344 kgsl_sx_reg_read_fill, "SX: %02x: ", buff, ppos);
345}
346
347static const struct file_operations kgsl_sx_debug_fops = {
348 .open = kgsl_dbgfs_open,
349 .release = kgsl_dbgfs_release,
350 .read = kgsl_sx_debug_read,
351};
352
353static void kgsl_cp_reg_read_init(struct kgsl_device *device)
354{
355 kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
356}
357
358static void kgsl_cp_reg_read_fill(struct kgsl_device *device, int i,
359 unsigned int *vals, int linec)
360{
361 int j;
362
363 for (j = 0; j < linec; ++j) {
364 kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1628);
365 kgsl_regread(device, REG_RBBM_DEBUG_OUT, vals+j);
366 msleep(100);
367 }
368}
369
370static ssize_t kgsl_cp_debug_read(
371 struct file *file,
372 char __user *buff,
373 size_t buff_count,
374 loff_t *ppos)
375{
376 struct kgsl_device *device = file->private_data;
377 return kgsl_reg_read(device, 20, kgsl_cp_reg_read_init,
378 kgsl_cp_reg_read_fill,
379 "CP: %02x: ", buff, ppos);
380}
381
382static const struct file_operations kgsl_cp_debug_fops = {
383 .open = kgsl_dbgfs_open,
384 .release = kgsl_dbgfs_release,
385 .read = kgsl_cp_debug_read,
386};
387
388static void kgsl_mh_reg_read_init(struct kgsl_device *device)
389{
390 kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
391}
392
393static void kgsl_mh_reg_read_fill(struct kgsl_device *device, int i,
394 unsigned int *vals, int linec)
395{
396 int j;
397
398 for (j = 0; j < linec; ++j) {
399 kgsl_regwrite(device, REG_MH_DEBUG_CTRL, i+j);
400 kgsl_regread(device, REG_MH_DEBUG_DATA, vals+j);
401 }
402}
403
404static ssize_t kgsl_mh_debug_read(
405 struct file *file,
406 char __user *buff,
407 size_t buff_count,
408 loff_t *ppos)
409{
410 struct kgsl_device *device = file->private_data;
411 return kgsl_reg_read(device, 0x40, kgsl_mh_reg_read_init,
412 kgsl_mh_reg_read_fill,
413 "MH: %02x: ", buff, ppos);
414}
415
416static const struct file_operations kgsl_mh_debug_fops = {
417 .open = kgsl_dbgfs_open,
418 .release = kgsl_dbgfs_release,
419 .read = kgsl_mh_debug_read,
420};
421
422void adreno_debugfs_init(struct kgsl_device *device)
423{
424 if (!device->d_debugfs || IS_ERR(device->d_debugfs))
425 return;
426
427 debugfs_create_file("ib_dump", 0600, device->d_debugfs, device,
428 &kgsl_ib_dump_fops);
429 debugfs_create_file("istore", 0400, device->d_debugfs, device,
430 &kgsl_istore_fops);
431 debugfs_create_file("sx_debug", 0400, device->d_debugfs, device,
432 &kgsl_sx_debug_fops);
433 debugfs_create_file("cp_debug", 0400, device->d_debugfs, device,
434 &kgsl_cp_debug_fops);
435 debugfs_create_file("mh_debug", 0400, device->d_debugfs, device,
436 &kgsl_mh_debug_fops);
437 debugfs_create_file("cff_dump", 0644, device->d_debugfs, device,
438 &kgsl_cff_dump_enable_fops);
439
440 /* Create post mortem control files */
441
442 pm_d_debugfs = debugfs_create_dir("postmortem", device->d_debugfs);
443
444 if (IS_ERR(pm_d_debugfs))
445 return;
446
447 debugfs_create_file("dump", 0600, pm_d_debugfs, device,
448 &pm_dump_fops);
449 debugfs_create_file("regs_enabled", 0644, pm_d_debugfs, device,
450 &pm_regs_enabled_fops);
451}