1 /*
2 * Copyright (c) 2020, Intel Corporation. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <lib/mmio.h>
8 #include <common/debug.h>
9 #include <drivers/delay_timer.h>
10
11 #include "socfpga_mailbox.h"
12 #include "socfpga_sip_svc.h"
13
14
is_mailbox_cmdbuf_full(uint32_t cin)15 static bool is_mailbox_cmdbuf_full(uint32_t cin)
16 {
17 uint32_t cout = mmio_read_32(MBOX_OFFSET + MBOX_COUT);
18
19 return (((cin + 1U) % MBOX_CMD_BUFFER_SIZE) == cout);
20 }
21
is_mailbox_cmdbuf_empty(uint32_t cin)22 static bool is_mailbox_cmdbuf_empty(uint32_t cin)
23 {
24 uint32_t cout = mmio_read_32(MBOX_OFFSET + MBOX_COUT);
25
26 return (((cout + 1U) % MBOX_CMD_BUFFER_SIZE) == cin);
27 }
28
wait_for_mailbox_cmdbuf_empty(uint32_t cin)29 static int wait_for_mailbox_cmdbuf_empty(uint32_t cin)
30 {
31 unsigned int timeout = 200U;
32
33 do {
34 if (is_mailbox_cmdbuf_empty(cin)) {
35 break;
36 }
37 mdelay(10U);
38 } while (--timeout != 0U);
39
40 if (timeout == 0U) {
41 return MBOX_TIMEOUT;
42 }
43
44 return MBOX_RET_OK;
45 }
46
write_mailbox_cmd_buffer(uint32_t * cin,uint32_t cout,uint32_t data,bool * is_doorbell_triggered)47 static int write_mailbox_cmd_buffer(uint32_t *cin, uint32_t cout,
48 uint32_t data,
49 bool *is_doorbell_triggered)
50 {
51 unsigned int timeout = 100U;
52
53 do {
54 if (is_mailbox_cmdbuf_full(*cin)) {
55 if (!(*is_doorbell_triggered)) {
56 mmio_write_32(MBOX_OFFSET +
57 MBOX_DOORBELL_TO_SDM, 1U);
58 *is_doorbell_triggered = true;
59 }
60 mdelay(10U);
61 } else {
62 mmio_write_32(MBOX_OFFSET + MBOX_CMD_BUFFER +
63 (*cin * 4), data);
64 (*cin)++;
65 *cin %= MBOX_CMD_BUFFER_SIZE;
66 mmio_write_32(MBOX_OFFSET + MBOX_CIN, *cin);
67 break;
68 }
69 } while (--timeout != 0U);
70
71 if (timeout == 0U) {
72 return MBOX_TIMEOUT;
73 }
74
75 if (*is_doorbell_triggered) {
76 int ret = wait_for_mailbox_cmdbuf_empty(*cin);
77 return ret;
78 }
79
80 return MBOX_RET_OK;
81 }
82
fill_mailbox_circular_buffer(uint32_t header_cmd,uint32_t * args,unsigned int len)83 static int fill_mailbox_circular_buffer(uint32_t header_cmd, uint32_t *args,
84 unsigned int len)
85 {
86 uint32_t sdm_read_offset, cmd_free_offset;
87 unsigned int i;
88 int ret;
89 bool is_doorbell_triggered = false;
90
91 cmd_free_offset = mmio_read_32(MBOX_OFFSET + MBOX_CIN);
92 sdm_read_offset = mmio_read_32(MBOX_OFFSET + MBOX_COUT);
93
94 ret = write_mailbox_cmd_buffer(&cmd_free_offset, sdm_read_offset,
95 header_cmd, &is_doorbell_triggered);
96 if (ret != 0) {
97 goto restart_mailbox;
98 }
99
100 for (i = 0U; i < len; i++) {
101 is_doorbell_triggered = false;
102 ret = write_mailbox_cmd_buffer(&cmd_free_offset,
103 sdm_read_offset, args[i],
104 &is_doorbell_triggered);
105 if (ret != 0) {
106 goto restart_mailbox;
107 }
108 }
109
110 if (!is_doorbell_triggered) {
111 mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_TO_SDM, 1U);
112 }
113
114 return MBOX_RET_OK;
115
116 restart_mailbox:
117 /*
118 * Attempt to restart mailbox if the driver not able to write
119 * into mailbox command buffer
120 */
121 if (MBOX_CMD_MASK(header_cmd) != MBOX_CMD_RESTART) {
122 INFO("Mailbox timed out: Attempting mailbox reset\n");
123 ret = mailbox_init();
124
125 if (ret == MBOX_TIMEOUT) {
126 INFO("Error: Mailbox fail to restart\n");
127 }
128 }
129
130 return MBOX_TIMEOUT;
131 }
132
mailbox_read_response(unsigned int * job_id,uint32_t * response,unsigned int resp_len)133 int mailbox_read_response(unsigned int *job_id, uint32_t *response,
134 unsigned int resp_len)
135 {
136 uint32_t rin;
137 uint32_t rout;
138 uint32_t resp_data;
139 unsigned int ret_resp_len;
140
141 if (mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM) == 1U) {
142 mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0U);
143 }
144
145 rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
146 rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT);
147
148 if (rout != rin) {
149 resp_data = mmio_read_32(MBOX_OFFSET +
150 MBOX_RESP_BUFFER + ((rout++)*4U));
151
152 rout %= MBOX_RESP_BUFFER_SIZE;
153 mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);
154
155
156 if (MBOX_RESP_CLIENT_ID(resp_data) != MBOX_ATF_CLIENT_ID) {
157 return MBOX_WRONG_ID;
158 }
159
160 *job_id = MBOX_RESP_JOB_ID(resp_data);
161
162 ret_resp_len = MBOX_RESP_LEN(resp_data);
163
164 if (ret_resp_len != 0U) {
165 ret_resp_len = iterate_resp(ret_resp_len, response,
166 resp_len);
167 }
168
169 if (MBOX_RESP_ERR(resp_data) > 0U) {
170 INFO("Error in response: %x\n", resp_data);
171 return -MBOX_RESP_ERR(resp_data);
172 }
173
174 return ret_resp_len;
175 }
176 return MBOX_NO_RESPONSE;
177 }
178
179
mailbox_poll_response(uint32_t job_id,uint32_t urgent,uint32_t * response,unsigned int resp_len)180 int mailbox_poll_response(uint32_t job_id, uint32_t urgent, uint32_t *response,
181 unsigned int resp_len)
182 {
183 unsigned int timeout = 40U;
184 unsigned int sdm_loop = 255U;
185 unsigned int ret_resp_len;
186 uint32_t rin;
187 uint32_t rout;
188 uint32_t resp_data;
189
190 while (sdm_loop != 0U) {
191
192 do {
193 if (mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM)
194 == 1U) {
195 break;
196 }
197 mdelay(10U);
198 } while (--timeout != 0U);
199
200 if (timeout == 0U) {
201 break;
202 }
203
204 mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0U);
205
206 if ((urgent & 1U) != 0U) {
207 mdelay(5U);
208 if ((mmio_read_32(MBOX_OFFSET + MBOX_STATUS) &
209 MBOX_STATUS_UA_MASK) ^
210 (urgent & MBOX_STATUS_UA_MASK)) {
211 mmio_write_32(MBOX_OFFSET + MBOX_URG, 0U);
212 return MBOX_RET_OK;
213 }
214
215 mmio_write_32(MBOX_OFFSET + MBOX_URG, 0U);
216 INFO("Error: Mailbox did not get UA");
217 return MBOX_RET_ERROR;
218 }
219
220 rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
221 rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT);
222
223 while (rout != rin) {
224 resp_data = mmio_read_32(MBOX_OFFSET +
225 MBOX_RESP_BUFFER + ((rout++)*4U));
226
227 rout %= MBOX_RESP_BUFFER_SIZE;
228 mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);
229
230 if (MBOX_RESP_CLIENT_ID(resp_data) != MBOX_ATF_CLIENT_ID
231 || MBOX_RESP_JOB_ID(resp_data) != job_id) {
232 continue;
233 }
234
235 ret_resp_len = MBOX_RESP_LEN(resp_data);
236
237 if (ret_resp_len != 0U) {
238 ret_resp_len = iterate_resp(ret_resp_len,
239 response,
240 resp_len);
241 }
242
243 if (MBOX_RESP_ERR(resp_data) > 0U) {
244 INFO("Error in response: %x\n", resp_data);
245 return -MBOX_RESP_ERR(resp_data);
246 }
247
248 return ret_resp_len;
249 }
250
251 sdm_loop--;
252 }
253
254 INFO("Timed out waiting for SDM\n");
255 return MBOX_TIMEOUT;
256 }
257
iterate_resp(uint32_t mbox_resp_len,uint32_t * resp_buf,unsigned int resp_len)258 unsigned int iterate_resp(uint32_t mbox_resp_len, uint32_t *resp_buf,
259 unsigned int resp_len)
260 {
261 unsigned int timeout, total_resp_len = 0U;
262 uint32_t resp_data;
263 uint32_t rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
264 uint32_t rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT);
265
266 while (mbox_resp_len > 0U) {
267 timeout = 100U;
268 mbox_resp_len--;
269 resp_data = mmio_read_32(MBOX_OFFSET +
270 MBOX_RESP_BUFFER +
271 (rout)*4U);
272
273 if ((resp_buf != NULL) && (resp_len != 0U)) {
274 *(resp_buf + total_resp_len)
275 = resp_data;
276 resp_len--;
277 total_resp_len++;
278 }
279 rout++;
280 rout %= MBOX_RESP_BUFFER_SIZE;
281 mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);
282
283 do {
284 rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
285 if (rout == rin) {
286 mdelay(10U);
287 } else {
288 break;
289 }
290 timeout--;
291 } while ((mbox_resp_len > 0U) && (timeout != 0U));
292
293 if (timeout == 0U) {
294 INFO("Timed out waiting for SDM\n");
295 return MBOX_TIMEOUT;
296 }
297 }
298 return total_resp_len;
299 }
300
mailbox_send_cmd_async(uint32_t * job_id,uint32_t cmd,uint32_t * args,unsigned int len,unsigned int indirect)301 int mailbox_send_cmd_async(uint32_t *job_id, uint32_t cmd, uint32_t *args,
302 unsigned int len, unsigned int indirect)
303 {
304 int status;
305
306 status = fill_mailbox_circular_buffer(
307 MBOX_CLIENT_ID_CMD(MBOX_ATF_CLIENT_ID) |
308 MBOX_JOB_ID_CMD(*job_id) |
309 MBOX_CMD_LEN_CMD(len) |
310 MBOX_INDIRECT(indirect) |
311 cmd, args, len);
312 if (status < 0) {
313 return status;
314 }
315
316 *job_id = (*job_id + 1U) % MBOX_MAX_IND_JOB_ID;
317
318 return MBOX_RET_OK;
319 }
320
mailbox_send_cmd(uint32_t job_id,uint32_t cmd,uint32_t * args,unsigned int len,uint32_t urgent,uint32_t * response,unsigned int resp_len)321 int mailbox_send_cmd(uint32_t job_id, uint32_t cmd, uint32_t *args,
322 unsigned int len, uint32_t urgent, uint32_t *response,
323 unsigned int resp_len)
324 {
325 int status = 0;
326
327 if (urgent != 0U) {
328 urgent |= mmio_read_32(MBOX_OFFSET + MBOX_STATUS) &
329 MBOX_STATUS_UA_MASK;
330 mmio_write_32(MBOX_OFFSET + MBOX_URG, cmd);
331 mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_TO_SDM, 1U);
332 }
333
334 else {
335 status = fill_mailbox_circular_buffer(
336 MBOX_CLIENT_ID_CMD(MBOX_ATF_CLIENT_ID) |
337 MBOX_JOB_ID_CMD(job_id) |
338 MBOX_CMD_LEN_CMD(len) |
339 cmd, args, len);
340 }
341
342 if (status != 0) {
343 return status;
344 }
345
346 status = mailbox_poll_response(job_id, urgent, response, resp_len);
347
348 return status;
349 }
350
mailbox_clear_response(void)351 void mailbox_clear_response(void)
352 {
353 mmio_write_32(MBOX_OFFSET + MBOX_ROUT,
354 mmio_read_32(MBOX_OFFSET + MBOX_RIN));
355 }
356
mailbox_set_int(uint32_t interrupt)357 void mailbox_set_int(uint32_t interrupt)
358 {
359
360 mmio_write_32(MBOX_OFFSET+MBOX_INT, MBOX_COE_BIT(interrupt) |
361 MBOX_UAE_BIT(interrupt));
362 }
363
364
mailbox_set_qspi_open(void)365 void mailbox_set_qspi_open(void)
366 {
367 mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
368 mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_OPEN, NULL, 0U,
369 CMD_CASUAL, NULL, 0U);
370 }
371
mailbox_set_qspi_direct(void)372 void mailbox_set_qspi_direct(void)
373 {
374 mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_DIRECT, NULL, 0U,
375 CMD_CASUAL, NULL, 0U);
376 }
377
mailbox_set_qspi_close(void)378 void mailbox_set_qspi_close(void)
379 {
380 mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
381 mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_CLOSE, NULL, 0U,
382 CMD_CASUAL, NULL, 0U);
383 }
384
mailbox_qspi_set_cs(uint32_t device_select)385 void mailbox_qspi_set_cs(uint32_t device_select)
386 {
387 uint32_t cs_setting;
388
389 /* QSPI device select settings at 31:28 */
390 cs_setting = (device_select << 28);
391 mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
392 mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_SET_CS, &cs_setting,
393 1U, CMD_CASUAL, NULL, 0U);
394 }
395
mailbox_reset_cold(void)396 void mailbox_reset_cold(void)
397 {
398 mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
399 mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_REBOOT_HPS, NULL, 0U,
400 CMD_CASUAL, NULL, 0U);
401 }
402
mailbox_rsu_get_spt_offset(uint32_t * resp_buf,unsigned int resp_buf_len)403 int mailbox_rsu_get_spt_offset(uint32_t *resp_buf, unsigned int resp_buf_len)
404 {
405 return mailbox_send_cmd(MBOX_JOB_ID, MBOX_GET_SUBPARTITION_TABLE,
406 NULL, 0U, CMD_CASUAL, resp_buf,
407 resp_buf_len);
408 }
409
410 struct rsu_status_info {
411 uint64_t current_image;
412 uint64_t fail_image;
413 uint32_t state;
414 uint32_t version;
415 uint32_t error_location;
416 uint32_t error_details;
417 uint32_t retry_counter;
418 };
419
mailbox_rsu_status(uint32_t * resp_buf,unsigned int resp_buf_len)420 int mailbox_rsu_status(uint32_t *resp_buf, unsigned int resp_buf_len)
421 {
422 int ret;
423 struct rsu_status_info *info = (struct rsu_status_info *)resp_buf;
424
425 info->retry_counter = ~0U;
426
427 ret = mailbox_send_cmd(MBOX_JOB_ID, MBOX_RSU_STATUS, NULL, 0U,
428 CMD_CASUAL, resp_buf,
429 resp_buf_len);
430
431 if (ret < 0) {
432 return ret;
433 }
434
435 if (info->retry_counter != ~0U) {
436 if ((info->version & RSU_VERSION_ACMF_MASK) == 0U) {
437 info->version |= RSU_VERSION_ACMF;
438 }
439 }
440
441 return ret;
442 }
443
mailbox_rsu_update(uint32_t * flash_offset)444 int mailbox_rsu_update(uint32_t *flash_offset)
445 {
446 return mailbox_send_cmd(MBOX_JOB_ID, MBOX_RSU_UPDATE,
447 flash_offset, 2U,
448 CMD_CASUAL, NULL, 0U);
449 }
450
mailbox_hps_stage_notify(uint32_t execution_stage)451 int mailbox_hps_stage_notify(uint32_t execution_stage)
452 {
453 return mailbox_send_cmd(MBOX_JOB_ID, MBOX_HPS_STAGE_NOTIFY,
454 &execution_stage, 1U, CMD_CASUAL,
455 NULL, 0U);
456 }
457
mailbox_init(void)458 int mailbox_init(void)
459 {
460 int status;
461
462 mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE |
463 MBOX_INT_FLAG_UAE);
464 mmio_write_32(MBOX_OFFSET + MBOX_URG, 0U);
465 mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0U);
466
467 status = mailbox_send_cmd(0U, MBOX_CMD_RESTART, NULL, 0U,
468 CMD_URGENT, NULL, 0U);
469
470 if (status != 0) {
471 return status;
472 }
473
474 mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE |
475 MBOX_INT_FLAG_UAE);
476
477 return MBOX_RET_OK;
478 }
479
intel_mailbox_get_config_status(uint32_t cmd)480 int intel_mailbox_get_config_status(uint32_t cmd)
481 {
482 int status;
483 uint32_t res, response[6];
484
485 status = mailbox_send_cmd(MBOX_JOB_ID, cmd, NULL, 0U, CMD_CASUAL,
486 response, ARRAY_SIZE(response));
487
488 if (status < 0) {
489 return status;
490 }
491
492 res = response[RECONFIG_STATUS_STATE];
493 if ((res != 0U) && (res != MBOX_CFGSTAT_STATE_CONFIG)) {
494 return res;
495 }
496
497 res = response[RECONFIG_STATUS_PIN_STATUS];
498 if ((res & PIN_STATUS_NSTATUS) == 0U) {
499 return MBOX_CFGSTAT_STATE_ERROR_HARDWARE;
500 }
501
502 res = response[RECONFIG_STATUS_SOFTFUNC_STATUS];
503 if ((res & SOFTFUNC_STATUS_SEU_ERROR) != 0U) {
504 return MBOX_CFGSTAT_STATE_ERROR_HARDWARE;
505 }
506
507 if ((res & SOFTFUNC_STATUS_CONF_DONE) != 0U &&
508 (res & SOFTFUNC_STATUS_INIT_DONE) != 0U) {
509 return MBOX_RET_OK;
510 }
511
512 return MBOX_CFGSTAT_STATE_CONFIG;
513 }
514
intel_mailbox_is_fpga_not_ready(void)515 int intel_mailbox_is_fpga_not_ready(void)
516 {
517 int ret = intel_mailbox_get_config_status(MBOX_RECONFIG_STATUS);
518
519 if ((ret != MBOX_RET_OK) && (ret != MBOX_CFGSTAT_STATE_CONFIG)) {
520 ret = intel_mailbox_get_config_status(MBOX_CONFIG_STATUS);
521 }
522
523 return ret;
524 }
525