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