From 5637def2b3a14d55c58c725c20ca6c477dfb6c24 Mon Sep 17 00:00:00 2001 From: Vincent Wan Date: Mon, 12 Aug 2019 14:40:13 -0700 Subject: [PATCH] power: policy: add PM policy function for TI CC13X2/CC26X2 Create a residency-based system power policy function for TI CC13X2/CC26X2 that uses TI's Power module. Signed-off-by: Vincent Wan --- subsys/power/policy/CMakeLists.txt | 3 +- subsys/power/policy/Kconfig | 12 ++ .../policy/policy_residency_cc13x2_cc26x2.c | 142 ++++++++++++++++++ 3 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 subsys/power/policy/policy_residency_cc13x2_cc26x2.c diff --git a/subsys/power/policy/CMakeLists.txt b/subsys/power/policy/CMakeLists.txt index c335bfc604a..a8c8f1daadf 100644 --- a/subsys/power/policy/CMakeLists.txt +++ b/subsys/power/policy/CMakeLists.txt @@ -1,4 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_sources_ifdef(CONFIG_SYS_PM_POLICY_DUMMY policy_dummy.c) -zephyr_sources_ifdef(CONFIG_SYS_PM_POLICY_RESIDENCY policy_residency.c) +zephyr_sources_ifdef(CONFIG_SYS_PM_POLICY_RESIDENCY_DEFAULT policy_residency.c) +zephyr_sources_ifdef(CONFIG_SYS_PM_POLICY_RESIDENCY_CC13X2_CC26X2 policy_residency_cc13x2_cc26x2.c) diff --git a/subsys/power/policy/Kconfig b/subsys/power/policy/Kconfig index 1908fb311b8..710f502e56b 100644 --- a/subsys/power/policy/Kconfig +++ b/subsys/power/policy/Kconfig @@ -7,6 +7,8 @@ choice config SYS_PM_POLICY_RESIDENCY bool "PM Policy based on CPU residency" + select SYS_PM_POLICY_RESIDENCY_DEFAULT if !SOC_SERIES_CC13X2_CC26X2 + select SYS_PM_POLICY_RESIDENCY_CC13X2_CC26X2 if SOC_SERIES_CC13X2_CC26X2 help Select this option for PM policy based on CPU residencies. @@ -22,6 +24,16 @@ config SYS_PM_POLICY_APP endchoice +config SYS_PM_POLICY_RESIDENCY_DEFAULT + bool + help + Use the default residency policy implementation + +config SYS_PM_POLICY_RESIDENCY_CC13X2_CC26X2 + bool + help + Use the residency policy implementation for TI CC13x2/CC26x2 + if SYS_PM_POLICY_RESIDENCY config SYS_PM_MIN_RESIDENCY_SLEEP_1 diff --git a/subsys/power/policy/policy_residency_cc13x2_cc26x2.c b/subsys/power/policy/policy_residency_cc13x2_cc26x2.c new file mode 100644 index 00000000000..265e0c02ee6 --- /dev/null +++ b/subsys/power/policy/policy_residency_cc13x2_cc26x2.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2019 Linaro Limited. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "pm_policy.h" + +#include + +#include +#include + +#include +#include +#include + +#define LOG_LEVEL CONFIG_SYS_PM_LOG_LEVEL +#include +LOG_MODULE_DECLARE(power); + +#define SECS_TO_TICKS CONFIG_SYS_CLOCK_TICKS_PER_SEC + +/* Wakeup delay from standby in microseconds */ +#define WAKEDELAYSTANDBY 240 + +extern PowerCC26X2_ModuleState PowerCC26X2_module; + +/* PM Policy based on SoC/Platform residency requirements */ +static const unsigned int pm_min_residency[] = { +#ifdef CONFIG_SYS_POWER_SLEEP_STATES +#ifdef CONFIG_HAS_SYS_POWER_STATE_SLEEP_1 + CONFIG_SYS_PM_MIN_RESIDENCY_SLEEP_1 * SECS_TO_TICKS / MSEC_PER_SEC, +#endif + +#ifdef CONFIG_HAS_SYS_POWER_STATE_SLEEP_2 + CONFIG_SYS_PM_MIN_RESIDENCY_SLEEP_2 * SECS_TO_TICKS / MSEC_PER_SEC, +#endif + +#endif /* CONFIG_SYS_POWER_SLEEP_STATES */ +}; + +enum power_states sys_pm_policy_next_state(s32_t ticks) +{ + u32_t constraints; + bool disallowed = false; + int i; + + /* check operating conditions, optimally choose DCDC versus GLDO */ + SysCtrl_DCDC_VoltageConditionalControl(); + + /* query the declared constraints */ + constraints = Power_getConstraintMask(); + + if ((ticks != K_FOREVER) && (ticks < pm_min_residency[0])) { + LOG_DBG("Not enough time for PM operations: %d", ticks); + return SYS_POWER_STATE_ACTIVE; + } + + for (i = ARRAY_SIZE(pm_min_residency) - 1; i >= 0; i--) { +#ifdef CONFIG_SYS_PM_STATE_LOCK + if (!sys_pm_ctrl_is_state_enabled((enum power_states)(i))) { + continue; + } +#endif + if ((ticks == K_FOREVER) || + (ticks >= pm_min_residency[i])) { + /* Verify if Power module has constraints set to + * disallow a state + */ + switch (i) { + case 0: /* Idle mode */ + if ((constraints & (1 << + PowerCC26XX_DISALLOW_IDLE)) != 0) { + disallowed = true; + } + break; + case 1: /* Standby mode */ + if ((constraints & (1 << + PowerCC26XX_DISALLOW_STANDBY)) != 0) { + disallowed = true; + } + /* Set timeout for wakeup event */ + __ASSERT( + CONFIG_SYS_PM_MIN_RESIDENCY_SLEEP_2 > 1, + "CONFIG_SYS_PM_MIN_RESIDENCY_SLEEP_2 must " + "be greater than 1."); + if (ticks != K_FOREVER) { + /* NOTE: Ideally we'd like to set a + * timer to wake up just a little + * earlier to take care of the wakeup + * sequence, ie. by WAKEDELAYSTANDBY + * microsecs. However, given + * k_timer_start (called later by + * ClockP_start) does not currently + * have sub-millisecond accuracy, wakeup + * would be at up to (WAKEDELAYSTANDBY + * + 1 ms) ahead of the next timeout. + * This also has the implication that + * SYS_PM_MIN_RESIDENCY_SLEEP_2 + * must be greater than 1. + */ + ticks -= (WAKEDELAYSTANDBY * + CONFIG_SYS_CLOCK_TICKS_PER_SEC + + 1000000) / 1000000; +#if (CONFIG_SYS_CLOCK_TICKS_PER_SEC <= 1000) + /* + * ClockP_setTimeout cannot handle any + * more ticks + */ + ticks = MIN(ticks, UINT32_MAX / 1000 * + CONFIG_SYS_CLOCK_TICKS_PER_SEC); +#endif + ClockP_setTimeout(ClockP_handle( + (ClockP_Struct *) + &PowerCC26X2_module.clockObj), + ticks); + } + break; + default: + /* This should never be reached */ + LOG_ERR("Invalid sleep state detected\n"); + } + + if (disallowed) { + disallowed = false; + continue; + } + + 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_POWER_STATE_ACTIVE; +}