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 :
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 1 : 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 1 : struct pm_state_info {
115 0 : 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 : * zephyr,pm-device-disabled;
138 : * };
139 : * };
140 : * @endcode
141 : */
142 1 : uint8_t substate_id;
143 :
144 : /**
145 : * Whether or not this state triggers device power management.
146 : *
147 : * When this property is false the power management subsystem
148 : * will suspend devices before entering this state and will
149 : * properly resume them when leaving it.
150 : */
151 1 : bool pm_device_disabled;
152 :
153 : /**
154 : * Minimum residency duration in microseconds. It is the minimum
155 : * time for a given idle state to be worthwhile energywise.
156 : *
157 : * @note 0 means that this property is not available for this state.
158 : */
159 1 : uint32_t min_residency_us;
160 :
161 : /**
162 : * Worst case latency in microseconds required to exit the idle state.
163 : *
164 : * @note 0 means that this property is not available for this state.
165 : */
166 1 : uint32_t exit_latency_us;
167 : };
168 :
169 : /**
170 : * Power state information needed to lock a power state.
171 : */
172 1 : struct pm_state_constraint {
173 : /**
174 : * Power management state
175 : *
176 : * @see pm_state
177 : **/
178 1 : enum pm_state state;
179 : /**
180 : * Power management sub-state
181 : *
182 : * @see pm_state
183 : **/
184 1 : uint8_t substate_id;
185 : };
186 :
187 : /** @cond INTERNAL_HIDDEN */
188 :
189 : /**
190 : * @brief Helper macro that expands to 1 if a phandle node is enabled, 0 otherwise.
191 : *
192 : * @param node_id Node identifier.
193 : * @param prop Property holding phandle-array.
194 : * @param idx Index within the array.
195 : */
196 : #define Z_DT_PHANDLE_01(node_id, prop, idx) \
197 : COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(DT_PHANDLE_BY_IDX(node_id, prop, idx)), \
198 : (1), (0))
199 :
200 : /**
201 : * @brief Helper macro to initialize an entry of a struct pm_state_info array
202 : * when using UTIL_LISTIFY in PM_STATE_INFO_LIST_FROM_DT_CPU.
203 : *
204 : * @note Only enabled states are initialized.
205 : *
206 : * @param i UTIL_LISTIFY entry index.
207 : * @param node_id A node identifier with compatible zephyr,power-state
208 : */
209 : #define Z_PM_STATE_INFO_FROM_DT_CPU(i, node_id) \
210 : COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(DT_PHANDLE_BY_IDX(node_id, cpu_power_states, i)), \
211 : (PM_STATE_INFO_DT_INIT(DT_PHANDLE_BY_IDX(node_id, cpu_power_states, i)),), ())
212 :
213 : /**
214 : * @brief Helper macro to initialize an entry of a struct pm_state array when
215 : * using UTIL_LISTIFY in PM_STATE_LIST_FROM_DT_CPU.
216 : *
217 : * @note Only enabled states are initialized.
218 : *
219 : * @param i UTIL_LISTIFY entry index.
220 : * @param node_id A node identifier with compatible zephyr,power-state
221 : */
222 : #define Z_PM_STATE_FROM_DT_CPU(i, node_id) \
223 : COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(DT_PHANDLE_BY_IDX(node_id, cpu_power_states, i)), \
224 : (PM_STATE_DT_INIT(DT_PHANDLE_BY_IDX(node_id, cpu_power_states, i)),), ())
225 :
226 : /** @endcond */
227 :
228 : /**
229 : * @brief Initializer for struct pm_state_info given a DT node identifier with
230 : * zephyr,power-state compatible.
231 : *
232 : * @param node_id A node identifier with compatible zephyr,power-state
233 : */
234 1 : #define PM_STATE_INFO_DT_INIT(node_id) \
235 : { \
236 : .state = PM_STATE_DT_INIT(node_id), \
237 : .substate_id = DT_PROP_OR(node_id, substate_id, 0), \
238 : .min_residency_us = DT_PROP_OR(node_id, min_residency_us, 0), \
239 : .exit_latency_us = DT_PROP_OR(node_id, exit_latency_us, 0), \
240 : .pm_device_disabled = DT_PROP(node_id, zephyr_pm_device_disabled), \
241 : }
242 :
243 : /**
244 : * @brief Initializer for enum pm_state given a DT node identifier with
245 : * zephyr,power-state compatible.
246 : *
247 : * @param node_id A node identifier with compatible zephyr,power-state
248 : */
249 1 : #define PM_STATE_DT_INIT(node_id) \
250 : DT_ENUM_IDX(node_id, power_state_name)
251 :
252 : /**
253 : * @brief Obtain number of CPU power states supported and enabled by the given
254 : * CPU node identifier.
255 : *
256 : * @param node_id A CPU node identifier.
257 : * @return Number of supported and enabled CPU power states.
258 : */
259 1 : #define DT_NUM_CPU_POWER_STATES(node_id) \
260 : COND_CODE_1(DT_NODE_HAS_PROP(node_id, cpu_power_states), \
261 : (DT_FOREACH_PROP_ELEM_SEP(node_id, cpu_power_states, Z_DT_PHANDLE_01, (+))), \
262 : (0))
263 :
264 : /**
265 : * @brief Initialize an array of struct pm_state_info with information from all
266 : * the states present and enabled in the given CPU node identifier.
267 : *
268 : * Example devicetree fragment:
269 : *
270 : * @code{.dts}
271 : * cpus {
272 : * ...
273 : * cpu0: cpu@0 {
274 : * device_type = "cpu";
275 : * ...
276 : * cpu-power-states = <&state0 &state1>;
277 : * };
278 : *
279 : * power-states {
280 : * state0: state0 {
281 : * compatible = "zephyr,power-state";
282 : * power-state-name = "suspend-to-idle";
283 : * min-residency-us = <10000>;
284 : * exit-latency-us = <100>;
285 : * };
286 : *
287 : * state1: state1 {
288 : * compatible = "zephyr,power-state";
289 : * power-state-name = "suspend-to-ram";
290 : * min-residency-us = <50000>;
291 : * exit-latency-us = <500>;
292 : * zephyr,pm-device-disabled;
293 : * };
294 : * };
295 : * };
296 :
297 : * @endcode
298 : *
299 : * Example usage:
300 : *
301 : * @code{.c}
302 : * const struct pm_state_info states[] =
303 : * PM_STATE_INFO_LIST_FROM_DT_CPU(DT_NODELABEL(cpu0));
304 : * @endcode
305 : *
306 : * @param node_id A CPU node identifier.
307 : */
308 1 : #define PM_STATE_INFO_LIST_FROM_DT_CPU(node_id) \
309 : { \
310 : LISTIFY(DT_PROP_LEN_OR(node_id, cpu_power_states, 0), \
311 : Z_PM_STATE_INFO_FROM_DT_CPU, (), node_id) \
312 : }
313 :
314 : /**
315 : * @brief Initialize an array of struct pm_state with information from all the
316 : * states present and enabled in the given CPU node identifier.
317 : *
318 : * Example devicetree fragment:
319 : *
320 : * @code{.dts}
321 : * cpus {
322 : * ...
323 : * cpu0: cpu@0 {
324 : * device_type = "cpu";
325 : * ...
326 : * cpu-power-states = <&state0 &state1>;
327 : * };
328 : *
329 : * power-states {
330 : * state0: state0 {
331 : * compatible = "zephyr,power-state";
332 : * power-state-name = "suspend-to-idle";
333 : * min-residency-us = <10000>;
334 : * exit-latency-us = <100>;
335 : * };
336 : *
337 : * state1: state1 {
338 : * compatible = "zephyr,power-state";
339 : * power-state-name = "suspend-to-ram";
340 : * min-residency-us = <50000>;
341 : * exit-latency-us = <500>;
342 : * };
343 : * };
344 : * };
345 : * @endcode
346 : *
347 : * Example usage:
348 : *
349 : * @code{.c}
350 : * const enum pm_state states[] = PM_STATE_LIST_FROM_DT_CPU(DT_NODELABEL(cpu0));
351 : * @endcode
352 : *
353 : * @param node_id A CPU node identifier.
354 : */
355 1 : #define PM_STATE_LIST_FROM_DT_CPU(node_id) \
356 : { \
357 : LISTIFY(DT_PROP_LEN_OR(node_id, cpu_power_states, 0), \
358 : Z_PM_STATE_FROM_DT_CPU, (), node_id) \
359 : }
360 :
361 :
362 : #if defined(CONFIG_PM) || defined(__DOXYGEN__)
363 : /**
364 : * Obtain information about all supported states by a CPU.
365 : *
366 : * @param cpu CPU index.
367 : * @param states Where to store the list of supported states.
368 : *
369 : * @return Number of supported states.
370 : */
371 1 : uint8_t pm_state_cpu_get_all(uint8_t cpu, const struct pm_state_info **states);
372 :
373 : /**
374 : * @}
375 : */
376 :
377 : #else /* CONFIG_PM */
378 :
379 : static inline uint8_t pm_state_cpu_get_all(uint8_t cpu, const struct pm_state_info **states)
380 : {
381 : ARG_UNUSED(cpu);
382 : ARG_UNUSED(states);
383 :
384 : return 0;
385 : }
386 :
387 : #endif /* CONFIG_PM */
388 :
389 : #ifdef __cplusplus
390 : }
391 : #endif
392 :
393 : #endif
|