ARM: OMAP2+: Add functions to save and restore powerdomain context
authorRuss Dill <Russ.Dill@ti.com>
Wed, 16 May 2018 15:17:00 +0000 (20:47 +0530)
committerTony Lindgren <tony@atomide.com>
Fri, 18 May 2018 13:56:26 +0000 (06:56 -0700)
The powerdomain control registers are stored in the WKUP powerdomain on
AM33XX/AM43XX, which is lost on RTC-only suspend and also hibernate. This
adds context save and restore functions for those registers.
Sometimes the powerdomain state does not need to change,
perhaps we only need to change memory retention states, so make
sure the restored state is different from the current state before we wait
for a transition.

Signed-off-by: Keerthy <j-keerthy@ti.com>
Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
Signed-off-by: Russ Dill <Russ.Dill@ti.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
arch/arm/mach-omap2/powerdomain.c
arch/arm/mach-omap2/powerdomain.h
arch/arm/mach-omap2/prm33xx.c
arch/arm/mach-omap2/prm44xx.c

index 76eb6ec5f157e9753cf7bc9773801a35d55ffd27..ee693f679ae861d0285302752492e6d3a29ce564 100644 (file)
@@ -1199,3 +1199,63 @@ bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm)
 
        return 0;
 }
+
+/**
+ * pwrdm_save_context - save powerdomain registers
+ *
+ * Register state is going to be lost due to a suspend or hibernate
+ * event. Save the powerdomain registers.
+ */
+static int pwrdm_save_context(struct powerdomain *pwrdm, void *unused)
+{
+       if (arch_pwrdm && arch_pwrdm->pwrdm_save_context)
+               arch_pwrdm->pwrdm_save_context(pwrdm);
+       return 0;
+}
+
+/**
+ * pwrdm_save_context - restore powerdomain registers
+ *
+ * Restore powerdomain control registers after a suspend or resume
+ * event.
+ */
+static int pwrdm_restore_context(struct powerdomain *pwrdm, void *unused)
+{
+       if (arch_pwrdm && arch_pwrdm->pwrdm_restore_context)
+               arch_pwrdm->pwrdm_restore_context(pwrdm);
+       return 0;
+}
+
+static int pwrdm_lost_power(struct powerdomain *pwrdm, void *unused)
+{
+       int state;
+
+       /*
+        * Power has been lost across all powerdomains, increment the
+        * counter.
+        */
+
+       state = pwrdm_read_pwrst(pwrdm);
+       if (state != PWRDM_POWER_OFF) {
+               pwrdm->state_counter[state]++;
+               pwrdm->state_counter[PWRDM_POWER_OFF]++;
+       }
+       pwrdm->state = state;
+
+       return 0;
+}
+
+void pwrdms_save_context(void)
+{
+       pwrdm_for_each(pwrdm_save_context, NULL);
+}
+
+void pwrdms_restore_context(void)
+{
+       pwrdm_for_each(pwrdm_restore_context, NULL);
+}
+
+void pwrdms_lost_power(void)
+{
+       pwrdm_for_each(pwrdm_lost_power, NULL);
+}
index 28a796ce07d7302aed19ce7e5ae25fcbbdb584df..9a907fb14044ea8f05a2ca412fc890b4f0707706 100644 (file)
@@ -144,6 +144,7 @@ struct powerdomain {
        s64 timer;
        s64 state_timer[PWRDM_MAX_PWRSTS];
 #endif
+       u32 context;
 };
 
 /**
@@ -198,6 +199,8 @@ struct pwrdm_ops {
        int     (*pwrdm_set_lowpwrstchange)(struct powerdomain *pwrdm);
        int     (*pwrdm_wait_transition)(struct powerdomain *pwrdm);
        int     (*pwrdm_has_voltdm)(void);
+       void    (*pwrdm_save_context)(struct powerdomain *pwrdm);
+       void    (*pwrdm_restore_context)(struct powerdomain *pwrdm);
 };
 
 int pwrdm_register_platform_funcs(struct pwrdm_ops *custom_funcs);
@@ -273,4 +276,8 @@ extern struct powerdomain gfx_omap2_pwrdm;
 extern void pwrdm_lock(struct powerdomain *pwrdm);
 extern void pwrdm_unlock(struct powerdomain *pwrdm);
 
+extern void pwrdms_save_context(void);
+extern void pwrdms_restore_context(void);
+
+extern void pwrdms_lost_power(void);
 #endif
index ebaf80d72a109fdaabb1fbeb21da6d401119ce8d..d5141669c28dd6cfff6e93713dee669038a80ac3 100644 (file)
@@ -342,6 +342,35 @@ static void am33xx_prm_global_warm_sw_reset(void)
                                  AM33XX_PRM_RSTCTRL_OFFSET);
 }
 
+static void am33xx_pwrdm_save_context(struct powerdomain *pwrdm)
+{
+       pwrdm->context = am33xx_prm_read_reg(pwrdm->prcm_offs,
+                                               pwrdm->pwrstctrl_offs);
+       /*
+        * Do not save LOWPOWERSTATECHANGE, writing a 1 indicates a request,
+        * reading back a 1 indicates a request in progress.
+        */
+       pwrdm->context &= ~AM33XX_LOWPOWERSTATECHANGE_MASK;
+}
+
+static void am33xx_pwrdm_restore_context(struct powerdomain *pwrdm)
+{
+       int st, ctrl;
+
+       st = am33xx_prm_read_reg(pwrdm->prcm_offs,
+                                pwrdm->pwrstst_offs);
+
+       am33xx_prm_write_reg(pwrdm->context, pwrdm->prcm_offs,
+                            pwrdm->pwrstctrl_offs);
+
+       /* Make sure we only wait for a transition if there is one */
+       st &= OMAP_POWERSTATEST_MASK;
+       ctrl = OMAP_POWERSTATEST_MASK & pwrdm->context;
+
+       if (st != ctrl)
+               am33xx_pwrdm_wait_transition(pwrdm);
+}
+
 struct pwrdm_ops am33xx_pwrdm_operations = {
        .pwrdm_set_next_pwrst           = am33xx_pwrdm_set_next_pwrst,
        .pwrdm_read_next_pwrst          = am33xx_pwrdm_read_next_pwrst,
@@ -357,6 +386,8 @@ struct pwrdm_ops am33xx_pwrdm_operations = {
        .pwrdm_set_mem_retst            = am33xx_pwrdm_set_mem_retst,
        .pwrdm_wait_transition          = am33xx_pwrdm_wait_transition,
        .pwrdm_has_voltdm               = am33xx_check_vcvp,
+       .pwrdm_save_context             = am33xx_pwrdm_save_context,
+       .pwrdm_restore_context          = am33xx_pwrdm_restore_context,
 };
 
 static struct prm_ll_data am33xx_prm_ll_data = {
index acb95936dfe74c350e9cea47e2b57dcfbb7e28f9..47b657ceba8f246d490116dc3c746c0abf05244d 100644 (file)
@@ -667,6 +667,54 @@ static int omap4_check_vcvp(void)
        return 0;
 }
 
+/**
+ * omap4_pwrdm_save_context - Saves the powerdomain state
+ * @pwrdm: pointer to individual powerdomain
+ *
+ * The function saves the powerdomain state control information.
+ * This is needed in rtc+ddr modes where we lose powerdomain context.
+ */
+static void omap4_pwrdm_save_context(struct powerdomain *pwrdm)
+{
+       pwrdm->context = omap4_prminst_read_inst_reg(pwrdm->prcm_partition,
+                                                    pwrdm->prcm_offs,
+                                                    pwrdm->pwrstctrl_offs);
+
+       /*
+        * Do not save LOWPOWERSTATECHANGE, writing a 1 indicates a request,
+        * reading back a 1 indicates a request in progress.
+        */
+       pwrdm->context &= ~OMAP4430_LOWPOWERSTATECHANGE_MASK;
+}
+
+/**
+ * omap4_pwrdm_restore_context - Restores the powerdomain state
+ * @pwrdm: pointer to individual powerdomain
+ *
+ * The function restores the powerdomain state control information.
+ * This is needed in rtc+ddr modes where we lose powerdomain context.
+ */
+static void omap4_pwrdm_restore_context(struct powerdomain *pwrdm)
+{
+       int st, ctrl;
+
+       st = omap4_prminst_read_inst_reg(pwrdm->prcm_partition,
+                                        pwrdm->prcm_offs,
+                                        pwrdm->pwrstctrl_offs);
+
+       omap4_prminst_write_inst_reg(pwrdm->context,
+                                    pwrdm->prcm_partition,
+                                    pwrdm->prcm_offs,
+                                    pwrdm->pwrstctrl_offs);
+
+       /* Make sure we only wait for a transition if there is one */
+       st &= OMAP_POWERSTATEST_MASK;
+       ctrl = OMAP_POWERSTATEST_MASK & pwrdm->context;
+
+       if (st != ctrl)
+               omap4_pwrdm_wait_transition(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,
@@ -685,6 +733,8 @@ struct pwrdm_ops omap4_pwrdm_operations = {
        .pwrdm_set_mem_retst    = omap4_pwrdm_set_mem_retst,
        .pwrdm_wait_transition  = omap4_pwrdm_wait_transition,
        .pwrdm_has_voltdm       = omap4_check_vcvp,
+       .pwrdm_save_context     = omap4_pwrdm_save_context,
+       .pwrdm_restore_context  = omap4_pwrdm_restore_context,
 };
 
 static int omap44xx_prm_late_init(void);