power: Eliminate SYS_PM_* power states.

The power management framework used two different abstractions
to describe power states. The SYS_PM_* given coarse information
what kind of power state (low power or deep sleep) was used,
while the SYS_POWER_STATE_* abstraction provided information
about particular power mode.

This commit removes the SYS_PM_* abstraction as the same
information is already carried in SYS_POWER_STATE_*.

Signed-off-by: Piotr Zięcik <piotr.ziecik@nordicsemi.no>
This commit is contained in:
Piotr Zięcik 2019-01-16 14:49:16 +01:00 committed by Anas Nashif
commit d02e3ebd4c
8 changed files with 151 additions and 178 deletions

View file

@ -113,21 +113,9 @@ can be done in the available time. The power management operation must halt
execution on a CPU or SOC low power state. Before entering the low power state,
the SOC interface must setup a wake event.
The power management subsystem expects the :code:`sys_suspend()` to
return one of the following values based on the power management operations
the SOC interface executed:
:code:`SYS_PM_NOT_HANDLED`
Indicates that no power management operations were performed.
:code:`SYS_PM_LOW_POWER_STATE`
Indicates that the CPU was put in a low power state.
:code:`SYS_PM_DEEP_SLEEP`
Indicates that the SOC was put in a deep sleep state.
The power management subsystem expects the :code:`sys_suspend()` to return
the power state which was used or :code:`SYS_POWER_STATE_ACTIVE` if SoC was
kept in active state.
Resume Hook function
====================
@ -184,26 +172,26 @@ The power management subsystem classifies power management schemes
into two categories based on whether the CPU loses execution context during the
power state transition.
* SYS_PM_LOW_POWER_STATE
* SYS_PM_DEEP_SLEEP
* Low Power State
* Deep Sleep State
SYS_PM_LOW_POWER_STATE
======================
Low Power State
===============
CPU does not lose execution context. Devices also do not lose power while
entering power states in this category. The wake latencies of power states
in this category are relatively low.
SYS_PM_DEEP_SLEEP
=================
Deep Sleep State
================
CPU is power gated and loses execution context. Execution will resume at
OS startup code or at a resume point determined by a bootloader that supports
deep sleep resume. Depending on the SOC's implementation of the power saving
feature, it may turn off power to most devices. RAM may be retained by some
implementations, while others may remove power from RAM saving considerable
power. Power states in this category save more power than
`SYS_PM_LOW_POWER_STATE`_ and would have higher wake latencies.
power. Power states in this category save more power than Low Power states
and would have higher wake latencies.
Device Power Management Infrastructure
**************************************
@ -451,11 +439,11 @@ the following configuration flags.
:option:`CONFIG_SYS_POWER_LOW_POWER_STATE`
The SOC interface enables this flag to use the :code:`SYS_PM_LOW_POWER_STATE` policy.
This flag enables support for the Low Power states.
:option:`CONFIG_SYS_POWER_DEEP_SLEEP`
This flag enables support for the :code:`SYS_PM_DEEP_SLEEP` policy.
This flag enables support for the Deep Sleep states.
:option:`CONFIG_DEVICE_POWER_MANAGEMENT`

View file

