Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/penberg...
[pandora-kernel.git] / arch / arm / mach-omap2 / powerdomain.c
index 562a3fe..eaed0df 100644 (file)
 #undef DEBUG
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
 #include <linux/list.h>
 #include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/io.h>
-
-#include <asm/atomic.h>
-
-#include "cm.h"
-#include "cm-regbits-34xx.h"
-#include "cm-regbits-44xx.h"
-#include "prm.h"
-#include "prm-regbits-34xx.h"
-#include "prm-regbits-44xx.h"
+#include <linux/string.h>
+#include "cm2xxx_3xxx.h"
+#include "prcm44xx.h"
+#include "cm44xx.h"
+#include "prm2xxx_3xxx.h"
+#include "prm44xx.h"
 
 #include <plat/cpu.h>
-#include <plat/powerdomain.h>
-#include <plat/clockdomain.h>
+#include "powerdomain.h"
+#include "clockdomain.h"
 #include <plat/prcm.h>
 
 #include "pm.h"
@@ -45,37 +37,6 @@ enum {
        PWRDM_STATE_PREV,
 };
 
-/* Variable holding value of the CPU dependent PWRSTCTRL Register Offset */
-static u16 pwrstctrl_reg_offs;
-
-/* Variable holding value of the CPU dependent PWRSTST Register Offset */
-static u16 pwrstst_reg_offs;
-
-/* OMAP3 and OMAP4 specific register bit initialisations
- * Notice that the names here are not according to each power
- * domain but the bit mapping used applies to all of them
- */
-
-/* OMAP3 and OMAP4 Memory Onstate Masks (common across all power domains) */
-#define OMAP_MEM0_ONSTATE_MASK OMAP3430_SHAREDL1CACHEFLATONSTATE_MASK
-#define OMAP_MEM1_ONSTATE_MASK OMAP3430_L1FLATMEMONSTATE_MASK
-#define OMAP_MEM2_ONSTATE_MASK OMAP3430_SHAREDL2CACHEFLATONSTATE_MASK
-#define OMAP_MEM3_ONSTATE_MASK OMAP3430_L2FLATMEMONSTATE_MASK
-#define OMAP_MEM4_ONSTATE_MASK OMAP4430_OCP_NRET_BANK_ONSTATE_MASK
-
-/* OMAP3 and OMAP4 Memory Retstate Masks (common across all power domains) */
-#define OMAP_MEM0_RETSTATE_MASK OMAP3430_SHAREDL1CACHEFLATRETSTATE_MASK
-#define OMAP_MEM1_RETSTATE_MASK OMAP3430_L1FLATMEMRETSTATE_MASK
-#define OMAP_MEM2_RETSTATE_MASK OMAP3430_SHAREDL2CACHEFLATRETSTATE_MASK
-#define OMAP_MEM3_RETSTATE_MASK OMAP3430_L2FLATMEMRETSTATE_MASK
-#define OMAP_MEM4_RETSTATE_MASK OMAP4430_OCP_NRET_BANK_RETSTATE_MASK
-
-/* OMAP3 and OMAP4 Memory Status bits */
-#define OMAP_MEM0_STATEST_MASK OMAP3430_SHAREDL1CACHEFLATSTATEST_MASK
-#define OMAP_MEM1_STATEST_MASK OMAP3430_L1FLATMEMSTATEST_MASK
-#define OMAP_MEM2_STATEST_MASK OMAP3430_SHAREDL2CACHEFLATSTATEST_MASK
-#define OMAP_MEM3_STATEST_MASK OMAP3430_L2FLATMEMSTATEST_MASK
-#define OMAP_MEM4_STATEST_MASK OMAP4430_OCP_NRET_BANK_STATEST_MASK
 
 /* pwrdm_list contains all registered struct powerdomains */
 static LIST_HEAD(pwrdm_list);
