diff options
Diffstat (limited to 'arch/arm/mach-omap2/pm-debug.c')
| -rw-r--r-- | arch/arm/mach-omap2/pm-debug.c | 362 |
1 files changed, 246 insertions, 116 deletions
diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 6cc375a275b..0b339861d75 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -20,133 +20,263 @@ */ #include <linux/kernel.h> -#include <linux/timer.h> +#include <linux/sched.h> #include <linux/clk.h> #include <linux/err.h> #include <linux/io.h> +#include <linux/module.h> +#include <linux/slab.h> -#include <mach/clock.h> -#include <mach/board.h> +#include "clock.h" +#include "powerdomain.h" +#include "clockdomain.h" +#include "omap-pm.h" -#include "prm.h" -#include "cm.h" +#include "soc.h" +#include "cm2xxx_3xxx.h" +#include "prm2xxx_3xxx.h" #include "pm.h" -int omap2_pm_debug; - -#define DUMP_PRM_MOD_REG(mod, reg) \ - regs[reg_count].name = #mod "." #reg; \ - regs[reg_count++].val = prm_read_mod_reg(mod, reg) -#define DUMP_CM_MOD_REG(mod, reg) \ - regs[reg_count].name = #mod "." #reg; \ - regs[reg_count++].val = cm_read_mod_reg(mod, reg) -#define DUMP_PRM_REG(reg) \ - regs[reg_count].name = #reg; \ - regs[reg_count++].val = __raw_readl(reg) -#define DUMP_CM_REG(reg) \ - regs[reg_count].name = #reg; \ - regs[reg_count++].val = __raw_readl(reg) -#define DUMP_INTC_REG(reg, off) \ - regs[reg_count].name = #reg; \ - regs[reg_count++].val = __raw_readl(IO_ADDRESS(0x480fe000 + (off))) - -void omap2_pm_dump(int mode, int resume, unsigned int us) +u32 enable_off_mode; + +#ifdef CONFIG_DEBUG_FS +#include <linux/debugfs.h> +#include <linux/seq_file.h> + +static int pm_dbg_init_done; + +static int pm_dbg_init(void); + +enum { + DEBUG_FILE_COUNTERS = 0, + DEBUG_FILE_TIMERS, +}; + +static const char pwrdm_state_names[][PWRDM_MAX_PWRSTS] = { + "OFF", + "RET", + "INA", + "ON" +}; + +void pm_dbg_update_time(struct powerdomain *pwrdm, int prev) { - struct reg { - const char *name; - u32 val; - } regs[32]; - int reg_count = 0, i; - const char *s1 = NULL, *s2 = NULL; - - if (!resume) { -#if 0 - /* MPU */ - DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRM_IRQENABLE_MPU_OFFSET); - DUMP_CM_MOD_REG(MPU_MOD, CM_CLKSTCTRL); - DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTCTRL); - DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTST); - DUMP_PRM_MOD_REG(MPU_MOD, PM_WKDEP); -#endif -#if 0 - /* INTC */ - DUMP_INTC_REG(INTC_MIR0, 0x0084); - DUMP_INTC_REG(INTC_MIR1, 0x00a4); - DUMP_INTC_REG(INTC_MIR2, 0x00c4); -#endif -#if 0 - DUMP_CM_MOD_REG(CORE_MOD, CM_FCLKEN1); - if (cpu_is_omap24xx()) { - DUMP_CM_MOD_REG(CORE_MOD, OMAP24XX_CM_FCLKEN2); - DUMP_PRM_MOD_REG(OMAP24XX_GR_MOD, - OMAP2_PRCM_CLKEMUL_CTRL_OFFSET); - DUMP_PRM_MOD_REG(OMAP24XX_GR_MOD, - OMAP2_PRCM_CLKSRC_CTRL_OFFSET); - } - DUMP_CM_MOD_REG(WKUP_MOD, CM_FCLKEN); - DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN1); - DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN2); - DUMP_CM_MOD_REG(WKUP_MOD, CM_ICLKEN); - DUMP_CM_MOD_REG(PLL_MOD, CM_CLKEN); - DUMP_CM_MOD_REG(PLL_MOD, CM_AUTOIDLE); - DUMP_PRM_MOD_REG(CORE_MOD, PM_PWSTST); -#endif -#if 0 - /* DSP */ - if (cpu_is_omap24xx()) { - DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_FCLKEN); - DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_ICLKEN); - DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_IDLEST); - DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_AUTOIDLE); - DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSEL); - DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSTCTRL); - DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTCTRL); - DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTST); - DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTCTRL); - DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTST); - } -#endif - } else { - DUMP_PRM_MOD_REG(CORE_MOD, PM_WKST1); - if (cpu_is_omap24xx()) - DUMP_PRM_MOD_REG(CORE_MOD, OMAP24XX_PM_WKST2); - DUMP_PRM_MOD_REG(WKUP_MOD, PM_WKST); - DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET); -#if 1 - DUMP_INTC_REG(INTC_PENDING_IRQ0, 0x0098); - DUMP_INTC_REG(INTC_PENDING_IRQ1, 0x00b8); - DUMP_INTC_REG(INTC_PENDING_IRQ2, 0x00d8); -#endif + s64 t; + + if (!pm_dbg_init_done) + return ; + + /* Update timer for previous state */ + t = sched_clock(); + + pwrdm->state_timer[prev] += t - pwrdm->timer; + + pwrdm->timer = t; +} + +static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user) +{ + struct seq_file *s = (struct seq_file *)user; + + if (strcmp(clkdm->name, "emu_clkdm") == 0 || + strcmp(clkdm->name, "wkup_clkdm") == 0 || + strncmp(clkdm->name, "dpll", 4) == 0) + return 0; + + seq_printf(s, "%s->%s (%d)\n", clkdm->name, clkdm->pwrdm.ptr->name, + clkdm->usecount); + + return 0; +} + +static int pwrdm_dbg_show_counter(struct powerdomain *pwrdm, void *user) +{ + struct seq_file *s = (struct seq_file *)user; + int i; + + if (strcmp(pwrdm->name, "emu_pwrdm") == 0 || + strcmp(pwrdm->name, "wkup_pwrdm") == 0 || + strncmp(pwrdm->name, "dpll", 4) == 0) + return 0; + + if (pwrdm->state != pwrdm_read_pwrst(pwrdm)) + printk(KERN_ERR "pwrdm state mismatch(%s) %d != %d\n", + pwrdm->name, pwrdm->state, pwrdm_read_pwrst(pwrdm)); + + seq_printf(s, "%s (%s)", pwrdm->name, + pwrdm_state_names[pwrdm->state]); + for (i = 0; i < PWRDM_MAX_PWRSTS; i++) + seq_printf(s, ",%s:%d", pwrdm_state_names[i], + pwrdm->state_counter[i]); + + seq_printf(s, ",RET-LOGIC-OFF:%d", pwrdm->ret_logic_off_counter); + for (i = 0; i < pwrdm->banks; i++) + seq_printf(s, ",RET-MEMBANK%d-OFF:%d", i + 1, + pwrdm->ret_mem_off_counter[i]); + + seq_printf(s, "\n"); + + return 0; +} + +static int pwrdm_dbg_show_timer(struct powerdomain *pwrdm, void *user) +{ + struct seq_file *s = (struct seq_file *)user; + int i; + + if (strcmp(pwrdm->name, "emu_pwrdm") == 0 || + strcmp(pwrdm->name, "wkup_pwrdm") == 0 || + strncmp(pwrdm->name, "dpll", 4) == 0) + return 0; + + pwrdm_state_switch(pwrdm); + + seq_printf(s, "%s (%s)", pwrdm->name, + pwrdm_state_names[pwrdm->state]); + + for (i = 0; i < 4; i++) + seq_printf(s, ",%s:%lld", pwrdm_state_names[i], + pwrdm->state_timer[i]); + + seq_printf(s, "\n"); + return 0; +} + +static int pm_dbg_show_counters(struct seq_file *s, void *unused) +{ + pwrdm_for_each(pwrdm_dbg_show_counter, s); + clkdm_for_each(clkdm_dbg_show_counter, s); + + return 0; +} + +static int pm_dbg_show_timers(struct seq_file *s, void *unused) +{ + pwrdm_for_each(pwrdm_dbg_show_timer, s); + return 0; +} + +static int pm_dbg_open(struct inode *inode, struct file *file) +{ + switch ((int)inode->i_private) { + case DEBUG_FILE_COUNTERS: + return single_open(file, pm_dbg_show_counters, + &inode->i_private); + case DEBUG_FILE_TIMERS: + default: + return single_open(file, pm_dbg_show_timers, + &inode->i_private); } +} + +static const struct file_operations debug_fops = { + .open = pm_dbg_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int pwrdm_suspend_get(void *data, u64 *val) +{ + int ret = -EINVAL; + + if (cpu_is_omap34xx()) + ret = omap3_pm_get_suspend_state((struct powerdomain *)data); + *val = ret; + + if (ret >= 0) + return 0; + return *val; +} + +static int pwrdm_suspend_set(void *data, u64 val) +{ + if (cpu_is_omap34xx()) + return omap3_pm_set_suspend_state( + (struct powerdomain *)data, (int)val); + return -EINVAL; +} + +DEFINE_SIMPLE_ATTRIBUTE(pwrdm_suspend_fops, pwrdm_suspend_get, + pwrdm_suspend_set, "%llu\n"); + +static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir) +{ + int i; + s64 t; + struct dentry *d; + + t = sched_clock(); + + for (i = 0; i < 4; i++) + pwrdm->state_timer[i] = 0; + + pwrdm->timer = t; + + if (strncmp(pwrdm->name, "dpll", 4) == 0) + return 0; + + d = debugfs_create_dir(pwrdm->name, (struct dentry *)dir); + if (d) + (void) debugfs_create_file("suspend", S_IRUGO|S_IWUSR, d, + (void *)pwrdm, &pwrdm_suspend_fops); - switch (mode) { - case 0: - s1 = "full"; - s2 = "retention"; - break; - case 1: - s1 = "MPU"; - s2 = "retention"; - break; - case 2: - s1 = "MPU"; - s2 = "idle"; - break; + return 0; +} + +static int option_get(void *data, u64 *val) +{ + u32 *option = data; + + *val = *option; + + return 0; +} + +static int option_set(void *data, u64 val) +{ + u32 *option = data; + + *option = val; + + if (option == &enable_off_mode) { + if (val) + omap_pm_enable_off_mode(); + else + omap_pm_disable_off_mode(); + if (cpu_is_omap34xx()) + omap3_pm_off_mode_enable(val); } - if (!resume) -#ifdef CONFIG_NO_HZ - printk(KERN_INFO - "--- Going to %s %s (next timer after %u ms)\n", s1, s2, - jiffies_to_msecs(get_next_timer_interrupt(jiffies) - - jiffies)); -#else - printk(KERN_INFO "--- Going to %s %s\n", s1, s2); -#endif - else - printk(KERN_INFO "--- Woke up (slept for %u.%03u ms)\n", - us / 1000, us % 1000); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(pm_dbg_option_fops, option_get, option_set, "%llu\n"); + +static int __init pm_dbg_init(void) +{ + struct dentry *d; + + if (pm_dbg_init_done) + return 0; + + d = debugfs_create_dir("pm_debug", NULL); + if (!d) + return -EINVAL; - for (i = 0; i < reg_count; i++) - printk(KERN_INFO "%-20s: 0x%08x\n", regs[i].name, regs[i].val); + (void) debugfs_create_file("count", S_IRUGO, + d, (void *)DEBUG_FILE_COUNTERS, &debug_fops); + (void) debugfs_create_file("time", S_IRUGO, + d, (void *)DEBUG_FILE_TIMERS, &debug_fops); + + pwrdm_for_each(pwrdms_setup, (void *)d); + + (void) debugfs_create_file("enable_off_mode", S_IRUGO | S_IWUSR, d, + &enable_off_mode, &pm_dbg_option_fops); + pm_dbg_init_done = 1; + + return 0; } +omap_arch_initcall(pm_dbg_init); + +#endif |
