diff --git a/include/power.h b/include/power.h index 42287873d43..55d10aac87e 100644 --- a/include/power.h +++ b/include/power.h @@ -162,25 +162,38 @@ extern void sys_pm_dump_debug_info(void); #ifdef CONFIG_PM_CONTROL_STATE_LOCK /** - * @brief Disable system PM state + * @brief Disable particular power state * - * Disable system Low power states like LPS or Deep Sleep states. + * @details Disabled state cannot be selected by the Zephyr power + * management policies. Application defined policy should + * use the @ref sys_pm_ctrl_is_state_enabled function to + * check if given state could is enabled and could be used. + * + * @param [in] state Power state to be disabled. */ -extern void sys_pm_ctrl_disable_state(int state); +extern void sys_pm_ctrl_disable_state(enum power_states state); /** - * @brief Enable system PM state + * @brief Enable particular power state * - * Enable system Low power states like LPS or Deep Sleep states. + * @details Enabled state can be selected by the Zephyr power + * management policies. Application defined policy should + * use the @ref sys_pm_ctrl_is_state_enabled function to + * check if given state could is enabled and could be used. + * By default all power states are enabled. + * + * @param [in] state Power state to be enabled. */ -extern void sys_pm_ctrl_enable_state(int state); +extern void sys_pm_ctrl_enable_state(enum power_states state); /** - * @brief Get enable status of a PM state + * @brief Check if particular power state is enabled * - * Get enable status of a system PM state. + * This function returns true if given power state is enabled. + * + * @param [in] state Power state. */ -extern bool sys_pm_ctrl_is_state_enabled(int state); +extern bool sys_pm_ctrl_is_state_enabled(enum power_states state); #endif /* CONFIG_PM_CONTROL_STATE_LOCK */ diff --git a/soc/arc/quark_se_c1000_ss/power.c b/soc/arc/quark_se_c1000_ss/power.c index 6e62164025a..f1fb49a17b2 100644 --- a/soc/arc/quark_se_c1000_ss/power.c +++ b/soc/arc/quark_se_c1000_ss/power.c @@ -42,12 +42,14 @@ static void _deep_sleep(enum power_states state) void sys_set_power_state(enum power_states state) { switch (state) { +#if (defined(CONFIG_SYS_POWER_LOW_POWER_STATE)) case SYS_POWER_STATE_CPU_LPS: qm_ss_power_cpu_ss1(QM_SS_POWER_CPU_SS1_TIMER_ON); break; case SYS_POWER_STATE_CPU_LPS_1: qm_ss_power_cpu_ss2(); break; +#endif #if (defined(CONFIG_SYS_POWER_DEEP_SLEEP)) case SYS_POWER_STATE_DEEP_SLEEP: qm_ss_power_soc_lpss_enable(); @@ -66,16 +68,17 @@ void sys_set_power_state(enum power_states state) void sys_power_state_post_ops(enum power_states state) { - u32_t limit; - switch (state) { +#if (defined(CONFIG_SYS_POWER_LOW_POWER_STATE)) case SYS_POWER_STATE_CPU_LPS_1: /* Expire the timer as it is disabled in SS2. */ - limit = _arc_v2_aux_reg_read(_ARC_V2_TMR0_LIMIT); + u32_t limit = _arc_v2_aux_reg_read(_ARC_V2_TMR0_LIMIT); _arc_v2_aux_reg_write(_ARC_V2_TMR0_COUNT, limit - 1); case SYS_POWER_STATE_CPU_LPS: __builtin_arc_seti(0); break; +#endif +#if (defined(CONFIG_SYS_POWER_DEEP_SLEEP)) case SYS_POWER_STATE_DEEP_SLEEP: qm_ss_power_soc_lpss_disable(); @@ -98,7 +101,7 @@ void sys_power_state_post_ops(enum power_states state) QM_IR_UNMASK_INTERRUPTS(QM_INTERRUPT_ROUTER->rtc_0_int_mask); __builtin_arc_seti(0); break; - break; +#endif default: break; } diff --git a/subsys/power/Kconfig b/subsys/power/Kconfig index f8dc846a662..230c14cff45 100644 --- a/subsys/power/Kconfig +++ b/subsys/power/Kconfig @@ -9,8 +9,8 @@ config PM_CONTROL_STATE_LOCK help Enable OS Power Management state locking capability if any application wants to temporarily disable certain - System Low Power states while doing any critical work - or needs quick response from hardware resources. + Power States while doing any critical work or needs quick + response from hardware resources. config PM_CONTROL_OS_DEBUG bool "Enable OS Power Management debug hooks" diff --git a/subsys/power/pm_ctrl.c b/subsys/power/pm_ctrl.c index 9e8f6105a98..dd5493268d8 100644 --- a/subsys/power/pm_ctrl.c +++ b/subsys/power/pm_ctrl.c @@ -15,65 +15,35 @@ #include LOG_MODULE_DECLARE(power); -struct pm_ctrl_info { - int pm_state; - atomic_t count; -}; +static atomic_t power_state_disable_count[SYS_POWER_STATE_MAX]; -static struct pm_ctrl_info pm_ctrl[] = { - {SYS_PM_LOW_POWER_STATE, ATOMIC_INIT(0)}, - {SYS_PM_DEEP_SLEEP, ATOMIC_INIT(0)}, -}; - -void sys_pm_ctrl_disable_state(int state) +void sys_pm_ctrl_disable_state(enum power_states state) { - if (state == SYS_PM_LOW_POWER_STATE) { - __ASSERT(pm_ctrl[0].count < UINT_MAX, - "Low Power state count overflowed\n"); - atomic_inc(&pm_ctrl[0].count); - } else if (state == SYS_PM_DEEP_SLEEP) { - __ASSERT(pm_ctrl[1].count < UINT_MAX, - "Deep Sleep state count overflowed\n"); - atomic_inc(&pm_ctrl[1].count); - } else { - LOG_WRN("\nInvalid PM state"); - } + atomic_val_t v; + + __ASSERT(state < SYS_POWER_STATE_MAX, "Invalid power state!"); + v = atomic_inc(&power_state_disable_count[state]); + __ASSERT(v < UINT_MAX, "Power state disable count overflowed!"); + + /* Make compiler happy when assertions are disabled. */ + (void)(v); } -void sys_pm_ctrl_enable_state(int state) +void sys_pm_ctrl_enable_state(enum power_states state) { - if (state == SYS_PM_LOW_POWER_STATE) { - __ASSERT(pm_ctrl[0].count > 0, - "Low Power state count underflowed\n"); - atomic_dec(&pm_ctrl[0].count); - } else if (state == SYS_PM_DEEP_SLEEP) { - __ASSERT(pm_ctrl[1].count > 0, - "Deep Sleep state count underflowed\n"); - atomic_dec(&pm_ctrl[1].count); - } else { - LOG_WRN("\nInvalid PM state"); - } + atomic_val_t v; + + __ASSERT(state < SYS_POWER_STATE_MAX, "Invalid power state!"); + v = atomic_dec(&power_state_disable_count[state]); + __ASSERT(v > 0, "Power state disable count underflowed!"); + + /* Make compiler happy when assertions are disabled. */ + (void)(v); } -bool sys_pm_ctrl_is_state_enabled(int state) +bool sys_pm_ctrl_is_state_enabled(enum power_states state) { - bool enabled = true; + __ASSERT(state < SYS_POWER_STATE_MAX, "Invalid power state!"); - switch (state) { - case SYS_PM_LOW_POWER_STATE: - if (pm_ctrl[0].count) { - enabled = false; - } - break; - case SYS_PM_DEEP_SLEEP: - if (pm_ctrl[1].count) { - enabled = false; - } - break; - default: - LOG_WRN("\nInvalid PM state"); - enabled = false; - } - - return enabled; + return (atomic_get(&power_state_disable_count[state]) == 0); } diff --git a/subsys/power/policy/policy_dummy.c b/subsys/power/policy/policy_dummy.c index bde542ec246..cfdc20f8cd4 100644 --- a/subsys/power/policy/policy_dummy.c +++ b/subsys/power/policy/policy_dummy.c @@ -57,13 +57,23 @@ static struct sys_pm_policy pm_policy[] = { int sys_pm_policy_next_state(s32_t ticks, enum power_states *pm_state) { static int cur_pm_idx; + int i = cur_pm_idx; - if (cur_pm_idx >= ARRAY_SIZE(pm_policy)) { - cur_pm_idx = 0; - } + do { + i = (i + 1) % ARRAY_SIZE(pm_policy); - *pm_state = pm_policy[cur_pm_idx].pm_state; - LOG_DBG("pm_state: %d, idx: %d\n", *pm_state, cur_pm_idx); +#ifdef CONFIG_PM_CONTROL_STATE_LOCK + if (!sys_pm_ctrl_is_state_enabled(pm_policy[i].pm_state)) { + continue; + } +#endif + cur_pm_state = i; + *pm_state = pm_policy[cur_pm_state].pm_state; - return pm_policy[cur_pm_idx++].sys_state; + LOG_DBG("pm_state: %d, idx: %d\n", *pm_state, i); + return pm_policy[cur_pm_state].sys_state; + } while (i != curr_pm_idx); + + LOG_DBG("No suitable power state found!"); + return SYS_PM_NOT_HANDLED; } diff --git a/subsys/power/policy/policy_residency.c b/subsys/power/policy/policy_residency.c index fec7173eebc..1a82a6ebff2 100644 --- a/subsys/power/policy/policy_residency.c +++ b/subsys/power/policy/policy_residency.c @@ -73,15 +73,20 @@ int sys_pm_policy_next_state(s32_t ticks, enum power_states *pm_state) } for (i = ARRAY_SIZE(pm_policy) - 1; i >= 0; i--) { +#ifdef CONFIG_PM_CONTROL_STATE_LOCK + if (!sys_pm_ctrl_is_state_enabled(pm_policy[i].pm_state)) { + continue; + } +#endif if ((ticks == K_FOREVER) || (ticks >= pm_policy[i].min_residency)) { - break; + *pm_state = pm_policy[i].pm_state; + LOG_DBG("ticks: %d, pm_state: %d, min_residency: %d\n", + ticks, *pm_state, pm_policy[i].min_residency); + return pm_policy[i].sys_state; } } - *pm_state = pm_policy[i].pm_state; - LOG_DBG("ticks: %d, pm_state: %d, min_residency: %d, idx: %d\n", - ticks, *pm_state, pm_policy[i].min_residency, i); - - return pm_policy[i].sys_state; + LOG_DBG("No suitable power state found!"); + return SYS_PM_NOT_HANDLED; } diff --git a/subsys/power/power.c b/subsys/power/power.c index ff2542d11c7..dc444eaad30 100644 --- a/subsys/power/power.c +++ b/subsys/power/power.c @@ -81,15 +81,6 @@ int sys_suspend(s32_t ticks) sys_state = sys_pm_policy_next_state(ticks, &pm_state); -#ifdef CONFIG_PM_CONTROL_STATE_LOCK - /* Check if PM state is locked */ - if ((sys_state != SYS_PM_NOT_HANDLED) && - !sys_pm_ctrl_is_state_enabled(sys_state)) { - LOG_DBG("PM state locked %d\n", sys_state); - return SYS_PM_NOT_HANDLED; - } -#endif - switch (sys_state) { case SYS_PM_LOW_POWER_STATE: sys_pm_notify_lps_entry(pm_state);