@@ -112,12 +73,19 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
 {
        int i;
 
-       if (!pwrdm)
+       if (!pwrdm || !pwrdm->name)
                return -EINVAL;
 
        if (!omap_chip_is(pwrdm->omap_chip))
                return -EINVAL;
 
+       if (cpu_is_omap44xx() &&
+           pwrdm->prcm_partition == OMAP4430_INVALID_PRCM_PARTITION) {
+               pr_err("powerdomain: %s: missing OMAP4 PRCM partition ID\n",
+                      pwrdm->name);
+               return -EINVAL;
+       }
+
        if (_pwrdm_lookup(pwrdm->name))
                return -EEXIST;
 
@@ -225,18 +193,6 @@ void pwrdm_init(struct powerdomain **pwrdm_list, struct pwrdm_ops *custom_funcs)
 {
        struct powerdomain **p = NULL;
 
-       if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
-               pwrstctrl_reg_offs = OMAP2_PM_PWSTCTRL;
-               pwrstst_reg_offs = OMAP2_PM_PWSTST;
-       } else if (cpu_is_omap44xx()) {
-               pwrstctrl_reg_offs = OMAP4_PM_PWSTCTRL;
-               pwrstst_reg_offs = OMAP4_PM_PWSTST;
-       } else {
-               printk(KERN_ERR "Power Domain struct not supported for " \
-                                                       "this CPU\n");
-               return;
-       }
-
        if (!custom_funcs)
                WARN(1, "powerdomain: No custom pwrdm functions registered\n");
        else
@@ -566,7 +522,7 @@ int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
  */
 int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
 {
-       u32 m;
+       int ret = -EINVAL;
 
        if (!pwrdm)
                return -EINVAL;
@@ -580,37 +536,10 @@ int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
        pr_debug("powerdomain: setting next memory powerstate for domain %s "
                 "bank %0x while pwrdm-ON to %0x\n", pwrdm->name, bank, pwrst);
 
-       /*
-        * The register bit names below may not correspond to the
-        * actual names of the bits in each powerdomain's register,
-        * but the type of value returned is the same for each
-        * powerdomain.
-        */
-       switch (bank) {
-       case 0:
-               m = OMAP_MEM0_ONSTATE_MASK;
-               break;
-       case 1:
-               m = OMAP_MEM1_ONSTATE_MASK;
-               break;
-       case 2:
-               m = OMAP_MEM2_ONSTATE_MASK;
-               break;
-       case 3:
-               m = OMAP_MEM3_ONSTATE_MASK;
-               break;
-       case 4:
-               m = OMAP_MEM4_ONSTATE_MASK;
-               break;
-       default:
-               WARN_ON(1); /* should never happen */
-               return -EEXIST;
-       }
-
-       prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)),
-                            pwrdm->prcm_offs, pwrstctrl_reg_offs);
+       if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_onst)
+               ret = arch_pwrdm->pwrdm_set_mem_onst(pwrdm, bank, pwrst);
 
-       return 0;
+       return ret;
 }
 
 /**
@@ -631,7 +560,7 @@ int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
  */
 int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
 {
-       u32 m;
+       int ret = -EINVAL;
 
        if (!pwrdm)
                return -EINVAL;
@@ -645,37 +574,10 @@ int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
        pr_debug("powerdomain: setting next memory powerstate for domain %s "
                 "bank %0x while pwrdm-RET to %0x\n", pwrdm->name, bank, pwrst);
 
-       /*
-        * The register bit names below may not correspond to the
-        * actual names of the bits in each powerdomain's register,
-        * but the type of value returned is the same for each
-        * powerdomain.
-        */
-       switch (bank) {
-       case 0:
-               m = OMAP_MEM0_RETSTATE_MASK;
-               break;
-       case 1:
-               m = OMAP_MEM1_RETSTATE_MASK;
-               break;
-       case 2:
-               m = OMAP_MEM2_RETSTATE_MASK;
-               break;
-       case 3:
-               m = OMAP_MEM3_RETSTATE_MASK;
-               break;
-       case 4:
-               m = OMAP_MEM4_RETSTATE_MASK;
-               break;
-       default:
-               WARN_ON(1); /* should never happen */
-               return -EEXIST;
-       }
-
-       prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)), pwrdm->prcm_offs,
-                            pwrstctrl_reg_offs);
+       if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_retst)
+               ret = arch_pwrdm->pwrdm_set_mem_retst(pwrdm, bank, pwrst);
 
