diff --git a/samples/power/power_mgr/Makefile b/samples/power/power_mgr/Makefile new file mode 100644 index 00000000000..9c69e09f6ec --- /dev/null +++ b/samples/power/power_mgr/Makefile @@ -0,0 +1,6 @@ +MDEF_FILE = prj.mdef +KERNEL_TYPE = micro +BOARD ?= quark_se_devboard +CONF_FILE = prj.conf + +include ${ZEPHYR_BASE}/Makefile.inc diff --git a/samples/power/power_mgr/README.txt b/samples/power/power_mgr/README.txt new file mode 100644 index 00000000000..0d94d267514 --- /dev/null +++ b/samples/power/power_mgr/README.txt @@ -0,0 +1,56 @@ +Title: Power management demo + +Description: + +A sample implementation of a power manager app that uses the zephyr +power management infrastructure. + +This app will cycle through the various power schemes at every call +to _sys_soc_suspend() hook function. +It will cycle through following states +1. Low Power State (LPS) - puts the CPU in C2 state +2. Tickless Idle - demonstrates hooks into tickless idle entry and exit +3. No-op - no operation and letting kernel do its idle + +-------------------------------------------------------------------------------- + +Building and Running Project: + +This application is architecture and SoC specific. It is written for x86 +architecture and uses features specific to quark_se platforms. + +This is a microkernel only project since the zephyr power management +infrastructure currently is only microkernel idle based. In future, when +nanokernel idle is supported, a separate nanokernel app would be created. + + make BOARD= + +-------------------------------------------------------------------------------- + +Troubleshooting: + +Problems caused by out-dated project information can be addressed by +issuing one of the following commands then rebuilding the project: + + make clean # discard results of previous builds + # but keep existing configuration info +or + make pristine # discard results of previous builds + # and restore pre-defined configuration info + +-------------------------------------------------------------------------------- + +Sample Output: + +Power Management Demo + +Going to low power state! + +Resume from low power state +Total Elapsed From Suspend To Resume = 163838 RTC Cycles +Tickless idle power saving! + +Exit from tickless idle +Total Elapsed From Suspend To Tickless Resume = 163838 RTC Cycles + +... \ No newline at end of file diff --git a/samples/power/power_mgr/prj.conf b/samples/power/power_mgr/prj.conf new file mode 100644 index 00000000000..4ec008c6614 --- /dev/null +++ b/samples/power/power_mgr/prj.conf @@ -0,0 +1,5 @@ +CONFIG_ADVANCED_POWER_MANAGEMENT=y +CONFIG_ADVANCED_IDLE=y +CONFIG_TICKLESS_IDLE=y +CONFIG_RTC=y +CONFIG_STDOUT_CONSOLE=y diff --git a/samples/power/power_mgr/prj.mdef b/samples/power/power_mgr/prj.mdef new file mode 100644 index 00000000000..19f1a086099 --- /dev/null +++ b/samples/power/power_mgr/prj.mdef @@ -0,0 +1,5 @@ +% Application : Power Management demo + +% TASK NAME PRIO ENTRY STACK GROUPS +% ================================== + TASK TASKA 7 main 2048 [EXE] diff --git a/samples/power/power_mgr/src/Makefile b/samples/power/power_mgr/src/Makefile new file mode 100644 index 00000000000..00066e15678 --- /dev/null +++ b/samples/power/power_mgr/src/Makefile @@ -0,0 +1 @@ +obj-y = main.o diff --git a/samples/power/power_mgr/src/main.c b/samples/power/power_mgr/src/main.c new file mode 100644 index 00000000000..6df7505f001 --- /dev/null +++ b/samples/power/power_mgr/src/main.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2016 Intel Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#if defined(CONFIG_STDOUT_CONSOLE) +#include +#define PRINT printf +#else +#include +#define PRINT printk +#endif +#include + +#define SLEEPTICKS SECONDS(5) +#define P_LVL2 0xb0800504 + +static int pm_state; /* 1 = LPS; 2 = Tickless Idle */ +static void quark_low_power(void); +static struct device *rtc_dev; +static uint32_t start_time, end_time; + +void main(void) +{ + struct rtc_config config; + + PRINT("Power Management Demo\n"); + + config.init_val = 0; + config.alarm_enable = 0; + config.alarm_val = RTC_ALARM_SECOND; + config.cb_fn = NULL; + + rtc_dev = device_get_binding(CONFIG_RTC_DRV_NAME); + rtc_enable(rtc_dev); + rtc_set_config(rtc_dev, &config); + + while (1) { + task_sleep(SLEEPTICKS); + } +} + +static int check_pm_policy(int32_t ticks) +{ + static int policy; + + /* + * Compare time available with wake latencies and select + * appropriate power saving policy + * + * For the demo we will alternate between following states + * + * 0 = no power saving operation + * 1 = low power state + * 2 = tickless idle power saving + * + */ + policy = (policy > 2 ? 0 : policy); + + return policy++; +} + +static int do_low_power(int32_t ticks) +{ + PRINT("\n\nGoing to low power state!\n"); + + /* Turn off peripherals/clocks here */ + + quark_low_power(); + + return 1; /* non-zero so kernel does not do idle wait */ +} + +static int do_tickless_idle(int32_t ticks) +{ + PRINT("Tickless idle power saving!\n"); + + /* Turn off peripherals/clocks here */ + + return 0; /* zero to let kernel do idle wait */ +} + +int _sys_soc_suspend(int32_t ticks) +{ + int ret = 0; + + pm_state = check_pm_policy(ticks); + + switch (pm_state) { + case 1: + start_time = rtc_read(rtc_dev); + ret = do_low_power(ticks); + break; + case 2: + start_time = rtc_read(rtc_dev); + ret = do_tickless_idle(ticks); + break; + default: + /* No PM operations */ + ret = 0; + break; + } + + return ret; +} + +static void low_power_resume(void) +{ + end_time = rtc_read(rtc_dev); + PRINT("\nResume from low power state\n"); + PRINT("Total Elapsed From Suspend To Resume = %d RTC Cycles\n", + end_time - start_time); +} + +static void tickless_idle_resume(void) +{ + end_time = rtc_read(rtc_dev); + PRINT("\nExit from tickless idle\n"); + PRINT("Total Elapsed From Suspend To Tickless Resume = %d RTC Cycles\n", + end_time - start_time); +} + +void _sys_soc_resume(void) +{ + switch (pm_state) { + case 1: + low_power_resume(); + break; + case 2: + tickless_idle_resume(); + break; + default: + break; + } + + pm_state = 0; + +} + +static void quark_low_power(void) +{ + __asm__ volatile ( + "sti\n\t" + /* + * Atomically enable interrupts and enter LPS. + * + * Reading P_LVL2 causes C2 transition. + */ + "movl (%%eax), %%eax\n\t" + ::"a"(P_LVL2)); + +} diff --git a/samples/power/power_mgr/testcase.ini b/samples/power/power_mgr/testcase.ini new file mode 100644 index 00000000000..732fea8222a --- /dev/null +++ b/samples/power/power_mgr/testcase.ini @@ -0,0 +1,5 @@ +[test] +build_only = true +tags = apps +arch_whitelist = x86 +platform_whitelist = quark_se_devboard arduino_101