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=bd74183f95ff3c4b4ad5dc14558540c20591a42b;hpb=694653afe8eb75191734cd4e6477c3182cf880b7;p=linux-2.6-omap-h63xx.git diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index bd74183f95f..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" @@ -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 */ @@ -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) @@ -312,6 +327,7 @@ static int omap3_pm_suspend(void) goto restore; } + omap_uart_prepare_suspend(); omap_sram_idle(); restore: @@ -363,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); @@ -505,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) @@ -536,9 +605,18 @@ 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; }