1 /*
2 * Copyright (c) 2022-2023, Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Intel SoC FPGA platform specific functions used by ARM SiP Services for
7 * supporting EL3 communication from zephyr.
8 */
9
10 #include <string.h>
11 #include <zephyr/drivers/sip_svc/sip_svc_agilex_mailbox.h>
12 #include <zephyr/drivers/sip_svc/sip_svc_agilex_smc.h>
13 #include <zephyr/drivers/sip_svc/sip_svc_driver.h>
14 #include <zephyr/internal/syscall_handler.h>
15
16 #include <zephyr/logging/log.h>
17
18 LOG_MODULE_REGISTER(intel_socfpga_agilex_sip_smc, CONFIG_ARM_SIP_SVC_DRIVER_LOG_LEVEL);
19
20 #define DT_DRV_COMPAT intel_socfpga_agilex_sip_smc
21
22 #define DT_SIP_SMC DT_COMPAT_GET_ANY_STATUS_OKAY(DT_DRV_COMPAT)
23
intel_sip_smc_plat_func_id_valid(const struct device * dev,uint32_t command,uint32_t func_id)24 static bool intel_sip_smc_plat_func_id_valid(const struct device *dev, uint32_t command,
25 uint32_t func_id)
26 {
27 ARG_UNUSED(dev);
28 bool valid = false;
29
30 if (command > SIP_SVC_PROTO_CMD_MAX) {
31 return false;
32 }
33
34 if (command == SIP_SVC_PROTO_CMD_SYNC) {
35 /* Synchronous SMC Function IDs */
36 switch (func_id) {
37 case SMC_FUNC_ID_GET_SVC_VERSION:
38 case SMC_FUNC_ID_REG_READ:
39 case SMC_FUNC_ID_REG_WRITE:
40 case SMC_FUNC_ID_REG_UPDATE:
41 case SMC_FUNC_ID_SET_HPS_BRIDGES:
42 case SMC_FUNC_ID_RSU_UPDATE_ADDR:
43 valid = true;
44 break;
45 default:
46 valid = false;
47 break;
48 }
49 } else if (command == SIP_SVC_PROTO_CMD_ASYNC) {
50 /* Asynchronous SMC Function IDs */
51 switch (func_id) {
52 case SMC_FUNC_ID_MAILBOX_SEND_COMMAND:
53 case SMC_FUNC_ID_MAILBOX_POLL_RESPONSE:
54 valid = true;
55 break;
56 default:
57 valid = false;
58 break;
59 }
60 }
61
62 return valid;
63 }
64
intel_sip_smc_plat_format_trans_id(const struct device * dev,uint32_t client_idx,uint32_t trans_idx)65 static uint32_t intel_sip_smc_plat_format_trans_id(const struct device *dev, uint32_t client_idx,
66 uint32_t trans_idx)
67 {
68 ARG_UNUSED(dev);
69
70 /* Combine the transaction id and client id to get the job id*/
71 return (((client_idx & 0xF) << 4) | (trans_idx & 0xF));
72 }
73
intel_sip_smc_plat_get_trans_idx(const struct device * dev,uint32_t trans_id)74 static uint32_t intel_sip_smc_plat_get_trans_idx(const struct device *dev, uint32_t trans_id)
75 {
76 ARG_UNUSED(dev);
77
78 return (trans_id & 0xF);
79 }
80
intel_sip_smc_plat_update_trans_id(const struct device * dev,struct sip_svc_request * request,uint32_t trans_id)81 static void intel_sip_smc_plat_update_trans_id(const struct device *dev,
82 struct sip_svc_request *request, uint32_t trans_id)
83 {
84 ARG_UNUSED(dev);
85
86 uint32_t *data;
87
88 if (request == NULL) {
89 LOG_ERR("request is empty");
90 return;
91 }
92
93 /* Assign the trans id into intel smc header a1 */
94 SMC_PLAT_PROTO_HEADER_SET_TRANS_ID(request->a1, trans_id);
95
96 /* Assign the trans id into mailbox header */
97 if ((void *)request->a2 != NULL) {
98 data = (uint32_t *)request->a2;
99 SIP_SVC_MB_HEADER_SET_TRANS_ID(data[0], trans_id);
100 }
101 }
102
intel_sip_smc_plat_free_async_memory(const struct device * dev,struct sip_svc_request * request)103 static void intel_sip_smc_plat_free_async_memory(const struct device *dev,
104 struct sip_svc_request *request)
105 {
106 ARG_UNUSED(dev);
107
108 /* Free mailbox command data dynamic memory space,
109 * this function will be called after sip_svc service
110 * process the async request.
111 */
112 if (request->a2) {
113 k_free((void *)request->a2);
114 }
115 }
116
intel_sip_smc_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)117 static int intel_sip_smc_plat_async_res_req(const struct device *dev, unsigned long *a0,
118 unsigned long *a1, unsigned long *a2, unsigned long *a3,
119 unsigned long *a4, unsigned long *a5, unsigned long *a6,
120 unsigned long *a7, char *buf, size_t size)
121 {
122 ARG_UNUSED(dev);
123
124 /* Fill in SMC parameter to read mailbox response */
125 *a0 = SMC_FUNC_ID_MAILBOX_POLL_RESPONSE;
126 *a1 = 0;
127 *a2 = (unsigned long)buf;
128 *a3 = size;
129
130 return 0;
131 }
132
intel_sip_smc_plat_async_res_res(const struct device * dev,struct arm_smccc_res * res,char * buf,size_t * size,uint32_t * trans_id)133 static int intel_sip_smc_plat_async_res_res(const struct device *dev, struct arm_smccc_res *res,
134 char *buf, size_t *size, uint32_t *trans_id)
135 {
136 ARG_UNUSED(dev);
137 uint32_t *resp = (uint32_t *)buf;
138
139 __ASSERT((res && buf && size && trans_id), "invalid parameters\n");
140
141 if (((long)res->a0) <= SMC_STATUS_OKAY) {
142 /* Extract transaction id from mailbox response header */
143 *trans_id = SIP_SVC_MB_HEADER_GET_TRANS_ID(resp[0]);
144 /* The final length should include both header and body */
145 *size = (SIP_SVC_MB_HEADER_GET_LENGTH(resp[0]) + 1) * 4;
146 } else {
147 LOG_INF("There is no valid polling response %ld", (long)res->a0);
148 return -EINPROGRESS;
149 }
150
151 LOG_INF("Got a valid polling response");
152 return 0;
153 }
154
intel_sip_smc_plat_get_error_code(const struct device * dev,struct arm_smccc_res * res)155 static uint32_t intel_sip_smc_plat_get_error_code(const struct device *dev,
156 struct arm_smccc_res *res)
157 {
158 ARG_UNUSED(dev);
159
160 if (res != NULL) {
161 return res->a0;
162 } else {
163 return SIP_SVC_ID_INVALID;
164 }
165 }
166
intel_sip_secure_monitor_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)167 static void intel_sip_secure_monitor_call(const struct device *dev, unsigned long function_id,
168 unsigned long arg0, unsigned long arg1,
169 unsigned long arg2, unsigned long arg3,
170 unsigned long arg4, unsigned long arg5,
171 unsigned long arg6, struct arm_smccc_res *res)
172 {
173 __ASSERT_NO_MSG(dev != NULL);
174 __ASSERT_NO_MSG(res != NULL);
175 uint64_t start, end;
176
177 LOG_DBG("Before %s call", DT_PROP(DT_SIP_SMC, method));
178 LOG_DBG("\tfunction_id %08lx", function_id);
179 LOG_DBG("\targ0 %08lx", arg0);
180 LOG_DBG("\targ1 %08lx", arg1);
181 LOG_DBG("\targ2 %08lx", arg2);
182 LOG_DBG("\targ3 %08lx", arg3);
183 LOG_DBG("\targ4 %08lx", arg4);
184 LOG_DBG("\targ5 %08lx", arg5);
185 LOG_DBG("\targ6 %08lx", arg6);
186
187 start = k_cycle_get_64();
188 arm_smccc_smc(function_id, arg0, arg1, arg2, arg3, arg4, arg5, arg6, res);
189 end = k_cycle_get_64();
190
191 LOG_INF("Time taken for %08lx is %08lld ns", function_id,
192 k_cyc_to_ns_ceil64(end - start));
193
194 LOG_DBG("After %s call", DT_PROP(DT_SIP_SMC, method));
195 LOG_DBG("\tres->a0 %08lx", res->a0);
196 LOG_DBG("\tres->a1 %08lx", res->a1);
197 LOG_DBG("\tres->a2 %08lx", res->a2);
198 LOG_DBG("\tres->a3 %08lx", res->a3);
199 LOG_DBG("\tres->a4 %08lx", res->a4);
200 LOG_DBG("\tres->a5 %08lx", res->a5);
201 LOG_DBG("\tres->a6 %08lx", res->a6);
202 LOG_DBG("\tres->a7 %08lx", res->a7);
203 }
204
arm_sip_smc_init(const struct device * dev)205 static int arm_sip_smc_init(const struct device *dev)
206 {
207 ARG_UNUSED(dev);
208
209 LOG_INF("Supervisory call %s registered successfully", DT_PROP(DT_SIP_SMC, method));
210
211 return 0;
212 }
213
214 static const struct svc_driver_api api = {
215 .sip_supervisory_call = intel_sip_secure_monitor_call,
216 .sip_svc_plat_get_trans_idx = intel_sip_smc_plat_get_trans_idx,
217 .sip_svc_plat_format_trans_id = intel_sip_smc_plat_format_trans_id,
218 .sip_svc_plat_func_id_valid = intel_sip_smc_plat_func_id_valid,
219 .sip_svc_plat_update_trans_id = intel_sip_smc_plat_update_trans_id,
220 .sip_svc_plat_get_error_code = intel_sip_smc_plat_get_error_code,
221 .sip_svc_plat_async_res_req = intel_sip_smc_plat_async_res_req,
222 .sip_svc_plat_async_res_res = intel_sip_smc_plat_async_res_res,
223 .sip_svc_plat_free_async_memory = intel_sip_smc_plat_free_async_memory};
224
225 BUILD_ASSERT((DT_PROP(DT_SIP_SMC, zephyr_num_clients) != 0), "num-clients should not be zero");
226 BUILD_ASSERT((CONFIG_ARM_SIP_SVC_EL3_MAX_ALLOWED_TRANSACTIONS > 0),
227 "CONFIG_ARM_SIP_SVC_EL3_MAX_ALLOWED_TRANSACTIONS should be greater than 0");
228
229 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
230
231 SIP_SVC_CONTROLLER_DEFINE(0, DT_PROP(DT_SIP_SMC, method), DEVICE_DT_GET(DT_SIP_SMC),
232 DT_PROP(DT_SIP_SMC, zephyr_num_clients),
233 CONFIG_ARM_SIP_SVC_EL3_MAX_ALLOWED_TRANSACTIONS,
234 CONFIG_ARM_SIP_SVC_EL3_MAILBOX_RESPONSE_SIZE);
235
236 DEVICE_DT_DEFINE(DT_SIP_SMC, arm_sip_smc_init, NULL, NULL, NULL, POST_KERNEL,
237 CONFIG_ARM_SIP_SVC_DRIVER_INIT_PRIORITY, &api);
238
239 #endif
240