1 /* 2 * Copyright (c) 2020 Intel corporation 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 #ifndef ZEPHYR_INCLUDE_PM_STATE_H_ 8 #define ZEPHYR_INCLUDE_PM_STATE_H_ 9 10 #include <zephyr/sys/util.h> 11 #include <zephyr/devicetree.h> 12 13 #ifdef __cplusplus 14 extern "C" { 15 #endif 16 17 /** 18 * @brief System Power Management States 19 * @defgroup subsys_pm_states States 20 * @ingroup subsys_pm 21 * @{ 22 */ 23 24 /** 25 * @enum pm_state Power management state 26 */ 27 enum pm_state { 28 /** 29 * @brief Runtime active state 30 * 31 * The system is fully powered and active. 32 * 33 * @note This state is correlated with ACPI G0/S0 state 34 */ 35 PM_STATE_ACTIVE, 36 /** 37 * @brief Runtime idle state 38 * 39 * Runtime idle is a system sleep state in which all of the cores 40 * enter deepest possible idle state and wait for interrupts, no 41 * requirements for the devices, leaving them at the states where 42 * they are. 43 * 44 * @note This state is correlated with ACPI S0ix state 45 */ 46 PM_STATE_RUNTIME_IDLE, 47 /** 48 * @brief Suspend to idle state 49 * 50 * The system goes through a normal platform suspend where it puts 51 * all of the cores in deepest possible idle state and *may* puts 52 * peripherals into low-power states. No operating state is lost (ie. 53 * the cpu core does not lose execution context), so the system can go 54 * back to where it left off easily enough. 55 * 56 * @note This state is correlated with ACPI S1 state 57 */ 58 PM_STATE_SUSPEND_TO_IDLE, 59 /** 60 * @brief Standby state 61 * 62 * In addition to putting peripherals into low-power states all 63 * non-boot CPUs are powered off. It should allow more energy to be 64 * saved relative to suspend to idle, but the resume latency will 65 * generally be greater than for that state. But it should be the same 66 * state with suspend to idle state on uniprocessor system. 67 * 68 * @note This state is correlated with ACPI S2 state 69 */ 70 PM_STATE_STANDBY, 71 /** 72 * @brief Suspend to ram state 73 * 74 * This state offers significant energy savings by powering off as much 75 * of the system as possible, where memory should be placed into the 76 * self-refresh mode to retain its contents. The state of devices and 77 * CPUs is saved and held in memory, and it may require some boot- 78 * strapping code in ROM to resume the system from it. 79 * 80 * @note This state is correlated with ACPI S3 state 81 */ 82 PM_STATE_SUSPEND_TO_RAM, 83 /** 84 * @brief Suspend to disk state 85 * 86 * This state offers significant energy savings by powering off as much 87 * of the system as possible, including the memory. The contents of 88 * memory are written to disk or other non-volatile storage, and on 89 * resume it's read back into memory with the help of boot-strapping 90 * code, restores the system to the same point of execution where it 91 * went to suspend to disk. 92 * 93 * @note This state is correlated with ACPI S4 state 94 */ 95 PM_STATE_SUSPEND_TO_DISK, 96 /** 97 * @brief Soft off state 98 * 99 * This state consumes a minimal amount of power and requires a large 100 * latency in order to return to runtime active state. The contents of 101 * system(CPU and memory) will not be preserved, so the system will be 102 * restarted as if from initial power-up and kernel boot. 103 * 104 * @note This state is correlated with ACPI G2/S5 state 105 */ 106 PM_STATE_SOFT_OFF, 107 /** Number of power management states (internal use) */ 108 PM_STATE_COUNT, 109 }; 110 111 /** 112 * Information about a power management state 113 */ 114 struct pm_state_info { 115 enum pm_state state; 116 117 /** 118 * Some platforms have multiple states that map to 119 * one Zephyr power state. This property allows the platform 120 * distinguish them. e.g: 121 * 122 * @code{.dts} 123 * power-states { 124 * state0: state0 { 125 * compatible = "zephyr,power-state"; 126 * power-state-name = "suspend-to-idle"; 127 * substate-id = <1>; 128 * min-residency-us = <10000>; 129 * exit-latency-us = <100>; 130 * }; 131 * state1: state1 { 132 * compatible = "zephyr,power-state"; 133 * power-state-name = "suspend-to-idle"; 134 * substate-id = <2>; 135 * min-residency-us = <20000>; 136 * exit-latency-us = <200>; 137 * }; 138 * }; 139 * @endcode 140 */ 141 uint8_t substate_id; 142 143 /** 144 * Minimum residency duration in microseconds. It is the minimum 145 * time for a given idle state to be worthwhile energywise. 146 * 147 * @note 0 means that this property is not available for this state. 148 */ 149 uint32_t min_residency_us; 150 151 /** 152 * Worst case latency in microseconds required to exit the idle state. 153 * 154 * @note 0 means that this property is not available for this state. 155 */ 156 uint32_t exit_latency_us; 157 }; 158 159 /** @cond INTERNAL_HIDDEN */ 160 161 /** 162 * @brief Helper macro to initialize an entry of a struct pm_state_info array 163 * when using UTIL_LISTIFY in PM_STATE_INFO_LIST_FROM_DT_CPU. 164 * 165 * @param i UTIL_LISTIFY entry index. 166 * @param node_id A node identifier with compatible zephyr,power-state 167 */ 168 #define Z_PM_STATE_INFO_FROM_DT_CPU(i, node_id) \ 169 PM_STATE_INFO_DT_INIT(DT_PHANDLE_BY_IDX(node_id, cpu_power_states, i)) 170 171 /** 172 * @brief Helper macro to initialize an entry of a struct pm_state array when 173 * using UTIL_LISTIFY in PM_STATE_LIST_FROM_DT_CPU. 174 * 175 * @param i UTIL_LISTIFY entry index. 176 * @param node_id A node identifier with compatible zephyr,power-state 177 */ 178 #define Z_PM_STATE_FROM_DT_CPU(i, node_id) \ 179 PM_STATE_DT_INIT(DT_PHANDLE_BY_IDX(node_id, cpu_power_states, i)) 180 181 /** @endcond */ 182 183 /** 184 * @brief Initializer for struct pm_state_info given a DT node identifier with 185 * zephyr,power-state compatible. 186 * 187 * @param node_id A node identifier with compatible zephyr,power-state 188 */ 189 #define PM_STATE_INFO_DT_INIT(node_id) \ 190 { \ 191 .state = PM_STATE_DT_INIT(node_id), \ 192 .substate_id = DT_PROP_OR(node_id, substate_id, 0), \ 193 .min_residency_us = DT_PROP_OR(node_id, min_residency_us, 0), \ 194 .exit_latency_us = DT_PROP_OR(node_id, exit_latency_us, 0), \ 195 } 196 197 /** 198 * @brief Initializer for enum pm_state given a DT node identifier with 199 * zephyr,power-state compatible. 200 * 201 * @param node_id A node identifier with compatible zephyr,power-state 202 */ 203 #define PM_STATE_DT_INIT(node_id) \ 204 DT_ENUM_IDX(node_id, power_state_name) 205 206 /** 207 * @brief Obtain number of CPU power states supported by the given CPU node 208 * identifier. 209 * 210 * @param node_id A CPU node identifier. 211 * @return Number of supported CPU power states. 212 */ 213 #define DT_NUM_CPU_POWER_STATES(node_id) \ 214 DT_PROP_LEN_OR(node_id, cpu_power_states, 0) 215 216 /** 217 * @brief Initialize an array of struct pm_state_info with information from all 218 * the states present in the given CPU node identifier. 219 * 220 * Example devicetree fragment: 221 * 222 * @code{.dts} 223 * cpus { 224 * ... 225 * cpu0: cpu@0 { 226 * device_type = "cpu"; 227 * ... 228 * cpu-power-states = <&state0 &state1>; 229 * }; 230 * }; 231 * 232 * ... 233 * power-states { 234 * state0: state0 { 235 * compatible = "zephyr,power-state"; 236 * power-state-name = "suspend-to-idle"; 237 * min-residency-us = <10000>; 238 * exit-latency-us = <100>; 239 * }; 240 * 241 * state1: state1 { 242 * compatible = "zephyr,power-state"; 243 * power-state-name = "suspend-to-ram"; 244 * min-residency-us = <50000>; 245 * exit-latency-us = <500>; 246 * }; 247 * }; 248 * @endcode 249 * 250 * Example usage: 251 * 252 * @code{.c} 253 * const struct pm_state_info states[] = 254 * PM_STATE_INFO_LIST_FROM_DT_CPU(DT_NODELABEL(cpu0)); 255 * @endcode 256 * 257 * @param node_id A CPU node identifier. 258 */ 259 #define PM_STATE_INFO_LIST_FROM_DT_CPU(node_id) \ 260 { \ 261 LISTIFY(DT_NUM_CPU_POWER_STATES(node_id), \ 262 Z_PM_STATE_INFO_FROM_DT_CPU, (,), node_id) \ 263 } 264 265 /** 266 * @brief Initialize an array of struct pm_state with information from all the 267 * states present in the given CPU node identifier. 268 * 269 * Example devicetree fragment: 270 * 271 * @code{.dts} 272 * cpus { 273 * ... 274 * cpu0: cpu@0 { 275 * device_type = "cpu"; 276 * ... 277 * cpu-power-states = <&state0 &state1>; 278 * }; 279 * }; 280 * 281 * ... 282 * power-states { 283 * state0: state0 { 284 * compatible = "zephyr,power-state"; 285 * power-state-name = "suspend-to-idle"; 286 * min-residency-us = <10000>; 287 * exit-latency-us = <100>; 288 * }; 289 * 290 * state1: state1 { 291 * compatible = "zephyr,power-state"; 292 * power-state-name = "suspend-to-ram"; 293 * min-residency-us = <50000>; 294 * exit-latency-us = <500>; 295 * }; 296 * }; 297 * @endcode 298 * 299 * Example usage: 300 * 301 * @code{.c} 302 * const enum pm_state states[] = PM_STATE_LIST_FROM_DT_CPU(DT_NODELABEL(cpu0)); 303 * @endcode 304 * 305 * @param node_id A CPU node identifier. 306 */ 307 #define PM_STATE_LIST_FROM_DT_CPU(node_id) \ 308 { \ 309 LISTIFY(DT_NUM_CPU_POWER_STATES(node_id), \ 310 Z_PM_STATE_FROM_DT_CPU, (,), node_id) \ 311 } 312 313 314 /** 315 * Obtain information about all supported states by a CPU. 316 * 317 * @param cpu CPU index. 318 * @param states Where to store the list of supported states. 319 * 320 * @return Number of supported states. 321 */ 322 uint8_t pm_state_cpu_get_all(uint8_t cpu, const struct pm_state_info **states); 323 324 /** 325 * @} 326 */ 327 328 #ifdef __cplusplus 329 } 330 #endif 331 332 #endif 333