aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/pm44xx.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/pm44xx.c')
-rw-r--r--arch/arm/mach-omap2/pm44xx.c57
1 files changed, 50 insertions, 7 deletions
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index 0dda6cf8b855..503097c72b82 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -29,6 +29,7 @@ u16 pm44xx_errata;
struct power_state {
struct powerdomain *pwrdm;
u32 next_state;
+ u32 next_logic_state;
#ifdef CONFIG_SUSPEND
u32 saved_state;
u32 saved_logic_state;
@@ -36,6 +37,8 @@ struct power_state {
struct list_head node;
};
+static u32 cpu_suspend_state = PWRDM_POWER_OFF;
+
static LIST_HEAD(pwrst_list);
#ifdef CONFIG_SUSPEND
@@ -54,7 +57,7 @@ static int omap4_pm_suspend(void)
/* Set targeted power domain states by suspend */
list_for_each_entry(pwrst, &pwrst_list, node) {
omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
- pwrdm_set_logic_retst(pwrst->pwrdm, PWRDM_POWER_OFF);
+ pwrdm_set_logic_retst(pwrst->pwrdm, pwrst->next_logic_state);
}
/*
@@ -66,7 +69,7 @@ static int omap4_pm_suspend(void)
* domain CSWR is not supported by hardware.
* More details can be found in OMAP4430 TRM section 4.3.4.2.
*/
- omap4_enter_lowpower(cpu_id, PWRDM_POWER_OFF);
+ omap4_enter_lowpower(cpu_id, cpu_suspend_state);
/* Restore next powerdomain state */
list_for_each_entry(pwrst, &pwrst_list, node) {
@@ -112,15 +115,22 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
* through hotplug path and CPU0 explicitly programmed
* further down in the code path
*/
- if (!strncmp(pwrdm->name, "cpu", 3))
+ if (!strncmp(pwrdm->name, "cpu", 3)) {
+ if (IS_PM44XX_ERRATUM(PM_OMAP4_CPU_OSWR_DISABLE))
+ cpu_suspend_state = PWRDM_POWER_RET;
return 0;
+ }
pwrst = kmalloc(sizeof(struct power_state), GFP_ATOMIC);
if (!pwrst)
return -ENOMEM;
pwrst->pwrdm = pwrdm;
- pwrst->next_state = PWRDM_POWER_RET;
+ pwrst->next_state = pwrdm_get_valid_lp_state(pwrdm, false,
+ PWRDM_POWER_RET);
+ pwrst->next_logic_state = pwrdm_get_valid_lp_state(pwrdm, true,
+ PWRDM_POWER_OFF);
+
list_add(&pwrst->node, &pwrst_list);
return omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
@@ -203,6 +213,32 @@ static inline int omap4_init_static_deps(void)
}
/**
+ * omap5_dra7_init_static_deps - Init static clkdm dependencies on OMAP5 and
+ * DRA7
+ *
+ * The dynamic dependency between MPUSS -> EMIF is broken and has
+ * not worked as expected. The hardware recommendation is to
+ * enable static dependencies for these to avoid system
+ * lock ups or random crashes.
+ */
+static inline int omap5_dra7_init_static_deps(void)
+{
+ struct clockdomain *mpuss_clkdm, *emif_clkdm;
+ int ret;
+
+ mpuss_clkdm = clkdm_lookup("mpu_clkdm");
+ emif_clkdm = clkdm_lookup("emif_clkdm");
+ if (!mpuss_clkdm || !emif_clkdm)
+ return -EINVAL;
+
+ ret = clkdm_add_wkdep(mpuss_clkdm, emif_clkdm);
+ if (ret)
+ pr_err("Failed to add MPUSS -> EMIF wakeup dependency\n");
+
+ return ret;
+}
+
+/**
* omap4_pm_init_early - Does early initialization necessary for OMAP4+ devices
*
* Initializes basic stuff for power management functionality.
@@ -212,6 +248,9 @@ int __init omap4_pm_init_early(void)
if (cpu_is_omap446x())
pm44xx_errata |= PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD;
+ if (soc_is_omap54xx() || soc_is_dra7xx())
+ pm44xx_errata |= PM_OMAP4_CPU_OSWR_DISABLE;
+
return 0;
}
@@ -239,10 +278,14 @@ int __init omap4_pm_init(void)
goto err2;
}
- if (cpu_is_omap44xx()) {
+ if (cpu_is_omap44xx())
ret = omap4_init_static_deps();
- if (ret)
- goto err2;
+ else if (soc_is_omap54xx() || soc_is_dra7xx())
+ ret = omap5_dra7_init_static_deps();
+
+ if (ret) {
+ pr_err("Failed to initialise static dependencies.\n");
+ goto err2;
}
ret = omap4_mpuss_init();