/* * 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; }