1 /*
2  * Copyright (c) 2023, Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef ZEPHYR_INCLUDE_SIP_SVC_DRIVER_H_
8 #define ZEPHYR_INCLUDE_SIP_SVC_DRIVER_H_
9 
10 #include <zephyr/device.h>
11 #include <zephyr/kernel.h>
12 #include <zephyr/arch/arm64/arm-smccc.h>
13 #include <zephyr/drivers/sip_svc/sip_svc_proto.h>
14 #include <zephyr/sip_svc/sip_svc_controller.h>
15 
16 #define DEV_API(dev) ((struct svc_driver_api *)(dev)->api)
17 
18 /**
19  * @brief Length of SVC conduit name.
20  *
21  */
22 #define SVC_CONDUIT_NAME_LENGTH (4)
23 
24 /**
25  * @brief Callback API for executing the supervisory call
26  * See @a sip_supervisory_call() for argument description
27  */
28 typedef void (*sip_supervisory_call_t)(const struct device *dev, unsigned long function_id,
29 				       unsigned long arg0, unsigned long arg1, unsigned long arg2,
30 				       unsigned long arg3, unsigned long arg4, unsigned long arg5,
31 				       unsigned long arg6, struct arm_smccc_res *res);
32 
33 /**
34  * @brief Callback API for validating function id for the supervisory call.
35  * See @a sip_svc_plat_func_id_valid() for argument description
36  */
37 typedef bool (*sip_svc_plat_func_id_valid_t)(const struct device *dev, uint32_t command,
38 					     uint32_t func_id);
39 
40 /**
41  * @brief Callback API for generating the transaction id from client id.
42  * See @a sip_svc_plat_format_trans_id() for argument description
43  */
44 typedef uint32_t (*sip_svc_plat_format_trans_id_t)(const struct device *dev, uint32_t client_idx,
45 						   uint32_t trans_idx);
46 
47 /**
48  * @brief Callback API for retrieving client transaction id from transaction id
49  * See @a sip_svc_plat_get_trans_idx() for argument description
50  */
51 typedef uint32_t (*sip_svc_plat_get_trans_idx_t)(const struct device *dev, uint32_t trans_id);
52 
53 /**
54  * @brief Callback API for updating transaction id for request packet for lower layer
55  * See @a sip_svc_plat_update_trans_id() for argument description
56  */
57 typedef void (*sip_svc_plat_update_trans_id_t)(const struct device *dev,
58 					       struct sip_svc_request *request, uint32_t trans_id);
59 
60 /**
61  * @brief Callback API for freeing command buffer in ASYNC packets
62  * See @a sip_svc_plat_free_async_memory() for argument description
63  */
64 typedef void (*sip_svc_plat_free_async_memory_t)(const struct device *dev,
65 						 struct sip_svc_request *request);
66 
67 /**
68  * @brief Callback API to construct Polling packet for ASYNC transaction.
69  * See @a sip_svc_plat_async_res_req() for argument description
70  */
71 typedef int (*sip_svc_plat_async_res_req_t)(const struct device *dev, unsigned long *a0,
72 					    unsigned long *a1, unsigned long *a2, unsigned long *a3,
73 					    unsigned long *a4, unsigned long *a5, unsigned long *a6,
74 					    unsigned long *a7, char *buf, size_t size);
75 
76 /**
77  * @brief Callback API to check the response of polling request
78  * See @a sip_svc_plat_async_res_res() for argument description
79  */
80 typedef int (*sip_svc_plat_async_res_res_t)(const struct device *dev, struct arm_smccc_res *res,
81 					    char *buf, size_t *size, uint32_t *trans_id);
82 
83 /**
84  * @brief Callback API for retrieving error code from a supervisory call response.
85  * See @a sip_svc_plat_get_error_code() for argument description.
86  */
87 typedef uint32_t (*sip_svc_plat_get_error_code_t)(const struct device *dev,
88 						  struct arm_smccc_res *res);
89 
90 /**
91  * @brief  API structure for sip_svc driver.
92  *
93  */
94 __subsystem struct svc_driver_api {
95 	sip_supervisory_call_t sip_supervisory_call;
96 	sip_svc_plat_func_id_valid_t sip_svc_plat_func_id_valid;
97 	sip_svc_plat_format_trans_id_t sip_svc_plat_format_trans_id;
98 	sip_svc_plat_get_trans_idx_t sip_svc_plat_get_trans_idx;
99 	sip_svc_plat_update_trans_id_t sip_svc_plat_update_trans_id;
100 	sip_svc_plat_free_async_memory_t sip_svc_plat_free_async_memory;
101 	sip_svc_plat_async_res_req_t sip_svc_plat_async_res_req;
102 	sip_svc_plat_async_res_res_t sip_svc_plat_async_res_res;
103 	sip_svc_plat_get_error_code_t sip_svc_plat_get_error_code;
104 };
105 
106 /**
107  * @brief supervisory call function which will execute the smc/hvc call
108  *
109  * @param dev  Pointer to the device structure for the driver instance.
110  * @param function_id  Function identifier for the supervisory call.
111  * @param arg0  Argument 0 for supervisory call.
112  * @param arg1  Argument 1 for supervisory call.
113  * @param arg2  Argument 2 for supervisory call.
114  * @param arg3  Argument 3 for supervisory call.
115  * @param arg4  Argument 4 for supervisory call.
116  * @param arg5  Argument 5 for supervisory call.
117  * @param arg6  Argument 6 for supervisory call.
118  * @param res Pointer to response buffer for supervisory call.
119  */
120 __syscall void sip_supervisory_call(const struct device *dev, unsigned long function_id,
121 				    unsigned long arg0, unsigned long arg1, unsigned long arg2,
122 				    unsigned long arg3, unsigned long arg4, unsigned long arg5,
123 				    unsigned long arg6, struct arm_smccc_res *res);
z_impl_sip_supervisory_call(const struct device * dev,unsigned long function_id,unsigned long arg0,unsigned long arg1,unsigned long arg2,unsigned long arg3,unsigned long arg4,unsigned long arg5,unsigned long arg6,struct arm_smccc_res * res)124 static inline void z_impl_sip_supervisory_call(const struct device *dev, unsigned long function_id,
125 					       unsigned long arg0, unsigned long arg1,
126 					       unsigned long arg2, unsigned long arg3,
127 					       unsigned long arg4, unsigned long arg5,
128 					       unsigned long arg6, struct arm_smccc_res *res)
129 {
130 	__ASSERT(dev, "dev shouldn't be NULL");
131 	const struct svc_driver_api *api = DEV_API(dev);
132 
133 	__ASSERT(api->sip_supervisory_call, "sip_supervisory_call shouldn't be NULL");
134 	__ASSERT(res, "response pointer shouldn't be NULL");
135 
136 	api->sip_supervisory_call(dev, function_id, arg0, arg1, arg2, arg3, arg4, arg5, arg6, res);
137 }
138 
139 /**
140  * @brief Validate the function id for the supervisory call.
141  *
142  * @param dev  Pointer to the device structure for the driver instance.
143  * @param command  Command which specify if the call is SYNC or ASYNC.
144  * @param func_id  Function identifier
145  *
146  * @retval true if command and function identifiers are valid.
147  * @retval false if command and function identifiers are invalid.
148  */
149 __syscall bool sip_svc_plat_func_id_valid(const struct device *dev, uint32_t command,
150 					  uint32_t func_id);
z_impl_sip_svc_plat_func_id_valid(const struct device * dev,uint32_t command,uint32_t func_id)151 static inline bool z_impl_sip_svc_plat_func_id_valid(const struct device *dev, uint32_t command,
152 						     uint32_t func_id)
153 {
154 	__ASSERT(dev, "dev shouldn't be NULL");
155 	const struct svc_driver_api *api = DEV_API(dev);
156 
157 	__ASSERT(api->sip_svc_plat_func_id_valid,
158 		 "sip_svc_plat_func_id_valid func shouldn't be NULL");
159 
160 	return api->sip_svc_plat_func_id_valid(dev, command, func_id);
161 }
162 
163 /**
164  * @brief Formats and generates the transaction id from client id.
165  *
166  * @param dev  Pointer to the device structure for the driver instance.
167  * @param client_idx client index.
168  * @param trans_idx transaction index.
169  *
170  * @retval transaction id, which is used for tracking each transaction.
171  */
172 __syscall uint32_t sip_svc_plat_format_trans_id(const struct device *dev, uint32_t client_idx,
173 						uint32_t trans_idx);
z_impl_sip_svc_plat_format_trans_id(const struct device * dev,uint32_t client_idx,uint32_t trans_idx)174 static inline uint32_t z_impl_sip_svc_plat_format_trans_id(const struct device *dev,
175 							   uint32_t client_idx, uint32_t trans_idx)
176 {
177 	__ASSERT(dev, "dev shouldn't be NULL");
178 	const struct svc_driver_api *api = DEV_API(dev);
179 
180 	__ASSERT(api->sip_svc_plat_format_trans_id,
181 		 "sip_svc_plat_format_trans_id func shouldn't be NULL");
182 
183 	return api->sip_svc_plat_format_trans_id(dev, client_idx, trans_idx);
184 }
185 
186 /**
187  * @brief Retrieve client transaction id from packet transaction id.
188  *
189  * @param dev  Pointer to the device structure for the driver instance.
190  * @param trans_id transaction identifier if for a transaction.
191  *
192  * @retval client transaction id form Transaction id.
193  */
194 __syscall uint32_t sip_svc_plat_get_trans_idx(const struct device *dev, uint32_t trans_id);
z_impl_sip_svc_plat_get_trans_idx(const struct device * dev,uint32_t trans_id)195 static inline uint32_t z_impl_sip_svc_plat_get_trans_idx(const struct device *dev,
196 							 uint32_t trans_id)
197 {
198 	__ASSERT(dev, "dev shouldn't be NULL");
199 	const struct svc_driver_api *api = DEV_API(dev);
200 
201 	__ASSERT(api->sip_svc_plat_get_trans_idx,
202 		 "sip_svc_plat_get_trans_idx func shouldn't be NULL");
203 
204 	return api->sip_svc_plat_get_trans_idx(dev, trans_id);
205 }
206 
207 /**
208  * @brief Update transaction id for sip_svc_request for lower layer.
209  *
210  * @param dev  Pointer to the device structure for the driver instance.
211  * @param request  Pointer to sip_svc_request structure.
212  * @param trans_id Transaction id.
213  */
214 __syscall void sip_svc_plat_update_trans_id(const struct device *dev,
215 					    struct sip_svc_request *request, uint32_t trans_id);
z_impl_sip_svc_plat_update_trans_id(const struct device * dev,struct sip_svc_request * request,uint32_t trans_id)216 static inline void z_impl_sip_svc_plat_update_trans_id(const struct device *dev,
217 						       struct sip_svc_request *request,
218 						       uint32_t trans_id)
219 {
220 	__ASSERT(dev, "dev shouldn't be NULL");
221 	const struct svc_driver_api *api = DEV_API(dev);
222 
223 	__ASSERT(api->sip_svc_plat_update_trans_id,
224 		 "sip_svc_plat_update_trans_id func shouldn't be NULL");
225 	__ASSERT(request, "request shouldn't be NULL");
226 
227 	return api->sip_svc_plat_update_trans_id(dev, request, trans_id);
228 }
229 
230 /**
231  * @brief Retrieve the error code from arm_smccc_res response.
232  *
233  * @param dev  Pointer to the device structure for the driver instance.
234  * @param res  Pointer to struct arm_smccc_res response.
235  *
236  * @retval 0 on success.
237  * @retval SIP_SVC_ID_INVALID on failure
238  */
239 __syscall uint32_t sip_svc_plat_get_error_code(const struct device *dev, struct arm_smccc_res *res);
z_impl_sip_svc_plat_get_error_code(const struct device * dev,struct arm_smccc_res * res)240 static inline uint32_t z_impl_sip_svc_plat_get_error_code(const struct device *dev,
241 							  struct arm_smccc_res *res)
242 {
243 	__ASSERT(dev, "dev shouldn't be NULL");
244 	const struct svc_driver_api *api = DEV_API(dev);
245 
246 	__ASSERT(api->sip_svc_plat_get_error_code,
247 		 "sip_svc_plat_get_error_code func shouldn't be NULL");
248 	__ASSERT(res, "res shouldn't be NULL");
249 
250 	return api->sip_svc_plat_get_error_code(dev, res);
251 }
252 
253 /**
254  * @brief Set arguments for polling supervisory call. For ASYNC polling of response.
255  *
256  * @param dev  Pointer to the device structure for the driver instance.
257  * @param a0  Argument 0 for supervisory call.
258  * @param a1  Argument 1 for supervisory call.
259  * @param a2  Argument 2 for supervisory call.
260  * @param a3  Argument 3 for supervisory call.
261  * @param a4  Argument 4 for supervisory call.
262  * @param a5  Argument 5 for supervisory call.
263  * @param a6  Argument 6 for supervisory call.
264  * @param a7  Argument 7 for supervisory call.
265  * @param buf Pointer for response buffer.
266  * @param size Size of response buffer.
267  *
268  * @retval  0 on success
269  */
270 __syscall int sip_svc_plat_async_res_req(const struct device *dev, unsigned long *a0,
271 					 unsigned long *a1, unsigned long *a2, unsigned long *a3,
272 					 unsigned long *a4, unsigned long *a5, unsigned long *a6,
273 					 unsigned long *a7, char *buf, size_t size);
z_impl_sip_svc_plat_async_res_req(const struct device * dev,unsigned long * a0,unsigned long * a1,unsigned long * a2,unsigned long * a3,unsigned long * a4,unsigned long * a5,unsigned long * a6,unsigned long * a7,char * buf,size_t size)274 static inline int z_impl_sip_svc_plat_async_res_req(const struct device *dev, unsigned long *a0,
275 						    unsigned long *a1, unsigned long *a2,
276 						    unsigned long *a3, unsigned long *a4,
277 						    unsigned long *a5, unsigned long *a6,
278 						    unsigned long *a7, char *buf, size_t size)
279 {
280 	__ASSERT(dev, "dev shouldn't be NULL");
281 	const struct svc_driver_api *api = DEV_API(dev);
282 
283 	__ASSERT(api->sip_svc_plat_async_res_req,
284 		 "sip_svc_plat_async_res_req func shouldn't be NULL");
285 	__ASSERT(a0, "a0 shouldn't be NULL");
286 	__ASSERT(a1, "a1 shouldn't be NULL");
287 	__ASSERT(a2, "a2 shouldn't be NULL");
288 	__ASSERT(a3, "a3 shouldn't be NULL");
289 	__ASSERT(a4, "a4 shouldn't be NULL");
290 	__ASSERT(a5, "a5 shouldn't be NULL");
291 	__ASSERT(a6, "a6 shouldn't be NULL");
292 	__ASSERT(a7, "a7 shouldn't be NULL");
293 	__ASSERT(((buf == NULL && size == 0) || (buf != NULL && size != 0)),
294 		 "buf and size should represent a buffer");
295 	return api->sip_svc_plat_async_res_req(dev, a0, a1, a2, a3, a4, a5, a6, a7, buf, size);
296 }
297 
298 /**
299  * @brief Check the response of polling supervisory call and retrieve the response
300  *        size and transaction id.
301  *
302  * @param dev  Pointer to the device structure for the driver instance.
303  * @param res  Pointer to struct arm_smccc_res response.
304  * @param buf  Pointer to response buffer.
305  * @param size  Size of response in response buffer
306  * @param trans_id  Transaction id of the response.
307  *
308  * @retval 0 on getting a valid polling response from supervisory call.
309  * @retval -EINPROGRESS on no valid polling response from supervisory call.
310  */
311 __syscall int sip_svc_plat_async_res_res(const struct device *dev, struct arm_smccc_res *res,
312 					 char *buf, size_t *size, uint32_t *trans_id);
z_impl_sip_svc_plat_async_res_res(const struct device * dev,struct arm_smccc_res * res,char * buf,size_t * size,uint32_t * trans_id)313 static inline int z_impl_sip_svc_plat_async_res_res(const struct device *dev,
314 						    struct arm_smccc_res *res, char *buf,
315 						    size_t *size, uint32_t *trans_id)
316 {
317 	__ASSERT(dev, "dev shouldn't be NULL");
318 	const struct svc_driver_api *api = DEV_API(dev);
319 
320 	__ASSERT(api->sip_svc_plat_async_res_res,
321 		 "sip_svc_plat_async_res_res func shouldn't be NULL");
322 	__ASSERT(res, "res shouldn't be NULL");
323 	__ASSERT(buf, "buf shouldn't be NULL");
324 	__ASSERT(size, "size shouldn't be NULL");
325 	__ASSERT(trans_id, "buf shouldn't be NULL");
326 
327 	return api->sip_svc_plat_async_res_res(dev, res, buf, size, trans_id);
328 }
329 
330 /**
331  * @brief Free the command buffer used for ASYNC packet after sending it to lower layers.
332  *
333  * @param dev  Pointer to the device structure for the driver instance.
334  * @param request Pointer to sip_svc_request packet.
335  */
336 __syscall void sip_svc_plat_free_async_memory(const struct device *dev,
337 					      struct sip_svc_request *request);
z_impl_sip_svc_plat_free_async_memory(const struct device * dev,struct sip_svc_request * request)338 static inline void z_impl_sip_svc_plat_free_async_memory(const struct device *dev,
339 							 struct sip_svc_request *request)
340 {
341 	__ASSERT(dev, "dev shouldn't be NULL");
342 	const struct svc_driver_api *api = DEV_API(dev);
343 
344 	__ASSERT(api->sip_svc_plat_free_async_memory,
345 		 "sip_svc_plat_free_async_memory func shouldn't be NULL");
346 	__ASSERT(request, "request shouldn't be NULL");
347 
348 	api->sip_svc_plat_free_async_memory(dev, request);
349 }
350 
351 
352 #include <syscalls/sip_svc_driver.h>
353 
354 #endif /* ZEPHYR_INCLUDE_SIP_SVC_DRIVER_H_ */
355