socfpga_mailbox.c 9.16 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
static int fill_mailbox_circular_buffer(uint32_t header_cmd, uint32_t *args,
15
16
					int len)
{
17
	uint32_t sdm_read_offset, cmd_free_offset;
18
19
20
	int i;

	cmd_free_offset = mmio_read_32(MBOX_OFFSET + MBOX_CIN);
21
22
23
24
25
26
	sdm_read_offset = mmio_read_32(MBOX_OFFSET + MBOX_COUT);

	if ((cmd_free_offset < sdm_read_offset) &&
		(cmd_free_offset + len > sdm_read_offset)) {
		return MBOX_BUFFER_FULL;
	}
27
28
29
30
31
32
33
34
35
36
37
38
39
40

	mmio_write_32(MBOX_OFFSET + MBOX_CMD_BUFFER + (cmd_free_offset++ * 4),
			header_cmd);


	for (i = 0; i < len; i++) {
		cmd_free_offset %= MBOX_CMD_BUFFER_SIZE;
		mmio_write_32(MBOX_OFFSET + MBOX_CMD_BUFFER +
				(cmd_free_offset++ * 4), args[i]);
	}

	cmd_free_offset %= MBOX_CMD_BUFFER_SIZE;
	mmio_write_32(MBOX_OFFSET + MBOX_CIN, cmd_free_offset);

41
	return MBOX_RET_OK;
42
43
}

44
int mailbox_read_response(uint32_t *job_id, uint32_t *response, int resp_len)
45
46
47
{
	int rin = 0;
	int rout = 0;
48
	int resp_data = 0;
49
	int ret_resp_len;
50

51
52
	if (mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM))
		mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0);
53
54
55
56

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

57
	if (rout != rin) {
58
		resp_data = mmio_read_32(MBOX_OFFSET +
59
60
61
62
63
				    MBOX_RESP_BUFFER + ((rout++)*4));

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

64
65

		if (MBOX_RESP_CLIENT_ID(resp_data) != MBOX_ATF_CLIENT_ID) {
66
67
68
			return MBOX_WRONG_ID;
		}

69
70
		*job_id = MBOX_RESP_JOB_ID(resp_data);

71
72
73
74
75
76
77
		ret_resp_len = MBOX_RESP_LEN(resp_data);

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

78
79
80
		if (MBOX_RESP_ERR(resp_data) > 0) {
			INFO("Error in response: %x\n", resp_data);
			return -resp_data;
81
82
		}

83
		return ret_resp_len;
84
85
86
87
88
	}
	return MBOX_NO_RESPONSE;
}


89
int mailbox_poll_response(uint32_t job_id, int urgent, uint32_t *response,
90
				int resp_len)
91
{
92
	int timeout = 0xFFFFFF;
93
94
	int rin = 0;
	int rout = 0;
95
	int resp_data = 0;
96
	int ret_resp_len;
97
98

	while (1) {
99

100
		while (timeout > 0 &&
101
102
			!(mmio_read_32(MBOX_OFFSET +
				MBOX_DOORBELL_FROM_SDM) & 1)) {
103
104
105
			timeout--;
		}

106
		if (!timeout) {
107
			INFO("Timed out waiting for SDM\n");
108
109
110
111
112
113
			return MBOX_TIMEOUT;
		}

		mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0);

		if (urgent & 1) {
114
			mdelay(5);
115
116
117
118
			if ((mmio_read_32(MBOX_OFFSET + MBOX_STATUS) &
				MBOX_STATUS_UA_MASK) ^
				(urgent & MBOX_STATUS_UA_MASK)) {
				mmio_write_32(MBOX_OFFSET + MBOX_URG, 0);
119
				return MBOX_RET_OK;
120
121
122
123
			}

			mmio_write_32(MBOX_OFFSET + MBOX_URG, 0);
			INFO("Error: Mailbox did not get UA");
124
			return MBOX_RET_ERROR;
125
126
127
128
129
130
		}

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

		while (rout != rin) {
131
			resp_data = mmio_read_32(MBOX_OFFSET +
132
133
134
135
136
					    MBOX_RESP_BUFFER + ((rout++)*4));

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

137
138
			if (MBOX_RESP_CLIENT_ID(resp_data) != MBOX_ATF_CLIENT_ID
				|| MBOX_RESP_JOB_ID(resp_data) != job_id)
139
140
				continue;

141
142
143
144
145
146
147
148
			ret_resp_len = MBOX_RESP_LEN(resp_data);

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

149
150
151
			if (MBOX_RESP_ERR(resp_data) > 0) {
				INFO("Error in response: %x\n", resp_data);
				return -MBOX_RESP_ERR(resp_data);
152
			}
153

154
			return ret_resp_len;
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
		}
	}
}

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) {
		timeout = 0xFFFFFF;
		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 {
			timeout--;
			rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
		} while ((rout == rin) && (mbox_resp_len > 0) && (timeout > 0));

		if (timeout == 0) {
			INFO("Timed out waiting for SDM\n");
			return MBOX_TIMEOUT;
190
191
		}
	}
192
	return total_resp_len;
193
194
}

195
int mailbox_send_cmd_async(uint32_t *job_id, unsigned int cmd, uint32_t *args,
196
			  int len, int indirect)
197
{
198
199
200
201
202
203
204
205
206
207
208
	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;
	}
209
210

	mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_TO_SDM, 1);
211
	*job_id = (*job_id + 1) % MBOX_MAX_IND_JOB_ID;
212

213
	return MBOX_RET_OK;
214
215
}

216
int mailbox_send_cmd(uint32_t job_id, unsigned int cmd, uint32_t *args,
217
			int len, int urgent, uint32_t *response, int resp_len)
