blob: c1b9e4ce24b2e4ab8e2e2b81f3a0243946c69505 [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
Jeremy Gebbeneebc4612011-08-31 10:15:21 -070023#include "a2xx_reg.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070024
25unsigned int kgsl_cff_dump_enable;
26int kgsl_pm_regs_enabled;
27
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070028static struct dentry *pm_d_debugfs;
29
30static int pm_dump_set(void *data, u64 val)
31{
32 struct kgsl_device *device = data;
33
34 if (val) {
35 mutex_lock(&device->mutex);
36 adreno_postmortem_dump(device, 1);
37 mutex_unlock(&device->mutex);
38 }
39
40 return 0;
41}
42
43DEFINE_SIMPLE_ATTRIBUTE(pm_dump_fops,
44 NULL,
45 pm_dump_set, "%llu\n");
46
47static int pm_regs_enabled_set(void *data, u64 val)
48{
49 kgsl_pm_regs_enabled = val ? 1 : 0;
50 return 0;
51}
52
53static int pm_regs_enabled_get(void *data, u64 *val)
54{
55 *val = kgsl_pm_regs_enabled;
56 return 0;
57}
58
59DEFINE_SIMPLE_ATTRIBUTE(pm_regs_enabled_fops,
60 pm_regs_enabled_get,
61 pm_regs_enabled_set, "%llu\n");
62
63
64static int kgsl_cff_dump_enable_set(void *data, u64 val)
65{
66#ifdef CONFIG_MSM_KGSL_CFF_DUMP
67 kgsl_cff_dump_enable = (val != 0);
68 return 0;
69#else
70 return -EINVAL;
71#endif
72}
73
74static int kgsl_cff_dump_enable_get(void *data, u64 *val)
75{
76 *val = kgsl_cff_dump_enable;
77 return 0;
78}
79
80DEFINE_SIMPLE_ATTRIBUTE(kgsl_cff_dump_enable_fops, kgsl_cff_dump_enable_get,
81 kgsl_cff_dump_enable_set, "%llu\n");
82
83static int kgsl_dbgfs_open(struct inode *inode, struct file *file)
84{
85 file->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
86 file->private_data = inode->i_private;
87 return 0;
88}
89
90static int kgsl_dbgfs_release(struct inode *inode, struct file *file)
91{
92 return 0;
93}
94
95static int kgsl_hex_dump(const char *prefix, int c, uint8_t *data,
96 int rowc, int linec, char __user *buff)
97{
98 int ss;
99 /* Prefix of 20 chars max, 32 bytes per row, in groups of four - that's
100 * 8 groups at 8 chars per group plus a space, plus new-line, plus
101 * ending character */
102 char linebuf[20 + 64 + 1 + 1];
103
104 ss = snprintf(linebuf, sizeof(linebuf), prefix, c);
105 hex_dump_to_buffer(data, linec, rowc, 4, linebuf+ss,
106 sizeof(linebuf)-ss, 0);
Tarun Karra44cbeb72011-08-18 13:30:24 -0700107 strlcat(linebuf, "\n", sizeof(linebuf));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700108 linebuf[sizeof(linebuf)-1] = 0;
109 ss = strlen(linebuf);
110 if (copy_to_user(buff, linebuf, ss+1))
111 return -EFAULT;
112 return ss;
113}
114
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700115static int kgsl_regread_nolock(struct kgsl_device *device,
116 unsigned int offsetwords, unsigned int *value)
117{
118 unsigned int *reg;
119
120 if (offsetwords*sizeof(uint32_t) >= device->regspace.sizebytes) {
121 KGSL_DRV_ERR(device, "invalid offset %d\n", offsetwords);
122 return -ERANGE;
123 }
124
125 reg = (unsigned int *)(device->regspace.mmio_virt_base
126 + (offsetwords << 2));
127 *value = __raw_readl(reg);
128 return 0;
129}
130
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700131static ssize_t kgsl_istore_read(
132 struct file *file,
133 char __user *buff,
134 size_t buff_count,
135 loff_t *ppos)
136{
Jeremy Gebbenddf6b572011-09-09 13:39:49 -0700137 int i, count, remaining, pos = 0, tot = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138 struct kgsl_device *device = file->private_data;
139 const int rowc = 8;
Jeremy Gebbenddf6b572011-09-09 13:39:49 -0700140 struct adreno_device *adreno_dev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700141
142 if (!ppos || !device)
143 return 0;
144
Jeremy Gebbenddf6b572011-09-09 13:39:49 -0700145 adreno_dev = ADRENO_DEVICE(device);
146 count = adreno_dev->istore_size * ADRENO_ISTORE_WORDS;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700147 remaining = count;
148 for (i = 0; i < count; i += rowc) {
149 unsigned int vals[rowc];
150 int j, ss;
151 int linec = min(remaining, rowc);
152 remaining -= rowc;
153
154 if (pos >= *ppos) {
155 for (j = 0; j < linec; ++j)
156 kgsl_regread_nolock(device,
Jeremy Gebbenddf6b572011-09-09 13:39:49 -0700157 ADRENO_ISTORE_START + i + j,
158 vals + j);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159 } else
160 memset(vals, 0, sizeof(vals));
161
162 ss = kgsl_hex_dump("IS: %04x: ", i, (uint8_t *)vals, rowc*4,
163 linec*4, buff);
164 if (ss < 0)
165 return ss;
166
167 if (pos >= *ppos) {
168 if (tot+ss >= buff_count)
169 return tot;
170 tot += ss;
171 buff += ss;
172 *ppos += ss;
173 }
174 pos += ss;
175 }
176
177 return tot;
178}
179
180static const struct file_operations kgsl_istore_fops = {
181 .open = kgsl_dbgfs_open,
182 .release = kgsl_dbgfs_release,
183 .read = kgsl_istore_read,
184 .llseek = default_llseek,
185};
186
187typedef void (*reg_read_init_t)(struct kgsl_device *device);
188typedef void (*reg_read_fill_t)(struct kgsl_device *device, int i,
189 unsigned int *vals, int linec);
190static ssize_t kgsl_reg_read(struct kgsl_device *device, int count,
191 reg_read_init_t reg_read_init,
192 reg_read_fill_t reg_read_fill, const char *prefix, char __user *buff,
193 loff_t *ppos)
194{
195 int i, remaining;
196 const int rowc = 8;
197
198 if (!ppos || *ppos || !device)
199 return 0;
200
201 mutex_lock(&device->mutex);
202 reg_read_init(device);
203 remaining = count;
204 for (i = 0; i < count; i += rowc) {
205 unsigned int vals[rowc];
206 int ss;
207 int linec = min(remaining, rowc);
208 remaining -= rowc;
209
210 reg_read_fill(device, i, vals, linec);
211 ss = kgsl_hex_dump(prefix, i, (uint8_t *)vals, rowc*4, linec*4,
212 buff);
213 if (ss < 0) {
214 mutex_unlock(&device->mutex);
215 return ss;
216 }
217 buff += ss;
218 *ppos += ss;
219 }
220 mutex_unlock(&device->mutex);
221
222 return *ppos;
223}
224
225
226static void kgsl_sx_reg_read_init(struct kgsl_device *device)
227{
228 kgsl_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0xFF);
229 kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
230}
231
232static void kgsl_sx_reg_read_fill(struct kgsl_device *device, int i,
233 unsigned int *vals, int linec)
234{
235 int j;
236
237 for (j = 0; j < linec; ++j) {
238 kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1B00 | i);
239 kgsl_regread(device, REG_RBBM_DEBUG_OUT, vals+j);
240 }
241}
242
243static ssize_t kgsl_sx_debug_read(
244 struct file *file,
245 char __user *buff,
246 size_t buff_count,
247 loff_t *ppos)
248{
249 struct kgsl_device *device = file->private_data;
250 return kgsl_reg_read(device, 0x1B, kgsl_sx_reg_read_init,
251 kgsl_sx_reg_read_fill, "SX: %02x: ", buff, ppos);
252}
253
254static const struct file_operations kgsl_sx_debug_fops = {
255 .open = kgsl_dbgfs_open,
256 .release = kgsl_dbgfs_release,
257 .read = kgsl_sx_debug_read,
258};
259
260static void kgsl_cp_reg_read_init(struct kgsl_device *device)
261{
262 kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
263}
264
265static void kgsl_cp_reg_read_fill(struct kgsl_device *device, int i,
266 unsigned int *vals, int linec)
267{
268 int j;
269
270 for (j = 0; j < linec; ++j) {
271 kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1628);
272 kgsl_regread(device, REG_RBBM_DEBUG_OUT, vals+j);
273 msleep(100);
274 }
275}
276
277static ssize_t kgsl_cp_debug_read(
278 struct file *file,
279 char __user *buff,
280 size_t buff_count,
281 loff_t *ppos)
282{
283 struct kgsl_device *device = file->private_data;
284 return kgsl_reg_read(device, 20, kgsl_cp_reg_read_init,
285 kgsl_cp_reg_read_fill,
286 "CP: %02x: ", buff, ppos);
287}
288
289static const struct file_operations kgsl_cp_debug_fops = {
290 .open = kgsl_dbgfs_open,
291 .release = kgsl_dbgfs_release,
292 .read = kgsl_cp_debug_read,
293};
294
295static void kgsl_mh_reg_read_init(struct kgsl_device *device)
296{
297 kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
298}
299
300static void kgsl_mh_reg_read_fill(struct kgsl_device *device, int i,
301 unsigned int *vals, int linec)
302{
303 int j;
304
305 for (j = 0; j < linec; ++j) {
Jeremy Gebben4e8aada2011-07-12 10:07:47 -0600306 kgsl_regwrite(device, MH_DEBUG_CTRL, i+j);
307 kgsl_regread(device, MH_DEBUG_DATA, vals+j);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700308 }
309}
310
311static ssize_t kgsl_mh_debug_read(
312 struct file *file,
313 char __user *buff,
314 size_t buff_count,
315 loff_t *ppos)
316{
317 struct kgsl_device *device = file->private_data;
318 return kgsl_reg_read(device, 0x40, kgsl_mh_reg_read_init,
319 kgsl_mh_reg_read_fill,
320 "MH: %02x: ", buff, ppos);
321}
322
323static const struct file_operations kgsl_mh_debug_fops = {
324 .open = kgsl_dbgfs_open,
325 .release = kgsl_dbgfs_release,
326 .read = kgsl_mh_debug_read,
327};
328
329void adreno_debugfs_init(struct kgsl_device *device)
330{
Ranjhith Kalisamy823c1482011-09-05 20:31:07 +0530331 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
332
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700333 if (!device->d_debugfs || IS_ERR(device->d_debugfs))
334 return;
335
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700336 debugfs_create_file("istore", 0400, device->d_debugfs, device,
337 &kgsl_istore_fops);
338 debugfs_create_file("sx_debug", 0400, device->d_debugfs, device,
339 &kgsl_sx_debug_fops);
340 debugfs_create_file("cp_debug", 0400, device->d_debugfs, device,
341 &kgsl_cp_debug_fops);
342 debugfs_create_file("mh_debug", 0400, device->d_debugfs, device,
343 &kgsl_mh_debug_fops);
344 debugfs_create_file("cff_dump", 0644, device->d_debugfs, device,
345 &kgsl_cff_dump_enable_fops);
Ranjhith Kalisamy823c1482011-09-05 20:31:07 +0530346 debugfs_create_u32("wait_timeout", 0644, device->d_debugfs,
347 &adreno_dev->wait_timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700348
349 /* Create post mortem control files */
350
351 pm_d_debugfs = debugfs_create_dir("postmortem", device->d_debugfs);
352
353 if (IS_ERR(pm_d_debugfs))
354 return;
355
356 debugfs_create_file("dump", 0600, pm_d_debugfs, device,
357 &pm_dump_fops);
358 debugfs_create_file("regs_enabled", 0644, pm_d_debugfs, device,
359 &pm_regs_enabled_fops);
360}