1
2
3
4
5
6
7#include <common.h>
8#include <wait_bit.h>
9#include <asm/io.h>
10#include <asm/arch/mailbox_s10.h>
11#include <asm/arch/system_manager.h>
12#include <asm/secure.h>
13
14DECLARE_GLOBAL_DATA_PTR;
15
16#define MBOX_READL(reg) \
17 readl(SOCFPGA_MAILBOX_ADDRESS + (reg))
18
19#define MBOX_WRITEL(data, reg) \
20 writel(data, SOCFPGA_MAILBOX_ADDRESS + (reg))
21
22#define MBOX_READ_RESP_BUF(rout) \
23 MBOX_READL(MBOX_RESP_BUF + ((rout) * sizeof(u32)))
24
25#define MBOX_WRITE_CMD_BUF(data, cin) \
26 MBOX_WRITEL(data, MBOX_CMD_BUF + ((cin) * sizeof(u32)))
27
28static __always_inline int mbox_polling_resp(u32 rout)
29{
30 u32 rin;
31 unsigned long i = ~0;
32
33 while (i) {
34 rin = MBOX_READL(MBOX_RIN);
35 if (rout != rin)
36 return 0;
37
38 i--;
39 }
40
41 return -ETIMEDOUT;
42}
43
44
45
46
47static __always_inline int mbox_fill_cmd_circular_buff(u32 header, u32 len,
48 u32 *arg)
49{
50 u32 cin;
51 u32 cout;
52 u32 i;
53
54 cin = MBOX_READL(MBOX_CIN) % MBOX_CMD_BUFFER_SIZE;
55 cout = MBOX_READL(MBOX_COUT) % MBOX_CMD_BUFFER_SIZE;
56
57
58
59
60 if (((cin + 1) % MBOX_CMD_BUFFER_SIZE) == cout ||
61 ((MBOX_CMD_BUFFER_SIZE - cin + cout - 1) %
62 MBOX_CMD_BUFFER_SIZE) < (len + 1))
63 return -ENOMEM;
64
65
66 MBOX_WRITE_CMD_BUF(header, cin++);
67
68 cin %= MBOX_CMD_BUFFER_SIZE;
69
70
71 for (i = 0; i < len; i++) {
72 MBOX_WRITE_CMD_BUF(arg[i], cin++);
73
74 cin %= MBOX_CMD_BUFFER_SIZE;
75 }
76
77
78 MBOX_WRITEL(cin, MBOX_CIN);
79
80 return 0;
81}
82
83
84static __always_inline int mbox_prepare_cmd_only(u8 id, u32 cmd,
85 u8 is_indirect, u32 len,
86 u32 *arg)
87{
88 u32 header;
89 int ret;
90
91
92 if ((len + 1) > MBOX_CMD_BUFFER_SIZE)
93 return -EINVAL;
94
95 if (cmd > MBOX_MAX_CMD_INDEX)
96 return -EINVAL;
97
98 header = MBOX_CMD_HEADER(MBOX_CLIENT_ID_UBOOT, id, len,
99 (is_indirect) ? 1 : 0, cmd);
100
101 ret = mbox_fill_cmd_circular_buff(header, len, arg);
102
103 return ret;
104}
105
106
107static __always_inline int mbox_send_cmd_only_common(u8 id, u32 cmd,
108 u8 is_indirect, u32 len,
109 u32 *arg)
110{
111 int ret = mbox_prepare_cmd_only(id, cmd, is_indirect, len, arg);
112
113 MBOX_WRITEL(1, MBOX_DOORBELL_TO_SDM);
114
115 return ret;
116}
117
118
119static __always_inline int __mbox_rcv_resp(u32 *resp_buf, u32 resp_buf_max_len)
120{
121 u32 rin;
122 u32 rout;
123 u32 resp_len = 0;
124
125
126 if (MBOX_READL(MBOX_DOORBELL_FROM_SDM) & 1)
127 MBOX_WRITEL(0, MBOX_DOORBELL_FROM_SDM);
128
129
130 rout = MBOX_READL(MBOX_ROUT);
131
132 rin = MBOX_READL(MBOX_RIN);
133
134 while (rin != rout && (resp_len < resp_buf_max_len)) {
135
136 if (resp_buf)
137 resp_buf[resp_len++] = MBOX_READ_RESP_BUF(rout);
138
139 rout++;
140
141 rout %= MBOX_RESP_BUFFER_SIZE;
142
143 MBOX_WRITEL(rout, MBOX_ROUT);
144 }
145
146 return resp_len;
147}
148
149
150static __always_inline int mbox_send_cmd_common(u8 id, u32 cmd, u8 is_indirect,
151 u32 len, u32 *arg, u8 urgent,
152 u32 *resp_buf_len,
153 u32 *resp_buf)
154{
155 u32 rin;
156 u32 resp;
157 u32 rout;
158 u32 status;
159 u32 resp_len;
160 u32 buf_len;
161 int ret;
162
163 if (urgent) {
164
165 status = MBOX_READL(MBOX_STATUS) & MBOX_STATUS_UA_MSK;
166
167 MBOX_WRITEL(cmd, MBOX_URG);
168 } else {
169 ret = mbox_prepare_cmd_only(id, cmd, is_indirect, len, arg);
170 if (ret)
171 return ret;
172 }
173
174
175 MBOX_WRITEL(1, MBOX_DOORBELL_TO_SDM);
176
177 while (1) {
178 ret = ~0;
179
180
181 while (!MBOX_READL(MBOX_DOORBELL_FROM_SDM) && ret--)
182 ;
183 if (!ret)
184 return -ETIMEDOUT;
185
186
187 MBOX_WRITEL(0, MBOX_DOORBELL_FROM_SDM);
188
189 if (urgent) {
190 u32 new_status = MBOX_READL(MBOX_STATUS);
191
192
193 if ((new_status & MBOX_STATUS_UA_MSK) ^ status)
194 return 0;
195
196 return -ECOMM;
197 }
198
199
200 rout = MBOX_READL(MBOX_ROUT);
201
202
203 rin = MBOX_READL(MBOX_RIN);
204
205 if (rout != rin) {
206
207 resp = MBOX_READ_RESP_BUF(rout);
208 rout++;
209
210 rout %= MBOX_RESP_BUFFER_SIZE;
211
212 MBOX_WRITEL(rout, MBOX_ROUT);
213
214
215 if ((MBOX_RESP_CLIENT_GET(resp) ==
216 MBOX_CLIENT_ID_UBOOT) &&
217 (MBOX_RESP_ID_GET(resp) == id)) {
218 ret = MBOX_RESP_ERR_GET(resp);
219 if (ret)
220 return ret;
221
222 if (resp_buf_len) {
223 buf_len = *resp_buf_len;
224 *resp_buf_len = 0;
225 } else {
226 buf_len = 0;
227 }
228
229 resp_len = MBOX_RESP_LEN_GET(resp);
230 while (resp_len) {
231 ret = mbox_polling_resp(rout);
232 if (ret)
233 return ret;
234
235
236
237 resp = MBOX_READ_RESP_BUF(rout);
238 rout++;
239 resp_len--;
240 rout %= MBOX_RESP_BUFFER_SIZE;
241 MBOX_WRITEL(rout, MBOX_ROUT);
242 if (buf_len) {
243
244 resp_buf[*resp_buf_len] = resp;
245 (*resp_buf_len)++;
246 buf_len--;
247 }
248 }
249 return ret;
250 }
251 }
252 };
253
254 return -EIO;
255}
256
257int mbox_init(void)
258{
259 int ret;
260
261
262 MBOX_WRITEL(MBOX_ALL_INTRS, MBOX_FLAGS);
263
264
265 MBOX_WRITEL(0, MBOX_URG);
266
267
268 MBOX_WRITEL(0, MBOX_DOORBELL_FROM_SDM);
269
270 ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_RESTART, MBOX_CMD_DIRECT, 0,
271 NULL, 1, 0, NULL);
272 if (ret)
273 return ret;
274
275
276 MBOX_WRITEL(MBOX_ALL_INTRS, MBOX_FLAGS);
277
278 return 0;
279}
280
281#ifdef CONFIG_CADENCE_QSPI
282int mbox_qspi_close(void)
283{
284 return mbox_send_cmd(MBOX_ID_UBOOT, MBOX_QSPI_CLOSE, MBOX_CMD_DIRECT,
285 0, NULL, 0, 0, NULL);
286}
287
288int mbox_qspi_open(void)
289{
290 static const struct socfpga_system_manager *sysmgr_regs =
291 (struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS;
292
293 int ret;
294 u32 resp_buf[1];
295 u32 resp_buf_len;
296
297 ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_QSPI_OPEN, MBOX_CMD_DIRECT,
298 0, NULL, 0, 0, NULL);
299 if (ret) {
300
301 ret = mbox_qspi_close();
302 if (ret)
303 return ret;
304
305 ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_QSPI_OPEN,
306 MBOX_CMD_DIRECT, 0, NULL, 0, 0, NULL);
307 if (ret)
308 return ret;
309 }
310
311
312 resp_buf_len = 1;
313 ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_QSPI_DIRECT, MBOX_CMD_DIRECT,
314 0, NULL, 0, (u32 *)&resp_buf_len,
315 (u32 *)&resp_buf);
316 if (ret)
317 goto error;
318
319
320 printf("QSPI: Reference clock at %d Hz\n", resp_buf[0]);
321 writel(resp_buf[0], &sysmgr_regs->boot_scratch_cold0);
322
323 return 0;
324
325error:
326 mbox_qspi_close();
327
328 return ret;
329}
330#endif
331
332int mbox_reset_cold(void)
333{
334 int ret;
335
336 ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_REBOOT_HPS, MBOX_CMD_DIRECT,
337 0, NULL, 0, 0, NULL);
338 if (ret) {
339
340 hang();
341 }
342 return 0;
343}
344
345
346static __always_inline int mbox_get_fpga_config_status_common(u32 cmd)
347{
348 u32 reconfig_status_resp_len;
349 u32 reconfig_status_resp[RECONFIG_STATUS_RESPONSE_LEN];
350 int ret;
351
352 reconfig_status_resp_len = RECONFIG_STATUS_RESPONSE_LEN;
353 ret = mbox_send_cmd_common(MBOX_ID_UBOOT, cmd,
354 MBOX_CMD_DIRECT, 0, NULL, 0,
355 &reconfig_status_resp_len,
356 reconfig_status_resp);
357
358 if (ret)
359 return ret;
360
361
362 ret = reconfig_status_resp[RECONFIG_STATUS_STATE];
363 if (ret && ret != MBOX_CFGSTAT_STATE_CONFIG)
364 return ret;
365
366
367 ret = reconfig_status_resp[RECONFIG_STATUS_PIN_STATUS];
368 if (!(ret & RCF_PIN_STATUS_NSTATUS))
369 return MBOX_CFGSTAT_STATE_ERROR_HARDWARE;
370
371 ret = reconfig_status_resp[RECONFIG_STATUS_SOFTFUNC_STATUS];
372 if (ret & RCF_SOFTFUNC_STATUS_SEU_ERROR)
373 return MBOX_CFGSTAT_STATE_ERROR_HARDWARE;
374
375 if ((ret & RCF_SOFTFUNC_STATUS_CONF_DONE) &&
376 (ret & RCF_SOFTFUNC_STATUS_INIT_DONE) &&
377 !reconfig_status_resp[RECONFIG_STATUS_STATE])
378 return 0;
379
380 return MBOX_CFGSTAT_STATE_CONFIG;
381}
382
383int mbox_get_fpga_config_status(u32 cmd)
384{
385 return mbox_get_fpga_config_status_common(cmd);
386}
387
388int __secure mbox_get_fpga_config_status_psci(u32 cmd)
389{
390 return mbox_get_fpga_config_status_common(cmd);
391}
392
393int mbox_send_cmd(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg,
394 u8 urgent, u32 *resp_buf_len, u32 *resp_buf)
395{
396 return mbox_send_cmd_common(id, cmd, is_indirect, len, arg, urgent,
397 resp_buf_len, resp_buf);
398}
399
400int __secure mbox_send_cmd_psci(u8 id, u32 cmd, u8 is_indirect, u32 len,
401 u32 *arg, u8 urgent, u32 *resp_buf_len,
402 u32 *resp_buf)
403{
404 return mbox_send_cmd_common(id, cmd, is_indirect, len, arg, urgent,
405 resp_buf_len, resp_buf);
406}
407
408int mbox_send_cmd_only(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg)
409{
410 return mbox_send_cmd_only_common(id, cmd, is_indirect, len, arg);
411}
412
413int __secure mbox_send_cmd_only_psci(u8 id, u32 cmd, u8 is_indirect, u32 len,
414 u32 *arg)
415{
416 return mbox_send_cmd_only_common(id, cmd, is_indirect, len, arg);
417}
418
419int mbox_rcv_resp(u32 *resp_buf, u32 resp_buf_max_len)
420{
421 return __mbox_rcv_resp(resp_buf, resp_buf_max_len);
422}
423
424int __secure mbox_rcv_resp_psci(u32 *resp_buf, u32 resp_buf_max_len)
425{
426 return __mbox_rcv_resp(resp_buf, resp_buf_max_len);
427}
428