From c4612d0236f13e6e2379490c866f2d792e3133d0 Mon Sep 17 00:00:00 2001 From: Ramakrishna Pallala Date: Tue, 14 Aug 2018 13:08:43 +0530 Subject: [PATCH 1/3] arch: arm: nordic_nrf: Add an API to check for valid PM state Add an API _sys_soc_is_valid_power_state to check if a PM state is valid or not. Signed-off-by: Ramakrishna Pallala --- arch/arm/soc/nordic_nrf/nrf52/power.c | 18 ++++++++++++++++++ arch/arm/soc/nordic_nrf/nrf52/soc_power.h | 5 +++++ 2 files changed, 23 insertions(+) diff --git a/arch/arm/soc/nordic_nrf/nrf52/power.c b/arch/arm/soc/nordic_nrf/nrf52/power.c index a43a030c5780..fb8bb3c022e2 100644 --- a/arch/arm/soc/nordic_nrf/nrf52/power.c +++ b/arch/arm/soc/nordic_nrf/nrf52/power.c @@ -100,3 +100,21 @@ void _sys_soc_power_state_post_ops(enum power_states state) break; } } + +bool _sys_soc_is_valid_power_state(enum power_states state) +{ + switch (state) { + case SYS_POWER_STATE_CPU_LPS: + case SYS_POWER_STATE_CPU_LPS_1: +#if defined(CONFIG_SYS_POWER_DEEP_SLEEP) + case SYS_POWER_STATE_DEEP_SLEEP: +#endif + return true; + break; + default: + SYS_LOG_DBG("Unsupported State\n"); + break; + } + + return false; +} diff --git a/arch/arm/soc/nordic_nrf/nrf52/soc_power.h b/arch/arm/soc/nordic_nrf/nrf52/soc_power.h index 701104f73848..74cc9cb115a4 100644 --- a/arch/arm/soc/nordic_nrf/nrf52/soc_power.h +++ b/arch/arm/soc/nordic_nrf/nrf52/soc_power.h @@ -27,6 +27,11 @@ enum power_states { */ void _sys_soc_set_power_state(enum power_states state); +/** + * @brief Check a low power state is supported by SoC + */ +bool _sys_soc_is_valid_power_state(enum power_states state); + /** * @brief Do any SoC or architecture specific post ops after low power states. */ From 48eebc94f43ec1192e5aacd843adfc4f13326a3f Mon Sep 17 00:00:00 2001 From: Ramakrishna Pallala Date: Thu, 16 Aug 2018 10:39:40 +0530 Subject: [PATCH 2/3] subsys: power: Add OS managed Power Management framework Add support for OS managed Power Management framework for Zephyr under 'subsys/power'. This framework takes care of implementing the _sys_soc_suspend/_sys_soc_resume API's, a PM policy based on SoC Low Power residencies and also provides necessary API's to do devices suspend and resume. Also add necessary changes to support the existing Application managed Power Management framework. Signed-off-by: Ramakrishna Pallala --- kernel/Kconfig.power_mgmt | 23 ++++++++ subsys/CMakeLists.txt | 1 + subsys/Kconfig | 2 + subsys/power/CMakeLists.txt | 5 ++ subsys/power/Kconfig | 88 +++++++++++++++++++++++++++ subsys/power/device.c | 115 ++++++++++++++++++++++++++++++++++++ subsys/power/pm_policy.h | 57 ++++++++++++++++++ subsys/power/policy.c | 98 ++++++++++++++++++++++++++++++ subsys/power/power.c | 107 +++++++++++++++++++++++++++++++++ 9 files changed, 496 insertions(+) create mode 100644 subsys/power/CMakeLists.txt create mode 100644 subsys/power/Kconfig create mode 100644 subsys/power/device.c create mode 100644 subsys/power/pm_policy.h create mode 100644 subsys/power/policy.c create mode 100644 subsys/power/power.c diff --git a/kernel/Kconfig.power_mgmt b/kernel/Kconfig.power_mgmt index 73baa7be807f..8e6c15e54834 100644 --- a/kernel/Kconfig.power_mgmt +++ b/kernel/Kconfig.power_mgmt @@ -14,6 +14,29 @@ menuconfig SYS_POWER_MANAGEMENT timer is due to expire. if SYS_POWER_MANAGEMENT +choice POWER_MANAGEMENT_CONTROL + prompt "Power Management Control" + default PM_CONTROL_APP + help + Select the Application managed or OS managed power saving + mechanism. + +config PM_CONTROL_APP + bool + prompt "Handled at Application level" + help + This option enbles the Application to handle all the Power + Management flows for the platform. + +config PM_CONTROL_OS + bool + prompt "Handle at OS level" + help + This option allows the OS to handle all the Power + Management flows for the platform. + +endchoice # POWER_MANAGEMENT_CONTROL + config SYS_POWER_LOW_POWER_STATE bool "Low power state" depends on SYS_POWER_LOW_POWER_STATE_SUPPORTED diff --git a/subsys/CMakeLists.txt b/subsys/CMakeLists.txt index 3e71bac6f69e..50b74b669752 100644 --- a/subsys/CMakeLists.txt +++ b/subsys/CMakeLists.txt @@ -14,3 +14,4 @@ add_subdirectory_ifdef(CONFIG_USB usb) add_subdirectory(random) add_subdirectory(storage) add_subdirectory_ifdef(CONFIG_SETTINGS settings) +add_subdirectory_ifdef(CONFIG_PM_CONTROL_OS power) diff --git a/subsys/Kconfig b/subsys/Kconfig index 0630d7d67518..f3deb779855f 100644 --- a/subsys/Kconfig +++ b/subsys/Kconfig @@ -34,3 +34,5 @@ source "subsys/storage/Kconfig" source "subsys/settings/Kconfig" source "subsys/app_memory/Kconfig" + +source "subsys/power/Kconfig" diff --git a/subsys/power/CMakeLists.txt b/subsys/power/CMakeLists.txt new file mode 100644 index 000000000000..fc6ed85e682b --- /dev/null +++ b/subsys/power/CMakeLists.txt @@ -0,0 +1,5 @@ +zephyr_sources( + power.c + policy.c + device.c + ) diff --git a/subsys/power/Kconfig b/subsys/power/Kconfig new file mode 100644 index 000000000000..d88499e5b2a1 --- /dev/null +++ b/subsys/power/Kconfig @@ -0,0 +1,88 @@ + +if PM_CONTROL_OS +menu "OS Power Management" + +if SYS_POWER_LOW_POWER_STATE +config PM_CONTROL_OS_LPS + bool "Platform supports LPS" + help + Select this option if SoC support LPS state. + +if PM_CONTROL_OS_LPS +config PM_LPS_MIN_RES + int "LPS minimum residency" + default 5 + help + Minimum residency in ticks to enter LPS state. +endif + +config PM_CONTROL_OS_LPS_1 + bool "Platform supports LPS_1" + help + Select this option if SoC support LPS_1 state. + +if PM_CONTROL_OS_LPS_1 +config PM_LPS_1_MIN_RES + int "LPS_1 minimum residency" + default 10 + help + Minimum residency in ticks to enter LPS_1 state. +endif + +config PM_CONTROL_OS_LPS_2 + bool "Platform supports LPS_2" + help + Select this option if SoC support LPS_2 state. + +if PM_CONTROL_OS_LPS_2 +config PM_LPS_2_MIN_RES + int "LPS_2 minimum residency" + default 30 + help + Minimum residency in ticks to enter LPS_2 state. +endif +endif # SYS_POWER_LOW_POWER_STATE + +if SYS_POWER_DEEP_SLEEP +config PM_CONTROL_OS_DEEP_SLEEP + bool "Platform supports DEEP_SLEEP" + help + Select this option if SoC support DEEP_SLEEP state. + +if PM_CONTROL_OS_DEEP_SLEEP +config PM_DEEP_SLEEP_MIN_RES + int "DEEP_SLEEP minimum residency" + default 60 + help + Minimum residency in ticks to enter DEEP_SLEEP state. +endif + +config PM_CONTROL_OS_DEEP_SLEEP_1 + bool "Platform supports DEEP_SLEEP_1" + help + Select this option if SoC support DEEP_SLEEP_1 state. + +if PM_CONTROL_OS_DEEP_SLEEP_1 +config PM_DEEP_SLEEP_1_MIN_RES + int "DEEP_SLEEP_1 minimum residency" + default 90 + help + Minimum residency in ticks to enter DEEP_SLEEP_1 state. +endif + +config PM_CONTROL_OS_DEEP_SLEEP_2 + bool "Platform supports DEEP_SLEEP_2" + help + Select this option if SoC support DEEP_SLEEP_2 state. + +if PM_CONTROL_OS_DEEP_SLEEP_2 +config PM_DEEP_SLEEP_2_MIN_RES + int "DEEP_SLEEP_2 minimum residency" + default 120 + help + Minimum residency in ticks to enter DEEP_SLEEP_2 state. +endif +endif # PM_CONTROL_OS_DEEP_SLEEP + +endmenu +endif # PM_CONTROL_OS diff --git a/subsys/power/device.c b/subsys/power/device.c new file mode 100644 index 000000000000..2f4111835442 --- /dev/null +++ b/subsys/power/device.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2018 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include "pm_policy.h" + +#define LOG_MODULE_NAME power +#define LOG_LEVEL CONFIG_PM_LOG_LEVEL /* From power module Kconfig */ +#include +LOG_MODULE_DECLARE(); + +/* + * FIXME: Remove the conditional inclusion of + * core_devices array once we enble the capability + * to build the device list based on devices power + * and clock domain dependencies. + */ +#ifdef CONFIG_SOC_SERIES_NRF52X +#define MAX_PM_DEVICES 15 +#define NUM_CORE_DEVICES 4 +#define MAX_DEV_NAME_LEN 16 +static const char core_devices[NUM_CORE_DEVICES][MAX_DEV_NAME_LEN] = { + "clk_k32src", + "clk_m16src", + "sys_clock", + "UART_0", +}; +#else +#error "Add SoC's core devices list for PM" +#endif + +/* + * Ordered list to store devices on which + * device power policies would be executed. + */ +static int device_ordered_list[MAX_PM_DEVICES]; +static int device_retval[MAX_PM_DEVICES]; +static struct device *pm_device_list; +static int device_count; + +int sys_pm_suspend_devices(void) +{ + for (int i = device_count - 1; i >= 0; i--) { + int idx = device_ordered_list[i]; + + /* TODO: Improve the logic by checking device status + * and set the device states accordingly. + */ + device_retval[i] = device_set_power_state(&pm_device_list[idx], + DEVICE_PM_SUSPEND_STATE); + if (device_retval[i]) { + LOG_ERR("%s suspend operation failed\n", + pm_device_list[idx].config->name); + return device_retval[i]; + } + } + + return 0; +} + +void sys_pm_resume_devices(void) +{ + int i; + + for (i = 0; i < device_count; i++) { + if (!device_retval[i]) { + int idx = device_ordered_list[i]; + + device_set_power_state(&pm_device_list[idx], + DEVICE_PM_ACTIVE_STATE); + } + } +} + +void sys_pm_create_device_list(void) +{ + int count; + int i, j; + bool is_core_dev; + + /* + * Create an ordered list of devices that will be suspended. + * Ordering should be done based on dependencies. Devices + * in the beginning of the list will be resumed first. + */ + device_list_get(&pm_device_list, &count); + + /* Reserve for 32KHz, 16MHz, system clock, etc... */ + device_count = NUM_CORE_DEVICES; + + for (i = 0; (i < count) && (device_count < MAX_PM_DEVICES); i++) { + + /* Check if the device is core device */ + for (j = 0, is_core_dev = false; j < NUM_CORE_DEVICES; j++) { + if (!strcmp(pm_device_list[i].config->name, + &core_devices[j][0])) { + is_core_dev = true; + break; + } + } + + if (is_core_dev) { + device_ordered_list[j] = i; + } else { + device_ordered_list[device_count++] = i; + } + } +} diff --git a/subsys/power/pm_policy.h b/subsys/power/pm_policy.h new file mode 100644 index 000000000000..0fb5a99d039c --- /dev/null +++ b/subsys/power/pm_policy.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2018 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _PM_POLICY_H_ +#define _PM_POLICY_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Function to create device PM list + */ +extern void sys_pm_create_device_list(void); + +/** + * @brief Function to suspend the devices in PM device list + */ +extern int sys_pm_suspend_devices(void); + +/** + * @brief Function to resume the devices in PM device list + */ +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); + +/** + * @brief Application defined function for Lower Power entry + * + * Application defined function for doing any target specific operations + * for low power entry. + */ +extern void sys_pm_notify_lps_entry(enum power_states state); + +/** + * @brief Application defined function for Lower Power exit + * + * Application defined function for doing any target specific operations + * for low power exit. + */ +extern void sys_pm_notify_lps_exit(enum power_states state); + +#ifdef __cplusplus +} +#endif + +#endif /* _PM_POLICY_H_ */ diff --git a/subsys/power/policy.c b/subsys/power/policy.c new file mode 100644 index 000000000000..ef204e1dde51 --- /dev/null +++ b/subsys/power/policy.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2018 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "pm_policy.h" + +#define LOG_MODULE_NAME power +#define LOG_LEVEL CONFIG_PM_LOG_LEVEL /* From power module Kconfig */ +#include +LOG_MODULE_DECLARE(); + +#ifdef CONFIG_TICKLESS_KERNEL +#define SECS_TO_TICKS CONFIG_TICKLESS_KERNEL_TIME_UNIT_IN_MICRO_SECS +#else +#define SECS_TO_TICKS CONFIG_SYS_CLOCK_TICKS_PER_SEC +#endif + +#if !(defined(CONFIG_PM_CONTROL_OS_LPS) || \ + defined(CONFIG_PM_CONTROL_OS_LPS_1) || \ + defined(CONFIG_PM_CONTROL_OS_LPS_2) || \ + defined(CONFIG_PM_CONTROL_OS_DEEP_SLEEP) || \ + defined(CONFIG_PM_CONTROL_OS_DEEP_SLEEP_1) || \ + defined(CONFIG_PM_CONTROL_OS_DEEP_SLEEP_2)) +#error "Low Power states not selected by policy" +#endif + +struct sys_soc_pm_policy { + enum power_states pm_state; + int sys_state; + int min_residency; +}; + +/* PM Policy based on SoC/Platform residency requirements */ +static struct sys_soc_pm_policy pm_policy[] = { +#ifdef CONFIG_PM_CONTROL_OS_LPS + {SYS_POWER_STATE_CPU_LPS, SYS_PM_LOW_POWER_STATE, + CONFIG_PM_LPS_MIN_RES * SECS_TO_TICKS}, +#endif + +#ifdef CONFIG_PM_CONTROL_OS_LPS_1 + {SYS_POWER_STATE_CPU_LPS_1, SYS_PM_LOW_POWER_STATE, + CONFIG_PM_LPS_1_MIN_RES * SECS_TO_TICKS}, +#endif + +#ifdef CONFIG_PM_CONTROL_OS_LPS_2 + {SYS_POWER_STATE_CPU_LPS_2, SYS_PM_LOW_POWER_STATE, + CONFIG_PM_LPS_2_MIN_RES * SECS_TO_TICKS}, +#endif + +#ifdef CONFIG_PM_CONTROL_OS_DEEP_SLEEP + {SYS_POWER_STATE_DEEP_SLEEP, SYS_PM_DEEP_SLEEP, + CONFIG_PM_DEEP_SLEEP_MIN_RES * SECS_TO_TICKS}, +#endif + +#ifdef CONFIG_PM_CONTROL_OS_DEEP_SLEEP_1 + {SYS_POWER_STATE_DEEP_SLEEP_1, SYS_PM_DEEP_SLEEP, + CONFIG_PM_DEEP_SLEEP_1_MIN_RES * SECS_TO_TICKS}, +#endif + +#ifdef CONFIG_PM_CONTROL_OS_DEEP_SLEEP_2 + {SYS_POWER_STATE_DEEP_SLEEP_2, SYS_PM_DEEP_SLEEP, + 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) +{ + 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; + } + + for (i = 0; i < (ARRAY_SIZE(pm_policy) - 1); i++) { + if ((ticks >= pm_policy[i].min_residency) && + (ticks < pm_policy[i + 1].min_residency)) { + break; + } + } + + if (!_sys_soc_is_valid_power_state(pm_policy[i].pm_state)) { + LOG_ERR("pm_state(%d) not supported by SoC\n", + pm_policy[i].pm_state); + return SYS_PM_NOT_HANDLED; + } + + *pm_state = pm_policy[i].pm_state; + LOG_DBG("pm_state: %d, min_residency: %d, idx: %d\n", + *pm_state, pm_policy[i].min_residency, i); + + return pm_policy[i].sys_state; +} diff --git a/subsys/power/power.c b/subsys/power/power.c new file mode 100644 index 000000000000..fa039836a889 --- /dev/null +++ b/subsys/power/power.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2018 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include "pm_policy.h" + +#define LOG_MODULE_NAME power +#define LOG_LEVEL CONFIG_PM_LOG_LEVEL /* From power module Kconfig */ +#include +LOG_MODULE_REGISTER(); + +static int post_ops_done = 1; +static enum power_states pm_state; + +int _sys_soc_suspend(s32_t ticks) +{ + int sys_state; + + post_ops_done = 0; + + sys_state = sys_pm_policy_next_state(ticks, &pm_state); + + switch (sys_state) { + case SYS_PM_LOW_POWER_STATE: + sys_pm_notify_lps_entry(pm_state); + /* Do CPU LPS operations */ + _sys_soc_set_power_state(pm_state); + break; + case SYS_PM_DEEP_SLEEP: + /* Don't need pm idle exit event notification */ + _sys_soc_pm_idle_exit_notification_disable(); + + sys_pm_notify_lps_entry(pm_state); + + /* Save device states and turn off peripherals as necessary */ + if (sys_pm_suspend_devices()) { + LOG_ERR("System level device suspend failed\n"); + break; + } + + /* Enter CPU deep sleep state */ + _sys_soc_set_power_state(pm_state); + + /* 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) { + /* + * 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_soc_power_state_post_ops(pm_state); + } + } + + return sys_state; +} + +void _sys_soc_resume(void) +{ + /* + * This notification is called from the ISR of the event + * that caused exit from kernel idling after PM operations. + * + * Some CPU low power states require enabling of interrupts + * atomically when entering those states. The wake up from + * such a state first executes code in the ISR of the interrupt + * that caused the wake. This hook will be called from the ISR. + * For such CPU LPS states, do post operations and restores here. + * The kernel scheduler will get control after the ISR finishes + * and it may schedule another thread. + * + * Call _sys_soc_pm_idle_exit_notification_disable() if this + * notification is not required. + */ + if (!post_ops_done) { + post_ops_done = 1; + sys_pm_notify_lps_exit(pm_state); + _sys_soc_power_state_post_ops(pm_state); + } +} + +static int sys_pm_init(struct device *dev) +{ + ARG_UNUSED(dev); + + sys_pm_create_device_list(); + return 0; +} + +SYS_INIT(sys_pm_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); From 7f6d3e53637eb9b9c0bc83258e72696c2143cd00 Mon Sep 17 00:00:00 2001 From: Ramakrishna Pallala Date: Fri, 17 Aug 2018 20:14:56 +0530 Subject: [PATCH 3/3] samples: subsys: Add sample app to demo OS managed PM Add a sample application to demonstrate OS managed Power Management framework. Signed-off-by: Ramakrishna Pallala --- samples/subsys/power/power.rst | 10 +++ samples/subsys/power/power_mgr/CMakeLists.txt | 6 ++ samples/subsys/power/power_mgr/README.rst | 79 +++++++++++++++++++ samples/subsys/power/power_mgr/prj.conf | 13 +++ .../subsys/power/power_mgr/prj_tickless.conf | 16 ++++ samples/subsys/power/power_mgr/sample.yaml | 6 ++ samples/subsys/power/power_mgr/src/main.c | 61 ++++++++++++++ 7 files changed, 191 insertions(+) create mode 100644 samples/subsys/power/power.rst create mode 100644 samples/subsys/power/power_mgr/CMakeLists.txt create mode 100644 samples/subsys/power/power_mgr/README.rst create mode 100644 samples/subsys/power/power_mgr/prj.conf create mode 100644 samples/subsys/power/power_mgr/prj_tickless.conf create mode 100644 samples/subsys/power/power_mgr/sample.yaml create mode 100644 samples/subsys/power/power_mgr/src/main.c diff --git a/samples/subsys/power/power.rst b/samples/subsys/power/power.rst new file mode 100644 index 000000000000..8e2c53ba882c --- /dev/null +++ b/samples/subsys/power/power.rst @@ -0,0 +1,10 @@ +.. _power_management-samples: + +Power Management Samples +######################## + +.. toctree:: + :maxdepth: 1 + :glob: + + **/* diff --git a/samples/subsys/power/power_mgr/CMakeLists.txt b/samples/subsys/power/power_mgr/CMakeLists.txt new file mode 100644 index 000000000000..800ba5841af3 --- /dev/null +++ b/samples/subsys/power/power_mgr/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.8.2) +include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) +project(NONE) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/subsys/power/power_mgr/README.rst b/samples/subsys/power/power_mgr/README.rst new file mode 100644 index 000000000000..17e5bc64c933 --- /dev/null +++ b/samples/subsys/power/power_mgr/README.rst @@ -0,0 +1,79 @@ +.. _os-power-mgr-sample: + +OS Power management demo +########################### + +Overview +******** + +This sample demonstrates OS managed power saving mechanism through the sample +application which will periodically go sleep there by invoking the idle thread +which will call the _sys_soc_suspend() to enter into low power states. The Low +Power state will be selected based on the next timeout event. + +Requirements +************ + +This application uses nrf52 DK board for the demo. + +Building, Flashing and Running +****************************** + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/power/power_mgr + :board: nrf52_pca10040 + :goals: build flash + :compact: + +Running: + +1. Open UART terminal. +2. Power Cycle Device. +3. Device will enter into Low Power Modes periodically. + + +Sample Output +================= +nrf52 core output +----------------- + +.. code-block:: console + + ***OS Power Management Demo on arm**** + Demo Description + Application creates Idleness, Due to which System Idle Thread is + scheduled and it enters into various Low Power States. + + <-- App doing busy wait for 10 Sec --> + + <-- App going to sleep for 6000 msec --> + Entering Low Power state (0) + Entering Low Power state (0) + Entering Low Power state (0) + Entering Low Power state (0) + + <-- App doing busy wait for 10 Sec --> + + <-- App going to sleep for 11000 msec --> + Entering Low Power state (1) + Entering Low Power state (1) + Entering Low Power state (1) + Entering Low Power state (1) + + <-- App doing busy wait for 10 Sec --> + + <-- App going to sleep for 6000 msec --> + Entering Low Power state (0) + Entering Low Power state (0) + Entering Low Power state (0) + Entering Low Power state (0) + + <-- App doing busy wait for 10 Sec --> + + <-- App going to sleep for 11000 msec --> + Entering Low Power state (1) + Entering Low Power state (1) + Entering Low Power state (1) + Entering Low Power state (1) + OS managed Power Management Test completed + diff --git a/samples/subsys/power/power_mgr/prj.conf b/samples/subsys/power/power_mgr/prj.conf new file mode 100644 index 000000000000..f1e799e11bdc --- /dev/null +++ b/samples/subsys/power/power_mgr/prj.conf @@ -0,0 +1,13 @@ +CONFIG_SYS_POWER_MANAGEMENT=y +CONFIG_SYS_POWER_LOW_POWER_STATE=y +CONFIG_SYS_POWER_DEEP_SLEEP=y +CONFIG_DEVICE_POWER_MANAGEMENT=y +CONFIG_TICKLESS_IDLE=y + +CONFIG_PM_CONTROL_OS=y +CONFIG_PM_CONTROL_OS_LPS=y +CONFIG_PM_LPS_MIN_RES=5 +CONFIG_PM_CONTROL_OS_LPS_1=y +CONFIG_PM_LPS_1_MIN_RES=10 +CONFIG_PM_CONTROL_OS_DEEP_SLEEP=y +CONFIG_PM_DEEP_SLEEP_MIN_RES=60 diff --git a/samples/subsys/power/power_mgr/prj_tickless.conf b/samples/subsys/power/power_mgr/prj_tickless.conf new file mode 100644 index 000000000000..fa8e0f4dc114 --- /dev/null +++ b/samples/subsys/power/power_mgr/prj_tickless.conf @@ -0,0 +1,16 @@ +CONFIG_NUM_COOP_PRIORITIES=29 +CONFIG_NUM_PREEMPT_PRIORITIES=40 +CONFIG_SYS_POWER_MANAGEMENT=y +CONFIG_SYS_POWER_LOW_POWER_STATE=y +CONFIG_SYS_POWER_DEEP_SLEEP=y +CONFIG_DEVICE_POWER_MANAGEMENT=y +CONFIG_TICKLESS_KERNEL=y +CONFIG_TICKLESS_IDLE=y + +CONFIG_PM_CONTROL_OS=y +CONFIG_PM_CONTROL_OS_LPS=y +CONFIG_PM_LPS_MIN_RES=5 +CONFIG_PM_CONTROL_OS_LPS_1=y +CONFIG_PM_LPS_1_MIN_RES=10 +CONFIG_PM_CONTROL_OS_DEEP_SLEEP=y +CONFIG_PM_DEEP_SLEEP_MIN_RES=60 diff --git a/samples/subsys/power/power_mgr/sample.yaml b/samples/subsys/power/power_mgr/sample.yaml new file mode 100644 index 000000000000..a665dfdfc775 --- /dev/null +++ b/samples/subsys/power/power_mgr/sample.yaml @@ -0,0 +1,6 @@ +sample: + name: OS managed Power Management Sample +tests: + ospm.low_power_state: + platform_whitelist: nrf52840_pca10056 nrf52_pca10040 + tags: power diff --git a/samples/subsys/power/power_mgr/src/main.c b/samples/subsys/power/power_mgr/src/main.c new file mode 100644 index 000000000000..2765a424af13 --- /dev/null +++ b/samples/subsys/power/power_mgr/src/main.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define SECONDS_TO_SLEEP 1 + +#define BUSY_WAIT_DELAY_US (10 * 1000000) + +#define LPS_STATE_ENTER_TO ((CONFIG_PM_LPS_MIN_RES + 1) * 1000) +#define LPS1_STATE_ENTER_TO ((CONFIG_PM_LPS_1_MIN_RES + 1) * 1000) + +#define DEMO_DESCRIPTION \ + "Demo Description\n" \ + "Application creates Idleness, Due to which System Idle Thread is\n"\ + "scheduled and it enters into various Low Power States.\n"\ + +void sys_pm_notify_lps_entry(enum power_states state) +{ + printk("Entering Low Power state (%d)\n", state); +} + +void sys_pm_notify_lps_exit(enum power_states state) +{ + printk("Entering Low Power state (%d)\n", state); +} + +/* Application main Thread */ +void main(void) +{ + printk("\n\n***OS Power Management Demo on %s****\n", CONFIG_ARCH); + printk(DEMO_DESCRIPTION); + + for (int i = 1; i <= 4; i++) { + printk("\n<-- App doing busy wait for 10 Sec -->\n"); + k_busy_wait(BUSY_WAIT_DELAY_US); + + /* Create Idleness to make Idle thread run */ + if ((i % 2) == 0) { + printk("\n<-- App going to sleep for %d msec -->\n", + LPS1_STATE_ENTER_TO); + k_sleep(LPS1_STATE_ENTER_TO); + } else { + printk("\n<-- App going to sleep for %d msec -->\n", + LPS_STATE_ENTER_TO); + k_sleep(LPS_STATE_ENTER_TO); + } + } + + printk("OS managed Power Management Test completed\n"); +}