Merge branch 'next' of https://source.denx.de/u-boot/custodians/u-boot-watchdog into...
[J-u-boot.git] / drivers / fpga / intel_sdm_mb.c
1 // 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>
8 #include <log.h>
9 #include <watchdog.h>
10 #include <asm/arch/mailbox_s10.h>
11 #include <asm/arch/smc_api.h>
12 #include <linux/delay.h>
13 #include <linux/intel-smc.h>
14
15 #define RECONFIG_STATUS_POLL_RESP_TIMEOUT_MS            60000
16 #define RECONFIG_STATUS_INTERVAL_DELAY_US               1000000
17
18 #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  */
27 static 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                 schedule();
48         }
49
50         return -ETIMEDOUT;
51 }
52
53 static 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                 schedule();
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  */
117 int 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
154 static 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
176 static 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  */
192 static 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  */
218 static 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  */
237 static 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);
255                 schedule();
256         }
257
258         return -ETIMEDOUT;
259 }
260
261 static 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 */
308 static 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;
317         int resp_err = 0;
318         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
340                         resp_err = mbox_send_cmd_only(cmd_id, MBOX_RECONFIG_DATA,
341                                                  MBOX_CMD_INDIRECT, 3, args);
342                         if (!resp_err) {
343                                 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) {
365                                 resp_err = MBOX_RESP_ERR_GET(resp_hdr);
366                                 debug("Response error code: %08x\n", resp_err);
367                         }
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)
379                                 return resp_err;
380                 }
381                 schedule();
382         }
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  */
391 int intel_sdm_mb_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size)
392 {
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 }
427 #endif
This page took 0.049316 seconds and 4 git commands to generate.