diff options
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-omap2/pm-debug.c | 226 | ||||
-rw-r--r-- | arch/arm/mach-omap2/pm.h | 4 |
2 files changed, 229 insertions, 1 deletions
diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 7383e85eac26..982aa67f2685 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c | |||
@@ -52,6 +52,8 @@ int omap2_pm_debug; | |||
52 | regs[reg_count].name = #reg; \ | 52 | regs[reg_count].name = #reg; \ |
53 | regs[reg_count++].val = __raw_readl(OMAP2_IO_ADDRESS(0x480fe000 + (off))) | 53 | regs[reg_count++].val = __raw_readl(OMAP2_IO_ADDRESS(0x480fe000 + (off))) |
54 | 54 | ||
55 | static int __init pm_dbg_init(void); | ||
56 | |||
55 | void omap2_pm_dump(int mode, int resume, unsigned int us) | 57 | void omap2_pm_dump(int mode, int resume, unsigned int us) |
56 | { | 58 | { |
57 | struct reg { | 59 | struct reg { |
@@ -157,6 +159,8 @@ void omap2_pm_dump(int mode, int resume, unsigned int us) | |||
157 | #include <linux/debugfs.h> | 159 | #include <linux/debugfs.h> |
158 | #include <linux/seq_file.h> | 160 | #include <linux/seq_file.h> |
159 | 161 | ||
162 | static void pm_dbg_regset_store(u32 *ptr); | ||
163 | |||
160 | struct dentry *pm_dbg_dir; | 164 | struct dentry *pm_dbg_dir; |
161 | 165 | ||
162 | static int pm_dbg_init_done; | 166 | static int pm_dbg_init_done; |
@@ -166,6 +170,160 @@ enum { | |||
166 | DEBUG_FILE_TIMERS, | 170 | DEBUG_FILE_TIMERS, |
167 | }; | 171 | }; |
168 | 172 | ||
173 | struct pm_module_def { | ||
174 | char name[8]; /* Name of the module */ | ||
175 | short type; /* CM or PRM */ | ||
176 | unsigned short offset; | ||
177 | int low; /* First register address on this module */ | ||
178 | int high; /* Last register address on this module */ | ||
179 | }; | ||
180 | |||
181 | #define MOD_CM 0 | ||
182 | #define MOD_PRM 1 | ||
183 | |||
184 | static const struct pm_module_def *pm_dbg_reg_modules; | ||
185 | static const struct pm_module_def omap3_pm_reg_modules[] = { | ||
186 | { "IVA2", MOD_CM, OMAP3430_IVA2_MOD, 0, 0x4c }, | ||
187 | { "OCP", MOD_CM, OCP_MOD, 0, 0x10 }, | ||
188 | { "MPU", MOD_CM, MPU_MOD, 4, 0x4c }, | ||
189 | { "CORE", MOD_CM, CORE_MOD, 0, 0x4c }, | ||
190 | { "SGX", MOD_CM, OMAP3430ES2_SGX_MOD, 0, 0x4c }, | ||
191 | { "WKUP", MOD_CM, WKUP_MOD, 0, 0x40 }, | ||
192 | { "CCR", MOD_CM, PLL_MOD, 0, 0x70 }, | ||
193 | { "DSS", MOD_CM, OMAP3430_DSS_MOD, 0, 0x4c }, | ||
194 | { "CAM", MOD_CM, OMAP3430_CAM_MOD, 0, 0x4c }, | ||
195 | { "PER", MOD_CM, OMAP3430_PER_MOD, 0, 0x4c }, | ||
196 | { "EMU", MOD_CM, OMAP3430_EMU_MOD, 0x40, 0x54 }, | ||
197 | { "NEON", MOD_CM, OMAP3430_NEON_MOD, 0x20, 0x48 }, | ||
198 | { "USB", MOD_CM, OMAP3430ES2_USBHOST_MOD, 0, 0x4c }, | ||
199 | |||
200 | { "IVA2", MOD_PRM, OMAP3430_IVA2_MOD, 0x50, 0xfc }, | ||
201 | { "OCP", MOD_PRM, OCP_MOD, 4, 0x1c }, | ||
202 | { "MPU", MOD_PRM, MPU_MOD, 0x58, 0xe8 }, | ||
203 | { "CORE", MOD_PRM, CORE_MOD, 0x58, 0xf8 }, | ||
204 | { "SGX", MOD_PRM, OMAP3430ES2_SGX_MOD, 0x58, 0xe8 }, | ||
205 | { "WKUP", MOD_PRM, WKUP_MOD, 0xa0, 0xb0 }, | ||
206 | { "CCR", MOD_PRM, PLL_MOD, 0x40, 0x70 }, | ||
207 | { "DSS", MOD_PRM, OMAP3430_DSS_MOD, 0x58, 0xe8 }, | ||
208 | { "CAM", MOD_PRM, OMAP3430_CAM_MOD, 0x58, 0xe8 }, | ||
209 | { "PER", MOD_PRM, OMAP3430_PER_MOD, 0x58, 0xe8 }, | ||
210 | { "EMU", MOD_PRM, OMAP3430_EMU_MOD, 0x58, 0xe4 }, | ||
211 | { "GLBL", MOD_PRM, OMAP3430_GR_MOD, 0x20, 0xe4 }, | ||
212 | { "NEON", MOD_PRM, OMAP3430_NEON_MOD, 0x58, 0xe8 }, | ||
213 | { "USB", MOD_PRM, OMAP3430ES2_USBHOST_MOD, 0x58, 0xe8 }, | ||
214 | { "", 0, 0, 0, 0 }, | ||
215 | }; | ||
216 | |||
217 | #define PM_DBG_MAX_REG_SETS 4 | ||
218 | |||
219 | static void *pm_dbg_reg_set[PM_DBG_MAX_REG_SETS]; | ||
220 | |||
221 | static int pm_dbg_get_regset_size(void) | ||
222 | { | ||
223 | static int regset_size; | ||
224 | |||
225 | if (regset_size == 0) { | ||
226 | int i = 0; | ||
227 | |||
228 | while (pm_dbg_reg_modules[i].name[0] != 0) { | ||
229 | regset_size += pm_dbg_reg_modules[i].high + | ||
230 | 4 - pm_dbg_reg_modules[i].low; | ||
231 | i++; | ||
232 | } | ||
233 | } | ||
234 | return regset_size; | ||
235 | } | ||
236 | |||
237 | static int pm_dbg_show_regs(struct seq_file *s, void *unused) | ||
238 | { | ||
239 | int i, j; | ||
240 | unsigned long val; | ||
241 | int reg_set = (int)s->private; | ||
242 | u32 *ptr; | ||
243 | void *store = NULL; | ||
244 | int regs; | ||
245 | int linefeed; | ||
246 | |||
247 | if (reg_set == 0) { | ||
248 | store = kmalloc(pm_dbg_get_regset_size(), GFP_KERNEL); | ||
249 | ptr = store; | ||
250 | pm_dbg_regset_store(ptr); | ||
251 | } else { | ||
252 | ptr = pm_dbg_reg_set[reg_set - 1]; | ||
253 | } | ||
254 | |||
255 | i = 0; | ||
256 | |||
257 | while (pm_dbg_reg_modules[i].name[0] != 0) { | ||
258 | regs = 0; | ||
259 | linefeed = 0; | ||
260 | if (pm_dbg_reg_modules[i].type == MOD_CM) | ||
261 | seq_printf(s, "MOD: CM_%s (%08x)\n", | ||
262 | pm_dbg_reg_modules[i].name, | ||
263 | (u32)(OMAP3430_CM_BASE + | ||
264 | pm_dbg_reg_modules[i].offset)); | ||
265 | else | ||
266 | seq_printf(s, "MOD: PRM_%s (%08x)\n", | ||
267 | pm_dbg_reg_modules[i].name, | ||
268 | (u32)(OMAP3430_PRM_BASE + | ||
269 | pm_dbg_reg_modules[i].offset)); | ||
270 | |||
271 | for (j = pm_dbg_reg_modules[i].low; | ||
272 | j <= pm_dbg_reg_modules[i].high; j += 4) { | ||
273 | val = *(ptr++); | ||
274 | if (val != 0) { | ||
275 | regs++; | ||
276 | if (linefeed) { | ||
277 | seq_printf(s, "\n"); | ||
278 | linefeed = 0; | ||
279 | } | ||
280 | seq_printf(s, " %02x => %08lx", j, val); | ||
281 | if (regs % 4 == 0) | ||
282 | linefeed = 1; | ||
283 | } | ||
284 | } | ||
285 | seq_printf(s, "\n"); | ||
286 | i++; | ||
287 | } | ||
288 | |||
289 | if (store != NULL) | ||
290 | kfree(store); | ||
291 | |||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | static void pm_dbg_regset_store(u32 *ptr) | ||
296 | { | ||
297 | int i, j; | ||
298 | u32 val; | ||
299 | |||
300 | i = 0; | ||
301 | |||
302 | while (pm_dbg_reg_modules[i].name[0] != 0) { | ||
303 | for (j = pm_dbg_reg_modules[i].low; | ||
304 | j <= pm_dbg_reg_modules[i].high; j += 4) { | ||
305 | if (pm_dbg_reg_modules[i].type == MOD_CM) | ||
306 | val = cm_read_mod_reg( | ||
307 | pm_dbg_reg_modules[i].offset, j); | ||
308 | else | ||
309 | val = prm_read_mod_reg( | ||
310 | pm_dbg_reg_modules[i].offset, j); | ||
311 | *(ptr++) = val; | ||
312 | } | ||
313 | i++; | ||
314 | } | ||
315 | } | ||
316 | |||
317 | int pm_dbg_regset_save(int reg_set) | ||
318 | { | ||
319 | if (pm_dbg_reg_set[reg_set-1] == NULL) | ||
320 | return -EINVAL; | ||
321 | |||
322 | pm_dbg_regset_store(pm_dbg_reg_set[reg_set-1]); | ||
323 | |||
324 | return 0; | ||
325 | } | ||
326 | |||
169 | static const char pwrdm_state_names[][4] = { | 327 | static const char pwrdm_state_names[][4] = { |
170 | "OFF", | 328 | "OFF", |
171 | "RET", | 329 | "RET", |
@@ -280,6 +438,11 @@ static int pm_dbg_open(struct inode *inode, struct file *file) | |||
280 | }; | 438 | }; |
281 | } | 439 | } |
282 | 440 | ||
441 | static int pm_dbg_reg_open(struct inode *inode, struct file *file) | ||
442 | { | ||
443 | return single_open(file, pm_dbg_show_regs, inode->i_private); | ||
444 | } | ||
445 | |||
283 | static const struct file_operations debug_fops = { | 446 | static const struct file_operations debug_fops = { |
284 | .open = pm_dbg_open, | 447 | .open = pm_dbg_open, |
285 | .read = seq_read, | 448 | .read = seq_read, |
@@ -287,6 +450,40 @@ static const struct file_operations debug_fops = { | |||
287 | .release = single_release, | 450 | .release = single_release, |
288 | }; | 451 | }; |
289 | 452 | ||
453 | static const struct file_operations debug_reg_fops = { | ||
454 | .open = pm_dbg_reg_open, | ||
455 | .read = seq_read, | ||
456 | .llseek = seq_lseek, | ||
457 | .release = single_release, | ||
458 | }; | ||
459 | |||
460 | int pm_dbg_regset_init(int reg_set) | ||
461 | { | ||
462 | char name[2]; | ||
463 | |||
464 | if (!pm_dbg_init_done) | ||
465 | pm_dbg_init(); | ||
466 | |||
467 | if (reg_set < 1 || reg_set > PM_DBG_MAX_REG_SETS || | ||
468 | pm_dbg_reg_set[reg_set-1] != NULL) | ||
469 | return -EINVAL; | ||
470 | |||
471 | pm_dbg_reg_set[reg_set-1] = | ||
472 | kmalloc(pm_dbg_get_regset_size(), GFP_KERNEL); | ||
473 | |||
474 | if (pm_dbg_reg_set[reg_set-1] == NULL) | ||
475 | return -ENOMEM; | ||
476 | |||
477 | if (pm_dbg_dir != NULL) { | ||
478 | sprintf(name, "%d", reg_set); | ||
479 | |||
480 | (void) debugfs_create_file(name, S_IRUGO, | ||
481 | pm_dbg_dir, (void *)reg_set, &debug_reg_fops); | ||
482 | } | ||
483 | |||
484 | return 0; | ||
485 | } | ||
486 | |||
290 | static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused) | 487 | static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused) |
291 | { | 488 | { |
292 | int i; | 489 | int i; |
@@ -304,8 +501,20 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused) | |||
304 | 501 | ||
305 | static int __init pm_dbg_init(void) | 502 | static int __init pm_dbg_init(void) |
306 | { | 503 | { |
504 | int i; | ||
307 | struct dentry *d; | 505 | struct dentry *d; |
506 | char name[2]; | ||
308 | 507 | ||
508 | if (pm_dbg_init_done) | ||
509 | return 0; | ||
510 | |||
511 | if (cpu_is_omap34xx()) | ||
512 | pm_dbg_reg_modules = omap3_pm_reg_modules; | ||
513 | else { | ||
514 | printk(KERN_ERR "%s: only OMAP3 supported\n", __func__); | ||
515 | return -ENODEV; | ||
516 | } | ||
517 | |||
309 | d = debugfs_create_dir("pm_debug", NULL); | 518 | d = debugfs_create_dir("pm_debug", NULL); |
310 | if (IS_ERR(d)) | 519 | if (IS_ERR(d)) |
311 | return PTR_ERR(d); | 520 | return PTR_ERR(d); |
@@ -317,11 +526,26 @@ static int __init pm_dbg_init(void) | |||
317 | 526 | ||
318 | pwrdm_for_each(pwrdms_setup, NULL); | 527 | pwrdm_for_each(pwrdms_setup, NULL); |
319 | 528 | ||
529 | pm_dbg_dir = debugfs_create_dir("registers", d); | ||
530 | if (IS_ERR(pm_dbg_dir)) | ||
531 | return PTR_ERR(pm_dbg_dir); | ||
532 | |||
533 | (void) debugfs_create_file("current", S_IRUGO, | ||
534 | pm_dbg_dir, (void *)0, &debug_reg_fops); | ||
535 | |||
536 | for (i = 0; i < PM_DBG_MAX_REG_SETS; i++) | ||
537 | if (pm_dbg_reg_set[i] != NULL) { | ||
538 | sprintf(name, "%d", i+1); | ||
539 | (void) debugfs_create_file(name, S_IRUGO, | ||
540 | pm_dbg_dir, (void *)(i+1), &debug_reg_fops); | ||
541 | |||
542 | } | ||
543 | |||
320 | pm_dbg_init_done = 1; | 544 | pm_dbg_init_done = 1; |
321 | 545 | ||
322 | return 0; | 546 | return 0; |
323 | } | 547 | } |
324 | late_initcall(pm_dbg_init); | 548 | arch_initcall(pm_dbg_init); |
325 | 549 | ||
326 | #else | 550 | #else |
327 | void pm_dbg_update_time(struct powerdomain *pwrdm, int prev) {} | 551 | void pm_dbg_update_time(struct powerdomain *pwrdm, int prev) {} |
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 4589db1c8af8..8fa856770188 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h | |||
@@ -17,10 +17,14 @@ | |||
17 | extern void omap2_pm_dump(int mode, int resume, unsigned int us); | 17 | extern void omap2_pm_dump(int mode, int resume, unsigned int us); |
18 | extern int omap2_pm_debug; | 18 | extern int omap2_pm_debug; |
19 | extern void pm_dbg_update_time(struct powerdomain *pwrdm, int prev); | 19 | extern void pm_dbg_update_time(struct powerdomain *pwrdm, int prev); |
20 | extern int pm_dbg_regset_save(int reg_set); | ||
21 | extern int pm_dbg_regset_init(int reg_set); | ||
20 | #else | 22 | #else |
21 | #define omap2_pm_dump(mode, resume, us) do {} while (0); | 23 | #define omap2_pm_dump(mode, resume, us) do {} while (0); |
22 | #define omap2_pm_debug 0 | 24 | #define omap2_pm_debug 0 |
23 | #define pm_dbg_update_time(pwrdm, prev) do {} while (0); | 25 | #define pm_dbg_update_time(pwrdm, prev) do {} while (0); |
26 | #define pm_dbg_regset_save(reg_set) do {} while (0); | ||
27 | #define pm_dbg_regset_init(reg_set) do {} while (0); | ||
24 | #endif /* CONFIG_PM_DEBUG */ | 28 | #endif /* CONFIG_PM_DEBUG */ |
25 | 29 | ||
26 | extern void omap24xx_idle_loop_suspend(void); | 30 | extern void omap24xx_idle_loop_suspend(void); |