1 /*
2 * Copyright (c) 2024, Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT altr_socfpga_agilex_bridge
8
9 #include <errno.h>
10 #include <zephyr/device.h>
11 #include <zephyr/sip_svc/sip_svc.h>
12 #include <zephyr/drivers/sip_svc/sip_svc_agilex_smc.h>
13 #include <zephyr/drivers/fpga.h>
14 #include <zephyr/logging/log.h>
15 #include "fpga_altera_agilex_bridge.h"
16
17 LOG_MODULE_REGISTER(fpga_altera);
18
19 struct fpga_bridge_dev_data {
20 /* SiP SVC controller */
21 struct sip_svc_controller *mailbox_smc_dev;
22 /* SiP SVC client token id */
23 uint32_t mailbox_client_token;
24 };
25
26 #define MAX_TIMEOUT_MSECS (1 * 1000UL)
27
28 /**
29 * @brief Open SiP SVC client session
30 *
31 * @return 0 on success or negative value on failure
32 */
svc_client_open(const struct device * dev)33 static int32_t svc_client_open(const struct device *dev)
34 {
35 if (!dev) {
36 LOG_ERR("No such device found");
37 return -ENODEV;
38 }
39
40 struct fpga_bridge_dev_data *const data = (struct fpga_bridge_dev_data *const)(dev->data);
41
42 if ((!data->mailbox_smc_dev) || (data->mailbox_client_token == 0)) {
43 LOG_ERR("Mailbox client is not registered");
44 return -ENODEV;
45 }
46
47 if (sip_svc_open(data->mailbox_smc_dev, data->mailbox_client_token,
48 K_MSEC(MAX_TIMEOUT_MSECS))) {
49 LOG_ERR("Mailbox client open fail");
50 return -ENODEV;
51 }
52
53 return 0;
54 }
55
56 /**
57 * @brief Close the svc client
58 *
59 * @return 0 on success or negative value on fail
60 */
svc_client_close(const struct device * dev)61 static int32_t svc_client_close(const struct device *dev)
62 {
63 int32_t err;
64 uint32_t cmd_size = sizeof(uint32_t);
65 struct sip_svc_request request;
66
67 if (!dev) {
68 LOG_ERR("No such device found");
69 return -ENODEV;
70 }
71
72 struct fpga_bridge_dev_data *const data = (struct fpga_bridge_dev_data *const)(dev->data);
73
74 uint32_t *cmd_addr = (uint32_t *)k_malloc(cmd_size);
75
76 if (!cmd_addr) {
77 return -ENOMEM;
78 }
79
80 /* Fill the SiP SVC buffer with CANCEL request */
81 *cmd_addr = MAILBOX_CANCEL_COMMAND;
82
83 request.header = SIP_SVC_PROTO_HEADER(SIP_SVC_PROTO_CMD_ASYNC, 0);
84 request.a0 = SMC_FUNC_ID_MAILBOX_SEND_COMMAND;
85 request.a1 = 0;
86 request.a2 = (uint64_t)cmd_addr;
87 request.a3 = (uint64_t)cmd_size;
88 request.a4 = 0;
89 request.a5 = 0;
90 request.a6 = 0;
91 request.a7 = 0;
92 request.resp_data_addr = (uint64_t)NULL;
93 request.resp_data_size = 0;
94 request.priv_data = NULL;
95
96 err = sip_svc_close(data->mailbox_smc_dev, data->mailbox_client_token, &request);
97 if (err) {
98 k_free(cmd_addr);
99 LOG_ERR("Mailbox client close fail (%d)", err);
100 }
101
102 return err;
103 }
104
105 /**
106 * @brief Call back function which we receive when we send the data
107 * based on the current stage it will collect the data
108 *
109 * @param[in] c_token Token id for our svc services
110 * @param[in] response Buffer will contain the response
111 *
112 * @return void
113 */
smc_callback(uint32_t c_token,struct sip_svc_response * response)114 static void smc_callback(uint32_t c_token, struct sip_svc_response *response)
115 {
116 if (response == NULL) {
117 return;
118 }
119
120 uint32_t *resp_data = NULL;
121 uint32_t resp_len = 0;
122 uint32_t mbox_idx = 0;
123
124 struct sip_svc_private_data *private_data =
125 (struct sip_svc_private_data *)response->priv_data;
126 union mailbox_response_header response_header;
127
128 LOG_DBG("SiP SVC callback");
129
130 LOG_DBG("\tresponse data below:");
131 LOG_DBG("\theader=%08x", response->header);
132 LOG_DBG("\ta0=%016lx", response->a0);
133 LOG_DBG("\ta1=%016lx", response->a1);
134 LOG_DBG("\ta2=%016lx", response->a2);
135 LOG_DBG("\ta3=%016lx", response->a3);
136
137 private_data->response.header = response->header;
138 private_data->response.a0 = response->a0;
139 private_data->response.a1 = response->a1;
140 private_data->response.a2 = response->a2;
141 private_data->response.a3 = response->a3;
142 private_data->response.resp_data_size = response->resp_data_size;
143
144 /* Condition to check only for the mailbox command not for the non-mailbox command */
145 if (response->resp_data_size) {
146 resp_data = (uint32_t *)response->resp_data_addr;
147 resp_len = response->resp_data_size / 4;
148 private_data->mbox_response_len = resp_len;
149 if (resp_data && resp_len) {
150 response_header = (union mailbox_response_header)resp_data[0];
151 private_data->mbox_response_data =
152 (uint32_t *)k_malloc(sizeof(uint32_t) * resp_len);
153 for (mbox_idx = 0; mbox_idx < resp_len; mbox_idx++) {
154 LOG_DBG("\t\t[%4d] %08x", mbox_idx, resp_data[mbox_idx]);
155 private_data->mbox_response_data[mbox_idx] = resp_data[mbox_idx];
156 }
157 } else {
158 LOG_ERR("\t\tInvalid addr (%p) or len (%d)", resp_data, resp_len);
159 }
160 }
161 /* Condition for non-mailbox command*/
162 else {
163 LOG_DBG("Response Data size is zero !!");
164 }
165
166 /* Client only responsible to free the response data memory space,
167 * the command data memory space had been freed by SiP SVC service.
168 */
169 if (response->resp_data_addr) {
170 LOG_DBG("\tFree response memory %p", (char *)response->resp_data_addr);
171 k_free((char *)response->resp_data_addr);
172 }
173
174 k_sem_give(&(private_data->smc_sem));
175 }
176
177 /**
178 * @brief Send the data to SiP SVC service layer
179 * based on the command type further data will be send to SDM using mailbox
180 *
181 * @param[in] cmd_type Command type (Mailbox or Non-Mailbox)
182 * @param[in] function_identifier Function identifier for each command type
183 * @param[in] cmd_request
184 * @param[in] private_data
185 *
186 * @return 0 on success or negative value on fail
187 */
smc_send(const struct device * dev,uint32_t cmd_type,uint64_t function_identifier,uint32_t * cmd_request,struct sip_svc_private_data * private_data)188 static int32_t smc_send(const struct device *dev, uint32_t cmd_type, uint64_t function_identifier,
189 uint32_t *cmd_request, struct sip_svc_private_data *private_data)
190 {
191 int32_t trans_id = 0;
192 uint32_t *cmd_addr = NULL;
193 uint32_t *resp_addr = NULL;
194 struct sip_svc_request request;
195
196 if (!dev) {
197 LOG_ERR("No such device found");
198 return -ENODEV;
199 }
200
201 struct fpga_bridge_dev_data *const data = (struct fpga_bridge_dev_data *const)(dev->data);
202
203 if (!data->mailbox_smc_dev) {
204 LOG_ERR("Mailbox client is not registered");
205 return -ENODEV;
206 }
207
208 if (cmd_type == SIP_SVC_PROTO_CMD_ASYNC) {
209 cmd_addr = (uint32_t *)k_malloc(FPGA_MB_CMD_ADDR_MEM_SIZE);
210 if (!cmd_addr) {
211 LOG_ERR("Failed to allocate command memory");
212 return -ENOMEM;
213 }
214 cmd_addr[MBOX_CMD_HEADER_INDEX] =
215 MBOX_REQUEST_HEADER(cmd_request[SMC_REQUEST_A2_INDEX], 0, 0);
216 resp_addr = (uint32_t *)k_malloc(FPGA_MB_RESPONSE_MEM_SIZE);
217 if (!resp_addr) {
218 k_free(cmd_addr);
219 return -ENOMEM;
220 }
221
222 request.a2 = (uint64_t)cmd_addr;
223 request.a3 = sizeof(uint32_t);
224 request.resp_data_addr = (uint64_t)resp_addr;
225 request.resp_data_size = FPGA_MB_RESPONSE_MEM_SIZE;
226
227 #if defined(CONFIG_LOG)
228 for (int32_t mbox_idx = 0; mbox_idx < request.a3 / 4; mbox_idx++) {
229 LOG_DBG("\t [%d ] %08x", mbox_idx, cmd_addr[mbox_idx]);
230 }
231 #endif
232
233 } else {
234 request.a2 = cmd_request[SMC_REQUEST_A2_INDEX];
235 request.a3 = cmd_request[SMC_REQUEST_A3_INDEX];
236 request.resp_data_addr = 0;
237 request.resp_data_size = 0;
238 }
239
240 /* Fill SiP SVC request buffer */
241 request.header = SIP_SVC_PROTO_HEADER(cmd_type, 0);
242 request.a0 = function_identifier;
243 request.a1 = 0;
244 request.a4 = 0;
245 request.a5 = 0;
246 request.a6 = 0;
247 request.a7 = 0;
248 request.priv_data = (void *)private_data;
249
250 /* Send SiP SVC request */
251 trans_id = sip_svc_send(data->mailbox_smc_dev, data->mailbox_client_token, &request,
252 smc_callback);
253
254 if (trans_id == SIP_SVC_ID_INVALID) {
255 LOG_ERR("SiP SVC send request fail");
256 return -EBUSY;
257 }
258
259 return 0;
260 }
261
262 /* Validate the Reconfig status response */
fpga_reconfig_status_validate(struct fpga_config_status * reconfig_status_resp)263 static int32_t fpga_reconfig_status_validate(struct fpga_config_status *reconfig_status_resp)
264 {
265 uint32_t ret = 0;
266
267 /* Check for any error */
268 ret = reconfig_status_resp->state;
269 if (ret == MBOX_CFGSTAT_VAB_BS_PREAUTH) {
270 return MBOX_CONFIG_STATUS_STATE_CONFIG;
271 }
272
273 if (ret && ret != MBOX_CONFIG_STATUS_STATE_CONFIG)
274 return ret;
275
276 /* Make sure nStatus is not 0 */
277 ret = reconfig_status_resp->pin_status.pin_status;
278 if (!(ret & RECONFIG_PIN_STATUS_NSTATUS))
279 return MBOX_CFGSTAT_STATE_ERROR_HARDWARE;
280
281 ret = reconfig_status_resp->soft_function_status;
282 if ((ret & RECONFIG_SOFTFUNC_STATUS_CONF_DONE) &&
283 (ret & RECONFIG_SOFTFUNC_STATUS_INIT_DONE) && !reconfig_status_resp->state)
284 return 0; /* Configuration success */
285
286 return MBOX_CONFIG_STATUS_STATE_CONFIG;
287 }
288
289 /* Will send the SMC command to check the status of the FPGA */
fpga_config_ready_check(const struct device * dev)290 static int32_t fpga_config_ready_check(const struct device *dev)
291 {
292 uint32_t smc_cmd[2] = {0};
293 int32_t ret = 0;
294 struct sip_svc_private_data priv_data;
295
296 /* Initialize the semaphore */
297 k_sem_init(&(priv_data.smc_sem), 0, 1);
298
299 smc_cmd[SMC_REQUEST_A2_INDEX] = FPGA_CONFIG_STATUS;
300 smc_cmd[SMC_REQUEST_A3_INDEX] = 0;
301
302 /* Sending the FPGA config status mailbox command */
303 ret = smc_send(dev, SIP_SVC_PROTO_CMD_ASYNC, SMC_FUNC_ID_MAILBOX_SEND_COMMAND, smc_cmd,
304 &priv_data);
305 if (ret) {
306 LOG_ERR("Failed to Send the Mailbox Command !!");
307 return -ECANCELED;
308 }
309
310 k_sem_take(&(priv_data.smc_sem), K_FOREVER);
311
312 /* Verify the SMC response */
313 if (!priv_data.response.resp_data_size &&
314 priv_data.mbox_response_len != FPGA_CONFIG_STATUS_RESPONSE_LEN) {
315 return -EINVAL;
316 }
317
318 /* Verify the FPGA config status response */
319 ret = fpga_reconfig_status_validate(
320 (struct fpga_config_status *)priv_data.mbox_response_data);
321
322 k_free(priv_data.mbox_response_data);
323
324 return ret;
325 }
326
socfpga_bridges_reset(const struct device * dev,uint32_t enable)327 static int32_t socfpga_bridges_reset(const struct device *dev, uint32_t enable)
328 {
329 uint32_t smc_cmd[2] = {0};
330 int ret = 0;
331 struct sip_svc_private_data priv_data;
332
333 if (!dev) {
334 LOG_ERR("No such device found");
335 return -ENODEV;
336 }
337
338 /* Initialize the semaphore */
339 k_sem_init(&(priv_data.smc_sem), 0, 1);
340
341 smc_cmd[SMC_REQUEST_A2_INDEX] = FIELD_GET(BIT(0), enable);
342
343 smc_cmd[SMC_REQUEST_A2_INDEX] |= BIT(1);
344 smc_cmd[SMC_REQUEST_A3_INDEX] = BRIDGE_MASK;
345
346 ret = smc_send(dev, SIP_SVC_PROTO_CMD_SYNC, SMC_FUNC_ID_SET_HPS_BRIDGES, smc_cmd,
347 &priv_data);
348 if (ret) {
349 LOG_ERR("Failed to send the smc Command !!");
350 return ret;
351 }
352
353 /* Wait for the SiP SVC callback */
354 k_sem_take(&(priv_data.smc_sem), K_FOREVER);
355
356 /* Check error code */
357 if (priv_data.response.a0) {
358 ret = -ENOMSG;
359 }
360
361 return ret;
362 }
363
altera_fpga_on(const struct device * dev)364 static int altera_fpga_on(const struct device *dev)
365 {
366 int32_t ret = 0;
367
368 if (!dev) {
369 LOG_ERR("No such device found");
370 return -ENODEV;
371 }
372
373 /* Opening SIP SVC session */
374 ret = svc_client_open(dev);
375 if (ret) {
376 LOG_ERR("Client open Failed!");
377 return ret;
378 }
379
380 /* Check FPGA status before bridge enable/disable */
381 ret = fpga_config_ready_check(dev);
382 if (ret) {
383 LOG_ERR("FPGA not ready. Bridge reset aborted!");
384 svc_client_close(dev);
385 return -EIO;
386 }
387
388 /* Bridge reset */
389 ret = socfpga_bridges_reset(dev, 0x01);
390 if (ret) {
391 LOG_ERR("Bridge reset failed");
392 }
393
394 /* Ignoring the return value to return bridge reset status */
395 if (svc_client_close(dev)) {
396 LOG_ERR("Unregistering & Closing failed");
397 }
398
399 return ret;
400 }
401
altera_fpga_off(const struct device * dev)402 static int altera_fpga_off(const struct device *dev)
403 {
404 int32_t ret = 0;
405
406 if (!dev) {
407 LOG_ERR("No such device found");
408 return -ENODEV;
409 }
410
411 /* Opening SIP SVC session */
412 ret = svc_client_open(dev);
413 if (ret) {
414 LOG_ERR("Client open Failed!");
415 return ret;
416 }
417
418 /* Check FPGA status before bridge enable/disable */
419 ret = fpga_config_ready_check(dev);
420 if (ret) {
421 LOG_ERR("FPGA not ready. Bridge reset aborted!");
422 svc_client_close(dev);
423 return -EIO;
424 }
425
426 /* Bridge reset */
427 ret = socfpga_bridges_reset(dev, 0x00);
428 if (ret) {
429 LOG_ERR("Bridge reset failed");
430 }
431
432 /* Ignoring the return value to return bridge reset status */
433 if (svc_client_close(dev)) {
434 LOG_ERR("Unregistering & Closing failed");
435 }
436
437 return ret;
438 }
439
altera_fpga_init(const struct device * dev)440 static int altera_fpga_init(const struct device *dev)
441 {
442 if (!dev) {
443 LOG_ERR("No such device found");
444 return -ENODEV;
445 }
446
447 struct fpga_bridge_dev_data *const data = (struct fpga_bridge_dev_data *const)(dev->data);
448
449 data->mailbox_smc_dev = sip_svc_get_controller("smc");
450 if (!data->mailbox_smc_dev) {
451 LOG_ERR("Arm SiP service not found");
452 return -ENODEV;
453 }
454
455 data->mailbox_client_token = sip_svc_register(data->mailbox_smc_dev, NULL);
456 if (data->mailbox_client_token == SIP_SVC_ID_INVALID) {
457 data->mailbox_smc_dev = NULL;
458 LOG_ERR("Mailbox client register fail");
459 return -EINVAL;
460 }
461
462 return 0;
463 }
464
465 static const struct fpga_driver_api altera_fpga_api = {
466 .on = altera_fpga_on,
467 .off = altera_fpga_off,
468 };
469
470 #define CREATE_ALTERA_FPGA_BRIDGE_DEV(inst) \
471 static struct fpga_bridge_dev_data fpga_bridge_data_##inst; \
472 DEVICE_DT_INST_DEFINE(inst, \
473 altera_fpga_init, \
474 NULL, &fpga_bridge_data_##inst, \
475 NULL, POST_KERNEL, \
476 CONFIG_FPGA_INIT_PRIORITY, \
477 &altera_fpga_api); \
478
479 DT_INST_FOREACH_STATUS_OKAY(CREATE_ALTERA_FPGA_BRIDGE_DEV);
480