Line data Source code
1 0 : /*
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 : #include <errno.h>
13 :
14 : #ifdef __cplusplus
15 : extern "C" {
16 : #endif
17 :
18 : /**
19 : * @brief System Power Management States
20 : * @defgroup subsys_pm_states States
21 : * @ingroup subsys_pm
22 : * @{
23 : */
24 :
25 : /**
26 : * @enum pm_state Power management state
27 : */
28 1 : enum pm_state {
29 : /**
30 : * @brief Runtime active state
31 : *
32 : * The system is fully powered and active.
33 : *
34 : * @note This state is correlated with ACPI G0/S0 state
35 : */
36 : PM_STATE_ACTIVE,
37 : /**
38 : * @brief Runtime idle state
39 : *
40 : * Runtime idle is a system sleep state in which all of the cores
41 : * enter deepest possible idle state and wait for interrupts, no
42 : * requirements for the devices, leaving them at the states where
43 : * they are.
44 : *
45 : * @note This state is correlated with ACPI S0ix state
46 : */
47 : PM_STATE_RUNTIME_IDLE,
48 : /**
49 : * @brief Suspend to idle state
50 : *
51 : * The system goes through a normal platform suspend where it puts
52 : * all of the cores in deepest possible idle state and *may* puts
53 : * peripherals into low-power states. No operating state is lost (ie.
54 : * the cpu core does not lose execution context), so the system can go
55 : * back to where it left off easily enough.
56 : *
57 : * @note This state is correlated with ACPI S1 state
58 : */
59 : PM_STATE_SUSPEND_TO_IDLE,
60 : /**
61 : * @brief Standby state
62 : *
63 : * In addition to putting peripherals into low-power states all
64 : * non-boot CPUs are powered off. It should allow more energy to be
65 : * saved relative to suspend to idle, but the resume latency will
66 : * generally be greater than for that state. But it should be the same
67 : * state with suspend to idle state on uniprocessor system.
68 : *
69 : * @note This state is correlated with ACPI S2 state
70 : */
71 : PM_STATE_STANDBY,
72 : /**
73 : * @brief Suspend to ram state
74 : *
75 : * This state offers significant energy savings by powering off as much
76 : * of the system as possible, where memory should be placed into the
77 : * self-refresh mode to retain its contents. The state of devices and
78 : * CPUs is saved and held in memory, and it may require some boot-
79 : * strapping code in ROM to resume the system from it.
80 : *
81 : * @note This state is correlated with ACPI S3 state
82 : */
83 : PM_STATE_SUSPEND_TO_RAM,
84 : /**
85 : * @brief Suspend to disk state
86 : *
87 : * This state offers significant energy savings by powering off as much
88 : * of the system as possible, including the memory. The contents of
89 : * memory are written to disk or other non-volatile storage, and on
90 : * resume it's read back into memory with the help of boot-strapping
91 : * code, restores the system to the same point of execution where it
92 : * went to suspend to disk.
93 : *
94 : * @note This state is correlated with ACPI S4 state
95 : */
96 : PM_STATE_SUSPEND_TO_DISK,
97 : /**
98 : * @brief Soft off state
99 : *
100 : * This state consumes a minimal amount of power and requires a large
101 : * latency in order to return to runtime active state. The contents of
102 : * system(CPU and memory) will not be preserved, so the system will be
103 : * restarted as if from initial power-up and kernel boot.
104 : *
105 : * @note This state is correlated with ACPI G2/S5 state
106 : */
107 : PM_STATE_SOFT_OFF,
108 : /** Number of power management states (internal use) */
109 : PM_STATE_COUNT,
110 : };
111 :
112 : /**
113 : * Information about a power management state
114 : */
115 1 : struct pm_state_info {
116 0 : enum pm_state state;
117 :
118 : /**
119 : * Some platforms have multiple states that map to
120 : * one Zephyr power state. This property allows the platform
121 : * distinguish them. e.g:
122 : *
123 : * @code{.dts}
124 : * power-states {
125 : * state0: state0 {
126 : * compatible = "zephyr,power-state";
127 : * power-state-name = "suspend-to-idle";
128 : * substate-id = <1>;
129 : * min-residency-us = <10000>;
130 : * exit-latency-us = <100>;
131 : * };
132 : * state1: state1 {
133 : * compatible = "zephyr,power-state";
134 : * power-state-name = "suspend-to-idle";
135 : * substate-id = <2>;
136 : * min-residency-us = <20000>;
137 : * exit-latency-us = <200>;
138 : * zephyr,pm-device-disabled;
139 : * };
140 : * };
141 : * @endcode
142 : */
143 1 : uint8_t substate_id;
144 :
145 : /**
146 : * Whether or not this state triggers device power management.
147 : *
148 : * When this property is false the power management subsystem
149 : * will suspend devices before entering this state and will
150 : * properly resume them when leaving it.
151 : */
152 1 : bool pm_device_disabled;
153 :
154 : /**
155 : * Minimum residency duration in microseconds. It is the minimum
156 : * time for a given idle state to be worthwhile energywise.
157 : *
158 : * @note 0 means that this property is not available for this state.
159 : */
160 1 : uint32_t min_residency_us;
161 :
162 : /**
163 : * Worst case latency in microseconds required to exit the idle state.
164 : *
165 : * @note 0 means that this property is not available for this state.
166 : */
167 1 : uint32_t exit_latency_us;
168 : };
169 :
170 : /**
171 : * Power state information needed to lock a power state.
172 : */
173 1 : struct pm_state_constraint {
174 : /**
175 : * Power management state
176 : *
177 : * @see pm_state
178 : **/
179 1 : enum pm_state state;
180 : /**
181 : * Power management sub-state
182 : *
183 : * @see pm_state
184 : **/
185 1 : uint8_t substate_id;
186 : };
187 :
188 : /** @cond INTERNAL_HIDDEN */
189 :
190 : /**
191 : * @brief Helper macro that expands to 1 if a phandle node is enabled, 0 otherwise.
192 : *
193 : * @param node_id Node identifier.
194 : * @param prop Property holding phandle-array.
195 : * @param idx Index within the array.
196 : */
197 : #define Z_DT_PHANDLE_01(node_id, prop, idx) \
198 : COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(DT_PHANDLE_BY_IDX(node_id, prop, idx)), \
199 : (1), (0))
200 :
201 : /**
202 : * @brief Helper macro to initialize an entry of a struct pm_state_info array
203 : * when using UTIL_LISTIFY in PM_STATE_INFO_LIST_FROM_DT_CPU.
204 : *
205 : * @note Only enabled states are initialized.
206 : *
207 : * @param i UTIL_LISTIFY entry index.
208 : * @param node_id A node identifier with compatible zephyr,power-state
209 : */
210 : #define Z_PM_STATE_INFO_FROM_DT_CPU(i, node_id) \
211 : COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(DT_PHANDLE_BY_IDX(node_id, cpu_power_states, i)), \
212 : (PM_STATE_INFO_DT_INIT(DT_PHANDLE_BY_IDX(node_id, cpu_power_states, i)),), ())
213 :
214 : /**
215 : * @brief Helper macro to initialize an entry of a struct pm_state array when
216 : * using UTIL_LISTIFY in PM_STATE_LIST_FROM_DT_CPU.
217 : *
218 : * @note Only enabled states are initialized.
219 : *
220 : * @param i UTIL_LISTIFY entry index.
221 : * @param node_id A node identifier with compatible zephyr,power-state
222 : */
223 : #define Z_PM_STATE_FROM_DT_CPU(i, node_id) \
224 : COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(DT_PHANDLE_BY_IDX(node_id, cpu_power_states, i)), \
225 : (PM_STATE_DT_INIT(DT_PHANDLE_BY_IDX(node_id, cpu_power_states, i)),), ())
226 :
227 : /** @endcond */
228 :
229 : /**
230 : * @brief Initializer for struct pm_state_info given a DT node identifier with
231 : * zephyr,power-state compatible.
232 : *
233 : * @param node_id A node identifier with compatible zephyr,power-state
234 : */
235 1 : #define PM_STATE_INFO_DT_INIT(node_id) \
236 : { \
237 : .state = PM_STATE_DT_INIT(node_id), \
238 : .substate_id = DT_PROP_OR(node_id, substate_id, 0), \
239 : .min_residency_us = DT_PROP_OR(node_id, min_residency_us, 0), \
240 : .exit_latency_us = DT_PROP_OR(node_id, exit_latency_us, 0), \
241 : .pm_device_disabled = DT_PROP(node_id, zephyr_pm_device_disabled), \
242 : }
243 :
244 : /**
245 : * @brief Initializer for enum pm_state given a DT node identifier with
246 : * zephyr,power-state compatible.
247 : *
248 : * @param node_id A node identifier with compatible zephyr,power-state
249 : */
250 1 : #define PM_STATE_DT_INIT(node_id) \
251 : DT_ENUM_IDX(node_id, power_state_name)
252 :
253 : /**
254 : * @brief Obtain number of CPU power states supported and enabled by the given
255 : * CPU node identifier.
256 : *
257 : * @param node_id A CPU node identifier.
258 : * @return Number of supported and enabled CPU power states.
259 : */
260 1 : #define DT_NUM_CPU_POWER_STATES(node_id) \
261 : COND_CODE_1(DT_NODE_HAS_PROP(node_id, cpu_power_states), \
262 : (DT_FOREACH_PROP_ELEM_SEP(node_id, cpu_power_states, Z_DT_PHANDLE_01, (+))), \
263 : (0))
264 :
265 : /**
266 : * @brief Initialize an array of struct pm_state_info with information from all
267 : * the states present and enabled 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 : * power-states {
281 : * state0: state0 {
282 : * compatible = "zephyr,power-state";
283 : * power-state-name = "suspend-to-idle";
284 : * min-residency-us = <10000>;
285 : * exit-latency-us = <100>;
286 : * };
287 : *
288 : * state1: state1 {
289 : * compatible = "zephyr,power-state";
290 : * power-state-name = "suspend-to-ram";
291 : * min-residency-us = <50000>;
292 : * exit-latency-us = <500>;
293 : * zephyr,pm-device-disabled;
294 : * };
295 : * };
296 : * };
297 :
298 : * @endcode
299 : *
300 : * Example usage:
301 : *
302 : * @code{.c}
303 : * const struct pm_state_info states[] =
304 : * PM_STATE_INFO_LIST_FROM_DT_CPU(DT_NODELABEL(cpu0));
305 : * @endcode
306 : *
307 : * @param node_id A CPU node identifier.
308 : */
309 1 : #define PM_STATE_INFO_LIST_FROM_DT_CPU(node_id) \
310 : { \
311 : LISTIFY(DT_PROP_LEN_OR(node_id, cpu_power_states, 0), \
312 : Z_PM_STATE_INFO_FROM_DT_CPU, (), node_id) \
313 : }
314 :
315 : /**
316 : * @brief Initialize an array of struct pm_state with information from all the
317 : * states present and enabled in the given CPU node identifier.
318 : *
319 : * Example devicetree fragment:
320 : *
321 : * @code{.dts}
322 : * cpus {
323 : * ...
324 : * cpu0: cpu@0 {
325 : * device_type = "cpu";
326 : * ...
327 : * cpu-power-states = <&state0 &state1>;
328 : * };
329 : *
330 : * power-states {
331 : * state0: state0 {
332 : * compatible = "zephyr,power-state";
333 : * power-state-name = "suspend-to-idle";
334 : * min-residency-us = <10000>;
335 : * exit-latency-us = <100>;
336 : * };
337 : *
338 : * state1: state1 {
339 : * compatible = "zephyr,power-state";
340 : * power-state-name = "suspend-to-ram";
341 : * min-residency-us = <50000>;
342 : * exit-latency-us = <500>;
343 : * };
344 : * };
345 : * };
346 : * @endcode
347 : *
348 : * Example usage:
349 : *
350 : * @code{.c}
351 : * const enum pm_state states[] = PM_STATE_LIST_FROM_DT_CPU(DT_NODELABEL(cpu0));
352 : * @endcode
353 : *
354 : * @param node_id A CPU node identifier.
355 : */
356 1 : #define PM_STATE_LIST_FROM_DT_CPU(node_id) \
357 : { \
358 : LISTIFY(DT_PROP_LEN_OR(node_id, cpu_power_states, 0), \
359 : Z_PM_STATE_FROM_DT_CPU, (), node_id) \
360 : }
361 :
362 :
363 : #if defined(CONFIG_PM) || defined(__DOXYGEN__)
364 : /**
365 : * Obtain information about all supported states by a CPU.
366 : *
367 : * @param cpu CPU index.
368 : * @param states Where to store the list of supported states.
369 : *
370 : * @return Number of supported states.
371 : */
372 1 : uint8_t pm_state_cpu_get_all(uint8_t cpu, const struct pm_state_info **states);
373 :
374 : /**
375 : * Get power state structure.
376 : *
377 : * Function searches in all states assigned to the CPU and in disabled states.
378 : *
379 : * @param cpu CPU index.
380 : * @param state Power state.
381 : * @param substate_id Substate.
382 : *
383 : * @return Pointer to the power state structure or NULL if state is not found.
384 : */
385 1 : const struct pm_state_info *pm_state_get(uint8_t cpu, enum pm_state state, uint8_t substate_id);
386 :
387 : /**
388 : * @brief Convert a pm_state enum value to its string representation.
389 : *
390 : * @param state Power state.
391 : *
392 : * @return A constant string representing the state.
393 : */
394 1 : const char *pm_state_to_str(enum pm_state state);
395 :
396 :
397 : /**
398 : * @brief Parse a string and convert it to a pm_state enum value.
399 : *
400 : * @param name Input string (e.g., "suspend-to-ram").
401 : * @param out Pointer to store the parsed pm_state value.
402 : *
403 : * @return 0 on success, -EINVAL if the string is invalid or NULL.
404 : */
405 1 : int pm_state_from_str(const char *name, enum pm_state *out);
406 : /**
407 : * @}
408 : */
409 :
410 : #else /* CONFIG_PM */
411 :
412 : static inline uint8_t pm_state_cpu_get_all(uint8_t cpu, const struct pm_state_info **states)
413 : {
414 : ARG_UNUSED(cpu);
415 : ARG_UNUSED(states);
416 :
417 : return 0;
418 : }
419 :
420 : static inline const struct pm_state_info *pm_state_get(uint8_t cpu,
421 : enum pm_state state,
422 : uint8_t substate_id)
423 : {
424 : ARG_UNUSED(cpu);
425 : ARG_UNUSED(state);
426 : ARG_UNUSED(substate_id);
427 :
428 : return NULL;
429 : }
430 :
431 : #endif /* CONFIG_PM */
432 :
433 : #ifdef __cplusplus
434 : }
435 : #endif
436 :
437 : #endif
|