2025-10-10 16:07:00 +08:00

1245 lines
27 KiB
C
Executable File

// Copyright 2020-2022 Beken
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <string.h>
#include <os/os.h>
#include <driver/mailbox_channel.h>
#include <driver/mb_chnl_buff.h>
#include "mb_ipc_cmd.h"
#include "driver/dma.h"
#include "driver/flash.h"
#if CONFIG_CACHE_ENABLE
#include "cache.h"
#endif
#if (CONFIG_USB_CDC_ACM_DEMO)
#include "bk_cherry_usb_cdc_acm_api.h"
#endif
#define MOD_TAG "IPC"
#if (CONFIG_CPU_CNT > 1)
#define IPC_RSP_CMD_FLAG 0x80
#define IPC_RSP_CMD_MASK 0x7F
#define IPC_RSP_TIMEOUT 10 /* 10ms */
#define IPC_XCHG_DATA_MAX 32 // MB_CHNL_BUFF_LEN
typedef union
{
struct
{
mb_chnl_hdr_t chnl_hdr;
void * cmd_buff;
u16 cmd_data_len;
};
mb_chnl_cmd_t mb_cmd;
} ipc_cmd_t;
typedef union
{
struct
{
mb_chnl_hdr_t chnl_hdr;
void * rsp_buff;
u16 rsp_data_len;
};
mb_chnl_ack_t mb_ack;
} ipc_rsp_t;
typedef u32 (* ipc_rx_cmd_hdlr_t)(void * chnl_cb, mb_chnl_ack_t *ack_buf);
typedef struct
{
/* chnl data */
u8 chnl_inited;
u8 chnl_id;
beken_semaphore_t chnl_sema;
/* tx cmd data */
beken_semaphore_t rsp_sema;
u8 * tx_xchg_buff;
u8 tx_cmd;
volatile u8 tx_cmd_in_process;
volatile u8 tx_cmd_failed;
u32 rsp_buf[IPC_XCHG_DATA_MAX / sizeof(u32)];
u16 rsp_len;
/* rx cmd data */
ipc_rx_cmd_hdlr_t rx_cmd_handler;
u8 * rx_xchg_buff;
u8 rx_cmd;
volatile u8 rx_cmd_in_process;
u32 cmd_buf[IPC_XCHG_DATA_MAX / sizeof(u32)];
u16 cmd_len;
} ipc_chnl_cb_t;
#ifdef CONFIG_FREERTOS_SMP
#include "spinlock.h"
static volatile spinlock_t mb_ipc_spin_lock = SPIN_LOCK_INIT;
#endif // CONFIG_FREERTOS_SMP
static inline uint32_t ipc_enter_critical()
{
uint32_t flags = rtos_disable_int();
#ifdef CONFIG_FREERTOS_SMP
spin_lock(&mb_ipc_spin_lock);
#endif // CONFIG_FREERTOS_SMP
return flags;
}
static inline void ipc_exit_critical(uint32_t flags)
{
#ifdef CONFIG_FREERTOS_SMP
spin_unlock(&mb_ipc_spin_lock);
#endif // CONFIG_FREERTOS_SMP
rtos_enable_int(flags);
}
static void ipc_cmd_rx_isr(ipc_chnl_cb_t *chnl_cb, mb_chnl_cmd_t *cmd_buf)
{
u32 result = ACK_STATE_FAIL;
mb_chnl_ack_t * ack_buf = (mb_chnl_ack_t *)cmd_buf;
ipc_cmd_t * ipc_cmd = (ipc_cmd_t *)cmd_buf;
/* chnl_cb->rx_xchg_buff == ipc_cmd->cmd_buff. MUST be true. */
if(cmd_buf->hdr.cmd & IPC_RSP_CMD_FLAG) /* ipc rsp from other CPU. */
{
if(chnl_cb->tx_cmd_in_process == 0) /* unsolicited ipc response. */
{
goto ipc_cmd_rx_isr_exit;
}
if(chnl_cb->tx_cmd != (cmd_buf->hdr.cmd & IPC_RSP_CMD_MASK))
{
/* un-matched rpc response. */
goto ipc_cmd_rx_isr_exit;
}
/* communication ok, function is completed. */
chnl_cb->tx_cmd_failed = 0;
chnl_cb->tx_cmd_in_process = 0;
BK_LOGI(MOD_TAG, "IPC_RSP_CMD: %d, %d, %d\r\n", cmd_buf->param1, cmd_buf->param2, cmd_buf->param3);
if(ipc_cmd->cmd_data_len > sizeof(chnl_cb->rsp_buf))
{
/* buffer insufficient, failed. */
chnl_cb->tx_cmd_failed = 1;
chnl_cb->rsp_len = 0;
}
else
{
/* returns ACK_STATE_COMPLETE,
so must copy data from cmd_buff in case that the buffer is released. */
if((ipc_cmd->cmd_buff != NULL) && (ipc_cmd->cmd_data_len > 0))
{
#if CONFIG_CACHE_ENABLE
flush_dcache(ipc_cmd->cmd_buff, ipc_cmd->cmd_data_len);
#endif
memcpy(chnl_cb->rsp_buf, ipc_cmd->cmd_buff, ipc_cmd->cmd_data_len);
chnl_cb->rsp_len = ipc_cmd->cmd_data_len;
}
else
{
chnl_cb->rsp_len = 0;
}
}
rtos_set_semaphore(&chnl_cb->rsp_sema);
ipc_rsp_t * ipc_rsp = (ipc_rsp_t *)ack_buf;
/* it is a rsp command, nothing need to be returned. */
ipc_rsp->rsp_buff = NULL;
ipc_rsp->rsp_data_len = 0;
result = ACK_STATE_COMPLETE;
goto ipc_cmd_rx_isr_exit;
}
else
{
chnl_cb->rx_cmd = cmd_buf->hdr.cmd;
chnl_cb->rx_cmd_in_process = 1;
BK_LOGD(MOD_TAG, "IPC_CMD: %d, %d, %d\r\n", cmd_buf->param1, cmd_buf->param2, cmd_buf->param3);
if(ipc_cmd->cmd_data_len > sizeof(chnl_cb->cmd_buf))
{
result = ACK_STATE_FAIL;
}
else
{
/* may return ACK_STATE_COMPLETE,
so must copy data from cmd_buff in case that the buffer is released. */
if((ipc_cmd->cmd_buff != NULL) && (ipc_cmd->cmd_data_len > 0))
{
#if CONFIG_CACHE_ENABLE
flush_dcache(ipc_cmd->cmd_buff, ipc_cmd->cmd_data_len);
#endif
memcpy(chnl_cb->cmd_buf, ipc_cmd->cmd_buff, ipc_cmd->cmd_data_len);
chnl_cb->cmd_len = ipc_cmd->cmd_data_len;
}
else
{
chnl_cb->cmd_len = 0;
}
result = chnl_cb->rx_cmd_handler(chnl_cb, ack_buf);
}
if(result != ACK_STATE_PENDING)
chnl_cb->rx_cmd_in_process = 0;
}
ipc_cmd_rx_isr_exit:
/* overwrite the cmd_buf after the ISR handle complete.
* return the ack info to caller using the SAME buffer with cmd buffer.
* !!!! [input as param / output as result ] !!!!
*/
ack_buf->ack_state = result;
return;
}
static void ipc_cmd_tx_cmpl_isr(ipc_chnl_cb_t *chnl_cb, mb_chnl_ack_t *ack_buf) /* tx_cmpl_isr */
{
if(ack_buf->hdr.cmd == chnl_cb->tx_cmd)
{
if(chnl_cb->tx_cmd_in_process == 0) /* RSP_CMD rx_isr may arrive before this tx_cmpl_isr. */
return;
/* IPC cmd tx complete. */
if( (ack_buf->hdr.state & CHNL_STATE_COM_FAIL)
|| (ack_buf->ack_state == ACK_STATE_FAIL) )
{
chnl_cb->tx_cmd_failed = 1;
chnl_cb->tx_cmd_in_process = 0;
/* communication failed or function failed. */
rtos_set_semaphore(&chnl_cb->rsp_sema);
}
else if(ack_buf->ack_state == ACK_STATE_COMPLETE)
{
/* communication ok, function is completed. */
chnl_cb->tx_cmd_failed = 0;
chnl_cb->tx_cmd_in_process = 0;
ipc_rsp_t * ipc_rsp = (ipc_rsp_t *)ack_buf;
/* chnl_cb->tx_xchg_buff == ipc_rsp->rsp_buff. MUST be true. */
if(ipc_rsp->rsp_data_len > sizeof(chnl_cb->rsp_buf))
{
/* buffer insufficient, failed. */
chnl_cb->tx_cmd_failed = 1;
chnl_cb->rsp_len = 0;
}
else
{
if((ipc_rsp->rsp_buff != NULL) && (ipc_rsp->rsp_data_len > 0))
{
#if CONFIG_CACHE_ENABLE
flush_dcache(ipc_rsp->rsp_buff, ipc_rsp->rsp_data_len);;
#endif
memcpy(chnl_cb->rsp_buf, ipc_rsp->rsp_buff, ipc_rsp->rsp_data_len);
chnl_cb->rsp_len = ipc_rsp->rsp_data_len;
}
else
{
chnl_cb->rsp_len = 0;
}
}
rtos_set_semaphore(&chnl_cb->rsp_sema);
}
else
{
/* communication ok, function is pending. */
}
return;
}
/*
* !!! FAULT !!!
*/
BK_LOGE(MOD_TAG, "Fault in %s,cmd:%d\r\n", __func__, ack_buf->hdr.cmd);
return;
}
static bk_err_t ipc_chnl_init(ipc_chnl_cb_t *chnl_cb, u8 chnl_id, ipc_rx_cmd_hdlr_t rx_handler)
{
bk_err_t ret_code;
if(chnl_cb->chnl_inited)
return BK_OK;
memset(chnl_cb, 0, sizeof(ipc_chnl_cb_t));
chnl_cb->chnl_id = chnl_id;
chnl_cb->tx_xchg_buff = mb_chnl_get_tx_buff(chnl_id);
chnl_cb->rx_xchg_buff = mb_chnl_get_rx_buff(chnl_id);
if( (chnl_cb->tx_xchg_buff == NULL) ||
(chnl_cb->tx_xchg_buff == NULL) )
{
return BK_FAIL;
}
ret_code = rtos_init_semaphore_adv(&chnl_cb->chnl_sema, 1, 1);
if(ret_code != BK_OK)
{
return ret_code;
}
ret_code = rtos_init_semaphore(&chnl_cb->rsp_sema, 1);
if(ret_code != BK_OK)
{
rtos_deinit_semaphore(&chnl_cb->chnl_sema);
return ret_code;
}
ret_code = mb_chnl_open(chnl_id, chnl_cb);
if(ret_code != BK_OK)
{
rtos_deinit_semaphore(&chnl_cb->chnl_sema);
rtos_deinit_semaphore(&chnl_cb->rsp_sema);
return ret_code;
}
chnl_cb->rx_cmd_handler = rx_handler;
mb_chnl_ctrl(chnl_id, MB_CHNL_SET_RX_ISR, (void *)ipc_cmd_rx_isr);
mb_chnl_ctrl(chnl_id, MB_CHNL_SET_TX_CMPL_ISR, (void *)ipc_cmd_tx_cmpl_isr);
chnl_cb->chnl_inited = 1;
return BK_OK;
}
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 rsp_buf_len)
{
bk_err_t ret_val = BK_FAIL;
ipc_cmd_t ipc_cmd;
if(!chnl_cb->chnl_inited)
return BK_FAIL;
rtos_get_semaphore(&chnl_cb->chnl_sema, BEKEN_WAIT_FOREVER);
chnl_cb->tx_cmd = cmd;
chnl_cb->tx_cmd_failed = 0;
chnl_cb->tx_cmd_in_process = 1;
void * dst_buf = (void *)chnl_cb->tx_xchg_buff;
do
{
if(cmd_len > IPC_XCHG_DATA_MAX)
{
ret_val = BK_ERR_PARAM;
break;
}
if(cmd_buf == NULL)
cmd_len = 0;
if(cmd_len > 0)
memcpy(dst_buf, cmd_buf, cmd_len);
ipc_cmd.chnl_hdr.data = 0; /* clear hdr. */
ipc_cmd.chnl_hdr.cmd = cmd;
ipc_cmd.cmd_buff = dst_buf;
ipc_cmd.cmd_data_len = cmd_len;
ret_val = mb_chnl_write(chnl_cb->chnl_id, (mb_chnl_cmd_t *)&ipc_cmd);
if(ret_val != BK_OK)
{
break;
}
ret_val = rtos_get_semaphore(&chnl_cb->rsp_sema, IPC_RSP_TIMEOUT); /* isr_callback will set this semaphore. */
if(ret_val != BK_OK)
{
mb_chnl_ctrl(chnl_cb->chnl_id, MB_CHNL_TX_RESET, NULL);
break;
}
chnl_cb->tx_cmd_in_process = 0; /* must have been set to 0 by callback. */
if(chnl_cb->tx_cmd_failed)
{
ret_val = BK_FAIL;
break;
}
if((rsp_buf == NULL) || (rsp_buf_len == 0))
{
ret_val = BK_OK;
break;
}
if(rsp_buf_len < chnl_cb->rsp_len)
{
ret_val = BK_ERR_PARAM;
break;
}
if(chnl_cb->rsp_len > 0)
memcpy(rsp_buf, chnl_cb->rsp_buf, chnl_cb->rsp_len);
ret_val = BK_OK;
}while(0);
chnl_cb->tx_cmd_in_process = 0;
rtos_set_semaphore(&chnl_cb->chnl_sema);
return ret_val;
}
static bk_err_t ipc_send_special_cmd(ipc_chnl_cb_t *chnl_cb, u8 cmd)
{
bk_err_t ret_val;
ipc_cmd_t ipc_cmd;
if (!chnl_cb->chnl_inited)
return BK_FAIL;
ipc_cmd.chnl_hdr.data = 0; /* clear hdr. */
ipc_cmd.chnl_hdr.cmd = cmd;
ipc_cmd.cmd_buff = NULL;
ipc_cmd.cmd_data_len = 0;
ret_val = mb_chnl_ctrl(chnl_cb->chnl_id, MB_CHNL_WRITE_SYNC, &ipc_cmd);
return ret_val;
}
static ipc_chnl_cb_t ipc_chnl_cb; // = { .chnl_id = MB_CHNL_HW_CTRL, .chnl_inited = 0 };
#if CONFIG_SYS_CPU1
#if CONFIG_MAILBOX_V2_0
// static ipc_chnl_cb_t ipc_chnl_cb2;
#endif
#endif
typedef struct
{
u16 res_id;
u16 cpu_id;
} ipc_res_req_t;
typedef struct
{
u32 user_id;
u32 chnl_id;
} ipc_dma_free_t;
#if (CONFIG_SHELL_ASYNCLOG)
extern void shell_set_log_cpu(u8 req_cpu);
#endif
#if (CONFIG_SYS_CPU0)
static void mb_ipc_power_on_notify(void);
static void mb_ipc_heartbeat_notify(void);
static void mb_ipc_dump_notify(u32 dump);
#endif
static u32 ipc_cmd_handler(ipc_chnl_cb_t *chnl_cb, mb_chnl_ack_t *ack_buf)
{
/* must NOT change ack_buf->hdr. */
u32 result = ACK_STATE_FAIL;
ipc_rsp_t * ipc_rsp = (ipc_rsp_t *)ack_buf;
/* chnl_cb->rx_xchg_buff == ipc_cmd->cmd_buff == ipc_rsp->rsp_buff. MUST be true. */
ipc_rsp->rsp_buff = chnl_cb->rx_xchg_buff;
switch(chnl_cb->rx_cmd)
{
case IPC_RES_AVAILABLE_INDICATION:
if(chnl_cb->cmd_len >= sizeof(u16))
{
ipc_rsp->rsp_data_len = 0;
u16 res_id = *((u16 *)chnl_cb->cmd_buf);
if(amp_res_available(res_id) == BK_OK)
{
result = ACK_STATE_COMPLETE;
}
else
{
result = ACK_STATE_FAIL;
}
}
else
{
ipc_rsp->rsp_data_len = 0;
result = ACK_STATE_FAIL;
}
break;
case IPC_TEST_CMD:
if(chnl_cb->cmd_len >= sizeof(u32))
{
ipc_rsp->rsp_data_len = sizeof(u32);
u32 * p_src = (u32 *)chnl_cb->cmd_buf;
u32 * p_dst = (u32 *)ipc_rsp->rsp_buff;
*p_dst = (*p_src) + 1;
result = ACK_STATE_COMPLETE;
}
else
{
ipc_rsp->rsp_data_len = 0;
result = ACK_STATE_FAIL;
}
break;
case IPC_GET_POWER_SAVE_FLAG:
{
ipc_rsp->rsp_data_len = sizeof(u32);
u32 * p_dst = (u32 *)ipc_rsp->rsp_buff;
// return PS flag to caller.
*p_dst = 0xAA; //(u32)get_cpu1_ps_flag();
result = ACK_STATE_COMPLETE;
}
break;
#if (USB_CDC_CP1_IPC)
case IPC_CPU0_OPEN_USB_CDC:
{
IPC_CDC_DATA_t *ipc_cdc = (IPC_CDC_DATA_t *)chnl_cb->cmd_buf;
bk_usb_cdc_open(ipc_cdc);
result = ACK_STATE_COMPLETE;
}
break;
case IPC_CPU0_CLOSE_USB_CDC:
{
bk_usb_cdc_close();
result = ACK_STATE_COMPLETE;
}
break;
case IPC_CPU0_INIT_USB_CDC_PARAM:
{
IPC_CDC_DATA_t *p_cdc_data = (IPC_CDC_DATA_t *)chnl_cb->cmd_buf;
bk_usb_cdc_param_init(p_cdc_data);
result = ACK_STATE_COMPLETE;
}
break;
case IPC_CPU0_SET_USB_CDC_CMD:
{
IPC_CDC_DATA_t *p_cdc_data = (IPC_CDC_DATA_t *)chnl_cb->cmd_buf;
bk_cdc_acm_bulkout(p_cdc_data);
result = ACK_STATE_COMPLETE;
}
break;
#endif
#if (USB_CDC_CP0_IPC)
case IPC_CPU1_UPLOAD_USB_CDC_DATA:
{
IPC_CDC_DATA_t *p_cdc_data = (IPC_CDC_DATA_t *)chnl_cb->cmd_buf;
p_cdc_data->bk_cdc_acm_bulkin_cb();
result = ACK_STATE_COMPLETE;
}
break;
case IPC_CPU1_UPDATE_USB_CDC_STATE:
{
extern void (*usb_cdc_state_cb)(uint32_t);
uint8_t cdc_state = *((u8 *)chnl_cb->cmd_buf);
if(usb_cdc_state_cb != NULL)
usb_cdc_state_cb(cdc_state);
result = ACK_STATE_COMPLETE;
}
break;
#endif
#if CONFIG_SYS_CPU0
case IPC_CPU1_POWER_UP_INDICATION: // cpu1 indication, power up successfully.
{
/* no params. */
/* inform modules who care CPU1 state. */
mb_ipc_power_on_notify();
/* no returns. */
ipc_rsp->rsp_data_len = 0;
result = ACK_STATE_COMPLETE;
}
break;
case IPC_CPU1_HEART_BEAT_INDICATION: // cpu1 indication, alive indication.
// contains the power save flag?
if(chnl_cb->cmd_len >= sizeof(u32))
{
//u32 * p_src = (u32 *)chnl_cb->cmd_buf;
// save the param.
mb_ipc_heartbeat_notify();
}
/* succeeded anyway but no returns. */
ipc_rsp->rsp_data_len = 0;
result = ACK_STATE_COMPLETE;
break;
#endif
#if (CONFIG_SYS_CPU0)
case IPC_CPU1_TRAP_HANDLE_BEGIN: // cpu1 indication, dump begin.
{
ipc_rsp->rsp_data_len = 0;
result = ACK_STATE_COMPLETE;
mb_ipc_dump_notify(1);
/* no params, no returns. */
#if (CONFIG_SHELL_ASYNCLOG)
shell_set_log_cpu(MAILBOX_CPU1);
#endif
}
break;
case IPC_CPU1_TRAP_HANDLE_END: // cpu1 indication, dump end.
{
ipc_rsp->rsp_data_len = 0;
result = ACK_STATE_COMPLETE;
mb_ipc_dump_notify(0);
/* no params, no returns. */
#if (CONFIG_SHELL_ASYNCLOG)
shell_set_log_cpu(CONFIG_CPU_CNT);
shell_log_flush();
#endif
bk_reboot();
}
break;
#endif
#if 0 // (CONFIG_SYS_CPU1)
case IPC_SET_CPU1_HEART_RATE:
if(chnl_cb->cmd_len >= sizeof(u32))
{
ipc_rsp->rsp_data_len = 0;
//u32 * p_src = (u32 *)chnl_cb->cmd_buf;
// save the param.
//set_cpu1_heart_rate(*p_src);
result = ACK_STATE_COMPLETE;
}
else
{
ipc_rsp->rsp_data_len = 0;
result = ACK_STATE_FAIL;
}
break;
case IPC_GET_CPU1_HEART_RATE:
{
ipc_rsp->rsp_data_len = sizeof(u32);
u32 * p_dst = (u32 *)ipc_rsp->rsp_buff;
// return heart_rate to caller.
*p_dst = 0xBB; //(u32)get_cpu1_heart_rate();
result = ACK_STATE_COMPLETE;
}
break;
#endif
#ifdef AMP_RES_SERVER
case IPC_RES_ACQUIRE_CNT:
if(chnl_cb->cmd_len >= sizeof(ipc_res_req_t))
{
ipc_res_req_t * res_req = (ipc_res_req_t *)chnl_cb->cmd_buf;
amp_res_req_cnt_t * res_cnt_list = (amp_res_req_cnt_t *)ipc_rsp->rsp_buff;
/* call amp_res_acquire_cnt in interrupt disabled state. */
u32 int_mask = ipc_enter_critical();
bk_err_t ret_code = amp_res_acquire_cnt(res_req->res_id, res_req->cpu_id, res_cnt_list);
ipc_exit_critical(int_mask);
if(ret_code == BK_OK)
{
ipc_rsp->rsp_data_len = sizeof(amp_res_req_cnt_t);
result = ACK_STATE_COMPLETE;
}
else
{
ipc_rsp->rsp_data_len = 0;
result = ACK_STATE_FAIL;
}
}
else
{
ipc_rsp->rsp_data_len = 0;
result = ACK_STATE_FAIL;
}
break;
case IPC_RES_RELEASE_CNT:
if(chnl_cb->cmd_len >= sizeof(ipc_res_req_t))
{
ipc_res_req_t * res_req = (ipc_res_req_t *)chnl_cb->cmd_buf;
amp_res_req_cnt_t * res_cnt_list = (amp_res_req_cnt_t *)ipc_rsp->rsp_buff;
/* call amp_res_release_cnt in interrupt disabled state. */
u32 int_mask = ipc_enter_critical();
bk_err_t ret_code = amp_res_release_cnt(res_req->res_id, res_req->cpu_id, res_cnt_list);
ipc_exit_critical(int_mask);
if(ret_code == BK_OK)
{
ipc_rsp->rsp_data_len = sizeof(amp_res_req_cnt_t);
result = ACK_STATE_COMPLETE;
}
else
{
ipc_rsp->rsp_data_len = 0;
result = ACK_STATE_FAIL;
}
}
else
{
ipc_rsp->rsp_data_len = 0;
result = ACK_STATE_FAIL;
}
break;
#if CONFIG_GENERAL_DMA
case IPC_ALLOC_DMA_CHNL:
if(chnl_cb->cmd_len >= sizeof(u32))
{
u32 user_id = *((u32 *)chnl_cb->cmd_buf);
ipc_rsp->rsp_data_len = sizeof(u8);
u8 * chnl_id = (u8 *)ipc_rsp->rsp_buff;
extern u8 dma_chnl_alloc(u32 user_id);
*chnl_id = dma_chnl_alloc(user_id);
result = ACK_STATE_COMPLETE;
}
else
{
ipc_rsp->rsp_data_len = 0;
result = ACK_STATE_FAIL;
}
break;
case IPC_FREE_DMA_CHNL:
if(chnl_cb->cmd_len >= sizeof(ipc_dma_free_t))
{
ipc_dma_free_t * free_req = (ipc_dma_free_t *)chnl_cb->cmd_buf;
extern bk_err_t dma_chnl_free(u32 user_id, dma_id_t chnl_id);
bk_err_t ret_val = dma_chnl_free(free_req->user_id, (dma_id_t)free_req->chnl_id);
ipc_rsp->rsp_data_len = 0;
if(ret_val == BK_OK)
result = ACK_STATE_COMPLETE;
else
result = ACK_STATE_FAIL;
}
else
{
ipc_rsp->rsp_data_len = 0;
result = ACK_STATE_FAIL;
}
break;
case IPC_DMA_CHNL_USER:
if(chnl_cb->cmd_len >= sizeof(u8))
{
u8 chnl_id = *((u8 *)chnl_cb->cmd_buf);
ipc_rsp->rsp_data_len = sizeof(u32);
u32 * user_id = (u32 *)ipc_rsp->rsp_buff;
extern u32 dma_chnl_user(dma_id_t user_id);
*user_id = dma_chnl_user((dma_id_t)chnl_id);
result = ACK_STATE_COMPLETE;
}
else
{
ipc_rsp->rsp_data_len = 0;
result = ACK_STATE_FAIL;
}
break;
#endif
#endif
default:
{
ipc_rsp->rsp_data_len = 0;
result = ACK_STATE_FAIL;
}
break;
}
return result;
}
#if (CONFIG_SYS_CPU0)
#include "../../../components/bk_rtos/rtos_ext.h"
#define MB_IPC_START_CORE_FLAG 0x01
#define MB_IPC_STOP_CORE_FLAG 0x02
#define MB_IPC_POWER_UP_FLAG 0x04
#define MB_IPC_HEARTBEAT_FLAG 0x08
#define MB_IPC_ALL_FLAGS (MB_IPC_START_CORE_FLAG | MB_IPC_STOP_CORE_FLAG | MB_IPC_POWER_UP_FLAG | MB_IPC_HEARTBEAT_FLAG)
enum
{
CORE_POWER_OFF = 0,
CORE_STARTING,
CORE_POWER_ON,
};
static rtos_event_ext_t mb_ipc_heart_event;
static u32 cpu1_heartbeat_timestamp = 0;
static volatile u8 cpu1_state = CORE_POWER_OFF;
static volatile u8 cpu1_dump = 0;
void start_cpu1_core(void);
void stop_cpu1_core(void);
#if 0
void mb_ipc_reset_notify(u32 power_on)
{
if(power_on)
{
if(cpu1_state != CORE_POWER_ON)
{
cpu1_state = CORE_STARTING;
rtos_set_event_ex(&mb_ipc_heart_event, MB_IPC_START_CORE_FLAG);
}
}
else
{
cpu1_state = CORE_POWER_OFF;
rtos_set_event_ex(&mb_ipc_heart_event, MB_IPC_STOP_CORE_FLAG);
}
}
#endif
static void mb_ipc_heartbeat_notify(void)
{
rtos_set_event_ex(&mb_ipc_heart_event, MB_IPC_HEARTBEAT_FLAG);
}
static void mb_ipc_power_on_notify(void)
{
rtos_set_event_ex(&mb_ipc_heart_event, MB_IPC_POWER_UP_FLAG);
}
static void mb_ipc_dump_notify(u32 dump)
{
cpu1_dump = (dump != 0);
}
static int mb_ipc_heartbeat_timeout(void)
{
u32 cur_time;
cur_time = (u32)rtos_get_time();
if(cpu1_state == CORE_POWER_OFF)
{
return 0;
}
if((cpu1_state == CORE_STARTING) || (cpu1_dump != 0))
{
cpu1_heartbeat_timestamp = cur_time;
return 0;
}
if(cur_time >= cpu1_heartbeat_timestamp)
{
cur_time -= cpu1_heartbeat_timestamp;
}
else
{
cur_time += (~(cpu1_heartbeat_timestamp)) + 1; // wrap around.
}
if(cur_time < CONFIG_INT_WDT_PERIOD_MS)
{
cpu1_heartbeat_timestamp = (u32)rtos_get_time();
return 0;
}
return 1;
}
static void mb_ipc_task( void *para )
{
bk_err_t ret_val;
u32 events;
u32 check_time = BEKEN_WAIT_FOREVER;
ret_val = rtos_init_event_ex(&mb_ipc_heart_event);
if(ret_val != BK_OK)
{
rtos_delete_thread(NULL);
return;
}
while(1)
{
events = rtos_wait_event_ex(&mb_ipc_heart_event, MB_IPC_ALL_FLAGS, true, check_time);
if(events == 0)
{
// timeout, so check heartbeat.
events = MB_IPC_HEARTBEAT_FLAG;
}
if(events & MB_IPC_STOP_CORE_FLAG) // process this event at first!!!!
{
if(cpu1_state == CORE_POWER_OFF)
{
events = 0; // clear all events.
}
}
if(events & MB_IPC_START_CORE_FLAG)
{
u8 retry_cnt = 0;
while(cpu1_state == CORE_STARTING)
{
mb_ipc_heartbeat_timeout();
if(events & MB_IPC_POWER_UP_FLAG)
{
if(cpu1_state == CORE_STARTING)
{
cpu1_state = CORE_POWER_ON;
break; // cpu1 power on.
}
}
else
{
if(retry_cnt > 0)
{
BK_LOGE(MOD_TAG, "IPC retry to start core1\r\n");
stop_cpu1_core();
rtos_delay_milliseconds(6);
start_cpu1_core();
break;
}
else
{
events = rtos_wait_event_ex(&mb_ipc_heart_event, MB_IPC_POWER_UP_FLAG, true, 2000);// 2s
}
}
retry_cnt++;
}
// discard this event when not in CORE_STARTING state.
}
if(events & MB_IPC_HEARTBEAT_FLAG)
{
if(mb_ipc_heartbeat_timeout())
{
BK_LOGE(MOD_TAG, "IPC restart core1\r\n");
stop_cpu1_core();
rtos_delay_milliseconds(6);
start_cpu1_core();
}
}
if(cpu1_state == CORE_POWER_OFF)
{
check_time = BEKEN_WAIT_FOREVER;
}
else
{
check_time = CONFIG_INT_WDT_PERIOD_MS;
}
}
}
#if 0
int mb_ipc_cpu_is_power_on(u32 cpu_id)
{
if(cpu1_state == CORE_POWER_ON)
{
return 1;
}
return 0;
}
#endif
#endif
#if (CONFIG_SYS_CPU1)
#define MB_IPC_HEARTBEAT_TIME 2000
static void mb_ipc_task( void *para )
{
ipc_send_power_up();
while(1)
{
rtos_delay_milliseconds(MB_IPC_HEARTBEAT_TIME);
ipc_send_heart_beat(0);
}
}
#endif
bk_err_t ipc_init(void)
{
bk_err_t ret_val = BK_FAIL;
#if (CONFIG_SYS_CPU0 || CONFIG_SYS_CPU1)
ret_val = ipc_chnl_init(&ipc_chnl_cb, MB_CHNL_HW_CTRL, (ipc_rx_cmd_hdlr_t)ipc_cmd_handler);
#if CONFIG_SYS_CPU1
#if CONFIG_MAILBOX_V2_0
// if(ret_val == BK_OK)
// ret_val = ipc_chnl_init(&ipc_chnl_cb, CP2_MB_CHNL_CTRL, (ipc_rx_cmd_hdlr_t)ipc_cmd_handler);
#endif
#endif
if(ret_val != BK_OK)
{
BK_LOGE(MOD_TAG, "Ipc failed at %d: %d\r\n", __LINE__, ret_val);
return ret_val;
}
ret_val = rtos_create_thread(NULL, BEKEN_DEFAULT_WORKER_PRIORITY, "mb_ipc", mb_ipc_task, 1536, 0);
#endif
#if CONFIG_SYS_CPU2
ret_val = ipc_chnl_init(&ipc_chnl_cb, CP1_MB_CHNL_CTRL, (ipc_rx_cmd_hdlr_t)ipc_cmd_handler);
#endif
if(ret_val != BK_OK)
{
BK_LOGE(MOD_TAG, "Ipc failed at %d: %d\r\n", __LINE__, ret_val);
}
return ret_val;
}
bk_err_t ipc_send_available_ind(u16 resource_id)
{
return ipc_send_cmd(&ipc_chnl_cb, IPC_RES_AVAILABLE_INDICATION, \
(u8 *)&resource_id, sizeof(resource_id), NULL, 0);
}
u32 ipc_send_test_cmd(u32 param)
{
ipc_send_cmd(&ipc_chnl_cb, IPC_TEST_CMD, (u8 *)&param, sizeof(param), (u8 *)&param, sizeof(param));
return param;
}
u32 ipc_send_get_ps_flag(void)
{
u32 param = -1;
ipc_send_cmd(&ipc_chnl_cb, IPC_GET_POWER_SAVE_FLAG, NULL, 0, (u8 *)&param, sizeof(param));
return param;
}
#if 0 // (CONFIG_SYS_CPU0)
u32 ipc_send_get_heart_rate(void)
{
u32 param = -1;
ipc_send_cmd(&ipc_chnl_cb, IPC_GET_CPU1_HEART_RATE, NULL, 0, (u8 *)&param, sizeof(param));
return param;
}
bk_err_t ipc_send_set_heart_rate(u32 param)
{
return ipc_send_cmd(&ipc_chnl_cb, IPC_SET_CPU1_HEART_RATE, (u8 *)&param, sizeof(param), NULL, 0);
}
#endif
#if (CONFIG_SYS_CPU1)
bk_err_t ipc_send_power_up(void)
{
return ipc_send_cmd(&ipc_chnl_cb, IPC_CPU1_POWER_UP_INDICATION, NULL, 0, NULL, 0);
}
bk_err_t ipc_send_heart_beat(u32 param)
{
return ipc_send_cmd(&ipc_chnl_cb, IPC_CPU1_HEART_BEAT_INDICATION, (u8 *)&param, sizeof(param), NULL, 0);
}
#endif
#if CONFIG_SYS_CPU1
bk_err_t ipc_send_trap_handle_begin(void)
{
return ipc_send_special_cmd(&ipc_chnl_cb, IPC_CPU1_TRAP_HANDLE_BEGIN);
}
bk_err_t ipc_send_trap_handle_end(void)
{
return ipc_send_special_cmd(&ipc_chnl_cb, IPC_CPU1_TRAP_HANDLE_END);
}
#endif
#ifdef AMP_RES_CLIENT
bk_err_t ipc_send_res_acquire_cnt(u16 resource_id, u16 cpu_id, amp_res_req_cnt_t *cnt_list)
{
ipc_res_req_t res_req;
res_req.res_id = resource_id;
res_req.cpu_id = cpu_id;
return ipc_send_cmd(&ipc_chnl_cb, IPC_RES_ACQUIRE_CNT, \
(u8 *)&res_req, sizeof(res_req), (u8 *)cnt_list, sizeof(amp_res_req_cnt_t));
}
bk_err_t ipc_send_res_release_cnt(u16 resource_id, u16 cpu_id, amp_res_req_cnt_t *cnt_list)
{
ipc_res_req_t res_req;
res_req.res_id = resource_id;
res_req.cpu_id = cpu_id;
return ipc_send_cmd(&ipc_chnl_cb, IPC_RES_RELEASE_CNT, \
(u8 *)&res_req, sizeof(res_req), (u8 *)cnt_list, sizeof(amp_res_req_cnt_t));
}
#if CONFIG_GENERAL_DMA
u8 ipc_send_alloc_dma_chnl(u32 user_id)
{
bk_err_t ret_val = BK_FAIL;
u8 dma_chnl_id = -1;
ret_val = ipc_send_cmd(&ipc_chnl_cb, IPC_ALLOC_DMA_CHNL, \
(u8 *)&user_id, sizeof(user_id), (u8 *)&dma_chnl_id, sizeof(dma_chnl_id));
if(ret_val != BK_OK)
return (u8)(-1);
return dma_chnl_id;
}
bk_err_t ipc_send_free_dma_chnl(u32 user_id, u8 chnl_id)
{
bk_err_t ret_val = BK_FAIL;
ipc_dma_free_t dma_free;
dma_free.user_id = user_id;
dma_free.chnl_id = chnl_id;
ret_val = ipc_send_cmd(&ipc_chnl_cb, IPC_FREE_DMA_CHNL, \
(u8 *)&dma_free, sizeof(dma_free), NULL, 0);
return ret_val;
}
u32 ipc_send_dma_chnl_user(u8 chnl_id)
{
bk_err_t ret_val = BK_FAIL;
u32 user_id = -1;
ret_val = ipc_send_cmd(&ipc_chnl_cb, IPC_DMA_CHNL_USER, \
(u8 *)&chnl_id, sizeof(chnl_id), (u8 *)&user_id, sizeof(user_id));
if(ret_val != BK_OK)
return (u32)(-1);
return user_id;
}
#endif
#endif
void ipc_cdc_send_cmd(u8 cmd, u8 *cmd_buf, u16 cmd_len, u8 * rsp_buf, u16 rsp_buf_len)
{
ipc_send_cmd(&ipc_chnl_cb, cmd, (uint8_t *)cmd_buf, cmd_len, (uint8_t *)rsp_buf, rsp_buf_len);
}
#endif