#include <mach/pm.h>
#include <mach/clockdomain.h>
#include <mach/powerdomain.h>
+#include <mach/serial.h>
+#include <mach/control.h>
#include "cm.h"
#include "cm-regbits-34xx.h"
cm_write_mod_reg(fclk, OMAP3430_PER_MOD, CM_FCLKEN);
}
- if (system_rev > OMAP3430_REV_ES1_0) {
+ if (omap_rev() > OMAP3430_REV_ES1_0) {
/* USBHOST */
wkst = prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, PM_WKST);
if (wkst) {
disable_smartreflex(SR2);
omap2_gpio_prepare_for_retention();
+ omap_uart_prepare_idle(0);
+ omap_uart_prepare_idle(1);
+ omap_uart_prepare_idle(2);
_omap_sram_idle(NULL, save_state);
+ omap_uart_resume_idle(2);
+ omap_uart_resume_idle(1);
+ omap_uart_resume_idle(0);
omap2_gpio_resume_after_retention();
/* Enable smartreflex after WFI */
fck_core1 = cm_read_mod_reg(CORE_MOD,
CM_FCLKEN1);
- if (system_rev > OMAP3430_REV_ES1_0) {
+ if (omap_rev() > OMAP3430_REV_ES1_0) {
fck_core3 = cm_read_mod_reg(CORE_MOD,
OMAP3430ES2_CM_FCLKEN3);
fck_sgx = cm_read_mod_reg(OMAP3430ES2_SGX_MOD,
CM_FCLKEN);
fck_per = cm_read_mod_reg(OMAP3430_PER_MOD,
CM_FCLKEN);
+
+ /* Ignore UART clocks. These are handled by UART core (serial.c) */
+ fck_core1 &= ~(OMAP3430_EN_UART1 | OMAP3430_EN_UART2);
+ fck_per &= ~OMAP3430_EN_UART3;
+
if (fck_core1 | fck_core3 | fck_sgx | fck_dss |
fck_cam | fck_per | fck_usbhost)
return 1;
{
if (!enable_dyn_sleep)
return 0;
+ if (!omap_uart_can_sleep())
+ return 0;
if (omap3_fclks_active())
return 0;
if (atomic_read(&sleep_block) > 0)
return 1;
}
-/* _clkdm_deny_idle - private callback function used by set_pwrdm_state() */
-static int _clkdm_deny_idle(struct powerdomain *pwrdm,
- struct clockdomain *clkdm)
-{
- omap2_clkdm_deny_idle(clkdm);
- return 0;
-}
-
-/* _clkdm_allow_idle - private callback function used by set_pwrdm_state() */
-static int _clkdm_allow_idle(struct powerdomain *pwrdm,
- struct clockdomain *clkdm)
-{
- omap2_clkdm_allow_idle(clkdm);
- return 0;
-}
-
/* This sets pwrdm state (other than mpu & core. Currently only ON &
* RET are supported. Function is assuming that clkdm doesn't have
* hw_sup mode enabled. */
static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
{
u32 cur_state;
+ int sleep_switch = 0;
int ret = 0;
if (pwrdm == NULL || IS_ERR(pwrdm))
return -EINVAL;
- cur_state = pwrdm_read_next_pwrst(pwrdm);
+ while (!(pwrdm->pwrsts & (1 << state))) {
+ if (state == PWRDM_POWER_OFF)
+ return ret;
+ state--;
+ }
+ cur_state = pwrdm_read_next_pwrst(pwrdm);
if (cur_state == state)
return ret;
- pwrdm_for_each_clkdm(pwrdm, _clkdm_deny_idle);
+ if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
+ omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
+ sleep_switch = 1;
+ pwrdm_wait_transition(pwrdm);
+ }
ret = pwrdm_set_next_pwrst(pwrdm, state);
if (ret) {
goto err;
}
- pwrdm_for_each_clkdm(pwrdm, _clkdm_allow_idle);
+ if (sleep_switch) {
+ omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
+ pwrdm_wait_transition(pwrdm);
+ }
err:
return ret;
goto restore;
}
+ omap_uart_prepare_suspend();
omap_sram_idle();
restore:
list_for_each_entry(pwrst, &pwrst_list, node) {
set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
- if (state != pwrst->next_state) {
+ if (state > pwrst->next_state) {
printk(KERN_INFO "Powerdomain (%s) didn't enter "
"target state %d\n",
pwrst->pwrdm->name, pwrst->next_state);
.valid = suspend_valid_only_mem,
};
+
+/**
+ * omap3_iva_idle(): ensure IVA is in idle so it can be put into
+ * retention
+ *
+ * In cases where IVA2 is activated by bootcode, it may prevent
+ * full-chip retention or off-mode because it is not idle. This
+ * function forces the IVA2 into idle state so it can go
+ * into retention/off and thus allow full-chip retention/off.
+ *
+ **/
+static void __init omap3_iva_idle(void)
+{
+ /* ensure IVA2 clock is disabled */
+ cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
+
+ /* Reset IVA2 */
+ prm_write_mod_reg(OMAP3430_RST1_IVA2 |
+ OMAP3430_RST2_IVA2 |
+ OMAP3430_RST3_IVA2,
+ OMAP3430_IVA2_MOD, RM_RSTCTRL);
+
+ /* Enable IVA2 clock */
+ cm_write_mod_reg(OMAP3430_CM_FCLKEN_IVA2_EN_IVA2,
+ OMAP3430_IVA2_MOD, CM_FCLKEN);
+
+ /* Set IVA2 boot mode to 'idle' */
+ omap_ctrl_writel(OMAP3_IVA2_BOOTMOD_IDLE,
+ OMAP343X_CONTROL_IVA2_BOOTMOD);
+
+ /* Un-reset IVA2 */
+ prm_write_mod_reg(0, OMAP3430_IVA2_MOD, RM_RSTCTRL);
+
+ /* Disable IVA2 clock */
+ cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
+
+ /* Reset IVA2 */
+ prm_write_mod_reg(OMAP3430_RST1_IVA2 |
+ OMAP3430_RST2_IVA2 |
+ OMAP3430_RST3_IVA2,
+ OMAP3430_IVA2_MOD, RM_RSTCTRL);
+}
+
static void __init prcm_setup_regs(void)
{
+ /* reset modem */
+ prm_write_mod_reg(OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON |
+ OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST,
+ CORE_MOD, RM_RSTCTRL);
+ prm_write_mod_reg(0, CORE_MOD, RM_RSTCTRL);
+
/* XXX Reset all wkdeps. This should be done when initializing
* powerdomains */
prm_write_mod_reg(0, OMAP3430_IVA2_MOD, PM_WKDEP);
prm_write_mod_reg(0, OMAP3430_NEON_MOD, PM_WKDEP);
prm_write_mod_reg(0, OMAP3430_CAM_MOD, PM_WKDEP);
prm_write_mod_reg(0, OMAP3430_PER_MOD, PM_WKDEP);
- if (system_rev > OMAP3430_REV_ES1_0) {
+ if (omap_rev() > OMAP3430_REV_ES1_0) {
prm_write_mod_reg(0, OMAP3430ES2_SGX_MOD, PM_WKDEP);
prm_write_mod_reg(0, OMAP3430ES2_USBHOST_MOD, PM_WKDEP);
} else
OMAP3430_AUTO_DES1,
CORE_MOD, CM_AUTOIDLE2);
- if (system_rev > OMAP3430_REV_ES1_0) {
+ if (omap_rev() > OMAP3430_REV_ES1_0) {
cm_write_mod_reg(
OMAP3430ES2_AUTO_USBTLL,
CORE_MOD, CM_AUTOIDLE3);
OMAP3430_PER_MOD,
CM_AUTOIDLE);
- if (system_rev > OMAP3430_REV_ES1_0) {
+ if (omap_rev() > OMAP3430_REV_ES1_0) {
cm_write_mod_reg(
OMAP3430ES2_AUTO_USBHOST,
OMAP3430ES2_USBHOST_MOD,
* Set all plls to autoidle. This is needed until autoidle is
* enabled by clockfw
*/
- cm_write_mod_reg(1 << OMAP3430_CLKTRCTRL_IVA2_SHIFT,
- OMAP3430_IVA2_MOD,
- CM_AUTOIDLE2);
+ cm_write_mod_reg(1 << OMAP3430_AUTO_IVA2_DPLL_SHIFT,
+ OMAP3430_IVA2_MOD, CM_AUTOIDLE2);
cm_write_mod_reg(1 << OMAP3430_AUTO_MPU_DPLL_SHIFT,
MPU_MOD,
CM_AUTOIDLE2);
OMAP3_PRM_CLKSRC_CTRL_OFFSET);
/* setup wakup source */
- prm_write_mod_reg(OMAP3430_EN_IO | OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1,
+ prm_write_mod_reg(OMAP3430_EN_IO | OMAP3430_EN_GPIO1 |
+ OMAP3430_EN_GPT1 | OMAP3430_EN_GPT12,
WKUP_MOD, PM_WKEN);
/* No need to write EN_IO, that is always enabled */
- prm_write_mod_reg(OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1,
+ prm_write_mod_reg(OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1 |
+ OMAP3430_EN_GPT12,
WKUP_MOD, OMAP3430_PM_MPUGRPSEL);
/* For some reason IO doesn't generate wakeup event even if
* it is selected to mpu wakeup goup */
prm_write_mod_reg(OMAP3430_IO_EN | OMAP3430_WKUP_EN,
OCP_MOD, OMAP2_PRM_IRQENABLE_MPU_OFFSET);
+
+ omap3_iva_idle();
}
static int __init pwrdms_setup(struct powerdomain *pwrdm)
return set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
}
+static int __init clkdms_setup(struct clockdomain *clkdm)
+{
+ omap2_clkdm_allow_idle(clkdm);
+ return 0;
+}
+
int __init omap3_pm_init(void)
{
- struct power_state *pwrst;
+ struct power_state *pwrst, *tmp;
int ret;
printk(KERN_ERR "Power Management for TI OMAP3.\n");
goto err2;
}
+ (void) clkdm_for_each(clkdms_setup);
+
mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
if (mpu_pwrdm == NULL) {
printk(KERN_ERR "Failed to get mpu_pwrdm\n");
return ret;
err2:
free_irq(INT_34XX_PRCM_MPU_IRQ, NULL);
- list_for_each_entry(pwrst, &pwrst_list, node) {
+ list_for_each_entry_safe(pwrst, tmp, &pwrst_list, node) {
list_del(&pwrst->node);
kfree(pwrst);
}
OMAP3_PRM_VC_I2C_CFG_OFFSET);
/* Setup voltctrl and other setup times */
-
-#ifdef CONFIG_OMAP_SYSOFFMODE
- prm_write_mod_reg(OMAP3430_AUTO_OFF | OMAP3430_AUTO_RET |
- OMAP3430_SEL_OFF, OMAP3430_GR_MOD,
+ prm_write_mod_reg(OMAP3430_AUTO_RET, OMAP3430_GR_MOD,
OMAP3_PRM_VOLTCTRL_OFFSET);
prm_write_mod_reg(OMAP3430_CLKSETUP_DURATION, OMAP3430_GR_MOD,
OMAP3_PRM_VOLTOFFSET_OFFSET);
prm_write_mod_reg(OMAP3430_VOLTSETUP2_DURATION, OMAP3430_GR_MOD,
OMAP3_PRM_VOLTSETUP2_OFFSET);
-#else
- prm_set_mod_reg_bits(OMAP3430_AUTO_RET, OMAP3430_GR_MOD,
- OMAP3_PRM_VOLTCTRL_OFFSET);
-#endif
-
}
static int __init omap3_pm_early_init(void)