socfpga_mailbox.c 8.94 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
49
	int mbox_resp_len = 0;
	int resp_data = 0;
50
	int total_resp_len = 0;
51
	uint32_t *resp_buf = response;
52

53
54
	if (mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM))
		mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0);
55
56
57
58

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

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

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

66
67

		if (MBOX_RESP_CLIENT_ID(resp_data) != MBOX_ATF_CLIENT_ID) {
68
69
70
			return MBOX_WRONG_ID;
		}

71
72
		*job_id = MBOX_RESP_JOB_ID(resp_data);

73
74
75
		if (MBOX_RESP_ERR(resp_data) > 0) {
			INFO("Error in response: %x\n", resp_data);
			return -resp_data;
76
		}
77
		mbox_resp_len = MBOX_RESP_LEN(resp_data);
78

79
		while (mbox_resp_len > 0) {
80

81
82
			mbox_resp_len--;
			resp_data = mmio_read_32(MBOX_OFFSET +
83
84
						MBOX_RESP_BUFFER +
						(rout)*4);
85
86
			if (resp_buf && resp_len) {
				*(resp_buf + total_resp_len) = resp_data;
87
				resp_len--;
88
89
90
91
92
93
94
95
96
97
98
99
100
				total_resp_len++;
			}
			rout++;
			rout %= MBOX_RESP_BUFFER_SIZE;
			mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);
		}
		return total_resp_len;
	}

	return MBOX_NO_RESPONSE;
}


101
int mailbox_poll_response(uint32_t job_id, int urgent, uint32_t *response,
102
				int resp_len)
103
{
104
	int timeout = 0xFFFFFF;
105
106
	int rin = 0;
	int rout = 0;
107
108
	int mbox_resp_len = 0;
	int resp_data = 0;
109
	int total_resp_len = 0;
110
	uint32_t *resp_buf = response;
111
112

	while (1) {
113

114
		while (timeout > 0 &&
115
116
			!(mmio_read_32(MBOX_OFFSET +
				MBOX_DOORBELL_FROM_SDM) & 1)) {
117
118
119
			timeout--;
		}

120
		if (!timeout) {
121
122
123
124
125
126
127
			INFO("Timed out waiting for SDM");
			return MBOX_TIMEOUT;
		}

		mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0);

		if (urgent & 1) {
128
			mdelay(5);
129
130
131
132
			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);
133
				return MBOX_RET_OK;
134
135
136
137
			}

			mmio_write_32(MBOX_OFFSET + MBOX_URG, 0);
			INFO("Error: Mailbox did not get UA");
138
			return MBOX_RET_ERROR;
139
140
141
142
143
144
		}

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

		while (rout != rin) {
145
			resp_data = mmio_read_32(MBOX_OFFSET +
146
147
148
149
150
					    MBOX_RESP_BUFFER + ((rout++)*4));

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

151
152
			if (MBOX_RESP_CLIENT_ID(resp_data) != MBOX_ATF_CLIENT_ID
				|| MBOX_RESP_JOB_ID(resp_data) != job_id)
153
154
				continue;

155
156
157
			if (MBOX_RESP_ERR(resp_data) > 0) {
				INFO("Error in response: %x\n", resp_data);
				return -MBOX_RESP_ERR(resp_data);
158
			}
159
			mbox_resp_len = MBOX_RESP_LEN(resp_data);
160

161
162
163
			while (mbox_resp_len > 0) {
				mbox_resp_len--;
				resp_data = mmio_read_32(MBOX_OFFSET +
164
165
							MBOX_RESP_BUFFER +
							(rout)*4);
166
167
168
				if (resp_buf && resp_len) {
					*(resp_buf + total_resp_len)
							= resp_data;
169
					resp_len--;
170
171
172
173
174
175
176
177
178
179
180
					total_resp_len++;
				}
				rout++;
				rout %= MBOX_RESP_BUFFER_SIZE;
				mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);
			}
			return total_resp_len;
		}
	}
}

181
int mailbox_send_cmd_async(uint32_t *job_id, unsigned int cmd, uint32_t *args,
182
			  int len, int indirect)
183
{
184
185
186
187
188
189
190
191
192
193
194
	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;
	}
195
196

	mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_TO_SDM, 1);
197
	*job_id = (*job_id + 1) % MBOX_MAX_IND_JOB_ID;
198

199
	return MBOX_RET_OK;
200
201
}

202
int mailbox_send_cmd(uint32_t job_id, unsigned int cmd, uint32_t *args,
203
			int len, int urgent, uint32_t *response, int resp_len)