-       return 0;
+       return ret;
 }
 
 /**
@@ -754,46 +656,21 @@ int pwrdm_read_logic_retst(struct powerdomain *pwrdm)
  */
 int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
 {
-       u32 m;
+       int ret = -EINVAL;
 
        if (!pwrdm)
-               return -EINVAL;
+               return ret;
 
        if (pwrdm->banks < (bank + 1))
-               return -EEXIST;
+               return ret;
 
        if (pwrdm->flags & PWRDM_HAS_MPU_QUIRK)
                bank = 1;
 
-       /*
-        * The register bit names below may not correspond to the
-        * actual names of the bits in each powerdomain's register,
-        * but the type of value returned is the same for each
-        * powerdomain.
-        */
-       switch (bank) {
-       case 0:
-               m = OMAP_MEM0_STATEST_MASK;
-               break;
-       case 1:
-               m = OMAP_MEM1_STATEST_MASK;
-               break;
-       case 2:
-               m = OMAP_MEM2_STATEST_MASK;
-               break;
-       case 3:
-               m = OMAP_MEM3_STATEST_MASK;
-               break;
-       case 4:
-               m = OMAP_MEM4_STATEST_MASK;
-               break;
-       default:
-               WARN_ON(1); /* should never happen */
-               return -EEXIST;
-       }
+       if (arch_pwrdm && arch_pwrdm->pwrdm_read_mem_pwrst)
+               ret = arch_pwrdm->pwrdm_read_mem_pwrst(pwrdm, bank);
 
-       return prm_read_mod_bits_shift(pwrdm->prcm_offs,
-                                        pwrstst_reg_offs, m);
+       return ret;
 }
 
 /**
@@ -809,43 +686,21 @@ int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
  */
 int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
 {
-       u32 m;
+       int ret = -EINVAL;
 
        if (!pwrdm)
-               return -EINVAL;
+               return ret;
 
        if (pwrdm->banks < (bank + 1))
-               return -EEXIST;
+               return ret;
 
        if (pwrdm->flags & PWRDM_HAS_MPU_QUIRK)
                bank = 1;
 
-       /*
-        * The register bit names below may not correspond to the
-        * actual names of the bits in each powerdomain's register,
-        * but the type of value returned is the same for each
-        * powerdomain.
-        */
-       switch (bank) {
-       case 0:
-               m = OMAP3430_LASTMEM1STATEENTERED_MASK;
-               break;
-       case 1:
-               m = OMAP3430_LASTMEM2STATEENTERED_MASK;
-               break;
-       case 2:
-               m = OMAP3430_LASTSHAREDL2CACHEFLATSTATEENTERED_MASK;
-               break;
-       case 3:
-               m = OMAP3430_LASTL2FLATMEMSTATEENTERED_MASK;
-               break;
-       default:
-               WARN_ON(1); /* should never happen */
-               return -EEXIST;
-       }
+       if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_mem_pwrst)
+               ret = arch_pwrdm->pwrdm_read_prev_mem_pwrst(pwrdm, bank);
 
-       return prm_read_mod_bits_shift(pwrdm->prcm_offs,
-                                       OMAP3430_PM_PREPWSTST, m);
+       return ret;
 }
 
 /**
@@ -860,43 +715,18 @@ int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
  */
 int pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)
 {
-       u32 m;
+       int ret = -EINVAL;
 
        if (!pwrdm)
-               return -EINVAL;
+               return ret;
 
        if (pwrdm->banks < (bank + 1))
-               return -EEXIST;
+               return ret;
 
-       /*
-        * The register bit names below may not correspond to the
-        * actual names of the bits in each powerdomain's register,
-        * but the type of value returned is the same for each
-        * powerdomain.
-        */
-       switch (bank) {
-       case 0:
-               m = OMAP_MEM0_RETSTATE_MASK;
-               break;
-       case 1:
-               m = OMAP_MEM1_RETSTATE_MASK;
-               break;
-       case 2:
-               m = OMAP_MEM2_RETSTATE_MASK;
-               break;
-       case 3:
-               m = OMAP_MEM3_RETSTATE_MASK;
-               break;
-       case 4:
-               m = OMAP_MEM4_RETSTATE_MASK;
-               break;
-       default:
-               WARN_ON(1); /* should never happen */
-               return -EEXIST;
-       }
+       if (arch_pwrdm && arch_pwrdm->pwrdm_read_mem_retst)
+               ret = arch_pwrdm->pwrdm_read_mem_retst(pwrdm, bank);
 
-       return prm_read_mod_bits_shift(pwrdm->prcm_offs,
-                                       pwrstctrl_reg_offs, m);
+       return ret;
 }
 
 /**
@@ -910,8 +740,10 @@ int pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)
  */
 int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
 {
+       int ret = -EINVAL;
+
        if (!pwrdm)
-               return -EINVAL;
+               return ret;
 
        /*
         * XXX should get the powerdomain's current state here;
@@ -921,9 +753,10 @@ int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
        pr_debug("powerdomain: clearing previous power state reg for %s\n",
                 pwrdm->name);
 
-       prm_write_mod_reg(0, pwrdm->prcm_offs, OMAP3430_PM_PREPWSTST);
+       if (arch_pwrdm && arch_pwrdm->pwrdm_clear_all_prev_pwrst)
+               ret = arch_pwrdm->pwrdm_clear_all_prev_pwrst(pwrdm);
 
-       return 0;
+       return ret;
 }
 
 /**
@@ -939,19 +772,21 @@ int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
  */
 int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm)
 {
+       int ret = -EINVAL;
+
        if (!pwrdm)
-               return -EINVAL;
+               return ret;
 
        if (!(pwrdm->flags & PWRDM_HAS_HDWR_SAR))
-               return -EINVAL;
+               return ret;
 
        pr_debug("powerdomain: %s: setting SAVEANDRESTORE bit\n",
                 pwrdm->name);
 
-       prm_rmw_mod_reg_bits(0, 1 << OMAP3430ES2_SAVEANDRESTORE_SHIFT,
-                            pwrdm->prcm_offs, pwrstctrl_reg_offs);
+       if (arch_pwrdm && arch_pwrdm->pwrdm_enable_hdwr_sar)
+               ret = arch_pwrdm->pwrdm_enable_hdwr_sar(pwrdm);
 
-       return 0;
+       return ret;
 }
 
 /**
@@ -967,19 +802,21 @@ int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm)
  */
 int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm)
 {
+       int ret = -EINVAL;
+
        if (!pwrdm)
-               return -EINVAL;
+               return ret;
 
        if (!(pwrdm->flags & PWRDM_HAS_HDWR_SAR))
-               return -EINVAL;
+               return ret;
 
        pr_debug("powerdomain: %s: clearing SAVEANDRESTORE bit\n",
                 pwrdm->name);
 
-       prm_rmw_mod_reg_bits(1 << OMAP3430ES2_SAVEANDRESTORE_SHIFT, 0,
-                            pwrdm->prcm_offs, pwrstctrl_reg_offs);
+       if (arch_pwrdm && arch_pwrdm->pwrdm_disable_hdwr_sar)
+               ret = arch_pwrdm->pwrdm_disable_hdwr_sar(pwrdm);
 
-       return 0;
+       return ret;
 }
 
 /**
@@ -1006,6 +843,8 @@ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm)
  */
 int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm)
 {
+       int ret = -EINVAL;
+
        if (!pwrdm)
                return -EINVAL;
 
@@ -1015,11 +854,10 @@ int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm)
        pr_debug("powerdomain: %s: setting LOWPOWERSTATECHANGE bit\n",
                 pwrdm->name);
 
