1 // Copyright (C) 2022 Beken Corporation
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <stdio.h>
16 #include <string.h>
17
18 #include <os/os.h>
19 #include "mailbox_channel.h"
20 #include "mb_ipc_cmd.h"
21 #include "dma_driver.h"
22
23 #define MOD_TAG "IPC"
24
25 #define IPC_RSP_CMD_FLAG 0x80
26 #define IPC_RSP_CMD_MASK 0x7F
27
28 #define IPC_RSP_TIMEOUT 10 /* 10ms */
29 #define IPC_XCHG_DATA_MAX 64
30
31 typedef union
32 {
33 struct
34 {
35 mb_chnl_hdr_t chnl_hdr;
36 void * cmd_buff;
37 u16 cmd_data_len;
38 };
39
40 mb_chnl_cmd_t mb_cmd;
41 } ipc_cmd_t;
42
43 typedef union
44 {
45 struct
46 {
47 mb_chnl_hdr_t chnl_hdr;
48 void * rsp_buff;
49 u16 rsp_data_len;
50 };
51
52 mb_chnl_ack_t mb_ack;
53 } ipc_rsp_t;
54
55 typedef struct
56 {
57 u8 client_buff[IPC_XCHG_DATA_MAX];
58 u8 server_buff[IPC_XCHG_DATA_MAX];
59 } ipc_chnl_buf_t;
60
61 typedef u32 (* ipc_rx_cmd_hdlr_t)(void * chnl_cb, mb_chnl_ack_t *ack_buf);
62
63 typedef struct
64 {
65 /* chnl data */
66 u8 chnl_inited;
67 u8 chnl_id;
68 beken_semaphore_t chnl_sema;
69
70 /* tx cmd data */
71 beken_semaphore_t rsp_sema;
72 u8 * tx_xchg_buff;
73 u8 tx_cmd;
74 volatile u8 tx_cmd_in_process;
75 volatile u8 tx_cmd_failed;
76 u32 rsp_buf[IPC_XCHG_DATA_MAX / sizeof(u32)];
77 u16 rsp_len;
78
79 /* rx cmd data */
80 ipc_rx_cmd_hdlr_t rx_cmd_handler;
81 u8 * rx_xchg_buff;
82 u8 rx_cmd;
83 volatile u8 rx_cmd_in_process;
84 u32 cmd_buf[IPC_XCHG_DATA_MAX / sizeof(u32)];
85 u16 cmd_len;
86 } ipc_chnl_cb_t;
87
88 extern char _swap_start;
89 static ipc_chnl_buf_t * const ipc_xchg_buf = (ipc_chnl_buf_t *)(&_swap_start);
90
ipc_cmd_rx_isr(ipc_chnl_cb_t * chnl_cb,mb_chnl_cmd_t * cmd_buf)91 static void ipc_cmd_rx_isr(ipc_chnl_cb_t *chnl_cb, mb_chnl_cmd_t *cmd_buf)
92 {
93 u32 result = ACK_STATE_FAIL;
94 mb_chnl_ack_t * ack_buf = (mb_chnl_ack_t *)cmd_buf;
95 ipc_cmd_t * ipc_cmd = (ipc_cmd_t *)cmd_buf;
96
97 /* chnl_cb->rx_xchg_buff == ipc_cmd->cmd_buff. MUST be true. */
98
99 if(cmd_buf->hdr.cmd & IPC_RSP_CMD_FLAG) /* ipc rsp from other CPU. */
100 {
101 if(chnl_cb->tx_cmd_in_process == 0) /* unsolicited ipc response. */
102 {
103 goto ipc_cmd_rx_isr_exit;
104 }
105
106 if(chnl_cb->tx_cmd != (cmd_buf->hdr.cmd & IPC_RSP_CMD_MASK))
107 {
108 /* un-matched rpc response. */
109 goto ipc_cmd_rx_isr_exit;
110 }
111
112 /* communication ok, function is completed. */
113 chnl_cb->tx_cmd_failed = 0;
114 chnl_cb->tx_cmd_in_process = 0;
115
116 BK_LOGI(MOD_TAG, "IPC_RSP_CMD: %d, %d, %d\r\n", cmd_buf->param1, cmd_buf->param2, cmd_buf->param3);
117
118 if(ipc_cmd->cmd_data_len > sizeof(chnl_cb->rsp_buf))
119 {
120 /* buffer insufficient, failed. */
121 chnl_cb->tx_cmd_failed = 1;
122 chnl_cb->rsp_len = 0;
123 }
124 else
125 {
126 /* returns ACK_STATE_COMPLETE,
127 so must copy data from cmd_buff in case that the buffer is released. */
128 if((ipc_cmd->cmd_buff != NULL) && (ipc_cmd->cmd_data_len > 0))
129 {
130 memcpy(chnl_cb->rsp_buf, ipc_cmd->cmd_buff, ipc_cmd->cmd_data_len);
131
132 chnl_cb->rsp_len = ipc_cmd->cmd_data_len;
133 }
134 else
135 {
136 chnl_cb->rsp_len = 0;
137 }
138 }
139
140 rtos_set_semaphore(&chnl_cb->rsp_sema);
141
142 ipc_rsp_t * ipc_rsp = (ipc_rsp_t *)ack_buf;
143
144 /* it is a rsp command, nothing need to be returned. */
145 ipc_rsp->rsp_buff = NULL;
146 ipc_rsp->rsp_data_len = 0;
147
148 result = ACK_STATE_COMPLETE;
149
150 goto ipc_cmd_rx_isr_exit;
151 }
152 else
153 {
154 chnl_cb->rx_cmd = cmd_buf->hdr.cmd;
155 chnl_cb->rx_cmd_in_process = 1;
156
157 BK_LOGD(MOD_TAG, "IPC_CMD: %d, %d, %d\r\n", cmd_buf->param1, cmd_buf->param2, cmd_buf->param3);
158
159 if(ipc_cmd->cmd_data_len > sizeof(chnl_cb->cmd_buf))
160 {
161 result = ACK_STATE_FAIL;
162 }
163 else
164 {
165 /* may return ACK_STATE_COMPLETE,
166 so must copy data from cmd_buff in case that the buffer is released. */
167 if((ipc_cmd->cmd_buff != NULL) && (ipc_cmd->cmd_data_len > 0))
168 {
169 memcpy(chnl_cb->cmd_buf, ipc_cmd->cmd_buff, ipc_cmd->cmd_data_len);
170
171 chnl_cb->cmd_len = ipc_cmd->cmd_data_len;
172 }
173 else
174 {
175 chnl_cb->cmd_len = 0;
176 }
177
178 result = chnl_cb->rx_cmd_handler(chnl_cb, ack_buf);
179 }
180
181 if(result != ACK_STATE_PENDING)
182 chnl_cb->rx_cmd_in_process = 0;
183 }
184
185 ipc_cmd_rx_isr_exit:
186
187 /* overwrite the cmd_buf after the ISR handle complete.
188 * return the ack info to caller using the SAME buffer with cmd buffer.
189 * !!!! [input as param / output as result ] !!!!
190 */
191 ack_buf->ack_state = result;
192
193 return;
194
195 }
196
ipc_cmd_tx_cmpl_isr(ipc_chnl_cb_t * chnl_cb,mb_chnl_ack_t * ack_buf)197 static void ipc_cmd_tx_cmpl_isr(ipc_chnl_cb_t *chnl_cb, mb_chnl_ack_t *ack_buf) /* tx_cmpl_isr */
198 {
199 if(ack_buf->hdr.cmd == chnl_cb->tx_cmd)
200 {
201 if(chnl_cb->tx_cmd_in_process == 0) /* RSP_CMD rx_isr may arrive before this tx_cmpl_isr. */
202 return;
203
204 /* IPC cmd tx complete. */
205
206 if( (ack_buf->hdr.state & CHNL_STATE_COM_FAIL)
207 || (ack_buf->ack_state == ACK_STATE_FAIL) )
208 {
209 chnl_cb->tx_cmd_failed = 1;
210 chnl_cb->tx_cmd_in_process = 0;
211
212 /* communication failed or function failed. */
213 rtos_set_semaphore(&chnl_cb->rsp_sema);
214 }
215 else if(ack_buf->ack_state == ACK_STATE_COMPLETE)
216 {
217 /* communication ok, function is completed. */
218 chnl_cb->tx_cmd_failed = 0;
219 chnl_cb->tx_cmd_in_process = 0;
220
221 ipc_rsp_t * ipc_rsp = (ipc_rsp_t *)ack_buf;
222
223 /* chnl_cb->tx_xchg_buff == ipc_rsp->rsp_buff. MUST be true. */
224
225 if(ipc_rsp->rsp_data_len > sizeof(chnl_cb->rsp_buf))
226 {
227 /* buffer insufficient, failed. */
228 chnl_cb->tx_cmd_failed = 1;
229 chnl_cb->rsp_len = 0;
230 }
231 else
232 {
233 if((ipc_rsp->rsp_buff != NULL) && (ipc_rsp->rsp_data_len > 0))
234 {
235 memcpy(chnl_cb->rsp_buf, ipc_rsp->rsp_buff, ipc_rsp->rsp_data_len);
236 chnl_cb->rsp_len = ipc_rsp->rsp_data_len;
237 }
238 else
239 {
240 chnl_cb->rsp_len = 0;
241 }
242 }
243
244 rtos_set_semaphore(&chnl_cb->rsp_sema);
245 }
246 else
247 {
248 /* communication ok, function is pending. */
249 }
250
251 return;
252 }
253
254 /*
255 * !!! FAULT !!!
256 */
257 BK_LOGE(MOD_TAG, "Fault in %s,cmd:%d\r\n", __func__, ack_buf->hdr.cmd);
258
259 return;
260
261 }
262
ipc_chnl_init(u8 client,ipc_chnl_cb_t * chnl_cb,u8 chnl_id,ipc_rx_cmd_hdlr_t rx_handler)263 static bk_err_t ipc_chnl_init(u8 client, ipc_chnl_cb_t *chnl_cb, u8 chnl_id, ipc_rx_cmd_hdlr_t rx_handler)
264 {
265 bk_err_t ret_code;
266
267 if(chnl_cb->chnl_inited)
268 return BK_OK;
269
270 memset(chnl_cb, 0, sizeof(ipc_chnl_cb_t));
271 chnl_cb->chnl_id = chnl_id;
272
273 if(client)
274 {
275 /* client rx cmds from server. */
276 chnl_cb->tx_xchg_buff = ipc_xchg_buf[chnl_id].client_buff;
277 chnl_cb->rx_xchg_buff = ipc_xchg_buf[chnl_id].server_buff;
278 }
279 else
280 {
281 /* server rx cmds from client. */
282 chnl_cb->tx_xchg_buff = ipc_xchg_buf[chnl_id].server_buff;
283 chnl_cb->rx_xchg_buff = ipc_xchg_buf[chnl_id].client_buff;
284 }
285
286 ret_code = rtos_init_semaphore_adv(&chnl_cb->chnl_sema, 1, 1);
287 if(ret_code != BK_OK)
288 {
289 return ret_code;
290 }
291
292 ret_code = rtos_init_semaphore(&chnl_cb->rsp_sema, 1);
293 if(ret_code != BK_OK)
294 {
295 rtos_deinit_semaphore(&chnl_cb->chnl_sema);
296
297 return ret_code;
298 }
299
300 ret_code = mb_chnl_open(chnl_id, chnl_cb);
301 if(ret_code != BK_OK)
302 {
303 rtos_deinit_semaphore(&chnl_cb->chnl_sema);
304 rtos_deinit_semaphore(&chnl_cb->rsp_sema);
305
306 return ret_code;
307 }
308
309 chnl_cb->rx_cmd_handler = rx_handler;
310
311 mb_chnl_ctrl(chnl_id, MB_CHNL_SET_RX_ISR, (void *)ipc_cmd_rx_isr);
312 mb_chnl_ctrl(chnl_id, MB_CHNL_SET_TX_CMPL_ISR, (void *)ipc_cmd_tx_cmpl_isr);
313
314 chnl_cb->chnl_inited = 1;
315
316 return BK_OK;
317 }
318
ipc_send_cmd(ipc_chnl_cb_t * chnl_cb,u8 cmd,u8 * cmd_buf,u16 cmd_len,u8 * rsp_buf,u16 buf_len)319 static bk_err_t ipc_send_cmd(ipc_chnl_cb_t *chnl_cb, u8 cmd, u8 *cmd_buf, u16 cmd_len, u8 * rsp_buf, u16 buf_len)
320 {
321 bk_err_t ret_val = BK_FAIL;
322 ipc_cmd_t ipc_cmd;
323
324 if(!chnl_cb->chnl_inited)
325 return BK_FAIL;
326
327 rtos_get_semaphore(&chnl_cb->chnl_sema, BEKEN_WAIT_FOREVER);
328
329 chnl_cb->tx_cmd = cmd;
330 chnl_cb->tx_cmd_failed = 0;
331 chnl_cb->tx_cmd_in_process = 1;
332
333 /* client uses the CLIENT buffer to exchange info(Cmd/Rsp) with server. */
334 /* server uses the SERVER buffer to exchange info(Cmd/Rsp) with client. */
335 void * dst_buf = (void *)chnl_cb->tx_xchg_buff;
336
337 do
338 {
339 if(cmd_len > IPC_XCHG_DATA_MAX)
340 {
341 ret_val = BK_ERR_PARAM;
342 break;
343 }
344
345 if(cmd_buf == NULL)
346 cmd_len = 0;
347
348 if(cmd_len > 0)
349 memcpy(dst_buf, cmd_buf, cmd_len);
350
351 ipc_cmd.chnl_hdr.data = 0; /* clear hdr. */
352 ipc_cmd.chnl_hdr.cmd = cmd;
353 ipc_cmd.cmd_buff = dst_buf;
354 ipc_cmd.cmd_data_len = cmd_len;
355
356 ret_val = mb_chnl_write(chnl_cb->chnl_id, (mb_chnl_cmd_t *)&ipc_cmd);
357 if(ret_val != BK_OK)
358 {
359 break;
360 }
361
362 ret_val = rtos_get_semaphore(&chnl_cb->rsp_sema, IPC_RSP_TIMEOUT); /* isr_callback will set this semaphore. */
363 if(ret_val != BK_OK)
364 {
365 break;
366 }
367
368 chnl_cb->tx_cmd_in_process = 0; /* must have been set to 0 by callback. */
369
370 if(chnl_cb->tx_cmd_failed)
371 {
372 ret_val = BK_FAIL;
373 break;
374 }
375
376 if((rsp_buf == NULL) || (buf_len == 0))
377 {
378 ret_val = BK_OK;
379 break;
380 }
381
382 if(buf_len < chnl_cb->rsp_len)
383 {
384 ret_val = BK_ERR_PARAM;
385 break;
386 }
387
388 if(chnl_cb->rsp_len > 0)
389 memcpy(rsp_buf, chnl_cb->rsp_buf, chnl_cb->rsp_len);
390
391 ret_val = BK_OK;
392
393 }while(0);
394
395 chnl_cb->tx_cmd_in_process = 0;
396
397 rtos_set_semaphore(&chnl_cb->chnl_sema);
398
399 return ret_val;
400
401 }
402
403 static ipc_chnl_cb_t ipc_chnl_cb; // = { .chnl_id = MB_CHNL_HW_CTRL, .chnl_inited = 0 };
404
405 typedef struct
406 {
407 u16 res_id;
408 u16 cpu_id;
409 } ipc_res_req_t;
410
411 typedef struct
412 {
413 u32 user_id;
414 u32 chnl_id;
415 } ipc_dma_free_t;
416
417 #if CONFIG_SLAVE_CORE
418
419 /** ============================ IPC client ============================ **/
420
ipc_client_cmd_handler(ipc_chnl_cb_t * chnl_cb,mb_chnl_ack_t * ack_buf)421 static u32 ipc_client_cmd_handler(ipc_chnl_cb_t *chnl_cb, mb_chnl_ack_t *ack_buf)
422 {
423 /* must NOT change ack_buf->hdr. */
424
425 u32 result = ACK_STATE_FAIL;
426 ipc_rsp_t * ipc_rsp = (ipc_rsp_t *)ack_buf;
427
428 /* chnl_cb->rx_xchg_buff == ipc_cmd->cmd_buff == ipc_rsp->rsp_buff. MUST be true. */
429
430 ipc_rsp->rsp_buff = chnl_cb->rx_xchg_buff; //ipc_xchg_buf[chnl_cb->chnl_id].server_buff;
431
432 switch(chnl_cb->rx_cmd)
433 {
434 case IPC_TEST_CMD:
435 if(chnl_cb->cmd_len >= sizeof(u32))
436 {
437 ipc_rsp->rsp_data_len = sizeof(u32);
438
439 u32 * p_src = (u32 *)chnl_cb->cmd_buf;
440 u32 * p_dst = (u32 *)ipc_rsp->rsp_buff;
441
442 *p_dst = (*p_src) + 1;
443
444 result = ACK_STATE_COMPLETE;
445 }
446 else
447 {
448 ipc_rsp->rsp_data_len = 0;
449 result = ACK_STATE_FAIL;
450 }
451 break;
452
453 case IPC_GET_POWER_SAVE_FLAG:
454 {
455 ipc_rsp->rsp_data_len = sizeof(u32);
456
457 u32 * p_dst = (u32 *)ipc_rsp->rsp_buff;
458
459 // return PS flag to caller.
460 *p_dst = 0xAA; //(u32)get_cpu1_ps_flag();
461
462 result = ACK_STATE_COMPLETE;
463 }
464 break;
465
466 case IPC_SET_CPU1_HEART_RATE:
467 if(chnl_cb->cmd_len >= sizeof(u32))
468 {
469 ipc_rsp->rsp_data_len = 0;
470
471 //u32 * p_src = (u32 *)chnl_cb->cmd_buf;
472
473 // save the param.
474 //set_cpu1_heart_rate(*p_src);
475
476 result = ACK_STATE_COMPLETE;
477 }
478 else
479 {
480 ipc_rsp->rsp_data_len = 0;
481 result = ACK_STATE_FAIL;
482 }
483 break;
484
485 case IPC_GET_CPU1_HEART_RATE:
486 {
487 ipc_rsp->rsp_data_len = sizeof(u32);
488
489 u32 * p_dst = (u32 *)ipc_rsp->rsp_buff;
490
491 // return heart_rate to caller.
492 *p_dst = 0xBB; //(u32)get_cpu1_heart_rate();
493
494 result = ACK_STATE_COMPLETE;
495 }
496 break;
497
498 case IPC_RES_AVAILABLE_INDICATION:
499 if(chnl_cb->cmd_len >= sizeof(u16))
500 {
501 ipc_rsp->rsp_data_len = 0;
502
503 u16 res_id = *((u16 *)chnl_cb->cmd_buf);
504
505 if(amp_res_available(res_id) == BK_OK)
506 {
507 result = ACK_STATE_COMPLETE;
508 }
509 else
510 {
511 result = ACK_STATE_FAIL;
512 }
513 }
514 else
515 {
516 ipc_rsp->rsp_data_len = 0;
517 result = ACK_STATE_FAIL;
518 }
519 break;
520
521 default:
522 {
523 ipc_rsp->rsp_data_len = 0;
524 result = ACK_STATE_FAIL;
525 }
526 break;
527 }
528
529 return result;
530 }
531
ipc_client_init(void)532 bk_err_t ipc_client_init(void)
533 {
534 return ipc_chnl_init(1, &ipc_chnl_cb, MB_CHNL_HW_CTRL, (ipc_rx_cmd_hdlr_t)ipc_client_cmd_handler);
535 }
536
537 /** ============================ IPC client end ============================ **/
538
ipc_send_power_up(void)539 bk_err_t ipc_send_power_up(void)
540 {
541 return ipc_send_cmd(&ipc_chnl_cb, IPC_CPU1_POWER_UP_INDICATION, NULL, 0, NULL, 0);
542 }
543
ipc_send_heart_beat(u32 param)544 bk_err_t ipc_send_heart_beat(u32 param)
545 {
546 return ipc_send_cmd(&ipc_chnl_cb, IPC_CPU1_HEART_BEAT_INDICATION, (u8 *)¶m, sizeof(param), NULL, 0);
547 }
548
ipc_send_res_acquire_cnt(u16 resource_id,u16 cpu_id,amp_res_req_cnt_t * cnt_list)549 bk_err_t ipc_send_res_acquire_cnt(u16 resource_id, u16 cpu_id, amp_res_req_cnt_t *cnt_list)
550 {
551 ipc_res_req_t res_req;
552
553 res_req.res_id = resource_id;
554 res_req.cpu_id = cpu_id;
555
556 return ipc_send_cmd(&ipc_chnl_cb, IPC_RES_ACQUIRE_CNT, \
557 (u8 *)&res_req, sizeof(res_req), (u8 *)cnt_list, sizeof(amp_res_req_cnt_t));
558 }
559
ipc_send_res_release_cnt(u16 resource_id,u16 cpu_id,amp_res_req_cnt_t * cnt_list)560 bk_err_t ipc_send_res_release_cnt(u16 resource_id, u16 cpu_id, amp_res_req_cnt_t *cnt_list)
561 {
562 ipc_res_req_t res_req;
563
564 res_req.res_id = resource_id;
565 res_req.cpu_id = cpu_id;
566
567 return ipc_send_cmd(&ipc_chnl_cb, IPC_RES_RELEASE_CNT, \
568 (u8 *)&res_req, sizeof(res_req), (u8 *)cnt_list, sizeof(amp_res_req_cnt_t));
569 }
570
ipc_send_alloc_dma_chnl(u32 user_id)571 u8 ipc_send_alloc_dma_chnl(u32 user_id)
572 {
573 bk_err_t ret_val = BK_FAIL;
574 u8 dma_chnl_id = -1;
575
576 ret_val = ipc_send_cmd(&ipc_chnl_cb, IPC_ALLOC_DMA_CHNL, \
577 (u8 *)&user_id, sizeof(user_id), (u8 *)&dma_chnl_id, sizeof(dma_chnl_id));
578
579 if(ret_val != BK_OK)
580 return (u8)(-1);
581
582 return dma_chnl_id;
583 }
584
ipc_send_free_dma_chnl(u32 user_id,u8 chnl_id)585 bk_err_t ipc_send_free_dma_chnl(u32 user_id, u8 chnl_id)
586 {
587 bk_err_t ret_val = BK_FAIL;
588
589 ipc_dma_free_t dma_free;
590
591 dma_free.user_id = user_id;
592 dma_free.chnl_id = chnl_id;
593
594 ret_val = ipc_send_cmd(&ipc_chnl_cb, IPC_FREE_DMA_CHNL, \
595 (u8 *)&dma_free, sizeof(dma_free), NULL, 0);
596
597 return ret_val;
598 }
599
ipc_send_dma_chnl_user(u8 chnl_id)600 u32 ipc_send_dma_chnl_user(u8 chnl_id)
601 {
602 bk_err_t ret_val = BK_FAIL;
603 u32 user_id = -1;
604
605 ret_val = ipc_send_cmd(&ipc_chnl_cb, IPC_DMA_CHNL_USER, \
606 (u8 *)&chnl_id, sizeof(chnl_id), (u8 *)&user_id, sizeof(user_id));
607
608 if(ret_val != BK_OK)
609 return (u32)(-1);
610
611 return user_id;
612 }
613
614 #endif
615
616 #ifdef CONFIG_DUAL_CORE
617
ipc_send_test_cmd(u32 param)618 u32 ipc_send_test_cmd(u32 param)
619 {
620 ipc_send_cmd(&ipc_chnl_cb, IPC_TEST_CMD, (u8 *)¶m, sizeof(param), (u8 *)¶m, sizeof(param));
621
622 return param;
623 }
624
ipc_send_available_ind(u16 resource_id)625 bk_err_t ipc_send_available_ind(u16 resource_id)
626 {
627 return ipc_send_cmd(&ipc_chnl_cb, IPC_RES_AVAILABLE_INDICATION, \
628 (u8 *)&resource_id, sizeof(resource_id), NULL, 0);
629 }
630
631 #endif
632
633 #if CONFIG_MASTER_CORE
634
635 /** ============================ IPC server ============================ **/
636
ipc_server_cmd_handler(ipc_chnl_cb_t * chnl_cb,mb_chnl_ack_t * ack_buf)637 static u32 ipc_server_cmd_handler(ipc_chnl_cb_t *chnl_cb, mb_chnl_ack_t *ack_buf)
638 {
639 /* must NOT change ack_buf->hdr. */
640
641 u32 result = ACK_STATE_FAIL;
642 ipc_rsp_t * ipc_rsp = (ipc_rsp_t *)ack_buf;
643
644 /* chnl_cb->rx_xchg_buff == ipc_cmd->cmd_buff == ipc_rsp->rsp_buff. MUST be true. */
645
646 ipc_rsp->rsp_buff = chnl_cb->rx_xchg_buff;
647
648 switch(chnl_cb->rx_cmd)
649 {
650 case IPC_TEST_CMD:
651 if(chnl_cb->cmd_len >= sizeof(u32))
652 {
653 ipc_rsp->rsp_data_len = sizeof(u32);
654
655 u32 * p_src = (u32 *)chnl_cb->cmd_buf;
656 u32 * p_dst = (u32 *)ipc_rsp->rsp_buff;
657
658 *p_dst = (*p_src) + 1;
659
660 result = ACK_STATE_COMPLETE;
661 }
662 else
663 {
664 ipc_rsp->rsp_data_len = 0;
665 result = ACK_STATE_FAIL;
666 }
667 break;
668
669 case IPC_CPU1_POWER_UP_INDICATION: // cpu1 indication, power up successfully.
670 {
671 ipc_rsp->rsp_data_len = 0;
672 result = ACK_STATE_COMPLETE;
673
674 /* no params, no returns. */
675
676 /* inform modules who care CPU1 state. */
677 }
678 break;
679
680 case IPC_CPU1_HEART_BEAT_INDICATION: // cpu1 indication, alive indication.
681 // contains the power save flag?
682 if(chnl_cb->cmd_len >= sizeof(u32))
683 {
684 //u32 * p_src = (u32 *)chnl_cb->cmd_buf;
685
686 // save the param.
687 //set_cpu1_ps_flag(*p_src);
688 }
689
690 /* succeeded anyway but no returns. */
691 ipc_rsp->rsp_data_len = 0;
692 result = ACK_STATE_COMPLETE;
693 break;
694
695 case IPC_RES_ACQUIRE_CNT:
696 if(chnl_cb->cmd_len >= sizeof(ipc_res_req_t))
697 {
698 ipc_res_req_t * res_req = (ipc_res_req_t *)chnl_cb->cmd_buf;
699 amp_res_req_cnt_t * res_cnt_list = (amp_res_req_cnt_t *)ipc_rsp->rsp_buff;
700
701 /* call amp_res_acquire_cnt in interrupt disabled state. */
702 if(amp_res_acquire_cnt(res_req->res_id, res_req->cpu_id, res_cnt_list) == BK_OK)
703 {
704 ipc_rsp->rsp_data_len = sizeof(amp_res_req_cnt_t);
705
706 result = ACK_STATE_COMPLETE;
707 }
708 else
709 {
710 ipc_rsp->rsp_data_len = 0;
711 result = ACK_STATE_FAIL;
712 }
713 }
714 else
715 {
716 ipc_rsp->rsp_data_len = 0;
717 result = ACK_STATE_FAIL;
718 }
719 break;
720
721 case IPC_RES_RELEASE_CNT:
722 if(chnl_cb->cmd_len >= sizeof(ipc_res_req_t))
723 {
724 ipc_res_req_t * res_req = (ipc_res_req_t *)chnl_cb->cmd_buf;
725 amp_res_req_cnt_t * res_cnt_list = (amp_res_req_cnt_t *)ipc_rsp->rsp_buff;
726
727 /* call amp_res_release_cnt in interrupt disabled state. */
728 if(amp_res_release_cnt(res_req->res_id, res_req->cpu_id, res_cnt_list) == BK_OK)
729 {
730 ipc_rsp->rsp_data_len = sizeof(amp_res_req_cnt_t);
731
732 result = ACK_STATE_COMPLETE;
733 }
734 else
735 {
736 ipc_rsp->rsp_data_len = 0;
737 result = ACK_STATE_FAIL;
738 }
739 }
740 else
741 {
742 ipc_rsp->rsp_data_len = 0;
743 result = ACK_STATE_FAIL;
744 }
745 break;
746
747 case IPC_RES_AVAILABLE_INDICATION:
748 if(chnl_cb->cmd_len >= sizeof(u16))
749 {
750 ipc_rsp->rsp_data_len = 0;
751
752 u16 res_id = *((u16 *)chnl_cb->cmd_buf);
753
754 if(amp_res_available(res_id) == BK_OK)
755 {
756 result = ACK_STATE_COMPLETE;
757 }
758 else
759 {
760 result = ACK_STATE_FAIL;
761 }
762 }
763 else
764 {
765 ipc_rsp->rsp_data_len = 0;
766 result = ACK_STATE_FAIL;
767 }
768 break;
769
770 case IPC_ALLOC_DMA_CHNL:
771 if(chnl_cb->cmd_len >= sizeof(u32))
772 {
773 u32 user_id = *((u32 *)chnl_cb->cmd_buf);
774
775 ipc_rsp->rsp_data_len = sizeof(u8);
776
777 u8 * chnl_id = (u8 *)ipc_rsp->rsp_buff;
778
779 extern u8 dma_chnl_alloc(u32 user_id);
780
781 *chnl_id = dma_chnl_alloc(user_id);
782
783 result = ACK_STATE_COMPLETE;
784 }
785 else
786 {
787 ipc_rsp->rsp_data_len = 0;
788 result = ACK_STATE_FAIL;
789 }
790 break;
791
792 case IPC_FREE_DMA_CHNL:
793 if(chnl_cb->cmd_len >= sizeof(ipc_dma_free_t))
794 {
795 ipc_dma_free_t * free_req = (ipc_dma_free_t *)chnl_cb->cmd_buf;
796
797 extern bk_err_t dma_chnl_free(u32 user_id, dma_id_t chnl_id);
798
799 bk_err_t ret_val = dma_chnl_free(free_req->user_id, (dma_id_t)free_req->chnl_id);
800
801 ipc_rsp->rsp_data_len = 0;
802
803 if(ret_val == BK_OK)
804 result = ACK_STATE_COMPLETE;
805 else
806 result = ACK_STATE_FAIL;
807 }
808 else
809 {
810 ipc_rsp->rsp_data_len = 0;
811 result = ACK_STATE_FAIL;
812 }
813 break;
814
815 case IPC_DMA_CHNL_USER:
816 if(chnl_cb->cmd_len >= sizeof(u8))
817 {
818 u8 chnl_id = *((u8 *)chnl_cb->cmd_buf);
819
820 ipc_rsp->rsp_data_len = sizeof(u32);
821
822 u32 * user_id = (u32 *)ipc_rsp->rsp_buff;
823
824 extern u32 dma_chnl_user(dma_id_t user_id);
825
826 *user_id = dma_chnl_user((dma_id_t)chnl_id);
827
828 result = ACK_STATE_COMPLETE;
829 }
830 else
831 {
832 ipc_rsp->rsp_data_len = 0;
833 result = ACK_STATE_FAIL;
834 }
835 break;
836
837 case IPC_CALL_CMD:
838 /* will handle it in RPC channel. */
839 break;
840
841 default:
842 {
843 ipc_rsp->rsp_data_len = 0;
844 result = ACK_STATE_FAIL;
845 }
846 break;
847 }
848
849 return result;
850 }
851
ipc_server_init(void)852 bk_err_t ipc_server_init(void)
853 {
854 return ipc_chnl_init(0, &ipc_chnl_cb, MB_CHNL_HW_CTRL, (ipc_rx_cmd_hdlr_t)ipc_server_cmd_handler);
855 }
856
857 /** ============================ IPC server end ============================ **/
858
ipc_send_get_ps_flag(void)859 u32 ipc_send_get_ps_flag(void)
860 {
861 u32 param = -1;
862
863 ipc_send_cmd(&ipc_chnl_cb, IPC_GET_POWER_SAVE_FLAG, NULL, 0, (u8 *)¶m, sizeof(param));
864
865 return param;
866 }
867
ipc_send_get_heart_rate(void)868 u32 ipc_send_get_heart_rate(void)
869 {
870 u32 param = -1;
871
872 ipc_send_cmd(&ipc_chnl_cb, IPC_GET_CPU1_HEART_RATE, NULL, 0, (u8 *)¶m, sizeof(param));
873
874 return param;
875 }
876
ipc_send_set_heart_rate(u32 param)877 bk_err_t ipc_send_set_heart_rate(u32 param)
878 {
879 return ipc_send_cmd(&ipc_chnl_cb, IPC_SET_CPU1_HEART_RATE, (u8 *)¶m, sizeof(param), NULL, 0);
880 }
881
882 #endif
883
884 static ipc_chnl_cb_t rpc_chnl_cb; // = { .chnl_id = MB_CHNL_RPC, .chnl_inited = 0 };
885
886 #if CONFIG_SLAVE_CORE
887
888 /** ============================ RPC client ============================ **/
889
rpc_client_init(void)890 bk_err_t rpc_client_init(void)
891 {
892 return ipc_chnl_init(1, &rpc_chnl_cb, MB_CHNL_RPC, (ipc_rx_cmd_hdlr_t)ipc_client_cmd_handler);
893 }
894
rpc_client_call(rpc_call_def_t * rpc_param,u16 param_len,rpc_ret_def_t * ret_buf,u16 buf_len)895 bk_err_t rpc_client_call(rpc_call_def_t *rpc_param, u16 param_len, rpc_ret_def_t *ret_buf, u16 buf_len)
896 {
897 if(!rpc_chnl_cb.chnl_inited)
898 return BK_FAIL;
899
900 bk_err_t ret_val;
901
902 ret_val = ipc_send_cmd(&rpc_chnl_cb, IPC_CALL_CMD, (u8 *)rpc_param, param_len, (u8 *)ret_buf, buf_len);
903
904 if(ret_val != BK_OK)
905 return ret_val;
906
907 if((ret_buf == NULL) || (buf_len == 0))
908 {
909 return BK_OK;
910 }
911
912 if( (rpc_param->call_hdr.mod_id != ret_buf->call_hdr.mod_id) ||
913 (rpc_param->call_hdr.mod_id != ret_buf->call_hdr.mod_id) )
914 {
915 /* un-matched rpc response. */
916 return BK_FAIL;
917 }
918
919 return BK_OK;
920
921 }
922
923
924 /** ============================ RPC client end ============================ **/
925
926 #endif
927
928 #if CONFIG_MASTER_CORE
929
930 /** ============================ RPC server ============================ **/
931
932 static beken_semaphore_t server_ind_sema;
933
934 static void rpc_svr_task( void *para );
935
rpc_server_cmd_handler(ipc_chnl_cb_t * chnl_cb,mb_chnl_ack_t * ack_buf)936 static u32 rpc_server_cmd_handler(ipc_chnl_cb_t *chnl_cb, mb_chnl_ack_t *ack_buf)
937 {
938 /* must NOT change ack_buf->hdr. */
939
940 u32 result = ACK_STATE_FAIL;
941
942 switch(chnl_cb->rx_cmd)
943 {
944 case IPC_CALL_CMD:
945 result = ACK_STATE_PENDING;
946
947 /* informs server task to process the call. */
948 rtos_set_semaphore(&server_ind_sema);
949
950 break;
951
952 default:
953 return ipc_server_cmd_handler(chnl_cb, ack_buf);
954 break;
955 }
956
957 return result;
958 }
959
rpc_server_init(void)960 bk_err_t rpc_server_init(void)
961 {
962 bk_err_t ret_code;
963 beken_thread_t thread_handle = NULL;
964
965 ret_code = rtos_init_semaphore(&server_ind_sema, 1);
966 if(ret_code != BK_OK)
967 {
968 return ret_code;
969 }
970
971 ret_code = ipc_chnl_init(0, &rpc_chnl_cb, MB_CHNL_RPC, (ipc_rx_cmd_hdlr_t)rpc_server_cmd_handler);
972
973 if(ret_code != BK_OK)
974 {
975 rtos_deinit_semaphore(&server_ind_sema);
976
977 return ret_code;
978 }
979
980 ret_code = rtos_create_thread(&thread_handle,
981 BEKEN_DEFAULT_WORKER_PRIORITY, //BK_SYS_TASK_PRIO_7,
982 "rpc_svr",
983 (beken_thread_function_t)rpc_svr_task,
984 4096,
985 0);
986
987 return BK_OK;
988 }
989
rpc_server_listen_cmd(u32 timeout_ms)990 int rpc_server_listen_cmd(u32 timeout_ms)
991 {
992 bk_err_t ret_val;
993
994 ret_val = rtos_get_semaphore(&server_ind_sema, timeout_ms);
995
996 if(ret_val == BK_OK)
997 return 1;
998 else
999 return 0;
1000 }
1001
1002 typedef int (*rpc_svr_handler_t)(rpc_call_def_t * call_buf);
1003
1004 typedef struct
1005 {
1006 u8 rpc_mod_id;
1007 rpc_svr_handler_t svr_handler;
1008 } rpc_svr_dispatcher_t;
1009
1010 typedef struct
1011 {
1012 rpc_call_hdr_t call_hdr;
1013 bk_err_t ret_val; /* return fail code. */ /* struct of api_ret_data_t */
1014 } rpc_ret_fail_t;
1015
1016 extern int bk_gpio_api_svr(rpc_call_def_t * call_buf);
1017 extern int bk_dma_api_svr(rpc_call_def_t * call_buf);
1018
1019 static rpc_svr_dispatcher_t svr_dispatcher[] =
1020 {
1021 {RPC_MOD_GPIO, bk_gpio_api_svr },
1022 {RPC_MOD_DMA, bk_dma_api_svr },
1023 };
1024
rpc_server_handle_cmd(void)1025 void rpc_server_handle_cmd(void)
1026 {
1027 int rpc_handled = 0;
1028 int i;
1029
1030 if(rpc_chnl_cb.rx_cmd_in_process == 0) /* no rpc call cmd to handle. */
1031 return;
1032
1033 rpc_call_def_t *rpc_call = (rpc_call_def_t *)rpc_chnl_cb.cmd_buf;
1034
1035 for(i = 0; i < ARRAY_SIZE(svr_dispatcher); i++)
1036 {
1037 if(rpc_call->call_hdr.mod_id == svr_dispatcher[i].rpc_mod_id)
1038 {
1039 rpc_handled = svr_dispatcher[i].svr_handler(rpc_call);
1040 }
1041 }
1042
1043 if(rpc_handled == 0) /* rpc api not handled. */
1044 {
1045 rpc_ret_fail_t rsp_buf;
1046
1047 rsp_buf.call_hdr.call_id = rpc_call->call_hdr.call_id;
1048 rsp_buf.call_hdr.data_len = sizeof(rsp_buf) - sizeof(rsp_buf.call_hdr);
1049 rsp_buf.ret_val = BK_ERR_NOT_SUPPORT;
1050
1051 rpc_server_rsp((rpc_ret_def_t *)&rsp_buf, sizeof(rsp_buf)); // return fail info.
1052 }
1053
1054 return;
1055 }
1056
rpc_server_rsp(rpc_ret_def_t * rsp_param,u16 param_len)1057 bk_err_t rpc_server_rsp(rpc_ret_def_t *rsp_param, u16 param_len)
1058 {
1059 if(!rpc_chnl_cb.chnl_inited)
1060 return BK_FAIL;
1061
1062 if(rpc_chnl_cb.rx_cmd_in_process == 0)
1063 return BK_FAIL;
1064
1065 bk_err_t ret_val;
1066
1067 ret_val = ipc_send_cmd(&rpc_chnl_cb, IPC_CALL_CMD | IPC_RSP_CMD_FLAG, (u8 *)rsp_param, param_len, NULL, 0);
1068
1069 rpc_chnl_cb.rx_cmd_in_process = 0;
1070
1071 return ret_val;
1072
1073 }
1074
rpc_svr_task(void * para)1075 static void rpc_svr_task( void *para )
1076 {
1077 // rpc_server_init
1078
1079 while(1)
1080 {
1081 rpc_server_listen_cmd(BEKEN_WAIT_FOREVER);
1082 rpc_server_handle_cmd();
1083 }
1084 }
1085
1086 /** ============================ RPC server end ============================ **/
1087
1088 #endif
1089
1090