socfpga_mailbox.c 11.2 KB
Newer Older
1
/*
2
 * Copyright (c) 2020, Intel Corporation. All rights reserved.
3
4
5
6
7
8
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <lib/mmio.h>
#include <common/debug.h>
9
#include <drivers/delay_timer.h>
10

11
#include "socfpga_mailbox.h"
12
#include "socfpga_sip_svc.h"
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

static bool is_mailbox_cmdbuf_full(uint32_t cin)
{
	uint32_t cout = mmio_read_32(MBOX_OFFSET + MBOX_COUT);

	return (((cin + 1U) % MBOX_CMD_BUFFER_SIZE) == cout);
}

static bool is_mailbox_cmdbuf_empty(uint32_t cin)
{
	uint32_t cout = mmio_read_32(MBOX_OFFSET + MBOX_COUT);

	return (((cout + 1U) % MBOX_CMD_BUFFER_SIZE) == cin);
}

static int wait_for_mailbox_cmdbuf_empty(uint32_t cin)
{
	uint32_t timeout = 200U;

	do {
		if (is_mailbox_cmdbuf_empty(cin)) {
			break;
		}
		mdelay(10U);
	} while (--timeout != 0U);

	if (timeout == 0U) {
		return MBOX_TIMEOUT;
	}

	return MBOX_RET_OK;
}

static int write_mailbox_cmd_buffer(uint32_t *cin, uint32_t cout,
				    uint32_t data,
				    bool *is_doorbell_triggered)
{
	uint32_t timeout = 100U;

	do {
		if (is_mailbox_cmdbuf_full(*cin)) {
			if (!(*is_doorbell_triggered)) {
				mmio_write_32(MBOX_OFFSET +
57
					      MBOX_DOORBELL_TO_SDM, 1U);
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
				*is_doorbell_triggered = true;
			}
			mdelay(10U);
		} else {
			mmio_write_32(MBOX_OFFSET + MBOX_CMD_BUFFER +
				      (*cin * 4), data);
			(*cin)++;
			*cin %= MBOX_CMD_BUFFER_SIZE;
			mmio_write_32(MBOX_OFFSET + MBOX_CIN, *cin);
			break;
		}
	} while (--timeout != 0U);

	if (timeout == 0U) {
		return MBOX_TIMEOUT;
	}

	if (*is_doorbell_triggered) {
		int ret = wait_for_mailbox_cmdbuf_empty(*cin);
		return ret;
	}

	return MBOX_RET_OK;
}

83
static int fill_mailbox_circular_buffer(uint32_t header_cmd, uint32_t *args,
84
85
					int len)
{
86
	uint32_t sdm_read_offset, cmd_free_offset;
87
88
89
	uint32_t i;
	int ret;
	bool is_doorbell_triggered = false;
90
91

	cmd_free_offset = mmio_read_32(MBOX_OFFSET + MBOX_CIN);
92
93
	sdm_read_offset = mmio_read_32(MBOX_OFFSET + MBOX_COUT);

94
95
96
	ret = write_mailbox_cmd_buffer(&cmd_free_offset, sdm_read_offset,
				       header_cmd, &is_doorbell_triggered);
	if (ret != 0) {
97
		goto restart_mailbox;
98
	}
99

100
101
102
103
104
105
	for (i = 0U; i < len; i++) {
		is_doorbell_triggered = false;
		ret = write_mailbox_cmd_buffer(&cmd_free_offset,
					       sdm_read_offset, args[i],
					       &is_doorbell_triggered);
		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
117
118
119
120
121
122
123
124
125
126
127
128
129
130

restart_mailbox:
	/*
	 * Attempt to restart mailbox if the driver not able to write
	 * into mailbox command buffer
	 */
	if (MBOX_CMD_MASK(header_cmd) != MBOX_CMD_RESTART) {
		INFO("Mailbox timed out: Attempting mailbox reset\n");
		ret = mailbox_init();

		if (ret == MBOX_TIMEOUT) {
			INFO("Error: Mailbox fail to restart\n");
		}
	}

	return MBOX_TIMEOUT;
131
132
}

133
int mailbox_read_response(uint32_t *job_id, uint32_t *response, int resp_len)
134
135
136
{
	int rin = 0;
	int rout = 0;
137
	int resp_data = 0;
138
	int ret_resp_len;
139

140
141
142
	if (mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM) == 1U) {
		mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0U);
	}
