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