204
{
205
	int status = 0;
206
207
208
209
210

	if (urgent) {
		urgent |= mmio_read_32(MBOX_OFFSET + MBOX_STATUS) &
					MBOX_STATUS_UA_MASK;
		mmio_write_32(MBOX_OFFSET + MBOX_URG, cmd);
211
212
213
	}

	else {
214
215
216
		status = fill_mailbox_circular_buffer(
			MBOX_CLIENT_ID_CMD(MBOX_ATF_CLIENT_ID) |
			MBOX_JOB_ID_CMD(job_id) |
217
			MBOX_CMD_LEN_CMD(len) |
218
219
220
221
222
223
			cmd, args, len);
	}

	if (status)
		return status;

224
	mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_TO_SDM, 1);
225
	status = mailbox_poll_response(job_id, urgent, response, resp_len);
226
227
228
229
230
231
232
233

	return status;
}

void mailbox_clear_response(void)
{
	mmio_write_32(MBOX_OFFSET + MBOX_ROUT,
		mmio_read_32(MBOX_OFFSET + MBOX_RIN));
234
235
236
237
238
239
240
241
242
243
244
245
246
}

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);
247
248
	mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_OPEN, NULL, 0,
				CMD_CASUAL, NULL, 0);
249
250
251
252
}

void mailbox_set_qspi_direct(void)
{
253
254
	mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_DIRECT, NULL, 0,
				CMD_CASUAL, NULL, 0);
255
256
257
258
259
}

void mailbox_set_qspi_close(void)
{
	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
260
261
	mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_CLOSE, NULL, 0,
				CMD_CASUAL, NULL, 0);
262
263
264
265
}

void mailbox_qspi_set_cs(int device_select)
{
266
	uint32_t cs_setting = device_select;
267
268
269
270
271

	/* 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,
272
				1, CMD_CASUAL, NULL, 0);
273
274
275
276
277
}

void mailbox_reset_cold(void)
{
	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
278
279
	mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_REBOOT_HPS, NULL, 0,
				CMD_CASUAL, NULL, 0);
280
281
}

282
283
284
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,
285
				NULL, 0, CMD_CASUAL, (uint32_t *)resp_buf,
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
				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;

306
307
308
	ret = mailbox_send_cmd(MBOX_JOB_ID, MBOX_RSU_STATUS, NULL, 0,
				CMD_CASUAL, (uint32_t *)resp_buf,
				resp_buf_len);
309
310
311
312
313
314
315
316
317
318
319

	if (ret < 0)
		return ret;

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

	return ret;
}

320
int mailbox_rsu_update(uint32_t *flash_offset)
321
322
{
	return mailbox_send_cmd(MBOX_JOB_ID, MBOX_RSU_UPDATE,
323
324
				flash_offset, 2,
				CMD_CASUAL, NULL, 0);
325
326
}

327
int mailbox_hps_stage_notify(uint32_t execution_stage)
328
329
{
	return mailbox_send_cmd(MBOX_JOB_ID, MBOX_HPS_STAGE_NOTIFY,
330
331
				&execution_stage, 1, CMD_CASUAL,
				NULL, 0);
332
333
}

334
335
336
337
338
339
int mailbox_init(void)
{
	int status = 0;

	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE |
			MBOX_INT_FLAG_UAE);
340
341
342
	mmio_write_32(MBOX_OFFSET + MBOX_URG, 0);
	mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0);

343
344
	status = mailbox_send_cmd(0, MBOX_CMD_RESTART, NULL, 0,
					CMD_URGENT, NULL, 0);
345
346
347
348

	if (status)
		return status;

349
350
	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE |
			MBOX_INT_FLAG_UAE);
351

352
	return MBOX_RET_OK;
353
354
}

355
int intel_mailbox_get_config_status(uint32_t cmd)
356
{
357
358
	int status;
	uint32_t res, response[6];
359

360
361
	status = mailbox_send_cmd(MBOX_JOB_ID, cmd, NULL, 0, CMD_CASUAL, response,
				ARRAY_SIZE(response));
362
363

	if (status < 0)
364
		return status;
365
366
367

	res = response[RECONFIG_STATUS_STATE];
	if (res && res != MBOX_CFGSTAT_STATE_CONFIG)
368
		return res;
369
370
371

	res = response[RECONFIG_STATUS_PIN_STATUS];
	if (!(res & PIN_STATUS_NSTATUS))
372
		return MBOX_CFGSTAT_STATE_ERROR_HARDWARE;
373
374
375

	res = response[RECONFIG_STATUS_SOFTFUNC_STATUS];
	if (res & SOFTFUNC_STATUS_SEU_ERROR)
376
		return MBOX_CFGSTAT_STATE_ERROR_HARDWARE;
377
378
379

	if ((res & SOFTFUNC_STATUS_CONF_DONE) &&
		(res & SOFTFUNC_STATUS_INIT_DONE))
380
		return MBOX_RET_OK;
381

382
	return MBOX_CFGSTAT_STATE_CONFIG;
383
}
384
385
386
387
388
389
390
391
392
393

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;
}