static int ux500_suspend_enter(suspend_state_t state) { if (ux500_suspend_enabled()) { if (ux500_suspend_deepsleep_enabled() && state == PM_SUSPEND_MEM) return suspend(true); if (ux500_suspend_sleep_enabled()) return suspend(false); /* For debugging, if Sleep and DeepSleep disabled, do Idle */ prcmu_set_power_state(PRCMU_AP_IDLE, true, true); } dsb(); __asm__ __volatile__("wfi\n\t" : : : "memory"); return 0; }
static inline int ux500_enter_idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { int this_cpu = smp_processor_id(); bool recouple = false; if (atomic_inc_return(&master) == num_online_cpus()) { /* With this lock, we prevent the other cpu to exit and enter * this function again and become the master */ if (!spin_trylock(&master_lock)) goto wfi; /* decouple the gic from the A9 cores */ if (prcmu_gic_decouple()) { spin_unlock(&master_lock); goto out; } /* If an error occur, we will have to recouple the gic * manually */ recouple = true; /* At this state, as the gic is decoupled, if the other * cpu is in WFI, we have the guarantee it won't be wake * up, so we can safely go to retention */ if (!prcmu_is_cpu_in_wfi(this_cpu ? 0 : 1)) goto out; /* The prcmu will be in charge of watching the interrupts * and wake up the cpus */ if (prcmu_copy_gic_settings()) goto out; /* Check in the meantime an interrupt did * not occur on the gic ... */ if (prcmu_gic_pending_irq()) goto out; /* ... and the prcmu */ if (prcmu_pending_irq()) goto out; /* Go to the retention state, the prcmu will wait for the * cpu to go WFI and this is what happens after exiting this * 'master' critical section */ if (prcmu_set_power_state(PRCMU_AP_IDLE, true, true)) goto out; /* When we switch to retention, the prcmu is in charge * of recoupling the gic automatically */ recouple = false; spin_unlock(&master_lock); } wfi: cpu_do_idle(); out: atomic_dec(&master); if (recouple) { prcmu_gic_recouple(); spin_unlock(&master_lock); } return index; }
static int suspend(bool do_deepsleep) { bool pins_force = pins_suspend_force_mux && pins_suspend_force; int ret = 0; u32 pending_irq; if (suspend_sleep_is_blocked()) { pr_info("suspend/resume: interrupted by modem.\n"); return -EBUSY; } if (has_wake_lock(WAKE_LOCK_SUSPEND)) { pr_info("suspend/resume: aborted. wakelock has been taken.\n"); return -EBUSY; } nmk_gpio_clocks_enable(); ux500_suspend_dbg_add_wake_on_uart(); nmk_gpio_wakeups_suspend(); /* configure the prcm for a sleep wakeup */ prcmu_enable_wakeups(suspend_wakeups); ux500_suspend_dbg_test_set_wakeup(); context_vape_save(); if (pins_force) { /* * Save GPIO settings before applying power save * settings */ context_gpio_save(); /* Apply GPIO power save mux settings */ context_gpio_mux_safe_switch(true); pins_suspend_force_mux(); context_gpio_mux_safe_switch(false); /* Apply GPIO power save settings */ pins_suspend_force(); } ux500_pm_gic_decouple(); /* Copy GIC interrupt settings to PRCMU interrupt settings */ ux500_pm_prcmu_copy_gic_settings(); if (ux500_pm_gic_pending_interrupt()) { pr_info("suspend/resume: pending interrupt gic\n"); /* Recouple GIC with the interrupt bus */ ux500_pm_gic_recouple(); ret = -EBUSY; goto exit; } if (ux500_pm_prcmu_pending_interrupt(&pending_irq)) { pr_info("suspend/resume: pending interrupt prcmu: %u\n", pending_irq); /* Recouple GIC with the interrupt bus */ ux500_pm_gic_recouple(); ret = -EBUSY; goto exit; } ux500_pm_prcmu_set_ioforce(true); if (do_deepsleep) { context_varm_save_common(); context_varm_save_core(); context_gic_dist_disable_unneeded_irqs(); context_save_cpu_registers(); /* * Due to we have only 100us between requesting a powerstate * and wfi, we clean the cache before as well to assure the * final cache clean before wfi has as little as possible to * do. */ context_clean_l1_cache_all(); (void) prcmu_set_power_state(PRCMU_AP_DEEP_SLEEP, false, false); context_save_to_sram_and_wfi(true); context_restore_cpu_registers(); context_varm_restore_core(); context_varm_restore_common(); } else { context_clean_l1_cache_all(); (void) prcmu_set_power_state(PRCMU_AP_SLEEP, false, false); dsb(); __asm__ __volatile__("wfi\n\t" : : : "memory"); } context_vape_restore(); /* If GPIO woke us up then save the pins that caused the wake up */ ux500_pm_gpio_save_wake_up_status(); ux500_suspend_dbg_sleep_status(do_deepsleep); /* APE was turned off, restore IO ring */ ux500_pm_prcmu_set_ioforce(false); exit: if (pins_force) { /* Restore gpio settings */ context_gpio_mux_safe_switch(true); context_gpio_restore_mux(); context_gpio_mux_safe_switch(false); context_gpio_restore(); } /* Configure the prcmu with the wake-ups that cpuidle needs */ prcmu_enable_wakeups(running_wakeups); nmk_gpio_wakeups_resume(); ux500_suspend_dbg_remove_wake_on_uart(); nmk_gpio_clocks_disable(); return ret; }
static int suspend(bool do_deepsleep) { bool pins_force = pins_suspend_force_mux && pins_suspend_force; int ret = 0; if (sleep_is_blocked()) { pr_info("suspend/resume: interrupted by modem(%d) or event(%d)\n", atomic_read(&block_sleep_modem), atomic_read(&block_sleep_event)); return -EBUSY; } if (has_wake_lock(WAKE_LOCK_SUSPEND)) { pr_info("suspend/resume: wakelock has been locked!\n"); return -EBUSY; } nmk_gpio_clocks_enable(); ux500_suspend_dbg_add_wake_on_uart(); nmk_gpio_wakeups_suspend(); /* configure the prcm for a sleep wakeup */ prcmu_enable_wakeups(PRCMU_WAKEUP(ABB) | PRCMU_WAKEUP(RTC)); ux500_rtcrtt_next_seconds(alarm_sec); context_vape_save(); if (pins_force) { /* * Save GPIO settings before applying power save * settings */ context_gpio_save(); /* Apply GPIO power save mux settings */ context_gpio_mux_safe_switch(true); pins_suspend_force_mux(); context_gpio_mux_safe_switch(false); /* Apply GPIO power save settings */ pins_suspend_force(); } ux500_pm_gic_decouple(); if (ux500_pm_gic_pending_interrupt()) { pr_info("suspend/resume: pending interrupt\n"); /* Recouple GIC with the interrupt bus */ ux500_pm_gic_recouple(); ret = -EBUSY; goto exit; } ux500_pm_prcmu_set_ioforce(true); if (do_deepsleep) { context_varm_save_common(); context_varm_save_core(); context_gic_dist_disable_unneeded_irqs(); context_save_cpu_registers(); /* * Due to we have only 100us between requesting a powerstate * and wfi, we clean the cache before as well to assure the * final cache clean before wfi has as little as possible to * do. */ context_clean_l1_cache_all(); (void) prcmu_set_power_state(PRCMU_AP_DEEP_SLEEP, false, false); context_save_to_sram_and_wfi(true); context_restore_cpu_registers(); context_varm_restore_core(); context_varm_restore_common(); } else { context_clean_l1_cache_all(); (void) prcmu_set_power_state(APEXECUTE_TO_APSLEEP, false, false); dsb(); __asm__ __volatile__("wfi\n\t" : : : "memory"); } context_vape_restore(); /* If GPIO woke us up then save the pins that caused the wake up */ ux500_pm_gpio_save_wake_up_status(); ux500_suspend_dbg_sleep_status(do_deepsleep); /* APE was turned off, restore IO ring */ ux500_pm_prcmu_set_ioforce(false); exit: if (pins_force) { /* Restore gpio settings */ context_gpio_mux_safe_switch(true); context_gpio_restore_mux(); context_gpio_mux_safe_switch(false); context_gpio_restore(); } ux500_rtcrtt_off(); /* This is what cpuidle wants */ prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) | PRCMU_WAKEUP(ABB)); nmk_gpio_wakeups_resume(); ux500_suspend_dbg_remove_wake_on_uart(); nmk_gpio_clocks_disable(); return ret; }