143
144
145
146

	rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
	rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT);

147
	if (rout != rin) {
148
		resp_data = mmio_read_32(MBOX_OFFSET +
149
150
151
152
153
				    MBOX_RESP_BUFFER + ((rout++)*4));

		rout %= MBOX_RESP_BUFFER_SIZE;
		mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);

154
155

		if (MBOX_RESP_CLIENT_ID(resp_data) != MBOX_ATF_CLIENT_ID) {
156
157
158
			return MBOX_WRONG_ID;
		}

159
160
		*job_id = MBOX_RESP_JOB_ID(resp_data);

161
162
163
164
165
166
167
		ret_resp_len = MBOX_RESP_LEN(resp_data);

		if (ret_resp_len != 0) {
			ret_resp_len = iterate_resp(ret_resp_len, response,
						    resp_len);
		}

168
169
		if (MBOX_RESP_ERR(resp_data) > 0) {
			INFO("Error in response: %x\n", resp_data);
170
			return -MBOX_RESP_ERR(resp_data);
171
172
		}

173
		return ret_resp_len;
174
175
176
177
178
	}
	return MBOX_NO_RESPONSE;
}


179
int mailbox_poll_response(uint32_t job_id, int urgent, uint32_t *response,
180
				int resp_len)
181
{
182
	uint32_t timeout = 40U;
183
	uint32_t sdm_loop = 255U;
184
185
	int rin = 0;
	int rout = 0;
186
	int resp_data = 0;
187
	int ret_resp_len;
188

189
	while (sdm_loop != 0U) {
190

191
192
		do {
			if (mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM)
193
				== 1U) {
194
195
				break;
			}
196
			mdelay(10U);
197
		} while (--timeout != 0U);
198

199
		if (timeout == 0U) {
200
			break;
201
202
		}

203
		mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0U);
204

205
206
		if ((urgent & 1) != 0) {
			mdelay(5U);
207
208
209
			if ((mmio_read_32(MBOX_OFFSET + MBOX_STATUS) &
				MBOX_STATUS_UA_MASK) ^
				(urgent & MBOX_STATUS_UA_MASK)) {
210
				mmio_write_32(MBOX_OFFSET + MBOX_URG, 0U);
211
				return MBOX_RET_OK;
212
213
			}

214
			mmio_write_32(MBOX_OFFSET + MBOX_URG, 0U);
215
			INFO("Error: Mailbox did not get UA");
216
			return MBOX_RET_ERROR;
217
218
219
220
221
222
		}

		rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
		rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT);

		while (rout != rin) {
223
			resp_data = mmio_read_32(MBOX_OFFSET +
224
225
226
227
228
					    MBOX_RESP_BUFFER + ((rout++)*4));

			rout %= MBOX_RESP_BUFFER_SIZE;
			mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);

229
			if (MBOX_RESP_CLIENT_ID(resp_data) != MBOX_ATF_CLIENT_ID
230
				|| MBOX_RESP_JOB_ID(resp_data) != job_id) {
231
				continue;
232
			}
233

234
235
236
237
238
239
240
241
			ret_resp_len = MBOX_RESP_LEN(resp_data);

			if (ret_resp_len != 0) {
				ret_resp_len = iterate_resp(ret_resp_len,
							    response,
							    resp_len);
			}

242
243
244
			if (MBOX_RESP_ERR(resp_data) > 0) {
				INFO("Error in response: %x\n", resp_data);
				return -MBOX_RESP_ERR(resp_data);
245
			}
246

247
			return ret_resp_len;
248
		}
249
250

	sdm_loop--;
251
	}
252
253
254

	INFO("Timed out waiting for SDM\n");
	return MBOX_TIMEOUT;
255
256
257
258
259
260
261
262
263
264
}

int iterate_resp(int mbox_resp_len, uint32_t *resp_buf, int resp_len)
{
	uint32_t timeout;
	int resp_data = 0, total_resp_len = 0;
	int rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
	int rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT);

	while (mbox_resp_len > 0) {
265
		timeout = 100U;
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
		mbox_resp_len--;
		resp_data = mmio_read_32(MBOX_OFFSET +
					MBOX_RESP_BUFFER +
					(rout)*4);
		if (resp_buf && resp_len) {
			*(resp_buf + total_resp_len)
					= resp_data;
			resp_len--;
			total_resp_len++;
		}
		rout++;
		rout %= MBOX_RESP_BUFFER_SIZE;
		mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);

		do {
			rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
282
			if (rout == rin) {
283
				mdelay(10U);
284
285
286
287
288
			} else {
				break;
			}
			timeout--;
		} while ((mbox_resp_len > 0) && (timeout != 0U));
