blob: b53ca8f848a0c289cc9d3cd879867d42b5f38122 [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);
Jordan Crousec6b3a992012-02-04 10:23:51 -0700146 count = adreno_dev->istore_size * adreno_dev->instruction_size;
147
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700148 remaining = count;
149 for (i = 0; i < count; i += rowc) {
150 unsigned int vals[rowc];
151 int j, ss;
152 int linec = min(remaining, rowc);
153 remaining -= rowc;
154
155 if (pos >= *ppos) {
156 for (j = 0; j < linec; ++j)
157 kgsl_regread_nolock(device,
Jeremy Gebbenddf6b572011-09-09 13:39:49 -0700158 ADRENO_ISTORE_START + i + j,
159 vals + j);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160 } else
161 memset(vals, 0, sizeof(vals));
162
163 ss = kgsl_hex_dump("IS: %04x: ", i, (uint8_t *)vals, rowc*4,
164 linec*4, buff);
165 if (ss < 0)
166 return ss;
167
168 if (pos >= *ppos) {
169 if (tot+ss >= buff_count)
170 return tot;
171 tot += ss;
172 buff += ss;
173 *ppos += ss;
174 }
175 pos += ss;
176 }
177
178 return tot;
179}
180
181static const struct file_operations kgsl_istore_fops = {
182 .open = kgsl_dbgfs_open,
183 .release = kgsl_dbgfs_release,
184 .read = kgsl_istore_read,
185 .llseek = default_llseek,
186};
187
188typedef void (*reg_read_init_t)(struct kgsl_device *device);
189typedef void (*reg_read_fill_t)(struct kgsl_device *device, int i,
190 unsigned int *vals, int linec);
191static ssize_t kgsl_reg_read(struct kgsl_device *device, int count,
192 reg_read_init_t reg_read_init,
193 reg_read_fill_t reg_read_fill, const char *prefix, char __user *buff,
194 loff_t *ppos)
195{
196 int i, remaining;
197 const int rowc = 8;
198
199 if (!ppos || *ppos || !device)
200 return 0;
201
202 mutex_lock(&device->mutex);
203 reg_read_init(device);
204 remaining = count;
205 for (i = 0; i < count; i += rowc) {
206 unsigned int vals[rowc];
207 int ss;
208 int linec = min(remaining, rowc);
209 remaining -= rowc;
210
211 reg_read_fill(device, i, vals, linec);
212 ss = kgsl_hex_dump(prefix, i, (uint8_t *)vals, rowc*4, linec*4,
213 buff);
214 if (ss < 0) {
215 mutex_unlock(&device->mutex);
216 return ss;
217 }
218 buff += ss;
219 *ppos += ss;
220 }
221 mutex_unlock(&device->mutex);
222
223 return *ppos;
224}
225
226
227static void kgsl_sx_reg_read_init(struct kgsl_device *device)
228{
229 kgsl_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0xFF);
230 kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
231}
232
233static void kgsl_sx_reg_read_fill(struct kgsl_device *device, int i,
234 unsigned int *vals, int linec)
235{
236 int j;
237
238 for (j = 0; j < linec; ++j) {
239 kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1B00 | i);
240 kgsl_regread(device, REG_RBBM_DEBUG_OUT, vals+j);
241 }
242}
243
244static ssize_t kgsl_sx_debug_read(
245 struct file *file,
246 char __user *buff,
247 size_t buff_count,
248 loff_t *ppos)
249{
250 struct kgsl_device *device = file->private_data;
251 return kgsl_reg_read(device, 0x1B, kgsl_sx_reg_read_init,
252 kgsl_sx_reg_read_fill, "SX: %02x: ", buff, ppos);
253}
254
255static const struct file_operations kgsl_sx_debug_fops = {
256 .open = kgsl_dbgfs_open,
257 .release = kgsl_dbgfs_release,
258 .read = kgsl_sx_debug_read,
259};
260
261static void kgsl_cp_reg_read_init(struct kgsl_device *device)
262{
263 kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
264}
265
266static void kgsl_cp_reg_read_fill(struct kgsl_device *device, int i,
267 unsigned int *vals, int linec)
268{
269 int j;
270
271 for (j = 0; j < linec; ++j) {
272 kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1628);
273 kgsl_regread(device, REG_RBBM_DEBUG_OUT, vals+j);
274 msleep(100);
275 }
276}
277
278static ssize_t kgsl_cp_debug_read(
279 struct file *file,
280 char __user *buff,
281 size_t buff_count,
282 loff_t *ppos)
283{
284 struct kgsl_device *device = file->private_data;
285 return kgsl_reg_read(device, 20, kgsl_cp_reg_read_init,
286 kgsl_cp_reg_read_fill,
287 "CP: %02x: ", buff, ppos);
288}
289
290static const struct file_operations kgsl_cp_debug_fops = {
291 .open = kgsl_dbgfs_open,
292 .release = kgsl_dbgfs_release,
293 .read = kgsl_cp_debug_read,
294};
295
296static void kgsl_mh_reg_read_init(struct kgsl_device *device)
297{
298 kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
299}
300
301static void kgsl_mh_reg_read_fill(struct kgsl_device *device, int i,
302 unsigned int *vals, int linec)
303{
304 int j;
305
306 for (j = 0; j < linec; ++j) {
Jeremy Gebben4e8aada2011-07-12 10:07:47 -0600307 kgsl_regwrite(device, MH_DEBUG_CTRL, i+j);
308 kgsl_regread(device, MH_DEBUG_DATA, vals+j);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700309 }
310}
311
312static ssize_t kgsl_mh_debug_read(
313 struct file *file,
314 char __user *buff,
315 size_t buff_count,
316 loff_t *ppos)
317{
318 struct kgsl_device *device = file->private_data;
319 return kgsl_reg_read(device, 0x40, kgsl_mh_reg_read_init,
320 kgsl_mh_reg_read_fill,
321 "MH: %02x: ", buff, ppos);
322}
323
324static const struct file_operations kgsl_mh_debug_fops = {
325 .open = kgsl_dbgfs_open,
326 .release = kgsl_dbgfs_release,
327 .read = kgsl_mh_debug_read,
328};
329
330void adreno_debugfs_init(struct kgsl_device *device)
331{
Ranjhith Kalisamy823c1482011-09-05 20:31:07 +0530332 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
333
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700334 if (!device->d_debugfs || IS_ERR(device->d_debugfs))
335 return;
336
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700337 debugfs_create_file("istore", 0400, device->d_debugfs, device,
338 &kgsl_istore_fops);
339 debugfs_create_file("sx_debug", 0400, device->d_debugfs, device,
340 &kgsl_sx_debug_fops);
341 debugfs_create_file("cp_debug", 0400, device->d_debugfs, device,
342 &kgsl_cp_debug_fops);
343 debugfs_create_file("mh_debug", 0400, device->d_debugfs, device,
344 &kgsl_mh_debug_fops);
345 debugfs_create_file("cff_dump", 0644, device->d_debugfs, device,
346 &kgsl_cff_dump_enable_fops);
Ranjhith Kalisamy823c1482011-09-05 20:31:07 +0530347 debugfs_create_u32("wait_timeout", 0644, device->d_debugfs,
348 &adreno_dev->wait_timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700349
350 /* Create post mortem control files */
351
352 pm_d_debugfs = debugfs_create_dir("postmortem", device->d_debugfs);
353
354 if (IS_ERR(pm_d_debugfs))
355 return;
356
357 debugfs_create_file("dump", 0600, pm_d_debugfs, device,
358 &pm_dump_fops);
359 debugfs_create_file("regs_enabled", 0644, pm_d_debugfs, device,
360 &pm_regs_enabled_fops);
361}