Commit 3ba2a739 authored by Santosh Shilimkar's avatar Santosh Shilimkar Committed by Kevin Hilman

ARM: OMAP4: PM: Add MPUSS power domain OSWR support

This patch adds the MPUSS OSWR (Open Switch Retention) support. The MPUSS
OSWR configuration is as below.
	- CPUx L1 and logic lost, MPUSS logic lost, L2 memory is retained

OMAP4460 onwards, MPUSS power domain doesn't support OFF state any more
anymore just like CORE power domain. The deepest state supported is OSWR.
On OMAP4430 secure devices too, MPUSS off mode can't be used because of
a bug which alters Ducati and Tesla states. Hence MPUSS off mode as an
independent state isn't supported on OMAP44XX devices.

Ofcourse when MPUSS power domain transitions to OSWR along
with device off mode, it eventually hits off state since memory
contents are lost.

Hence the MPUSS off mode independent state is not attempted without
device off mode. All the necessary infrastructure code for MPUSS
off mode is in place as part of this series.
Signed-off-by: default avatarSantosh Shilimkar <santosh.shilimkar@ti.com>
Acked-by: default avatarJean Pihet <j-pihet@ti.com>
Reviewed-by: default avatarKevin Hilman <khilman@ti.com>
Tested-by: default avatarVishwanath BS <vishwanath.bs@ti.com>
Signed-off-by: default avatarKevin Hilman <khilman@ti.com>
parent 5e94c6e3
...@@ -190,6 +190,7 @@ extern int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state); ...@@ -190,6 +190,7 @@ extern int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state);
extern int omap4_finish_suspend(unsigned long cpu_state); extern int omap4_finish_suspend(unsigned long cpu_state);
extern void omap4_cpu_resume(void); extern void omap4_cpu_resume(void);
extern int omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state); extern int omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state);
extern u32 omap4_mpuss_read_prev_context_state(void);
#else #else
static inline int omap4_enter_lowpower(unsigned int cpu, static inline int omap4_enter_lowpower(unsigned int cpu,
unsigned int power_state) unsigned int power_state)
...@@ -216,6 +217,11 @@ static inline int omap4_finish_suspend(unsigned long cpu_state) ...@@ -216,6 +217,11 @@ static inline int omap4_finish_suspend(unsigned long cpu_state)
static inline void omap4_cpu_resume(void) static inline void omap4_cpu_resume(void)
{} {}
static inline u32 omap4_mpuss_read_prev_context_state(void)
{
return 0;
}
#endif #endif
#endif /* __ASSEMBLER__ */ #endif /* __ASSEMBLER__ */
#endif /* __ARCH_ARM_MACH_OMAP2PLUS_COMMON_H */ #endif /* __ARCH_ARM_MACH_OMAP2PLUS_COMMON_H */
...@@ -24,8 +24,8 @@ ...@@ -24,8 +24,8 @@
* ON ON ON * ON ON ON
* ON(Inactive) OFF ON(Inactive) * ON(Inactive) OFF ON(Inactive)
* OFF OFF CSWR * OFF OFF CSWR
* OFF OFF OSWR (*TBD) * OFF OFF OSWR
* OFF OFF OFF* (*TBD) * OFF OFF OFF(Device OFF *TBD)
* ---------------------------------------------- * ----------------------------------------------
* *
* Note: CPU0 is the master core and it is the last CPU to go down * Note: CPU0 is the master core and it is the last CPU to go down
...@@ -56,7 +56,11 @@ ...@@ -56,7 +56,11 @@
#include "common.h" #include "common.h"
#include "omap4-sar-layout.h" #include "omap4-sar-layout.h"
#include "pm.h" #include "pm.h"
#include "powerdomain.h" #include "prcm_mpu44xx.h"
#include "prminst44xx.h"
#include "prcm44xx.h"
#include "prm44xx.h"
#include "prm-regbits-44xx.h"
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
...@@ -138,6 +142,48 @@ static void scu_pwrst_prepare(unsigned int cpu_id, unsigned int cpu_state) ...@@ -138,6 +142,48 @@ static void scu_pwrst_prepare(unsigned int cpu_id, unsigned int cpu_state)
__raw_writel(scu_pwr_st, pm_info->scu_sar_addr); __raw_writel(scu_pwr_st, pm_info->scu_sar_addr);
} }
/* Helper functions for MPUSS OSWR */
static inline void mpuss_clear_prev_logic_pwrst(void)
{
u32 reg;
reg = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION,
OMAP4430_PRM_MPU_INST, OMAP4_RM_MPU_MPU_CONTEXT_OFFSET);
omap4_prminst_write_inst_reg(reg, OMAP4430_PRM_PARTITION,
OMAP4430_PRM_MPU_INST, OMAP4_RM_MPU_MPU_CONTEXT_OFFSET);
}
static inline void cpu_clear_prev_logic_pwrst(unsigned int cpu_id)
{
u32 reg;
if (cpu_id) {
reg = omap4_prcm_mpu_read_inst_reg(OMAP4430_PRCM_MPU_CPU1_INST,
OMAP4_RM_CPU1_CPU1_CONTEXT_OFFSET);
omap4_prcm_mpu_write_inst_reg(reg, OMAP4430_PRCM_MPU_CPU1_INST,
OMAP4_RM_CPU1_CPU1_CONTEXT_OFFSET);
} else {
reg = omap4_prcm_mpu_read_inst_reg(OMAP4430_PRCM_MPU_CPU0_INST,
OMAP4_RM_CPU0_CPU0_CONTEXT_OFFSET);
omap4_prcm_mpu_write_inst_reg(reg, OMAP4430_PRCM_MPU_CPU0_INST,
OMAP4_RM_CPU0_CPU0_CONTEXT_OFFSET);
}
}
/**
* omap4_mpuss_read_prev_context_state:
* Function returns the MPUSS previous context state
*/
u32 omap4_mpuss_read_prev_context_state(void)
{
u32 reg;
reg = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION,
OMAP4430_PRM_MPU_INST, OMAP4_RM_MPU_MPU_CONTEXT_OFFSET);
reg &= OMAP4430_LOSTCONTEXT_DFF_MASK;
return reg;
}
/* /*
* Store the CPU cluster state for L2X0 low power operations. * Store the CPU cluster state for L2X0 low power operations.
*/ */
...@@ -210,8 +256,18 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) ...@@ -210,8 +256,18 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
return -ENXIO; return -ENXIO;
} }
/*
* Check MPUSS next state and save interrupt controller if needed.
* In MPUSS OSWR or device OFF, interrupt controller contest is lost.
*/
mpuss_clear_prev_logic_pwrst();
pwrdm_clear_all_prev_pwrst(mpuss_pd); pwrdm_clear_all_prev_pwrst(mpuss_pd);
if ((pwrdm_read_next_pwrst(mpuss_pd) == PWRDM_POWER_RET) &&
(pwrdm_read_logic_retst(mpuss_pd) == PWRDM_POWER_OFF))
save_state = 2;
clear_cpu_prev_pwrst(cpu); clear_cpu_prev_pwrst(cpu);
cpu_clear_prev_logic_pwrst(cpu);
set_cpu_next_pwrst(cpu, power_state); set_cpu_next_pwrst(cpu, power_state);
set_cpu_wakeup_addr(cpu, virt_to_phys(omap4_cpu_resume)); set_cpu_wakeup_addr(cpu, virt_to_phys(omap4_cpu_resume));
scu_pwrst_prepare(cpu, power_state); scu_pwrst_prepare(cpu, power_state);
...@@ -294,6 +350,7 @@ int __init omap4_mpuss_init(void) ...@@ -294,6 +350,7 @@ int __init omap4_mpuss_init(void)
/* Clear CPU previous power domain state */ /* Clear CPU previous power domain state */
pwrdm_clear_all_prev_pwrst(pm_info->pwrdm); pwrdm_clear_all_prev_pwrst(pm_info->pwrdm);
cpu_clear_prev_logic_pwrst(0);
/* Initialise CPU0 power domain state to ON */ /* Initialise CPU0 power domain state to ON */
pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON); pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
...@@ -310,6 +367,7 @@ int __init omap4_mpuss_init(void) ...@@ -310,6 +367,7 @@ int __init omap4_mpuss_init(void)
/* Clear CPU previous power domain state */ /* Clear CPU previous power domain state */
pwrdm_clear_all_prev_pwrst(pm_info->pwrdm); pwrdm_clear_all_prev_pwrst(pm_info->pwrdm);
cpu_clear_prev_logic_pwrst(1);
/* Initialise CPU1 power domain state to ON */ /* Initialise CPU1 power domain state to ON */
pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON); pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
...@@ -320,6 +378,7 @@ int __init omap4_mpuss_init(void) ...@@ -320,6 +378,7 @@ int __init omap4_mpuss_init(void)
return -ENODEV; return -ENODEV;
} }
pwrdm_clear_all_prev_pwrst(mpuss_pd); pwrdm_clear_all_prev_pwrst(mpuss_pd);
mpuss_clear_prev_logic_pwrst();
/* Save device type on scratchpad for low level code to use */ /* Save device type on scratchpad for low level code to use */
if (omap_type() != OMAP2_DEVICE_TYPE_GP) if (omap_type() != OMAP2_DEVICE_TYPE_GP)
......
...@@ -27,6 +27,7 @@ struct power_state { ...@@ -27,6 +27,7 @@ struct power_state {
u32 next_state; u32 next_state;
#ifdef CONFIG_SUSPEND #ifdef CONFIG_SUSPEND
u32 saved_state; u32 saved_state;
u32 saved_logic_state;
#endif #endif
struct list_head node; struct list_head node;
}; };
...@@ -43,11 +44,13 @@ static int omap4_pm_suspend(void) ...@@ -43,11 +44,13 @@ static int omap4_pm_suspend(void)
/* Save current powerdomain state */ /* Save current powerdomain state */
list_for_each_entry(pwrst, &pwrst_list, node) { list_for_each_entry(pwrst, &pwrst_list, node) {
pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm); pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
pwrst->saved_logic_state = pwrdm_read_logic_retst(pwrst->pwrdm);
} }
/* Set targeted power domain states by suspend */ /* Set targeted power domain states by suspend */
list_for_each_entry(pwrst, &pwrst_list, node) { list_for_each_entry(pwrst, &pwrst_list, node) {
omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state); omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
pwrdm_set_logic_retst(pwrst->pwrdm, PWRDM_POWER_OFF);
} }
/* /*
...@@ -71,6 +74,7 @@ static int omap4_pm_suspend(void) ...@@ -71,6 +74,7 @@ static int omap4_pm_suspend(void)
ret = -1; ret = -1;
} }
omap_set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state); omap_set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
pwrdm_set_logic_retst(pwrst->pwrdm, pwrst->saved_logic_state);
} }
if (ret) if (ret)
pr_crit("Could not enter target state in pm_suspend\n"); pr_crit("Could not enter target state in pm_suspend\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment