static inline int imx5_cpu_do_idle(void) { int ret = tzic_enable_wake(); if (likely(!ret)) cpu_do_idle(); return ret; }
static void imx5_idle(void) { /* */ if (gpc_dvfs_clk == NULL) { gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs"); if (IS_ERR(gpc_dvfs_clk)) return; } clk_enable(gpc_dvfs_clk); mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF); if (!tzic_enable_wake()) cpu_do_idle(); clk_disable(gpc_dvfs_clk); }
static int mx37_suspend_enter(suspend_state_t state) { if (tzic_enable_wake(0) != 0) return -EAGAIN; switch (state) { case PM_SUSPEND_MEM: mxc_cpu_lp_set(STOP_POWER_OFF); break; case PM_SUSPEND_STANDBY: mxc_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF); break; default: return -EINVAL; } cpu_do_idle(); return 0; }
static int mx51_suspend_enter(suspend_state_t state) { if (gpc_dvfs_clk == NULL) gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs_clk"); /* gpc clock is needed for SRPG */ clk_enable(gpc_dvfs_clk); switch (state) { case PM_SUSPEND_MEM: mxc_cpu_lp_set(STOP_POWER_OFF); break; case PM_SUSPEND_STANDBY: mxc_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF); break; default: return -EINVAL; } if (tzic_enable_wake(0) != 0) return -EAGAIN; if (state == PM_SUSPEND_MEM) { cpu_do_suspend_workaround(); /*clear the EMPGC0/1 bits */ __raw_writel(0, MXC_SRPG_EMPGC0_SRPGCR); __raw_writel(0, MXC_SRPG_EMPGC1_SRPGCR); } else { if ((mxc_cpu_is_rev(CHIP_REV_2_0)) < 0) { /* do cpu_idle_workaround */ u32 l2_iram_addr = IDLE_IRAM_BASE_ADDR; if (!iram_ready) return 0; if (l2_iram_addr > 0x1FFE8000) cpu_cortexa8_do_idle(IO_ADDRESS(l2_iram_addr)); } else { cpu_do_idle(); } } clk_disable(gpc_dvfs_clk); return 0; }
/* set cpu low power mode before WFI instruction */ void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode) { u32 plat_lpc, arm_srpgcr, ccm_clpcr; u32 empgc0 = 0; u32 empgc1 = 0; int stop_mode = 0; /* always allow platform to issue a deep sleep mode request */ plat_lpc = __raw_readl(arm_plat_base + MXC_CORTEXA8_PLAT_LPC) & ~(MXC_CORTEXA8_PLAT_LPC_DSM); ccm_clpcr = __raw_readl(MXC_CCM_CLPCR) & ~(MXC_CCM_CLPCR_LPM_MASK); arm_srpgcr = __raw_readl(MXC_SRPG_ARM_SRPGCR) & ~(MXC_SRPGCR_PCR); if (!cpu_is_mx53()) { empgc0 = __raw_readl(MXC_SRPG_EMPGC0_SRPGCR) & ~(MXC_SRPGCR_PCR); empgc1 = __raw_readl(MXC_SRPG_EMPGC1_SRPGCR) & ~(MXC_SRPGCR_PCR); } switch (mode) { case WAIT_CLOCKED: break; case WAIT_UNCLOCKED: ccm_clpcr |= (0x1 << MXC_CCM_CLPCR_LPM_OFFSET); break; case WAIT_UNCLOCKED_POWER_OFF: case STOP_POWER_OFF: plat_lpc |= MXC_CORTEXA8_PLAT_LPC_DSM | MXC_CORTEXA8_PLAT_LPC_DBG_DSM; if (mode == WAIT_UNCLOCKED_POWER_OFF) { ccm_clpcr |= (0x1 << MXC_CCM_CLPCR_LPM_OFFSET); ccm_clpcr &= ~MXC_CCM_CLPCR_VSTBY; ccm_clpcr &= ~MXC_CCM_CLPCR_SBYOS; stop_mode = 0; } else { ccm_clpcr |= (0x2 << MXC_CCM_CLPCR_LPM_OFFSET); ccm_clpcr |= (0x3 << MXC_CCM_CLPCR_STBY_COUNT_OFFSET); ccm_clpcr |= MXC_CCM_CLPCR_VSTBY; ccm_clpcr |= MXC_CCM_CLPCR_SBYOS; stop_mode = 1; } arm_srpgcr |= MXC_SRPGCR_PCR; if (stop_mode && !cpu_is_mx53()) { empgc0 |= MXC_SRPGCR_PCR; empgc1 |= MXC_SRPGCR_PCR; } if (tzic_enable_wake(1) != 0) return; break; case STOP_POWER_ON: ccm_clpcr |= (0x2 << MXC_CCM_CLPCR_LPM_OFFSET); break; default: printk(KERN_WARNING "UNKNOWN cpu power mode: %d\n", mode); return; } __raw_writel(plat_lpc, arm_plat_base + MXC_CORTEXA8_PLAT_LPC); __raw_writel(ccm_clpcr, MXC_CCM_CLPCR); if (cpu_is_mx51() || (mx53_revision() >= IMX_CHIP_REVISION_2_0) || (mx50_revision() >= IMX_CHIP_REVISION_1_1)) __raw_writel(arm_srpgcr, MXC_SRPG_ARM_SRPGCR); /* Enable NEON SRPG for all but MX50TO1.0. */ if (!(mx50_revision() == IMX_CHIP_REVISION_1_0)) __raw_writel(arm_srpgcr, MXC_SRPG_NEON_SRPGCR); if (stop_mode && !cpu_is_mx53()) { __raw_writel(empgc0, MXC_SRPG_EMPGC0_SRPGCR); __raw_writel(empgc1, MXC_SRPG_EMPGC1_SRPGCR); } }
/* set cpu low power mode before WFI instruction */ void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode) { u32 plat_lpc, arm_srpgcr, ccm_clpcr; u32 empgc0, empgc1; int stop_mode = 0; /* always allow platform to issue a deep sleep mode request */ plat_lpc = __raw_readl(MXC_CORTEXA8_PLAT_LPC) & ~(MXC_CORTEXA8_PLAT_LPC_DSM); ccm_clpcr = __raw_readl(MXC_CCM_CLPCR) & ~(MXC_CCM_CLPCR_LPM_MASK); arm_srpgcr = __raw_readl(MXC_SRPG_ARM_SRPGCR) & ~(MXC_SRPGCR_PCR); empgc0 = __raw_readl(MXC_SRPG_EMPGC0_SRPGCR) & ~(MXC_SRPGCR_PCR); empgc1 = __raw_readl(MXC_SRPG_EMPGC1_SRPGCR) & ~(MXC_SRPGCR_PCR); switch (mode) { case WAIT_CLOCKED: break; case WAIT_UNCLOCKED: ccm_clpcr |= (0x1 << MXC_CCM_CLPCR_LPM_OFFSET); break; case WAIT_UNCLOCKED_POWER_OFF: case STOP_POWER_OFF: plat_lpc |= MXC_CORTEXA8_PLAT_LPC_DSM | MXC_CORTEXA8_PLAT_LPC_DBG_DSM; if (mode == WAIT_UNCLOCKED_POWER_OFF) { ccm_clpcr |= (0x1 << MXC_CCM_CLPCR_LPM_OFFSET); ccm_clpcr &= ~MXC_CCM_CLPCR_VSTBY; stop_mode = 0; } else { ccm_clpcr |= (0x2 << MXC_CCM_CLPCR_LPM_OFFSET); ccm_clpcr |= (0x3 << MXC_CCM_CLPCR_STBY_COUNT_OFFSET); ccm_clpcr |= MXC_CCM_CLPCR_VSTBY; ccm_clpcr |= MXC_CCM_CLPCR_SBYOS; stop_mode = 1; } arm_srpgcr |= MXC_SRPGCR_PCR; if (stop_mode) { empgc0 |= MXC_SRPGCR_PCR; empgc1 |= MXC_SRPGCR_PCR; } if (tzic_enable_wake(1) != 0) return; break; case STOP_POWER_ON: ccm_clpcr |= (0x2 << MXC_CCM_CLPCR_LPM_OFFSET); break; default: printk(KERN_WARNING "UNKNOWN cpu power mode: %d\n", mode); return; } __raw_writel(plat_lpc, MXC_CORTEXA8_PLAT_LPC); __raw_writel(ccm_clpcr, MXC_CCM_CLPCR); __raw_writel(arm_srpgcr, MXC_SRPG_ARM_SRPGCR); __raw_writel(arm_srpgcr, MXC_SRPG_NEON_SRPGCR); if (stop_mode) { __raw_writel(empgc0, MXC_SRPG_EMPGC0_SRPGCR); __raw_writel(empgc1, MXC_SRPG_EMPGC1_SRPGCR); } }