-       prm_rmw_mod_reg_bits(OMAP4430_LOWPOWERSTATECHANGE_MASK,
-                            (1 << OMAP4430_LOWPOWERSTATECHANGE_SHIFT),
-                            pwrdm->prcm_offs, pwrstctrl_reg_offs);
+       if (arch_pwrdm && arch_pwrdm->pwrdm_set_lowpwrstchange)
+               ret = arch_pwrdm->pwrdm_set_lowpwrstchange(pwrdm);
 
-       return 0;
+       return ret;
 }
 
 /**
@@ -1034,32 +872,15 @@ int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm)
  */
 int pwrdm_wait_transition(struct powerdomain *pwrdm)
 {
-       u32 c = 0;
+       int ret = -EINVAL;
 
        if (!pwrdm)
                return -EINVAL;
 
-       /*
-        * REVISIT: pwrdm_wait_transition() may be better implemented
-        * via a callback and a periodic timer check -- how long do we expect
-        * powerdomain transitions to take?
-        */
-
-       /* XXX Is this udelay() value meaningful? */
-       while ((prm_read_mod_reg(pwrdm->prcm_offs, pwrstst_reg_offs) &
-               OMAP_INTRANSITION_MASK) &&
-              (c++ < PWRDM_TRANSITION_BAILOUT))
-                       udelay(1);
+       if (arch_pwrdm && arch_pwrdm->pwrdm_wait_transition)
+               ret = arch_pwrdm->pwrdm_wait_transition(pwrdm);
 
-       if (c > PWRDM_TRANSITION_BAILOUT) {
-               printk(KERN_ERR "powerdomain: waited too long for "
-                      "powerdomain %s to complete transition\n", pwrdm->name);
-               return -EAGAIN;
-       }
-
-       pr_debug("powerdomain: completed transition in %d loops\n", c);
-
-       return 0;
+       return ret;
 }
 
 int pwrdm_state_switch(struct powerdomain *pwrdm)
@@ -1088,3 +909,32 @@ int pwrdm_post_transition(void)
        pwrdm_for_each(_pwrdm_post_transition_cb, NULL);
        return 0;
 }
+
+/**
+ * pwrdm_get_context_loss_count - get powerdomain's context loss count
+ * @pwrdm: struct powerdomain * to wait for
+ *
+ * Context loss count is the sum of powerdomain off-mode counter, the
+ * logic off counter and the per-bank memory off counter.  Returns 0
+ * (and WARNs) upon error, otherwise, returns the context loss count.
+ */
+u32 pwrdm_get_context_loss_count(struct powerdomain *pwrdm)
+{
+       int i, count;
+
+       if (!pwrdm) {
+               WARN(1, "powerdomain: %s: pwrdm is null\n", __func__);
+               return 0;
+       }
+
+       count = pwrdm->state_counter[PWRDM_POWER_OFF];
+       count += pwrdm->ret_logic_off_counter;
+
+       for (i = 0; i < pwrdm->banks; i++)
+               count += pwrdm->ret_mem_off_counter[i];
+
+       pr_debug("powerdomain: %s: context loss count = %u\n",
+                pwrdm->name, count);
+
+       return count;
+}