int sc8825_enter_lowpower(void) { int status, ret = 0; unsigned long flags, time; unsigned int cpu = smp_processor_id(); #ifdef CONFIG_SPRD_PM_DEBUG __raw_writel(0xfdffbfff, SPRD_INTC0_BASE + 0xc);//intc0 __raw_writel(0x02004000, SPRD_INTC0_BASE + 0x8);//intc0 __raw_writel(0xffffffff, SPRD_INTC0_BASE + 0x100c);//intc1 #endif time = get_sys_cnt(); if (!hw_irqs_disabled()) { flags = read_cpsr(); printk("##: Error(%s): IRQ is enabled(%08lx)!\n", "wakelock_suspend", flags); } /*TODO: * we need to known clock status in modem side */ #ifdef FORCE_DISABLE_DSP status = 0; #else #ifdef CONFIG_NKERNEL status = sc8825_get_clock_status(); #else /* * TODO: get clock status in native version, force deep sleep now */ status = 0; #endif #endif if (status & DEVICE_AHB) { /*printk("###### %s, DEVICE_AHB ###\n", __func__ );*/ set_sleep_mode(SLP_MODE_ARM); arm_sleep(); } else if (status & DEVICE_APB) { /*printk("###### %s, DEVICE_APB ###\n", __func__ );*/ set_sleep_mode(SLP_MODE_MCU); mcu_sleep(); } else { /*printk("###### %s, DEEP ###\n", __func__ );*/ set_sleep_mode(SLP_MODE_DEP); gic_save_context( ); scu_save_context(); ret = deep_sleep( ); scu_restore_context(); flush_cache_all(); gic_restore_context( ); gic_cpu_enable(cpu); gic_dist_enable( ); #if 1 void notrace __update_sched_clock(void); __update_sched_clock(); #endif } time_add(get_sys_cnt() - time, ret); return ret; }
/** * omap4_enter_lowpower: OMAP4 MPUSS Low Power Entry Function * The purpose of this function is to manage low power programming * of OMAP4 MPUSS subsystem * @cpu : CPU ID * @power_state: Low power state. * * MPUSS states for the context save: * save_state = * 0 - Nothing lost and no need to save: MPUSS INACTIVE * 1 - CPUx L1 and logic lost: MPUSS CSWR * 2 - CPUx L1 and logic lost + GIC lost: MPUSS OSWR * 3 - CPUx L1 and logic lost + GIC + L2 lost: DEVICE OFF */ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) { struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu); unsigned int save_state = 0, cpu_logic_state = PWRDM_POWER_RET; unsigned int wakeup_cpu; if (omap_rev() == OMAP4430_REV_ES1_0) return -ENXIO; switch (power_state) { case PWRDM_POWER_ON: case PWRDM_POWER_INACTIVE: save_state = 0; break; case PWRDM_POWER_OFF: cpu_logic_state = PWRDM_POWER_OFF; save_state = 1; break; case PWRDM_POWER_RET: if (IS_PM44XX_ERRATUM(PM_OMAP4_CPU_OSWR_DISABLE)) save_state = 0; break; default: /* * CPUx CSWR is invalid hardware state. Also CPUx OSWR * doesn't make much scense, since logic is lost and $L1 * needs to be cleaned because of coherency. This makes * CPUx OSWR equivalent to CPUX OFF and hence not supported */ WARN_ON(1); return -ENXIO; } pwrdm_pre_transition(NULL); /* * Check MPUSS next state and save interrupt controller if needed. * In MPUSS OSWR or device OFF, interrupt controller contest is lost. */ mpuss_clear_prev_logic_pwrst(); if ((pwrdm_read_next_pwrst(mpuss_pd) == PWRDM_POWER_RET) && (pwrdm_read_logic_retst(mpuss_pd) == PWRDM_POWER_OFF)) save_state = 2; cpu_clear_prev_logic_pwrst(cpu); pwrdm_set_next_pwrst(pm_info->pwrdm, power_state); pwrdm_set_logic_retst(pm_info->pwrdm, cpu_logic_state); set_cpu_wakeup_addr(cpu, virt_to_phys(omap_pm_ops.resume)); omap_pm_ops.scu_prepare(cpu, power_state); l2x0_pwrst_prepare(cpu, save_state); /* * Call low level function with targeted low power state. */ if (save_state) cpu_suspend(save_state, omap_pm_ops.finish_suspend); else omap_pm_ops.finish_suspend(save_state); if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD) && cpu) gic_dist_enable(); /* * Restore the CPUx power state to ON otherwise CPUx * power domain can transitions to programmed low power * state while doing WFI outside the low powe code. On * secure devices, CPUx does WFI which can result in * domain transition */ wakeup_cpu = smp_processor_id(); pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON); pwrdm_post_transition(NULL); return 0; }