289

290
		if (timeout == 0U) {
291
292
			INFO("Timed out waiting for SDM\n");
			return MBOX_TIMEOUT;
293
294
		}
	}
295
	return total_resp_len;
296
297
}

298
int mailbox_send_cmd_async(uint32_t *job_id, unsigned int cmd, uint32_t *args,
299
			  int len, int indirect)
300
{
301
302
303
304
305
306
307
308
309
310
311
	int status;

	status = fill_mailbox_circular_buffer(
				MBOX_CLIENT_ID_CMD(MBOX_ATF_CLIENT_ID) |
				MBOX_JOB_ID_CMD(*job_id) |
				MBOX_CMD_LEN_CMD(len) |
				MBOX_INDIRECT(indirect) |
				cmd, args, len);
	if (status < 0) {
		return status;
	}
312

313
	*job_id = (*job_id + 1U) % MBOX_MAX_IND_JOB_ID;
314

315
	return MBOX_RET_OK;
316
317
}

318
int mailbox_send_cmd(uint32_t job_id, unsigned int cmd, uint32_t *args,
319
			int len, int urgent, uint32_t *response, int resp_len)
320
{
321
	int status = 0;
322

323
	if (urgent != 0) {
324
325
326
		urgent |= mmio_read_32(MBOX_OFFSET + MBOX_STATUS) &
					MBOX_STATUS_UA_MASK;
		mmio_write_32(MBOX_OFFSET + MBOX_URG, cmd);
327
		mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_TO_SDM, 1U);
328
329
330
	}

	else {
331
332
333
		status = fill_mailbox_circular_buffer(
			MBOX_CLIENT_ID_CMD(MBOX_ATF_CLIENT_ID) |
			MBOX_JOB_ID_CMD(job_id) |
334
			MBOX_CMD_LEN_CMD(len) |
335
336
337
			cmd, args, len);
	}

338
	if (status != 0) {
339
		return status;
340
	}
341

342
	status = mailbox_poll_response(job_id, urgent, response, resp_len);
343
344
345
346
347
348
349
350

	return status;
}

void mailbox_clear_response(void)
{
	mmio_write_32(MBOX_OFFSET + MBOX_ROUT,
		mmio_read_32(MBOX_OFFSET + MBOX_RIN));
351
352
353
354
355
356
357
358
359
360
361
362
363
}

void mailbox_set_int(int interrupt)
{

	mmio_write_32(MBOX_OFFSET+MBOX_INT, MBOX_COE_BIT(interrupt) |
			MBOX_UAE_BIT(interrupt));
}


void mailbox_set_qspi_open(void)
{
	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
364
365
	mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_OPEN, NULL, 0,
				CMD_CASUAL, NULL, 0);
366
367
368
369
}

void mailbox_set_qspi_direct(void)
{
370
371
	mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_DIRECT, NULL, 0,
				CMD_CASUAL, NULL, 0);
372
373
374
375
376
}

void mailbox_set_qspi_close(void)
{
	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
377
378
	mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_CLOSE, NULL, 0,
				CMD_CASUAL, NULL, 0);
379
380
}

381
void mailbox_qspi_set_cs(uint32_t device_select)
382
{
383
	uint32_t cs_setting;
384
385

	/* QSPI device select settings at 31:28 */
386
	cs_setting = (device_select << 28);
387
388
	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
	mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_SET_CS, &cs_setting,
389
				1, CMD_CASUAL, NULL, 0);
390
391
392
393
394
}

void mailbox_reset_cold(void)
{
	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
395
396
	mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_REBOOT_HPS, NULL, 0,
				CMD_CASUAL, NULL, 0);
397
398
}

399
400
401
int mailbox_rsu_get_spt_offset(uint32_t *resp_buf, uint32_t resp_buf_len)
{
	return mailbox_send_cmd(MBOX_JOB_ID, MBOX_GET_SUBPARTITION_TABLE,
402
				NULL, 0, CMD_CASUAL, (uint32_t *)resp_buf,
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
				resp_buf_len);
}

