You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

354 lines
12 KiB

/*
* Copyright (c) Hisilicon Technologies Co., Ltd. 2019-2020. All rights reserved.
* Description: mailbox driver in liteos
*/
#include "drv_mbx.h"
#include "mbx_common.h"
#include "los_mbx.h"
#include "los_printf.h"
#include "los_base.h"
#include "los_memory.h"
#include "los_mux.h"
#define SC_GEN18 (void *)(td_uintptr_t)0x841448
static td_bool is_v2_chipset(td_void)
{
if (MBX_READL(SC_GEN18) & (0x1 << 13)) { /* if SC_GEN18[13]==1 then V2(CS) chipset */
return TD_TRUE;
}
return TD_FALSE;
}
td_s32 drv_mbx_open(td_u32 session_id)
{
return mbx_open(session_id, MBX_RX_BUFF_SIZE, MBX_TX_BUFF_SIZE);
}
td_s32 drv_mbx_close(td_u32 handle)
{
return mbx_close(handle);
}
td_s32 drv_mbx_register_irq_callback(td_u32 handle, session_callback func, const td_void * const data)
{
return mbx_register_irq_callback(handle, func, data);
}
td_s32 drv_mbx_rx(td_u32 handle, td_u8 *msg, td_u32 msg_len, const td_u32 * const rx_len, td_u32 timeout)
{
return mbx_rx(handle, msg, msg_len, (td_u32 *)rx_len, timeout);
}
td_s32 drv_mbx_tx(td_u32 handle, const td_u8 *msg, td_u32 msg_len, const td_u32 * const tx_len,
td_u32 timeout)
{
return mbx_tx(handle, msg, msg_len, (td_u32 *)tx_len, timeout);
}
td_void mbx_polling_rx(td_void)
{
#ifndef SUPPORT_MBX_INTERRUPT
struct mailbox *mailbox = NULL;
mailbox = get_mailbox_data();
if (mailbox == NULL) {
return;
}
mbx_rx_msg((td_void *)mailbox->acpu_vmcu0.rx_head_addr);
mbx_rx_msg((td_void *)mailbox->tcpu_vmcu0.rx_head_addr);
#endif
return;
}
static void init_acpu_reg(struct session * const session, const struct mailbox *mailbox)
{
if (session == NULL || mailbox == NULL) {
return;
}
if (mailbox->acpu_vmcu0.base_addr == NULL) {
return;
}
session->tx_reg = (struct reg *)MBX_MALLOC(sizeof(struct reg));
if (session->tx_reg == NULL) {
return;
}
if (is_v2_chipset() == TD_TRUE) {
session->tx_reg->argv_size = VMCU_TO_ACPU_ARGS_V2_NUM;
session->tx_reg->argv = mailbox->acpu_vmcu0.base_addr + VMCU_TO_ACPU_ARGS_V2_OFFSET;
} else {
session->tx_reg->argv_size = VMCU_TO_ACPU_ARGS_NUM;
session->tx_reg->argv = mailbox->acpu_vmcu0.base_addr + VMCU_TO_ACPU_ARGS_OFFSET;
}
#ifdef CHIP_TYPE_RESERVED23
session->tx_reg->argv_size = VMCU_TO_ACPU_ARGS_V2_NUM;
session->tx_reg->argv = mailbox->acpu_vmcu0.base_addr + VMCU_TO_ACPU_ARGS_V2_OFFSET;
#endif
session->tx_reg->version = mailbox->acpu_vmcu0.base_addr + MAILBOX_VERSION_OFFSET;
session->tx_reg->head = mailbox->acpu_vmcu0.base_addr + VMCU_TO_ACPU_HEAD_OFFSET;
session->tx_reg->trigger_rx = mailbox->acpu_vmcu0.base_addr + VMCU_TO_ACPU_SEND_OFFSET;
session->tx_reg->pending = mailbox->acpu_vmcu0.base_addr + ACPU_INTR_FROM_VMCU_OFFSET;
session->tx_reg->lock = (td_u32 *)&mailbox->tx_acpu_lock;
session->rx_reg = (struct reg *)MBX_MALLOC(sizeof(struct reg));
if (session->rx_reg == NULL) {
return;
}
session->rx_reg->argv_size = ACPU_TO_VMCU_ARGS_NUM;
session->rx_reg->version = mailbox->acpu_vmcu0.base_addr + MAILBOX_VERSION_OFFSET;
session->rx_reg->head = mailbox->acpu_vmcu0.base_addr + ACPU_TO_VMCU_HEAD_OFFSET;
session->rx_reg->argv = mailbox->acpu_vmcu0.base_addr + ACPU_TO_VMCU_ARGS_OFFSET;
session->rx_reg->trigger_rx = mailbox->acpu_vmcu0.base_addr + ACPU_TO_VMCU_SEND_OFFSET;
session->rx_reg->pending = mailbox->acpu_vmcu0.base_addr + VMCU_INTR_FROM_ACPU_OFFSET;
return;
}
static void init_tcpu_reg(struct session * const session, const struct mailbox * const mailbox)
{
if (session == NULL || mailbox == NULL) {
return;
}
if (mailbox->tcpu_vmcu0.base_addr == NULL) {
return;
}
session->tx_reg = (struct reg *)MBX_MALLOC(sizeof(struct reg));
if (session->tx_reg == NULL) {
return;
}
session->tx_reg->argv_size = VMCU_TO_TCPU_ARGS_NUM;
session->tx_reg->version = mailbox->tcpu_vmcu0.base_addr + MAILBOX_VERSION_OFFSET;
session->tx_reg->head = mailbox->tcpu_vmcu0.base_addr + VMCU_TO_TCPU_HEAD_OFFSET;
session->tx_reg->argv = mailbox->tcpu_vmcu0.base_addr + VMCU_TO_TCPU_ARGS_OFFSET;
session->tx_reg->trigger_rx = mailbox->tcpu_vmcu0.base_addr + VMCU_TO_TCPU_SEND_OFFSET;
session->tx_reg->pending = mailbox->tcpu_vmcu0.base_addr + TCPU_INTR_FROM_VMCU_OFFSET;
session->tx_reg->lock = (td_u32 *)&mailbox->tx_tcpu_lock;
session->rx_reg = (struct reg *)MBX_MALLOC(sizeof(struct reg));
if (session->rx_reg == NULL) {
return;
}
session->rx_reg->argv_size = TCPU_TO_VMCU_ARGS_NUM;
session->rx_reg->version = mailbox->tcpu_vmcu0.base_addr + MAILBOX_VERSION_OFFSET;
session->rx_reg->head = mailbox->tcpu_vmcu0.base_addr + TCPU_TO_VMCU_HEAD_OFFSET;
session->rx_reg->argv = mailbox->tcpu_vmcu0.base_addr + TCPU_TO_VMCU_ARGS_OFFSET;
session->rx_reg->trigger_rx = mailbox->tcpu_vmcu0.base_addr + TCPU_TO_VMCU_SEND_OFFSET;
session->rx_reg->pending = mailbox->tcpu_vmcu0.base_addr + VMCU_INTR_FROM_TCPU_OFFSET;
return;
}
static void init_dmcu0_reg(struct session *session, const struct mailbox *mailbox)
{
if (session == NULL || mailbox == NULL) {
return;
}
if (mailbox->acpu_dmcu0.base_addr == NULL) {
return;
}
session->tx_reg = (struct reg *)MBX_MALLOC(sizeof(struct reg));
if (session->tx_reg == NULL) {
return;
}
session->tx_reg->argv_size = DMCU_TO_ACPU_ARGS_V2_NUM;
session->tx_reg->argv = mailbox->acpu_dmcu0.base_addr + DMCU_TO_ACPU_ARGS_V2_OFFSET;
session->tx_reg->version = mailbox->acpu_dmcu0.base_addr + MAILBOX_VERSION_OFFSET;
session->tx_reg->head = mailbox->acpu_dmcu0.base_addr + DMCU_TO_ACPU_HEAD_OFFSET;
session->tx_reg->trigger_rx = mailbox->acpu_dmcu0.base_addr + DMCU_TO_ACPU_SEND_OFFSET;
session->tx_reg->pending = mailbox->acpu_dmcu0.base_addr + ACPU_INTR_FROM_DMCU_OFFSET;
session->tx_reg->lock = (td_u32 *)&mailbox->tx_dmcu0_lock;
session->rx_reg = (struct reg *)MBX_MALLOC(sizeof(struct reg));
if (session->rx_reg == NULL) {
MBX_FREE(session->tx_reg);
return;
}
session->rx_reg->argv_size = ACPU_TO_DMCU_ARGS_NUM;
session->rx_reg->version = mailbox->acpu_dmcu0.base_addr + MAILBOX_VERSION_OFFSET;
session->rx_reg->head = mailbox->acpu_dmcu0.base_addr + ACPU_TO_DMCU_HEAD_OFFSET;
session->rx_reg->argv = mailbox->acpu_dmcu0.base_addr + ACPU_TO_DMCU_ARGS_OFFSET;
session->rx_reg->trigger_rx = mailbox->acpu_dmcu0.base_addr + ACPU_TO_DMCU_SEND_OFFSET;
session->rx_reg->pending = mailbox->acpu_dmcu0.base_addr + DMCU_INTR_FROM_ACPU_OFFSET;
return;
}
td_void init_mailbox_reg(struct session *session, td_u32 session_id, const struct mailbox *mailbox)
{
td_u32 local_side, remote_side;
if (mailbox == NULL) {
return;
}
local_side = mailbox->local_cpu;
remote_side = SESSION_ID_SIDE0(session_id) == local_side ? \
SESSION_ID_SIDE1(session_id) : SESSION_ID_SIDE0(session_id);
if (local_side != SESSION_ID_SIDE0(session_id) && \
local_side != SESSION_ID_SIDE1(session_id)) {
return;
}
if (session == NULL) {
return;
}
switch (local_side) {
case VMCU0:
if (remote_side == ACPU) {
init_acpu_reg(session, mailbox);
} else if (remote_side == TCPU) {
init_tcpu_reg(session, mailbox);
} else {
session->tx_reg = NULL;
session->rx_reg = NULL;
}
break;
case DMCU0:
if (remote_side == ACPU) {
init_dmcu0_reg(session, mailbox);
} else {
session->tx_reg = NULL;
session->rx_reg = NULL;
}
break;
default:
session->tx_reg = NULL;
session->rx_reg = NULL;
break;
}
return;
}
#ifdef SUPPORT_MBX_INTERRUPT
#ifdef CONFIG_DRIVERS_MBX_DMCU
static MBX_IRQ_RET mailbox_dmcu0_irq_handler(int irq, void *dev_id)
{
int ret;
struct mailbox *mailbox;
mailbox = get_mailbox_data();
if (mailbox == NULL || mailbox->acpu_dmcu0.rx_head_addr == NULL) {
return MBX_IRQ_HANDLED;
}
ret = mbx_rx_msg((void *)mailbox->acpu_dmcu0.rx_head_addr);
if (ret != SOC_MBX_SUCCESS) {
MBX_WRITEL(0x00, mailbox->acpu_dmcu0.base_addr + DMCU_INTR_FROM_ACPU_OFFSET);
MBX_ERR_PRINT("mbx_rx_msg dmcu0 error and ret:0x%x\n", ret);
}
return MBX_IRQ_HANDLED;
}
#else
static MBX_IRQ_RET mailbox_acpu_irq_handler(td_void *dev_id)
{
td_s32 ret;
struct mailbox *mailbox;
mailbox = get_mailbox_data();
if (mailbox == NULL || (mailbox->acpu_vmcu0.rx_head_addr == NULL) || mailbox->acpu_vmcu0.base_addr == NULL) {
return MBX_IRQ_HANDLED;
}
ret = mbx_rx_msg((td_void *)mailbox->acpu_vmcu0.rx_head_addr);
if (ret != SOC_MBX_SUCCESS) {
MBX_WRITEL(0x00, mailbox->acpu_vmcu0.base_addr + VMCU_INTR_FROM_ACPU_OFFSET);
MBX_ERR_PRINT("mbx_rx_msg error from acpu and ret:0x%x\n", ret);
}
return MBX_IRQ_HANDLED;
}
static MBX_IRQ_RET mailbox_tcpu_irq_handler(td_void *dev_id)
{
td_s32 ret;
struct mailbox *mailbox;
mailbox = get_mailbox_data();
if ((mailbox == NULL) || (mailbox->tcpu_vmcu0.rx_head_addr == NULL) || (mailbox->tcpu_vmcu0.base_addr == NULL)) {
return MBX_IRQ_HANDLED;
}
ret = mbx_rx_msg((td_void *)mailbox->tcpu_vmcu0.rx_head_addr);
if (ret != SOC_MBX_SUCCESS) {
MBX_WRITEL(0x00, mailbox->tcpu_vmcu0.base_addr + VMCU_INTR_FROM_TCPU_OFFSET);
MBX_ERR_PRINT("mbx_rx_msg error from tcpu and ret:0x%x\n", ret);
}
return MBX_IRQ_HANDLED;
}
#endif
#endif
td_s32 drv_mbx_init(enum cpu_id local_cpu)
{
struct mailbox *mailbox;
#ifdef SUPPORT_MBX_INTERRUPT
td_s32 ret;
#endif
mailbox = get_mailbox_data();
if ((mailbox == NULL) || (local_cpu >= CPU_MAX) || (mailbox->initalized != TD_FALSE)) {
return SOC_ERR_MAILBOX_NOT_SUPPORT;
}
MBX_INIT_LIST_HEAD(&mailbox->list_head);
mailbox->local_cpu = local_cpu;
MBX_MUTEX_INIT(&mailbox->list_lock);
#ifdef CONFIG_DRIVERS_MBX_DMCU
MBX_MUTEX_INIT(&mailbox->tx_dmcu0_lock);
mailbox->acpu_dmcu0.base_addr = (td_u32 *)(MBX_ACPU_DMCU0_BASE_ADDR);
mailbox->acpu_dmcu0.rx_head_addr = mailbox->acpu_dmcu0.base_addr + ACPU_TO_DMCU_HEAD_OFFSET;
mailbox->initalized = TRUE;
#ifdef SUPPORT_MBX_INTERRUPT
ret = (td_s32)LOS_HwiCreate(MBX_IRQ_ACPU2DMCU, 0x01, 0, (HWI_PROC_FUNC)mailbox_dmcu0_irq_handler, 0);
if (ret != 0) {
MBX_ERR_PRINT("Request MBX_IRQ_ACPU2DMCU IRQ failed\n");
return SOC_ERR_MAILBOX_NOT_INIT;
}
LOS_HwiEnable(MBX_IRQ_ACPU2DMCU);
#endif
#else
MBX_MUTEX_INIT(&mailbox->tx_acpu_lock);
MBX_MUTEX_INIT(&mailbox->tx_tcpu_lock);
mailbox->acpu_vmcu0.base_addr = (td_u32 *)MBX_VMCU0_BASE_ADDR;
mailbox->acpu_vmcu0.rx_head_addr = mailbox->acpu_vmcu0.base_addr + ACPU_TO_VMCU_HEAD_OFFSET;
mailbox->tcpu_vmcu0.base_addr = (td_u32 *)MBX_VMCU0_BASE_ADDR;
mailbox->tcpu_vmcu0.rx_head_addr = mailbox->acpu_vmcu0.base_addr + TCPU_TO_VMCU_HEAD_OFFSET;
mailbox->initalized = TRUE;
#ifdef SUPPORT_MBX_INTERRUPT
ret = (td_s32)LOS_HwiCreate(MBX_IRQ_ACPU2VMCU, 0x01, 0, (HWI_PROC_FUNC)mailbox_acpu_irq_handler, 0);
if (ret != 0) {
MBX_ERR_PRINT("Request MBX_IRQ_ACPU2VMCU IRQ failed\n");
return SOC_ERR_MAILBOX_NOT_INIT;
}
LOS_InterruptUnmask(MBX_IRQ_ACPU2VMCU);
ret = (td_s32)LOS_HwiCreate(MBX_IRQ_TCPU2VMCU, 0x01, 0, (HWI_PROC_FUNC)mailbox_tcpu_irq_handler, 0);
if (ret != 0) {
MBX_ERR_PRINT("Request MBX_IRQ_TCPU2VMCU IRQ failed\n");
return SOC_ERR_MAILBOX_NOT_INIT;
}
LOS_InterruptUnmask(MBX_IRQ_TCPU2VMCU);
#endif
#endif
return SOC_MBX_SUCCESS;
}
td_s32 drv_mbx_deinit(td_void)
{
struct mailbox *mailbox;
mailbox = get_mailbox_data();
if (mailbox == NULL) {
return SOC_ERR_MAILBOX_NOT_SUPPORT;
}
mailbox->initalized = FALSE;
mailbox->local_cpu = 0;
#ifdef SUPPORT_MBX_INTERRUPT
LOS_HwiDelete(MBX_IRQ_ACPU2VMCU, 0);
LOS_HwiDelete(MBX_IRQ_TCPU2VMCU, 0);
#endif
return SOC_MBX_SUCCESS;
}