blob: f5fd9a14c266861ab06fb474d37d3b1aba09cb9b [file] [log] [blame]
Ang, Chee Hongdcc3bb62018-12-19 18:35:14 -08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018 Intel Corporation <www.intel.com>
4 */
5
6#include <common.h>
7#include <altera.h>
Simon Glass0f2af882020-05-10 11:40:05 -06008#include <log.h>
Chee Hong Ang4e87fcd2020-08-07 11:50:04 +08009#include <watchdog.h>
Ang, Chee Hongdcc3bb62018-12-19 18:35:14 -080010#include <asm/arch/mailbox_s10.h>
Chee Hong Angec4c6792020-12-24 18:21:07 +080011#include <asm/arch/smc_api.h>
Simon Glassdbd79542020-05-10 11:40:11 -060012#include <linux/delay.h>
Chee Hong Angec4c6792020-12-24 18:21:07 +080013#include <linux/intel-smc.h>
Ang, Chee Hongdcc3bb62018-12-19 18:35:14 -080014
15#define RECONFIG_STATUS_POLL_RESP_TIMEOUT_MS 60000
16#define RECONFIG_STATUS_INTERVAL_DELAY_US 1000000
17
Chee Hong Angec4c6792020-12-24 18:21:07 +080018#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_ATF)
19
20#define BITSTREAM_CHUNK_SIZE 0xFFFF0
21#define RECONFIG_STATUS_POLL_RETRY_MAX 100
22
23/*
24 * Polling the FPGA configuration status.
25 * Return 0 for success, non-zero for error.
26 */
27static int reconfig_status_polling_resp(void)
28{
29 int ret;
30 unsigned long start = get_timer(0);
31
32 while (1) {
33 ret = invoke_smc(INTEL_SIP_SMC_FPGA_CONFIG_ISDONE, NULL, 0,
34 NULL, 0);
35
36 if (!ret)
37 return 0; /* configuration success */
38
39 if (ret != INTEL_SIP_SMC_STATUS_BUSY)
40 return ret;
41
42 if (get_timer(start) > RECONFIG_STATUS_POLL_RESP_TIMEOUT_MS)
43 return -ETIMEDOUT; /* time out */
44
45 puts(".");
46 udelay(RECONFIG_STATUS_INTERVAL_DELAY_US);
47 WATCHDOG_RESET();
48 }
49
50 return -ETIMEDOUT;
51}
52
53static int send_bitstream(const void *rbf_data, size_t rbf_size)
54{
55 int i;
56 u64 res_buf[3];
57 u64 args[2];
58 u32 xfer_count = 0;
59 int ret, wr_ret = 0, retry = 0;
60 size_t buf_size = (rbf_size > BITSTREAM_CHUNK_SIZE) ?
61 BITSTREAM_CHUNK_SIZE : rbf_size;
62
63 while (rbf_size || xfer_count) {
64 if (!wr_ret && rbf_size) {
65 args[0] = (u64)rbf_data;
66 args[1] = buf_size;
67 wr_ret = invoke_smc(INTEL_SIP_SMC_FPGA_CONFIG_WRITE,
68 args, 2, NULL, 0);
69
70 debug("wr_ret = %d, rbf_data = %p, buf_size = %08lx\n",
71 wr_ret, rbf_data, buf_size);
72
73 if (wr_ret)
74 continue;
75
76 rbf_size -= buf_size;
77 rbf_data += buf_size;
78
79 if (buf_size >= rbf_size)
80 buf_size = rbf_size;
81
82 xfer_count++;
83 puts(".");
84 } else {
85 ret = invoke_smc(
86 INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE,
87 NULL, 0, res_buf, ARRAY_SIZE(res_buf));
88 if (!ret) {
89 for (i = 0; i < ARRAY_SIZE(res_buf); i++) {
90 if (!res_buf[i])
91 break;
92 xfer_count--;
93 wr_ret = 0;
94 retry = 0;
95 }
96 } else if (ret !=
97 INTEL_SIP_SMC_STATUS_BUSY)
98 return ret;
99 else if (!xfer_count)
100 return INTEL_SIP_SMC_STATUS_ERROR;
101
102 if (++retry >= RECONFIG_STATUS_POLL_RETRY_MAX)
103 return -ETIMEDOUT;
104
105 udelay(20000);
106 }
107 WATCHDOG_RESET();
108 }
109
110 return 0;
111}
112
113/*
114 * This is the interface used by FPGA driver.
115 * Return 0 for success, non-zero for error.
116 */
117int intel_sdm_mb_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size)
118{
119 int ret;
120 u64 arg = 1;
121
122 debug("Invoking FPGA_CONFIG_START...\n");
123
124 ret = invoke_smc(INTEL_SIP_SMC_FPGA_CONFIG_START, &arg, 1, NULL, 0);
125
126 if (ret) {
127 puts("Failure in RECONFIG mailbox command!\n");
128 return ret;
129 }
130
131 ret = send_bitstream(rbf_data, rbf_size);
132 if (ret) {
133 puts("Error sending bitstream!\n");
134 return ret;
135 }
136
137 /* Make sure we don't send MBOX_RECONFIG_STATUS too fast */
138 udelay(RECONFIG_STATUS_INTERVAL_DELAY_US);
139
140 debug("Polling with MBOX_RECONFIG_STATUS...\n");
141 ret = reconfig_status_polling_resp();
142 if (ret) {
143 puts("FPGA reconfiguration failed!");
144 return ret;
145 }
146
147 puts("FPGA reconfiguration OK!\n");
148
149 return ret;
150}
151
152#else
153
Ang, Chee Hongdcc3bb62018-12-19 18:35:14 -0800154static const struct mbox_cfgstat_state {
155 int err_no;
156 const char *error_name;
157} mbox_cfgstat_state[] = {
158 {MBOX_CFGSTAT_STATE_IDLE, "FPGA in idle mode."},
159 {MBOX_CFGSTAT_STATE_CONFIG, "FPGA in config mode."},
160 {MBOX_CFGSTAT_STATE_FAILACK, "Acknowledgment failed!"},
161 {MBOX_CFGSTAT_STATE_ERROR_INVALID, "Invalid bitstream!"},
162 {MBOX_CFGSTAT_STATE_ERROR_CORRUPT, "Corrupted bitstream!"},
163 {MBOX_CFGSTAT_STATE_ERROR_AUTH, "Authentication failed!"},
164 {MBOX_CFGSTAT_STATE_ERROR_CORE_IO, "I/O error!"},
165 {MBOX_CFGSTAT_STATE_ERROR_HARDWARE, "Hardware error!"},
166 {MBOX_CFGSTAT_STATE_ERROR_FAKE, "Fake error!"},
167 {MBOX_CFGSTAT_STATE_ERROR_BOOT_INFO, "Error in boot info!"},
168 {MBOX_CFGSTAT_STATE_ERROR_QSPI_ERROR, "Error in QSPI!"},
169 {MBOX_RESP_ERROR, "Mailbox general error!"},
170 {-ETIMEDOUT, "I/O timeout error"},
171 {-1, "Unknown error!"}
172};
173
174#define MBOX_CFGSTAT_MAX ARRAY_SIZE(mbox_cfgstat_state)
175
176static const char *mbox_cfgstat_to_str(int err)
177{
178 int i;
179
180 for (i = 0; i < MBOX_CFGSTAT_MAX - 1; i++) {
181 if (mbox_cfgstat_state[i].err_no == err)
182 return mbox_cfgstat_state[i].error_name;
183 }
184
185 return mbox_cfgstat_state[MBOX_CFGSTAT_MAX - 1].error_name;
186}
187
188/*
189 * Add the ongoing transaction's command ID into pending list and return
190 * the command ID for next transfer.
191 */
192static u8 add_transfer(u32 *xfer_pending_list, size_t list_size, u8 id)
193{
194 int i;
195
196 for (i = 0; i < list_size; i++) {
197 if (xfer_pending_list[i])
198 continue;
199 xfer_pending_list[i] = id;
200 debug("ID(%d) added to transaction pending list\n", id);
201 /*
202 * Increment command ID for next transaction.
203 * Valid command ID (4 bits) is from 1 to 15.
204 */
205 id = (id % 15) + 1;
206 break;
207 }
208
209 return id;
210}
211
212/*
213 * Check whether response ID match the command ID in the transfer
214 * pending list. If a match is found in the transfer pending list,
215 * it clears the transfer pending list and return the matched
216 * command ID.
217 */
218static int get_and_clr_transfer(u32 *xfer_pending_list, size_t list_size,
219 u8 id)
220{
221 int i;
222
223 for (i = 0; i < list_size; i++) {
224 if (id != xfer_pending_list[i])
225 continue;
226 xfer_pending_list[i] = 0;
227 return id;
228 }
229
230 return 0;
231}
232
233/*
234 * Polling the FPGA configuration status.
235 * Return 0 for success, non-zero for error.
236 */
237static int reconfig_status_polling_resp(void)
238{
239 int ret;
240 unsigned long start = get_timer(0);
241
242 while (1) {
243 ret = mbox_get_fpga_config_status(MBOX_RECONFIG_STATUS);
244 if (!ret)
245 return 0; /* configuration success */
246
247 if (ret != MBOX_CFGSTAT_STATE_CONFIG)
248 return ret;
249
250 if (get_timer(start) > RECONFIG_STATUS_POLL_RESP_TIMEOUT_MS)
251 break; /* time out */
252
253 puts(".");
254 udelay(RECONFIG_STATUS_INTERVAL_DELAY_US);
Chee Hong Ang4e87fcd2020-08-07 11:50:04 +0800255 WATCHDOG_RESET();
Ang, Chee Hongdcc3bb62018-12-19 18:35:14 -0800256 }
257
258 return -ETIMEDOUT;
259}
260
261static u32 get_resp_hdr(u32 *r_index, u32 *w_index, u32 *resp_count,
262 u32 *resp_buf, u32 buf_size, u32 client_id)
263{
264 u32 buf[MBOX_RESP_BUFFER_SIZE];
265 u32 mbox_hdr;
266 u32 resp_len;
267 u32 hdr_len;
268 u32 i;
269
270 if (*resp_count < buf_size) {
271 u32 rcv_len_max = buf_size - *resp_count;
272
273 if (rcv_len_max > MBOX_RESP_BUFFER_SIZE)
274 rcv_len_max = MBOX_RESP_BUFFER_SIZE;
275 resp_len = mbox_rcv_resp(buf, rcv_len_max);
276
277 for (i = 0; i < resp_len; i++) {
278 resp_buf[(*w_index)++] = buf[i];
279 *w_index %= buf_size;
280 (*resp_count)++;
281 }
282 }
283
284 /* No response in buffer */
285 if (*resp_count == 0)
286 return 0;
287
288 mbox_hdr = resp_buf[*r_index];
289
290 hdr_len = MBOX_RESP_LEN_GET(mbox_hdr);
291
292 /* Insufficient header length to return a mailbox header */
293 if ((*resp_count - 1) < hdr_len)
294 return 0;
295
296 *r_index += (hdr_len + 1);
297 *r_index %= buf_size;
298 *resp_count -= (hdr_len + 1);
299
300 /* Make sure response belongs to us */
301 if (MBOX_RESP_CLIENT_GET(mbox_hdr) != client_id)
302 return 0;
303
304 return mbox_hdr;
305}
306
307/* Send bit stream data to SDM via RECONFIG_DATA mailbox command */
308static int send_reconfig_data(const void *rbf_data, size_t rbf_size,
309 u32 xfer_max, u32 buf_size_max)
310{
311 u32 response_buffer[MBOX_RESP_BUFFER_SIZE];
312 u32 xfer_pending[MBOX_RESP_BUFFER_SIZE];
313 u32 resp_rindex = 0;
314 u32 resp_windex = 0;
315 u32 resp_count = 0;
316 u32 xfer_count = 0;
Ang, Chee Hongc4192f72019-02-17 20:07:50 -0800317 int resp_err = 0;
Ang, Chee Hongdcc3bb62018-12-19 18:35:14 -0800318 u8 cmd_id = 1;
319 u32 args[3];
320 int ret;
321
322 debug("SDM xfer_max = %d\n", xfer_max);
323 debug("SDM buf_size_max = %x\n\n", buf_size_max);
324
325 memset(xfer_pending, 0, sizeof(xfer_pending));
326
327 while (rbf_size || xfer_count) {
328 if (!resp_err && rbf_size && xfer_count < xfer_max) {
329 args[0] = MBOX_ARG_DESC_COUNT(1);
330 args[1] = (u64)rbf_data;
331 if (rbf_size >= buf_size_max) {
332 args[2] = buf_size_max;
333 rbf_size -= buf_size_max;
334 rbf_data += buf_size_max;
335 } else {
336 args[2] = (u64)rbf_size;
337 rbf_size = 0;
338 }
339
Ang, Chee Hongc4192f72019-02-17 20:07:50 -0800340 resp_err = mbox_send_cmd_only(cmd_id, MBOX_RECONFIG_DATA,
Ang, Chee Hongdcc3bb62018-12-19 18:35:14 -0800341 MBOX_CMD_INDIRECT, 3, args);
Ang, Chee Hongc4192f72019-02-17 20:07:50 -0800342 if (!resp_err) {
Ang, Chee Hongdcc3bb62018-12-19 18:35:14 -0800343 xfer_count++;
344 cmd_id = add_transfer(xfer_pending,
345 MBOX_RESP_BUFFER_SIZE,
346 cmd_id);
347 }
348 puts(".");
349 } else {
350 u32 resp_hdr = get_resp_hdr(&resp_rindex, &resp_windex,
351 &resp_count,
352 response_buffer,
353 MBOX_RESP_BUFFER_SIZE,
354 MBOX_CLIENT_ID_UBOOT);
355
356 /*
357 * If no valid response header found or
358 * non-zero length from RECONFIG_DATA
359 */
360 if (!resp_hdr || MBOX_RESP_LEN_GET(resp_hdr))
361 continue;
362
363 /* Check for response's status */
364 if (!resp_err) {
Ang, Chee Hongc4192f72019-02-17 20:07:50 -0800365 resp_err = MBOX_RESP_ERR_GET(resp_hdr);
366 debug("Response error code: %08x\n", resp_err);
Ang, Chee Hongdcc3bb62018-12-19 18:35:14 -0800367 }
368
369 ret = get_and_clr_transfer(xfer_pending,
370 MBOX_RESP_BUFFER_SIZE,
371 MBOX_RESP_ID_GET(resp_hdr));
372 if (ret) {
373 /* Claim and reuse the ID */
374 cmd_id = (u8)ret;
375 xfer_count--;
376 }
377
378 if (resp_err && !xfer_count)
Ang, Chee Hongc4192f72019-02-17 20:07:50 -0800379 return resp_err;
Ang, Chee Hongdcc3bb62018-12-19 18:35:14 -0800380 }
Chee Hong Ang4e87fcd2020-08-07 11:50:04 +0800381 WATCHDOG_RESET();
Ang, Chee Hongdcc3bb62018-12-19 18:35:14 -0800382 }
383
384 return 0;
385}
386
387/*
388 * This is the interface used by FPGA driver.
389 * Return 0 for success, non-zero for error.
390 */
Chee Hong Ang14192452020-08-07 11:50:03 +0800391int intel_sdm_mb_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size)
Ang, Chee Hongdcc3bb62018-12-19 18:35:14 -0800392{
393 int ret;
394 u32 resp_len = 2;
395 u32 resp_buf[2];
396
397 debug("Sending MBOX_RECONFIG...\n");
398 ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_RECONFIG, MBOX_CMD_DIRECT, 0,
399 NULL, 0, &resp_len, resp_buf);
400 if (ret) {
401 puts("Failure in RECONFIG mailbox command!\n");
402 return ret;
403 }
404
405 ret = send_reconfig_data(rbf_data, rbf_size, resp_buf[0], resp_buf[1]);
406 if (ret) {
407 printf("RECONFIG_DATA error: %08x, %s\n", ret,
408 mbox_cfgstat_to_str(ret));
409 return ret;
410 }
411
412 /* Make sure we don't send MBOX_RECONFIG_STATUS too fast */
413 udelay(RECONFIG_STATUS_INTERVAL_DELAY_US);
414
415 debug("Polling with MBOX_RECONFIG_STATUS...\n");
416 ret = reconfig_status_polling_resp();
417 if (ret) {
418 printf("RECONFIG_STATUS Error: %08x, %s\n", ret,
419 mbox_cfgstat_to_str(ret));
420 return ret;
421 }
422
423 puts("FPGA reconfiguration OK!\n");
424
425 return ret;
426}
Chee Hong Angec4c6792020-12-24 18:21:07 +0800427#endif