struct rsu_status_info {
	uint64_t current_image;
	uint64_t fail_image;
	uint32_t state;
	uint32_t version;
	uint32_t error_location;
	uint32_t error_details;
	uint32_t retry_counter;
};

int mailbox_rsu_status(uint32_t *resp_buf, uint32_t resp_buf_len)
{
	int ret;
	struct rsu_status_info *info = (struct rsu_status_info *)resp_buf;

421
	info->retry_counter = ~0U;
422

423
424
425
	ret = mailbox_send_cmd(MBOX_JOB_ID, MBOX_RSU_STATUS, NULL, 0,
				CMD_CASUAL, (uint32_t *)resp_buf,
				resp_buf_len);
426

427
	if (ret < 0) {
428
		return ret;
429
	}
430

431
432
	if (info->retry_counter != ~0U) {
		if ((info->version & RSU_VERSION_ACMF_MASK) == 0U) {
433
			info->version |= RSU_VERSION_ACMF;
434
435
		}
	}
436
437
438
439

	return ret;
}

440
int mailbox_rsu_update(uint32_t *flash_offset)
441
442
{
	return mailbox_send_cmd(MBOX_JOB_ID, MBOX_RSU_UPDATE,
443
444
				flash_offset, 2,
				CMD_CASUAL, NULL, 0);
445
446
}

447
int mailbox_hps_stage_notify(uint32_t execution_stage)
448
449
{
	return mailbox_send_cmd(MBOX_JOB_ID, MBOX_HPS_STAGE_NOTIFY,
450
451
				&execution_stage, 1, CMD_CASUAL,
				NULL, 0);
452
453
}

454
455
456
457
458
459
int mailbox_init(void)
{
	int status = 0;

	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE |
			MBOX_INT_FLAG_UAE);
460
461
	mmio_write_32(MBOX_OFFSET + MBOX_URG, 0U);
	mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0U);
462

463
	status = mailbox_send_cmd(0U, MBOX_CMD_RESTART, NULL, 0,
464
					CMD_URGENT, NULL, 0);
465

466
	if (status != 0) {
467
		return status;
468
	}
469

470
471
	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE |
			MBOX_INT_FLAG_UAE);
472

473
	return MBOX_RET_OK;
474
475
}

476
int intel_mailbox_get_config_status(uint32_t cmd)
477
{
478
479
	int status;
	uint32_t res, response[6];
480

481
482
	status = mailbox_send_cmd(MBOX_JOB_ID, cmd, NULL, 0, CMD_CASUAL, response,
				ARRAY_SIZE(response));
483

484
	if (status < 0) {
485
		return status;
486
	}
487
488

	res = response[RECONFIG_STATUS_STATE];
489
	if ((res != 0U) && (res != MBOX_CFGSTAT_STATE_CONFIG)) {
490
		return res;
491
	}
492
493

	res = response[RECONFIG_STATUS_PIN_STATUS];
494
	if ((res & PIN_STATUS_NSTATUS) == 0U) {
495
		return MBOX_CFGSTAT_STATE_ERROR_HARDWARE;
496
	}
497
498

	res = response[RECONFIG_STATUS_SOFTFUNC_STATUS];
499
	if ((res & SOFTFUNC_STATUS_SEU_ERROR) != 0U) {
500
		return MBOX_CFGSTAT_STATE_ERROR_HARDWARE;
501
	}
502

503
504
	if ((res & SOFTFUNC_STATUS_CONF_DONE) != 0U &&
		(res & SOFTFUNC_STATUS_INIT_DONE) != 0U) {
505
		return MBOX_RET_OK;
506
	}
507

508
	return MBOX_CFGSTAT_STATE_CONFIG;
509
}
510
511
512
513
514

int intel_mailbox_is_fpga_not_ready(void)
{
	int ret = intel_mailbox_get_config_status(MBOX_RECONFIG_STATUS);

515
	if ((ret != MBOX_RET_OK) && (ret != MBOX_CFGSTAT_STATE_CONFIG)) {
516
		ret = intel_mailbox_get_config_status(MBOX_CONFIG_STATUS);
517
	}
518
519
520

	return ret;
}