218
{
219
	int status = 0;
220
221
222
223
224

	if (urgent) {
		urgent |= mmio_read_32(MBOX_OFFSET + MBOX_STATUS) &
					MBOX_STATUS_UA_MASK;
		mmio_write_32(MBOX_OFFSET + MBOX_URG, cmd);
225
226
227
	}

	else {
228
229
230
		status = fill_mailbox_circular_buffer(
			MBOX_CLIENT_ID_CMD(MBOX_ATF_CLIENT_ID) |
			MBOX_JOB_ID_CMD(job_id) |
231
			MBOX_CMD_LEN_CMD(len) |
232
233
234
235
236
237
			cmd, args, len);
	}

	if (status)
		return status;

238
	mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_TO_SDM, 1);
239
	status = mailbox_poll_response(job_id, urgent, response, resp_len);
240
241
242
243
244
245
246
247

	return status;
}

void mailbox_clear_response(void)
{
	mmio_write_32(MBOX_OFFSET + MBOX_ROUT,
		mmio_read_32(MBOX_OFFSET + MBOX_RIN));
248
249
250
251
252
253
254
255
256
257
258
259
260
}

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);
261
262
	mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_OPEN, NULL, 0,
				CMD_CASUAL, NULL, 0);
263
264
265
266
}

void mailbox_set_qspi_direct(void)
{
267
268
	mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_DIRECT, NULL, 0,
				CMD_CASUAL, NULL, 0);
269
270
271
272
273
}

void mailbox_set_qspi_close(void)
{
	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
274
275
	mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_CLOSE, NULL, 0,
				CMD_CASUAL, NULL, 0);
276
277
278
279
}

void mailbox_qspi_set_cs(int device_select)
{
280
	uint32_t cs_setting = device_select;
281
282
283
284
285

	/* QSPI device select settings at 31:28 */
	cs_setting = (cs_setting << 28);
	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
	mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_SET_CS, &cs_setting,
286
				1, CMD_CASUAL, NULL, 0);
287
288
289
290
291
}

void mailbox_reset_cold(void)
{
	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
292
293
	mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_REBOOT_HPS, NULL, 0,
				CMD_CASUAL, NULL, 0);
294
295
}

296
297
298
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,
299
				NULL, 0, CMD_CASUAL, (uint32_t *)resp_buf,
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
				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;

	info->retry_counter = ~0;

320
321
322
	ret = mailbox_send_cmd(MBOX_JOB_ID, MBOX_RSU_STATUS, NULL, 0,
				CMD_CASUAL, (uint32_t *)resp_buf,
				resp_buf_len);
323
324
325
326
327
328
329
330
331
332
333

	if (ret < 0)
		return ret;

	if (info->retry_counter != ~0)
		if (!(info->version & RSU_VERSION_ACMF_MASK))
			info->version |= RSU_VERSION_ACMF;

	return ret;
}

334
int mailbox_rsu_update(uint32_t *flash_offset)
335
336
{
	return mailbox_send_cmd(MBOX_JOB_ID, MBOX_RSU_UPDATE,
337
338
				flash_offset, 2,
				CMD_CASUAL, NULL, 0);
339
340
}

341
int mailbox_hps_stage_notify(uint32_t execution_stage)
342
343
{
	return mailbox_send_cmd(MBOX_JOB_ID, MBOX_HPS_STAGE_NOTIFY,
344
345
				&execution_stage, 1, CMD_CASUAL,
				NULL, 0);
346
347
}

348
349
350
351
352
353
int mailbox_init(void)
{
	int status = 0;

	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE |
			MBOX_INT_FLAG_UAE);
354
355
356
	mmio_write_32(MBOX_OFFSET + MBOX_URG, 0);
	mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0);

357
358
	status = mailbox_send_cmd(0, MBOX_CMD_RESTART, NULL, 0,
					CMD_URGENT, NULL, 0);
359
360
361
362

	if (status)
		return status;

363
364
	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE |
			MBOX_INT_FLAG_UAE);
365

366
	return MBOX_RET_OK;
367
368
}

369
int intel_mailbox_get_config_status(uint32_t cmd)
370
{
371
372
	int status;
	uint32_t res, response[6];
373

374
375
	status = mailbox_send_cmd(MBOX_JOB_ID, cmd, NULL, 0, CMD_CASUAL, response,
				ARRAY_SIZE(response));
376
377

	if (status < 0)
378
		return status;
379
380
381

	res = response[RECONFIG_STATUS_STATE];
	if (res && res != MBOX_CFGSTAT_STATE_CONFIG)
382
		return res;
383
384
385

	res = response[RECONFIG_STATUS_PIN_STATUS];
	if (!(res & PIN_STATUS_NSTATUS))
386
		return MBOX_CFGSTAT_STATE_ERROR_HARDWARE;
387
388
389

	res = response[RECONFIG_STATUS_SOFTFUNC_STATUS];
	if (res & SOFTFUNC_STATUS_SEU_ERROR)
390
		return MBOX_CFGSTAT_STATE_ERROR_HARDWARE;
391
392
393

	if ((res & SOFTFUNC_STATUS_CONF_DONE) &&
		(res & SOFTFUNC_STATUS_INIT_DONE))
394
		return MBOX_RET_OK;
395

396
	return MBOX_CFGSTAT_STATE_CONFIG;
397
}
398
399
400
401
402
403
404
405
406
407

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

	if (ret && ret != MBOX_CFGSTAT_STATE_CONFIG)
		ret = intel_mailbox_get_config_status(MBOX_CONFIG_STATUS);

	return ret;
}