X-Git-Url: http://www.pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=arch%2Farm%2Fmach-omap2%2Fpm34xx.c;h=43aac5f6031983f6129064caca3cc32f774feecd;hb=0ec95b96fd77036a13398c66901e11cd301190d0;hp=457639f233aa9f2bf40c5c6844ff8cd959a1dac4;hpb=a811d91ab820a31f65ce83b9d335ec2011bda1cd;p=linux-2.6-omap-h63xx.git diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 457639f233a..43aac5f6031 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include "cm.h" #include "cm-regbits-34xx.h" @@ -109,7 +111,7 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id) 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) { @@ -171,9 +173,15 @@ static void omap_sram_idle(void) 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 */ @@ -194,7 +202,7 @@ static int omap3_fclks_active(void) 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, @@ -210,6 +218,11 @@ static int omap3_fclks_active(void) 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; @@ -220,6 +233,8 @@ static int omap3_can_sleep(void) { 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) @@ -239,8 +254,13 @@ static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state) 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; @@ -307,6 +327,7 @@ static int omap3_pm_suspend(void) goto restore; } + omap_uart_prepare_suspend(); omap_sram_idle(); restore: @@ -314,7 +335,7 @@ 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); @@ -358,8 +379,57 @@ static struct platform_suspend_ops omap_pm_ops = { .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); @@ -368,7 +438,7 @@ static void __init prcm_setup_regs(void) 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 @@ -418,7 +488,7 @@ static void __init prcm_setup_regs(void) 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); @@ -465,7 +535,7 @@ static void __init prcm_setup_regs(void) 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, @@ -476,9 +546,8 @@ static void __init prcm_setup_regs(void) * 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); @@ -501,15 +570,19 @@ static void __init prcm_setup_regs(void) 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) @@ -532,15 +605,24 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm) return set_pwrdm_state(pwrst->pwrdm, pwrst->next_state); } +/* + * Enable hw supervised mode for all clockdomains if it's + * supported. Initiate sleep transition for other clockdomains, if + * they are not used + */ static int __init clkdms_setup(struct clockdomain *clkdm) { - omap2_clkdm_allow_idle(clkdm); + if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO) + omap2_clkdm_allow_idle(clkdm); + else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP && + atomic_read(&clkdm->usecount) == 0) + omap2_clkdm_sleep(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"); @@ -583,7 +665,7 @@ err1: 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); }