1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3  * Copyright (c) 2018, Linaro Limited
4  */
5 
6 #ifndef __KERNEL_PM_H
7 #define __KERNEL_PM_H
8 
9 #include <stdbool.h>
10 #include <stdint.h>
11 #include <tee_api_types.h>
12 
13 /*
14  * Platform hints on targeted power state. Hints are stored in a 32bit
15  * unsigned value. Lower bits defines generic resource bit flags. Higher
16  * bits stores a platform specific value specific platform driver may
17  * understand. Registered callbacks may choose to use or ignore these hints.
18  *
19  * PM_HINT_CLOCK_STATE - When set clock shall be suspended/restored
20  * PM_HINT_POWER_STATE - When set device power shall be suspended/restored
21  * PM_HINT_IO_STATE - When set IO pins shall be suspended/restored
22  * PM_HINT_CONTEXT_STATE - When set the full context be suspended/restored
23  * PM_HINT_SUSPEND_TYPE - Contains the type of suspend operation
24  * PM_HINT_PLATFORM_STATE_MASK - Bit mask reserved for platform specific hints
25  * PM_HINT_PLATFORM_STATE_SHIFT - LSBit position of platform specific hints mask
26  */
27 #define PM_HINT_CLOCK_STATE		BIT(0)
28 #define PM_HINT_POWER_STATE		BIT(1)
29 #define PM_HINT_IO_STATE		BIT(2)
30 #define PM_HINT_CONTEXT_STATE		BIT(3)
31 #define PM_HINT_SUSPEND_TYPE_MASK       GENMASK_32(5, 4)
32 #define PM_HINT_SUSPEND_TYPE_SHIFT      U(4)
33 #define PM_HINT_PLATFORM_STATE_MASK	GENMASK_32(31, 16)
34 #define PM_HINT_PLATFORM_STATE_SHIFT	U(16)
35 
36 enum pm_suspend_type {
37 	PM_SUSPEND_STANDBY,
38 	PM_SUSPEND_TO_MEM,
39 };
40 
41 #define PM_HINT_SUSPEND_TYPE(__hint) \
42 	(((__hint) & PM_HINT_SUSPEND_TYPE_MASK) >> PM_HINT_SUSPEND_TYPE_SHIFT)
43 
44 #define PM_HINT_STATE(_x)		((_x) & ~PM_HINT_PLATFORM_STATE_MASK)
45 #define PM_HINT_PLATFORM_STATE(_x) \
46 	(((_x) & PM_HINT_PLATFORM_STATE_MASK) >> PM_HINT_PLATFORM_STATE_SHIFT)
47 
48 #define PM_HINT_IS_STATE(_x, _name) ((_x) & PM_HINT_ ## _name ## _STATE)
49 
50 /*
51  * PM_OP_SUSPEND: platform is suspending to a target low power state
52  * PM_OP_RESUME: platform is resuming from low power state
53  */
54 enum pm_op {
55 	PM_OP_SUSPEND = 0,
56 	PM_OP_RESUME = 1,
57 };
58 
59 /*
60  * Registered callbacks are called the ordering directives specified
61  * by the PM_CB_ORDER_* value. Driver ordered callbacks at suspended
62  * first/resumed last. Core service ordered callbacks are suspended
63  * last/resumed first.
64  */
65 enum pm_callback_order {
66 	PM_CB_ORDER_DRIVER = 0,
67 	PM_CB_ORDER_CORE_SERVICE,
68 	PM_CB_ORDER_MAX
69 };
70 
71 #define PM_CALLBACK_HANDLE_INITIALIZER(_callback, _handle, _order, _name)\
72 		((struct pm_callback_handle){				\
73 			.callback = (_callback),			\
74 			.handle = (_handle),				\
75 			.order = (_order),				\
76 			.name = (_name),				\
77 		})
78 
79 #define PM_CALLBACK_GET_HANDLE(pm_handle)	((pm_handle)->handle)
80 
81 struct pm_callback_handle;
82 typedef TEE_Result (*pm_callback)(enum pm_op op, uint32_t pm_hint,
83 				  const struct pm_callback_handle *pm_handle);
84 
85 /*
86  * Drivers and services can register a callback function for the platform
87  * suspend and resume sequences. A private address handle can be registered
88  * with the callback and retrieved from the callback. Callback can be
89  * registered with a specific call order as defined per PM_CB_ORDER_*.
90  *
91  * Callback shall return an error if failing to complete target transition.
92  * This information may be used by the platform to resume a platform on
93  * non-fatal failure to suspend.
94  *
95  * Callback implementations should ensure their functions belong to unpaged
96  * memory sections (see DECLARE_KEEP_PAGER()) since the callback is likely to
97  * be called from an unpaged execution context.
98  *
99  * Power Mamagement callback functions API:
100  *
101  * TEE_Result (*callback)(enum pm_op op,
102  *			  unsigned int pm_hint,
103  *			  const struct pm_callback_handle *pm_handle);
104  *
105  * @op - Target operation: either PM_SUSPEND or PM_RESUME
106  * @pm_hint - Hints on power state platform suspends to /resumes from.
107  *		PM_STATE_HINT_* defines the supported values.
108  * @pm_handle - Reference to the struct pm_callback_handle related to to
109  *		registered callback. Callback can retrieve the registered
110  *		private handle with PM_CALLBACK_GET_HANDLE().
111  *
112  * Return a TEE_Result compliant return code
113  */
114 /*
115  * struct pm_callback_handle store the callback registration directives.
116  *
117  * @callback - Registered callback function
118  * @handle - Registered private handler for the callback
119  * @order - Registered callback call order priority (PM_CB_ORDER_*)
120  * @flags - Flags set by pm core to keep track of execution
121  * @name - Registered callback name
122  */
123 struct pm_callback_handle {
124 	/* Set by the caller when registering a callback */
125 	pm_callback callback;
126 	void *handle;
127 	uint8_t order;
128 	/* Set by the system according to execution context */
129 	uint8_t flags;
130 	const char *name;
131 };
132 
133 /*
134  * Register a callback for suspend/resume sequence
135  * Refer to struct pm_callback_handle for description of the callbacks
136  * API and the registration directives.
137  *
138  * @pm_handle: Reference callback registration directives
139  */
140 void register_pm_cb(struct pm_callback_handle *pm_handle);
141 
142 /*
143  * Unregister a previously registered PM callback handle
144  * Refer to struct pm_callback_handle for description of the callbacks
145  * API and the registration directives.
146  *
147  * @pm_handle: Reference previously registered
148  *
149  * This function removes from the list of the PM called callbacks the
150  * entry that match callback function reference and private handle and
151  * PM order (PM_CB_ORDER_*).
152  */
153 void unregister_pm_cb(struct pm_callback_handle *pm_handle);
154 
155 /*
156  * Register a driver callback for generic suspend/resume.
157  * Refer to struct pm_callback_handle for description of the callbacks
158  * API.
159  *
160  * @callback: Registered callback function
161  * @handle: Registered private handle argument for the callback
162  * @name: Registered callback name
163  */
register_pm_driver_cb(pm_callback callback,void * handle,const char * name)164 static inline void register_pm_driver_cb(pm_callback callback, void *handle,
165 					 const char *name)
166 {
167 	register_pm_cb(&PM_CALLBACK_HANDLE_INITIALIZER(callback, handle,
168 						       PM_CB_ORDER_DRIVER,
169 						       name));
170 }
171 
172 /*
173  * Unregister a driver callback from generic suspend/resume sequence.
174  *
175  * @callback: Callback function that what registered
176  * @handle: Private handle argument that was registered for the callback
177  */
unregister_pm_driver_cb(pm_callback callback,void * handle)178 static inline void unregister_pm_driver_cb(pm_callback callback, void *handle)
179 {
180 	unregister_pm_cb(&PM_CALLBACK_HANDLE_INITIALIZER(callback, handle,
181 							 PM_CB_ORDER_DRIVER,
182 							 NULL));
183 }
184 
185 /*
186  * Register a core service callback for generic suspend/resume.
187  * Refer to struct pm_callback_handle for description of the callbacks
188  * API.
189  *
190  * @callback: Registered callback function
191  * @handle: Registered private handle argument for the callback
192  * @name: Registered callback name
193  */
register_pm_core_service_cb(pm_callback callback,void * handle,const char * name)194 static inline void register_pm_core_service_cb(pm_callback callback,
195 					       void *handle, const char *name)
196 {
197 	register_pm_cb(&PM_CALLBACK_HANDLE_INITIALIZER(callback, handle,
198 						       PM_CB_ORDER_CORE_SERVICE,
199 						       name));
200 }
201 
202 /*
203  * Unregister a core service callback from generic suspend/resume sequences
204  *
205  * @callback: Registered callback function
206  * @handle: Private handle argument that was registered for the callback
207  */
unregister_pm_core_service_cb(pm_callback callback,void * handle)208 static inline void unregister_pm_core_service_cb(pm_callback callback,
209 						 void *handle)
210 {
211 	enum pm_callback_order order = PM_CB_ORDER_CORE_SERVICE;
212 
213 	unregister_pm_cb(&PM_CALLBACK_HANDLE_INITIALIZER(callback, handle,
214 							 order, NULL));
215 }
216 
217 /*
218  * Request call to registered PM callbacks
219  *
220  * @op: Either PM_OP_SUSPEND or PM_OP_RESUME
221  * @pm_hint: Hint (PM_HINT_*) on state the platform suspends to/resumes from.
222  *
223  * Return a TEE_Result compliant status
224  */
225 TEE_Result pm_change_state(enum pm_op op, uint32_t pm_hint);
226 
227 #endif /*__KERNEL_PM_H*/
228