socfpga_mailbox.c 8.91 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

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

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

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

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

63
64

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

68
69
		*job_id = MBOX_RESP_JOB_ID(resp_data);

70
71
72
		if (MBOX_RESP_ERR(resp_data) > 0) {
			INFO("Error in response: %x\n", resp_data);
			return -resp_data;
73
74
		}

75
76
		return iterate_resp(MBOX_RESP_LEN(resp_data),
					response, resp_len);
77
78
79
80
81
	}
	return MBOX_NO_RESPONSE;
}


82
int mailbox_poll_response(uint32_t job_id, int urgent, uint32_t *response,
83
				int resp_len)
84
{
85
	int timeout = 0xFFFFFF;
86
87
	int rin = 0;
	int rout = 0;
88
	int resp_data = 0;
89
90

	while (1) {
91

92
		while (timeout > 0 &&
93
94
			!(mmio_read_32(MBOX_OFFSET +
				MBOX_DOORBELL_FROM_SDM) & 1)) {
95
96
97
			timeout--;
		}

98
		if (!timeout) {
99
			INFO("Timed out waiting for SDM\n");
100
101
102
103
104
105
			return MBOX_TIMEOUT;
		}

		mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0);

		if (urgent & 1) {
106
			mdelay(5);
107
108
109
110
			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);
111
				return MBOX_RET_OK;
112
113
114
115
			}

			mmio_write_32(MBOX_OFFSET + MBOX_URG, 0);
			INFO("Error: Mailbox did not get UA");
116
			return MBOX_RET_ERROR;
117
118
119
120
121
122
		}

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

		while (rout != rin) {
123
			resp_data = mmio_read_32(MBOX_OFFSET +
124
125
126
127
128
					    MBOX_RESP_BUFFER + ((rout++)*4));

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

129
130
			if (MBOX_RESP_CLIENT_ID(resp_data) != MBOX_ATF_CLIENT_ID
				|| MBOX_RESP_JOB_ID(resp_data) != job_id)
131
132
				continue;

133
134
135
			if (MBOX_RESP_ERR(resp_data) > 0) {
				INFO("Error in response: %x\n", resp_data);
				return -MBOX_RESP_ERR(resp_data);
136
			}
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174

			return iterate_resp(MBOX_RESP_LEN(resp_data),
						response, resp_len);
		}
	}
}

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;
175
176
		}
	}
177
	return total_resp_len;
178
179
}

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

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

198
	return MBOX_RET_OK;
199
200
}

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

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

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

	if (status)
		return status;

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

	return status;
}

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

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

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

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

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

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

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

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

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

	if (ret < 0)
		return ret;

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

	return ret;
}

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

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

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

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

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

	if (status)
		return status;

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

351
	return MBOX_RET_OK;
352
353
}

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

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

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

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

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

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

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

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

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