@ -15,13 +15,6 @@ extern "C" {
#ifdef CONFIG_SYS_POWER_MANAGEMENT
/* Constants identifying power state categories */
#define SYS_PM_ACTIVE_STATE 0 /* SOC and CPU are in active state */
#define SYS_PM_LOW_POWER_STATE 1 /* CPU low power state */
#define SYS_PM_DEEP_SLEEP 2 /* SOC low power state */
#define SYS_PM_NOT_HANDLED SYS_PM_ACTIVE_STATE
extern unsigned char sys_pm_idle_exit_notify;
@ -35,6 +28,7 @@ extern unsigned char sys_pm_idle_exit_notify;
* @brief Power Management states.
*/
enum power_states {
SYS_POWER_STATE_ACTIVE = (-1),
#ifdef CONFIG_SYS_POWER_LOW_POWER_STATE
# ifdef CONFIG_SYS_POWER_STATE_CPU_LPS_SUPPORTED
SYS_POWER_STATE_CPU_LPS,
@ -61,6 +55,64 @@ enum power_states {
SYS_POWER_STATE_MAX
};
/**
* @brief Check if particular power state is a low power state.
*
* This function returns true if given power state is a low power state.
*/
static inline bool sys_pm_is_low_power_state(enum power_states state)
{
switch (state) {
#ifdef CONFIG_SYS_POWER_LOW_POWER_STATE
# ifdef CONFIG_SYS_POWER_STATE_CPU_LPS_SUPPORTED
case SYS_POWER_STATE_CPU_LPS:
/* FALLTHROUGH */
# endif
# ifdef CONFIG_SYS_POWER_STATE_CPU_LPS_1_SUPPORTED
case SYS_POWER_STATE_CPU_LPS_1:
/* FALLTHROUGH */
# endif
# ifdef CONFIG_SYS_POWER_STATE_CPU_LPS_2_SUPPORTED
case SYS_POWER_STATE_CPU_LPS_2:
/* FALLTHROUGH */
# endif
return true;
#endif /* CONFIG_SYS_POWER_LOW_POWER_STATE */
default:
return false;
}
}
/**
* @brief Check if particular power state is a deep sleep state.
*
* This function returns true if given power state is a deep sleep state.
*/
static inline bool sys_pm_is_deep_sleep_state(enum power_states state)
{
switch (state) {
#ifdef CONFIG_SYS_POWER_DEEP_SLEEP
# ifdef CONFIG_SYS_POWER_STATE_DEEP_SLEEP_SUPPORTED
case SYS_POWER_STATE_DEEP_SLEEP:
/* FALLTHROUGH */
# endif
# ifdef CONFIG_SYS_POWER_STATE_DEEP_SLEEP_1_SUPPORTED
case SYS_POWER_STATE_DEEP_SLEEP_1:
/* FALLTHROUGH */
# endif
# ifdef CONFIG_SYS_POWER_STATE_DEEP_SLEEP_2_SUPPORTED
case SYS_POWER_STATE_DEEP_SLEEP_2:
/* FALLTHROUGH */
# endif
return true;
#endif /* CONFIG_SYS_POWER_DEEP_SLEEP */
default:
return false;
}
}
/**
* @brief Power Management Hooks
*
@ -105,7 +157,7 @@ void sys_resume_from_deep_sleep(void);
*
* This function would notify exit from kernel idling if a corresponding
* sys_suspend() notification was handled and did not return
* SYS_PM_NOT_HANDLED.
* SYS_POWER_STATE_ACTIVE.
*
* This function would be called from the ISR context of the event
* that caused the exit from kernel idling. This will be called immediately
@ -144,11 +196,9 @@ void sys_resume(void);
*
* @param ticks the upcoming kernel idle time
*
* @retval SYS_PM_NOT_HANDLED If low power state was not entered.
* @retval SYS_PM_LOW_POWER_STATE If CPU low power state was entered.
* @retval SYS_PM_DEEP_SLEEP If SOC low power state was entered.
* @return Power state which was selected and entered.
*/
extern int sys_suspend(s32_t ticks);
extern enum power_states sys_suspend(s32_t ticks);
#ifdef CONFIG_PM_CONTROL_OS_DEBUG
/**

View file

@ -82,7 +82,7 @@ static void sys_power_save_idle(void)
/*
* Call the suspend hook function of the soc interface to allow
* entry into a low power state. The function returns
* SYS_PM_NOT_HANDLED if low power state was not entered, in which
* SYS_POWER_STATE_ACTIVE if low power state was not entered, in which
* case, kernel does normal idle processing.
*
* This function is entered with interrupts disabled. If a low power
@ -92,7 +92,7 @@ static void sys_power_save_idle(void)
* idle processing re-enables interrupts which is essential for
* the kernel's scheduling logic.
*/
if (sys_suspend(ticks) == SYS_PM_NOT_HANDLED) {
if (sys_suspend(ticks) == SYS_POWER_STATE_ACTIVE) {
sys_pm_idle_exit_notify = 0U;
k_cpu_idle();
}

View file

@ -37,7 +37,7 @@ extern void sys_pm_resume_devices(void);
/**
* @brief Function to get the next PM state based on the ticks
*/
extern int sys_pm_policy_next_state(s32_t ticks, enum power_states *state);
extern enum power_states sys_pm_policy_next_state(s32_t ticks);
/**
* @brief Application defined function for Lower Power entry

View file

@ -9,71 +9,33 @@
#include <soc.h>
#include "pm_policy.h"
#define LOG_LEVEL CONFIG_PM_LOG_LEVEL /* From power module Kconfig */
#include <logging/log.h>
LOG_MODULE_DECLARE(power);
LOG_MODULE_DECLARE(power, CONFIG_PM_LOG_LEVEL);
#if !(defined(CONFIG_SYS_POWER_STATE_CPU_LPS_SUPPORTED) || \
defined(CONFIG_SYS_POWER_STATE_CPU_LPS_1_SUPPORTED) || \
defined(CONFIG_SYS_POWER_STATE_CPU_LPS_2_SUPPORTED) || \
defined(CONFIG_SYS_POWER_STATE_DEEP_SLEEP_SUPPORTED) || \
defined(CONFIG_SYS_POWER_STATE_DEEP_SLEEP_1_SUPPORTED) || \
defined(CONFIG_SYS_POWER_STATE_DEEP_SLEEP_2_SUPPORTED))
#error "Enable Low Power States at SoC Level"
#endif
struct sys_pm_policy {
enum power_states pm_state;
int sys_state;
};
/* PM Policy based on SoC/Platform residency requirements */
static struct sys_pm_policy pm_policy[] = {
#ifdef CONFIG_SYS_POWER_STATE_CPU_LPS_SUPPORTED
{SYS_POWER_STATE_CPU_LPS, SYS_PM_LOW_POWER_STATE},
#endif
#ifdef CONFIG_SYS_POWER_STATE_CPU_LPS_1_SUPPORTED
{SYS_POWER_STATE_CPU_LPS_1, SYS_PM_LOW_POWER_STATE},
#endif
#ifdef CONFIG_SYS_POWER_STATE_CPU_LPS_2_SUPPORTED
{SYS_POWER_STATE_CPU_LPS_2, SYS_PM_LOW_POWER_STATE},
#endif
#ifdef CONFIG_SYS_POWER_STATE_DEEP_SLEEP_SUPPORTED
{SYS_POWER_STATE_DEEP_SLEEP, SYS_PM_DEEP_SLEEP},
#endif
#ifdef CONFIG_SYS_POWER_STATE_DEEP_SLEEP_1_SUPPORTED
{SYS_POWER_STATE_DEEP_SLEEP_1, SYS_PM_DEEP_SLEEP},
#endif
#ifdef CONFIG_SYS_POWER_STATE_DEEP_SLEEP_2_SUPPORTED
{SYS_POWER_STATE_DEEP_SLEEP_2, SYS_PM_DEEP_SLEEP},
#endif
};
int sys_pm_policy_next_state(s32_t ticks, enum power_states *pm_state)
enum power_states sys_pm_policy_next_state(s32_t ticks)
{
static int cur_pm_idx;
int i = cur_pm_idx;
static u8_t cur_power_state;
int i = cur_power_state;
if (SYS_POWER_STATE_MAX == 0) {
/* No power states to go through. */
return SYS_POWER_STATE_ACTIVE;
}
do {
i = (i + 1) % ARRAY_SIZE(pm_policy);
i = (i + 1) % SYS_POWER_STATE_MAX;
#ifdef CONFIG_PM_CONTROL_STATE_LOCK
if (!sys_pm_ctrl_is_state_enabled(pm_policy[i].pm_state)) {
if (!sys_pm_ctrl_is_state_enabled((enum power_states)(i))) {
continue;
}
#endif
cur_pm_state = i;
*pm_state = pm_policy[cur_pm_state].pm_state;
cur_power_state = i;
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("Selected power state: %u", i);
return (enum power_states)(i);
} while (i != cur_power_state);
LOG_DBG("No suitable power state found!");
return SYS_PM_NOT_HANDLED;
return SYS_POWER_STATE_ACTIVE;
}

View file

@ -15,78 +15,57 @@ LOG_MODULE_DECLARE(power);
#define SECS_TO_TICKS CONFIG_SYS_CLOCK_TICKS_PER_SEC
#if !(defined(CONFIG_SYS_POWER_STATE_CPU_LPS_SUPPORTED) || \
defined(CONFIG_SYS_POWER_STATE_CPU_LPS_1_SUPPORTED) || \
defined(CONFIG_SYS_POWER_STATE_CPU_LPS_2_SUPPORTED) || \
defined(CONFIG_SYS_POWER_STATE_DEEP_SLEEP_SUPPORTED) || \
defined(CONFIG_SYS_POWER_STATE_DEEP_SLEEP_1_SUPPORTED) || \
defined(CONFIG_SYS_POWER_STATE_DEEP_SLEEP_2_SUPPORTED))
#error "Enable Low Power States at SoC Level"
#endif
struct sys_pm_policy {
enum power_states pm_state;
int sys_state;
int min_residency;
};
/* PM Policy based on SoC/Platform residency requirements */
static struct sys_pm_policy pm_policy[] = {
static const unsigned int pm_min_residency[] = {
#ifdef CONFIG_SYS_POWER_STATE_CPU_LPS_SUPPORTED
{SYS_POWER_STATE_CPU_LPS, SYS_PM_LOW_POWER_STATE,
CONFIG_PM_LPS_MIN_RES * SECS_TO_TICKS},
CONFIG_PM_LPS_MIN_RES * SECS_TO_TICKS,
#endif
#ifdef CONFIG_SYS_POWER_STATE_CPU_LPS_1_SUPPORTED
{SYS_POWER_STATE_CPU_LPS_1, SYS_PM_LOW_POWER_STATE,
CONFIG_PM_LPS_1_MIN_RES * SECS_TO_TICKS},
CONFIG_PM_LPS_1_MIN_RES * SECS_TO_TICKS,
#endif
#ifdef CONFIG_SYS_POWER_STATE_CPU_LPS_2_SUPPORTED
{SYS_POWER_STATE_CPU_LPS_2, SYS_PM_LOW_POWER_STATE,
CONFIG_PM_LPS_2_MIN_RES * SECS_TO_TICKS},
CONFIG_PM_LPS_2_MIN_RES * SECS_TO_TICKS,
#endif
#ifdef CONFIG_SYS_POWER_STATE_DEEP_SLEEP_SUPPORTED
{SYS_POWER_STATE_DEEP_SLEEP, SYS_PM_DEEP_SLEEP,
CONFIG_PM_DEEP_SLEEP_MIN_RES * SECS_TO_TICKS},
CONFIG_PM_DEEP_SLEEP_MIN_RES * SECS_TO_TICKS,
#endif
#ifdef CONFIG_SYS_POWER_STATE_DEEP_SLEEP_1_SUPPORTED
{SYS_POWER_STATE_DEEP_SLEEP_1, SYS_PM_DEEP_SLEEP,
CONFIG_PM_DEEP_SLEEP_1_MIN_RES * SECS_TO_TICKS},
CONFIG_PM_DEEP_SLEEP_1_MIN_RES * SECS_TO_TICKS,
#endif
#ifdef CONFIG_SYS_POWER_STATE_DEEP_SLEEP_2_SUPPORTED
{SYS_POWER_STATE_DEEP_SLEEP_2, SYS_PM_DEEP_SLEEP,
CONFIG_PM_DEEP_SLEEP_2_MIN_RES * SECS_TO_TICKS},
CONFIG_PM_DEEP_SLEEP_2_MIN_RES * SECS_TO_TICKS,
#endif
};
int sys_pm_policy_next_state(s32_t ticks, enum power_states *pm_state)
enum power_states sys_pm_policy_next_state(s32_t ticks)
{
int i;
if ((ticks != K_FOREVER) && (ticks < pm_policy[0].min_residency)) {
LOG_ERR("Not enough time for PM operations: %d\n", ticks);
return SYS_PM_NOT_HANDLED;
if ((ticks != K_FOREVER) && (ticks < pm_min_residency[0])) {
LOG_ERR("Not enough time for PM operations: %d", ticks);
return SYS_POWER_STATE_ACTIVE;
}
for (i = ARRAY_SIZE(pm_policy) - 1; i >= 0; i--) {
for (i = ARRAY_SIZE(pm_min_residency) - 1; i >= 0; i--) {
#ifdef CONFIG_PM_CONTROL_STATE_LOCK
if (!sys_pm_ctrl_is_state_enabled(pm_policy[i].pm_state)) {
if (!sys_pm_ctrl_is_state_enabled((enum power_states)(i))) {
continue;
}
#endif
if ((ticks == K_FOREVER) ||
(ticks >= pm_policy[i].min_residency)) {
*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;
(ticks >= pm_min_residency[i])) {
LOG_DBG("Selected power state %d "
"(ticks: %d, min_residency: %u)",
i, ticks, pm_min_residency[i]);
return (enum power_states)(i);
}
}
LOG_DBG("No suitable power state found!");
return SYS_PM_NOT_HANDLED;
return SYS_POWER_STATE_ACTIVE;
}

View file

@ -73,64 +73,56 @@ __weak void sys_pm_notify_lps_exit(enum power_states state)
/* This function can be overridden by the application. */
}
int sys_suspend(s32_t ticks)
enum power_states sys_suspend(s32_t ticks)
{
int sys_state;
bool deep_sleep;
pm_state = sys_pm_policy_next_state(ticks);
if (pm_state == SYS_POWER_STATE_ACTIVE) {
LOG_DBG("No PM operations done.");
return pm_state;
}
deep_sleep = sys_pm_is_deep_sleep_state(pm_state);
post_ops_done = 0;
sys_state = sys_pm_policy_next_state(ticks, &pm_state);
sys_pm_notify_lps_entry(pm_state);
switch (sys_state) {
case SYS_PM_LOW_POWER_STATE:
sys_pm_notify_lps_entry(pm_state);
/* Do CPU LPS operations */
sys_pm_debug_start_timer();
sys_set_power_state(pm_state);
sys_pm_debug_stop_timer();
break;
case SYS_PM_DEEP_SLEEP:
/* Don't need pm idle exit event notification */
sys_pm_idle_exit_notification_disable();
sys_pm_notify_lps_entry(pm_state);
/* Save device states and turn off peripherals as necessary */
if (deep_sleep) {
/* Suspend peripherals. */
if (sys_pm_suspend_devices()) {
LOG_ERR("System level device suspend failed\n");
break;
LOG_ERR("System level device suspend failed!");
sys_pm_notify_lps_exit(pm_state);
pm_state = SYS_POWER_STATE_ACTIVE;
return pm_state;
}
/* Enter CPU deep sleep state */
sys_pm_debug_start_timer();
sys_set_power_state(pm_state);
sys_pm_debug_stop_timer();
/*
* Disable idle exit notification as it is not needed
* in deep sleep mode.
*/
sys_pm_idle_exit_notification_disable();
}
/* Enter power state */
sys_pm_debug_start_timer();
sys_set_power_state(pm_state);
sys_pm_debug_stop_timer();
if (deep_sleep) {
/* Turn on peripherals and restore device states as necessary */
sys_pm_resume_devices();
break;
default:
/* No PM operations */
LOG_DBG("\nNo PM operations done\n");
break;
}
if (sys_state != SYS_PM_NOT_HANDLED) {
sys_pm_log_debug_info(pm_state);
sys_pm_log_debug_info(pm_state);
/*
* Do any arch or soc specific post operations specific to the
* power state.
*/
if (!post_ops_done) {
post_ops_done = 1;
sys_pm_notify_lps_exit(pm_state);
sys_power_state_post_ops(pm_state);
}
if (!post_ops_done) {
post_ops_done = 1;
sys_pm_notify_lps_exit(pm_state);
sys_power_state_post_ops(pm_state);
}
return sys_state;
return pm_state;
}
void sys_resume(void)

View file

@ -5,6 +5,7 @@
*/
#include <ztest.h>
#include <power.h>
#include <irq_offload.h>
#include <misc/stack.h>
@ -23,7 +24,8 @@ static void tdata_dump_callback(const struct k_thread *thread, void *user_data)
}
/*power hook functions*/
int sys_suspend(s32_t ticks)
enum power_states sys_suspend(s32_t ticks)
{
static bool test_flag;
@ -35,7 +37,7 @@ int sys_suspend(s32_t ticks)
test_flag = true;
}
return 0;
return SYS_POWER_STATE_ACTIVE;
}
void sys_resume(void)