- These changes make OMAP power state register fields available as attributes per field in debugfs decoded as text with the hex value - pwrdm_read_reg_field() might replace a lot of the explicit functions for reading register fields and clean up the existing OMAP code a bit. - the changes are usable via debugfs standalone or with the patch coming for powerdebug - I've only implemented the support for the MPU PD - to support additional the other powerdomains all that's needed is to add the register_def_t's and field_def_t's
here's a screenshot: ./powerdebug -P -d failed to initialize sensors
Power Domain Information: *******************
mpu_pwrdm context lostcontext_dff 0:false lostmem_l1 0:false lostmem_l2 0:false lostmem_ram 0:false rstst emulation_rst 0:false pwrstctl powerstate 3:on-active logicretstate 1:whole lowpowerstatechange 0:false l1_retstate 1:retention l2_retstate 1:retention ram_retstate 1:retention l1_onstate 3:on-active l2_onstate 3:on-active ram_onstate 3:on-active pwrst powerstatest 3:on-active logicstatest 1:on l1_statest 3:on-active l2_statest 3:on-active ram_statest 3:on-active intransition 0:false lastpowerstateentered 3:on-active
and the patch against Linaro 12.04 kernel is:
From 4b762379805848eebd3454d6bb344a50012069d4 Mon Sep 17 00:00:00 2001
From: Eric van Tassell <evt@evtM17x.(none)> Date: Sat, 5 May 2012 15:05:48 -0500 Subject: [PATCH] + basic infrastructure for creating powerdomain attribute files in debugfs + definitions to create the attributes for mpu power domain
--- arch/arm/mach-omap2/pm-debug.c | 4 ++ arch/arm/mach-omap2/pm44xx.c | 3 +- arch/arm/mach-omap2/powerdomain.c | 89 +++++++++++++++++++++++++++ arch/arm/mach-omap2/powerdomain.h | 46 +++++++++++++- arch/arm/mach-omap2/powerdomain44xx.c | 23 +++++++ arch/arm/mach-omap2/powerdomains44xx_data.c | 85 +++++++++++++++++++++++++ arch/arm/mach-omap2/prm44xx.h | 1 + 8 files changed, 254 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 4411163..2e365e3 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -224,6 +224,10 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir) (void) debugfs_create_file("suspend", S_IRUGO|S_IWUSR, d, (void *)pwrdm, &pwrdm_suspend_fops);
+#ifdef CONFIG_PM_DEBUG + if (d) + pwrdm_create_register_dirs(pwrdm, d); +#endif // CONFIG_PM_DEBUG return 0; }
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c index 4ab9b9d..f5c189e 100644 --- a/arch/arm/mach-omap2/pm44xx.c +++ b/arch/arm/mach-omap2/pm44xx.c @@ -155,7 +155,7 @@ static int __init clkdms_setup(struct clockdomain *clkdm, void *unused) }
-static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused) +static int __init pwrdms_setup(struct powerdomain *pwrdm, void *arg) { struct power_state *pwrst;
@@ -365,6 +365,7 @@ static int __init omap4_pm_init(void) OMAP44XX_IRQ_PRCM); goto err2; } + ret = pwrdm_for_each(pwrdms_setup, NULL); if (ret) { pr_err("Failed to setup powerdomains\n"); diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 8a18d1b..b392760 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -37,6 +37,11 @@
#define PWRDM_TRACE_STATES_FLAG (1<<31)
+#ifdef CONFIG_PM_DEBUG +#include "prm-regbits-44xx.h" +#include <linux/debugfs.h> +#endif // CONFIG_PM_DEBUG + enum { PWRDM_STATE_NOW = 0, PWRDM_STATE_PREV, @@ -201,6 +206,90 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
/* Public functions */
+#ifdef CONFIG_PM_DEBUG +///////////////////////////////////////////////////////////////////////////// +int pwrdm_read_reg_field(field_def_t *f) +{ + int ret = -EINVAL; + + + if (!f ) + return -EINVAL; + + if (!(f->reg)) + return -EINVAL; + + if (!f->reg->pwrdm) + return -EINVAL; + + if (arch_pwrdm && arch_pwrdm->pwrdm_read_reg_field) + ret = arch_pwrdm->pwrdm_read_reg_field(f); + return ret; +} + +#define BUFMAX 4096 +static char scratch[BUFMAX]; + + +static ssize_t pwrdm_dbg_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + field_def_t *f = (field_def_t *)file->private_data; + int n; + int val; + + val = pwrdm_read_reg_field(f); + memset(scratch, 0, BUFMAX); + n = sprintf(scratch, "%d:%s", val, f->decoder(val)); + return simple_read_from_buffer(buf, count, ppos, scratch, n + 1); +} + +static int pwrdm_dbg_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static const struct file_operations pwrdm_dbg_ops = { + .read = pwrdm_dbg_read, + .open = pwrdm_dbg_open, +}; +/////////////////////////////////////////////////////////////////////////////debug + +static void pwrdm_create_1register_dir(register_def_t *r, struct dentry *pd_dentry) +{ + struct dentry *reg_dentry; + int i; + + reg_dentry = debugfs_create_dir(r->name, pd_dentry); + for (i = 0; i < r->num_fields; i++) { + field_def_t *f = &(r->fields[i]); + + f->reg = r; // link field to register + + debugfs_create_file(f->name, + S_IRUGO, + reg_dentry, + (void *)&(r->fields[i]), + &pwrdm_dbg_ops); + } +} + +void pwrdm_create_register_dirs(struct powerdomain *p, struct dentry *pd_dentry) +{ + int i; + + if ((p == (struct powerdomain *)NULL) || (pd_dentry == (struct dentry *)NULL)) + return; + + for (i = 0; i < p->num_reg_defs; i++) { + p->register_defs[i]->pwrdm = p; + pwrdm_create_1register_dir(p->register_defs[i], pd_dentry); + } +} + +#endif // CONFIG_PM_DEBUG + /** * pwrdm_register_platform_funcs - register powerdomain implementation fns * @po: func pointers for arch specific implementations diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h index 0d72a8a..5eaf08c 100644 --- a/arch/arm/mach-omap2/powerdomain.h +++ b/arch/arm/mach-omap2/powerdomain.h @@ -76,6 +76,47 @@
struct clockdomain; struct powerdomain; +#ifdef CONFIG_PM_DEBUG +/* general PD decoder definitions */ + +/* field definitions for PD_MPU */ + +typedef struct { + char *name; + u32 shift; + u32 mask; + char * (*decoder)(u8); // note: decoder may be NULL + struct _register_def_t_ *reg; +} field_def_t; + +typedef struct _register_def_t_ { + u32 ix; + char *name; + field_def_t *fields; + u8 num_fields; + struct powerdomain *pwrdm; +} register_def_t; + +#define NUM_ELTS(whole, part) (sizeof(whole)/sizeof(part)) +#define NUM_FIELDS(whole) (sizeof(whole)/sizeof(field_def_t)) + +#define DECODER(name) \ + char *decode_##name(u8 ix) { \ + if (ix > sizeof(name)/sizeof(char *)) \ + return "*invalid*"; \ + else \ + return name[ix]; \ +} + +#define FIELD_ATTR(name_str, base_name, funcp) \ + { \ + .name = name_str, \ + .shift = base_name ## _SHIFT , \ + .mask = base_name ## _MASK , \ + .decoder = funcp \ + } + +#endif //CONFIG_PM_DEBUG
/** * struct powerdomain - OMAP powerdomain @@ -124,6 +165,8 @@ struct powerdomain { #ifdef CONFIG_PM_DEBUG s64 timer; s64 state_timer[PWRDM_MAX_PWRSTS]; + register_def_t **register_defs; + int num_reg_defs; #endif };
@@ -149,6 +192,7 @@ struct powerdomain { * @pwrdm_wait_transition: Wait for a pd state transition to complete */ struct pwrdm_ops { + int (*pwrdm_read_reg_field)(field_def_t *f); int (*pwrdm_set_next_pwrst)(struct powerdomain *pwrdm, u8 pwrst); int (*pwrdm_read_next_pwrst)(struct powerdomain *pwrdm); int (*pwrdm_read_pwrst)(struct powerdomain *pwrdm); @@ -173,6 +217,7 @@ int pwrdm_register_platform_funcs(struct pwrdm_ops *custom_funcs); int pwrdm_register_pwrdms(struct powerdomain **pwrdm_list); int pwrdm_complete_init(void);
+void pwrdm_create_register_dirs(struct powerdomain *p, struct dentry *pd_dentry); struct powerdomain *pwrdm_lookup(const char *name);
int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user), @@ -237,5 +282,4 @@ extern u32 omap2_pwrdm_get_mem_bank_stst_mask(u8 bank); extern struct powerdomain wkup_omap2_pwrdm; extern struct powerdomain gfx_omap2_pwrdm;
- #endif diff --git a/arch/arm/mach-omap2/powerdomain44xx.c b/arch/arm/mach-omap2/powerdomain44xx.c index a7880af..3d6d026 100644 --- a/arch/arm/mach-omap2/powerdomain44xx.c +++ b/arch/arm/mach-omap2/powerdomain44xx.c @@ -44,6 +44,28 @@ static int omap4_pwrdm_read_next_pwrst(struct powerdomain *pwrdm) return v; }
+static int omap4_pwrdm_read_reg_field(field_def_t *f) +{ + u32 v; + struct powerdomain *pwrdm; + register_def_t *reg; + + if ((reg = f->reg) == (register_def_t *)NULL) + return(0xdeadbeee); + + if ((pwrdm = reg->pwrdm) == (struct powerdomain *)NULL) + return(0xdeadbeef); + + v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, + pwrdm->prcm_offs, + reg->ix); + v &= f->mask; + v >>= f->shift; + return v; + + +} + static int omap4_pwrdm_read_pwrst(struct powerdomain *pwrdm) { u32 v; @@ -210,6 +232,7 @@ static int omap4_pwrdm_wait_transition(struct powerdomain *pwrdm) struct pwrdm_ops omap4_pwrdm_operations = { .pwrdm_set_next_pwrst = omap4_pwrdm_set_next_pwrst, .pwrdm_read_next_pwrst = omap4_pwrdm_read_next_pwrst, + .pwrdm_read_reg_field = omap4_pwrdm_read_reg_field, .pwrdm_read_pwrst = omap4_pwrdm_read_pwrst, .pwrdm_read_prev_pwrst = omap4_pwrdm_read_prev_pwrst, .pwrdm_set_lowpwrstchange = omap4_pwrdm_set_lowpwrstchange, diff --git a/arch/arm/mach-omap2/powerdomains44xx_data.c b/arch/arm/mach-omap2/powerdomains44xx_data.c index fbd4c5f..45d4a03 100644 --- a/arch/arm/mach-omap2/powerdomains44xx_data.c +++ b/arch/arm/mach-omap2/powerdomains44xx_data.c @@ -30,6 +30,83 @@ #include "prm44xx.h" #include "prcm_mpu44xx.h"
+#if CONFIG_PM_DEBUG + +char *pwrst_vals[] = {"off", "retention", "on-inactive", "on-active"}; +char *boolean_vals[] = {"false", "true"}; +char *statest_vals[] = {"off", "retention", "on-inactive", "on-active"}; +char *logicst_vals[] = {"off", "on"}; +char *logic_retst_vals[] = {"retention regigsters", "whole logic"}; + +DECODER(pwrst_vals); +DECODER(boolean_vals); +DECODER(statest_vals); +DECODER(logicst_vals); +DECODER(logic_retst_vals); + +field_def_t pwrst_fields[] = { + FIELD_ATTR("lastpowerstateentered", OMAP4430_LASTPOWERSTATEENTERED, decode_pwrst_vals), + FIELD_ATTR("intransition", OMAP4430_INTRANSITION, decode_boolean_vals), + FIELD_ATTR("ram_statest", OMAP4430_MPU_RAM_STATEST, decode_statest_vals), + FIELD_ATTR("l2_statest", OMAP4430_MPU_L2_STATEST, decode_statest_vals), + FIELD_ATTR("l1_statest", OMAP4430_MPU_L1_STATEST, decode_statest_vals), + FIELD_ATTR("logicstatest", OMAP4430_LOGICSTATEST, decode_logicst_vals), + FIELD_ATTR("powerstatest", OMAP_POWERSTATEST, decode_pwrst_vals), +}; + +field_def_t pwrstctl_fields[] = { + FIELD_ATTR("ram_onstate", OMAP4430_MPU_RAM_ONSTATE, decode_statest_vals), + FIELD_ATTR("l2_onstate", OMAP4430_MPU_L2_ONSTATE, decode_statest_vals), + FIELD_ATTR("l1_onstate", OMAP4430_MPU_L1_ONSTATE, decode_statest_vals), + FIELD_ATTR("ram_retstate", OMAP4430_MPU_RAM_RETSTATE, decode_statest_vals), + FIELD_ATTR("l2_retstate", OMAP4430_MPU_L2_RETSTATE, decode_statest_vals), + FIELD_ATTR("l1_retstate", OMAP4430_MPU_L1_RETSTATE, decode_statest_vals), + FIELD_ATTR("lowpowerstatechange", OMAP4430_LOWPOWERSTATECHANGE, decode_boolean_vals), + FIELD_ATTR("logicretstate", OMAP4430_LOGICRETSTATE, decode_logic_retst_vals), + FIELD_ATTR("powerstate", OMAP_POWERSTATE, decode_pwrst_vals), +}; + +field_def_t rstst_fields[] = { + + FIELD_ATTR("emulation_rst", OMAP4430_EMULATION_RST, decode_boolean_vals), +}; + +field_def_t ctx_fields[] = { + FIELD_ATTR("lostmem_ram", OMAP4430_LOSTMEM_MPU_RAM, decode_boolean_vals), + FIELD_ATTR("lostmem_l2", OMAP4430_LOSTMEM_MPU_L2, decode_boolean_vals), + FIELD_ATTR("lostmem_l1", OMAP4430_LOSTMEM_MPU_L1, decode_boolean_vals), + FIELD_ATTR("lostcontext_dff", OMAP4430_LOSTCONTEXT_DFF, decode_boolean_vals), +}; + + +register_def_t omap4_mpu_pwrst = {OMAP4_PM_PWSTST, + "pwrst", + pwrst_fields, + NUM_FIELDS(pwrst_fields)}; +register_def_t omap4_mpu_pwrstctl = {OMAP4_PM_PWSTCTRL, + "pwrstctl", + pwrstctl_fields, + NUM_FIELDS(pwrstctl_fields)}; +register_def_t omap4_mpu_rstst = {OMAP4_RM_RSTST, + "rstst", + rstst_fields, + NUM_FIELDS(rstst_fields)}; +register_def_t omap4_mpu_ctx = {OMAP4_RM_MPU_CONTEXT, + "context", + ctx_fields, + NUM_FIELDS(ctx_fields)}; + +register_def_t *omap4_mpu_regs[] = { + &omap4_mpu_pwrst, + &omap4_mpu_pwrstctl, + &omap4_mpu_rstst, + &omap4_mpu_ctx +}; + + +#endif // CONFIG_PM_DEBUG + + /* core_44xx_pwrdm: CORE power domain */ static struct powerdomain core_44xx_pwrdm = { .name = "core_pwrdm", @@ -218,6 +295,10 @@ static struct powerdomain mpu_443x_pwrdm = { [1] = PWRSTS_ON, /* mpu_l2 */ [2] = PWRSTS_ON, /* mpu_ram */ }, +#ifdef CONFIG_PM_DEBUG + .register_defs = omap4_mpu_regs, + .num_reg_defs = NUM_ELTS(omap4_mpu_regs,register_def_t *), +#endif };
static struct powerdomain mpu_446x_pwrdm = { @@ -236,6 +317,10 @@ static struct powerdomain mpu_446x_pwrdm = { [0] = PWRSTS_ON, /* mpu_l2 */ [1] = PWRSTS_ON, /* mpu_ram */ }, +#ifdef CONFIG_PM_DEBUG + .register_defs = omap4_mpu_regs, + .num_reg_defs = NUM_ELTS(omap4_mpu_regs,register_def_t *), +#endif };
/* ivahd_44xx_pwrdm: IVA-HD power domain */ diff --git a/arch/arm/mach-omap2/prm44xx.h b/arch/arm/mach-omap2/prm44xx.h index 3d66ccd..926257f 100644 --- a/arch/arm/mach-omap2/prm44xx.h +++ b/arch/arm/mach-omap2/prm44xx.h @@ -66,6 +66,7 @@ #define OMAP4_RM_RSTST 0x0008 #define OMAP4_PM_PWSTCTRL 0x0000 #define OMAP4_PM_PWSTST 0x0004 +#define OMAP4_RM_MPU_CONTEXT 0x0024
/* PRM */