/*
 * Copyright (c) Hisilicon Technologies Co., Ltd. 2019-2020. All rights reserved.
 * Description: mailbox driver for liteos
 */
#ifndef _DRV_MAILBOX_H_
#define _DRV_MAILBOX_H_

#include "los_mbx.h"

#ifdef CONFIG_DRIVERS_MBX_DMCU
#include <los_hwi.h>
#include <los_mux.h>
#include "delay.h"
#else
#include "los_list.h"
#include "los_mux.h"
#include "los_delay.h"
#endif

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */

#define SUPPORT_MBX_INTERRUPT
#define MAILBOX_VERSION_OFFSET        0x0
/* acpu to vmcu0 */
#ifdef CHIP_TYPE_RESERVED23
#define MBX_VMCU0_BASE_ADDR           0x00dfb000
#else
#define MBX_VMCU0_BASE_ADDR           0x0129b000
#endif
#define MBX_VMCU1_BASE_ADDR           0x012bb000

#define ACPU_TO_VMCU_HEAD_OFFSET      (0x0020 / 4)
#define ACPU_TO_VMCU_ARGS_OFFSET      (0x0040 / 4)
#define ACPU_TO_VMCU_ARGS_NUM         (16 * 4)
#define ACPU_TO_VMCU_SEND_OFFSET      (0x0400 / 4)
#define ACPU_INTR_FROM_VMCU_OFFSET    (0x0418 / 4)
/* vmcu0 to acpu */
#define VMCU_TO_ACPU_HEAD_OFFSET      (0x0100 / 4)
#define VMCU_TO_ACPU_ARGS_OFFSET      (0x0420 / 4)
#define VMCU_TO_ACPU_ARGS_V2_OFFSET   (0x0110 / 4)
#define VMCU_TO_ACPU_ARGS_NUM         (12 * 4)
#define VMCU_TO_ACPU_ARGS_V2_NUM      (16 * 4)
#define VMCU_TO_ACPU_SEND_OFFSET      (0x0410 / 4)
#define VMCU_INTR_FROM_ACPU_OFFSET    (0x0408 / 4)

/* tcpu to vmcu0 */
#define TCPU_TO_VMCU_HEAD_OFFSET      (0x0200 / 4)
#define TCPU_TO_VMCU_ARGS_OFFSET      (0x0240 / 4)
#define TCPU_TO_VMCU_ARGS_NUM         (16 * 4)
#define TCPU_TO_VMCU_SEND_OFFSET      (0x0404 / 4)
#define TCPU_INTR_FROM_VMCU_OFFSET    (0x041C / 4)
/* vmcu0 to tcpu */
#define VMCU_TO_TCPU_HEAD_OFFSET      (0x0300 / 4)
#define VMCU_TO_TCPU_ARGS_OFFSET      (0x0310 / 4)
#define VMCU_TO_TCPU_ARGS_NUM         (4 * 4)
#define VMCU_TO_TCPU_SEND_OFFSET      (0x0414 / 4)
#define VMCU_INTR_FROM_TCPU_OFFSET    (0x040C / 4)

#define MBX_IRQ_ACPU2VMCU             (26 + 13)
#define ACPU2VMCU_IRQ_NAME            "ACPU2VMCU_IRQ"
#define MBX_IRQ_TCPU2VMCU             (26 + 12)
#define TCPU2VMCU_IRQ_NAME            "TCPU2VMCU_IRQ"

/* acpu to dmcu0 */
#ifndef CONFIG_MBX_BASE_ADDR_DMCU
#define CONFIG_MBX_BASE_ADDR_DMCU       0x117B000
#endif
#define MBX_ACPU_DMCU0_BASE_ADDR        CONFIG_MBX_BASE_ADDR_DMCU
#define ACPU_TO_DMCU_HEAD_OFFSET        (0x0020 / 4)
#define ACPU_TO_DMCU_ARGS_OFFSET        (0x0040 / 4)
#define ACPU_TO_DMCU_ARGS_NUM           (16 * 4)
#define ACPU_TO_DMCU_SEND_OFFSET        (0x0400 / 4)
#define ACPU_INTR_FROM_DMCU_OFFSET      (0x0418 / 4)

/* dmcu0 to acpu */
#define DMCU_TO_ACPU_HEAD_OFFSET        (0x0100 / 4)
#define DMCU_TO_ACPU_ARGS_V2_OFFSET     (0x0110 / 4)
#define DMCU_TO_ACPU_ARGS_OFFSET        (0x0420 / 4)
#define DMCU_TO_ACPU_ARGS_V2_NUM        (16 * 4)
#define DMCU_TO_ACPU_ARGS_NUM           (12 * 4)
#define DMCU_TO_ACPU_SEND_OFFSET        (0x0410 / 4)
#define DMCU_INTR_FROM_ACPU_OFFSET      (0x0408 / 4)

#define MBX_IRQ_ACPU2DMCU               (26 + 12)
#define DMCU2ACPU_IRQ_NAME               "ACPU2DMCU_IRQ"


#define SOC_ERRCODE_DEF(moduleid, errid) (td_u32)(0x80000000 | ((moduleid) << 16)  | (errid))
#define SOC_MAILBOX_ID                   0x6D
#define SOC_MBX_SUCCESS                  0
#define SOC_MBX_FAILURE                  (-1)
#define MBX_DELAY_TIME                  10
#define MBX_RX_BUFF_SIZE                4100
#define MBX_TX_BUFF_SIZE                0

#define SOC_ERR_MAILBOX_NOT_INIT                   SOC_ERRCODE_DEF(SOC_MAILBOX_ID, 0x0001)
#define SOC_ERR_MAILBOX_INVALID_HANDLE             SOC_ERRCODE_DEF(SOC_MAILBOX_ID, 0x0002)
#define SOC_ERR_MAILBOX_INVALID_PTR                SOC_ERRCODE_DEF(SOC_MAILBOX_ID, 0x0003)
#define SOC_ERR_MAILBOX_INVALID_PARA               SOC_ERRCODE_DEF(SOC_MAILBOX_ID, 0x0004)
#define SOC_ERR_MAILBOX_INVALID_FLAG               SOC_ERRCODE_DEF(SOC_MAILBOX_ID, 0x0005)
#define SOC_ERR_MAILBOX_INVALID_RECEIVER           SOC_ERRCODE_DEF(SOC_MAILBOX_ID, 0x0006)
#define SOC_ERR_MAILBOX_NO_MEMORY                  SOC_ERRCODE_DEF(SOC_MAILBOX_ID, 0x0007)
#define SOC_ERR_MAILBOX_NOT_SUPPORT                SOC_ERRCODE_DEF(SOC_MAILBOX_ID, 0x0008)
#define SOC_ERR_MAILBOX_ERR_RECEIVE                SOC_ERRCODE_DEF(SOC_MAILBOX_ID, 0x0009)
#define SOC_ERR_MAILBOX_UNEXPECTED_RECEIVE_LEN     SOC_ERRCODE_DEF(SOC_MAILBOX_ID, 0x000A)
#define SOC_ERR_MAILBOX_CRC_CHECK_ERROR            SOC_ERRCODE_DEF(SOC_MAILBOX_ID, 0x000B)
#define SOC_ERR_MAILBOX_UNKNOWN_CMD                SOC_ERRCODE_DEF(SOC_MAILBOX_ID, 0x000C)
#define SOC_ERR_MAILBOX_NO_SESSION                 SOC_ERRCODE_DEF(SOC_MAILBOX_ID, 0x000D)
#define SOC_ERR_MAILBOX_TIMEOUT                    SOC_ERRCODE_DEF(SOC_MAILBOX_ID, 0x000E)
#define SOC_ERR_MAILBOX_UNKNOWN                    SOC_ERRCODE_DEF(SOC_MAILBOX_ID, 0x000F)
#define SOC_ERR_MAILBOX_PENDING                    SOC_ERRCODE_DEF(SOC_MAILBOX_ID, 0x0010)

#define SESSION_BUSY                      (1 << 0)
#define SESSION_ID_SIDE0(session_id)      (((session_id) >> 4) & 0xF)
#define SESSION_ID_SIDE1(session_id)      ((session_id) & 0xF)
#define SESSION_ID_NUM(session_id)        (((session_id) >> 8) & 0xFF)
#define SESSION_ID_PORT(session_id)       (((session_id) >> 16) & 0x7F)
#define SESSION_ID_HANDLE(session_id)     (((session_id) >> 8) & 0x7FFF)
#define GEN_SESSION_HANDLE(num, port)     (((num) & 0xFF)  | ((port) & 0x7F) << 8)
#define SESSION_HANDLE_NUM(handle)        ((handle) & 0xFF)
#define SESSION_HANDLE_PORT(handle)       (((handle) >> 8) & 0x7F)

struct buffer {
    td_u8 *addr;
    td_u32 size;
    td_u32 rd_idx;
    td_u32 wr_idx;
};

struct reg {
    td_u32 *version;
    td_u32 *head;
    td_u32 *argv;
    td_u32 argv_size;
    td_u32 *trigger_rx;
    td_u32 *pending;
    td_u32 *lock;
};

struct session {
    td_u32 num;
    td_u32 port;
    td_u32 rx_status;
    td_s32 tx_status;
    struct buffer rx_buf;
    struct buffer tx_buf;
    struct reg *rx_reg;
    struct reg *tx_reg;
    session_callback func;
    const td_void *data;
    LOS_DL_LIST node;
};

union msg_head {
    struct {
        td_u32 reserved         : 9;  /* [8:0]   */
        td_u32 port             : 7;  /* [15:9]  */
        td_u32 num              : 8;  /* [23:16] */
        td_u32 msg_len          : 7;  /* [30:24] */
        td_u32 ongoing          : 1;  /* [31]    */
    } bits;
    td_u32 head;
};

struct addr_info {
    td_u32 *base_addr;
    td_u32 *rx_head_addr;
};

struct mailbox {
    enum cpu_id local_cpu;
    td_u32 initalized;
    td_u32 list_lock;
    LOS_DL_LIST list_head;
    struct addr_info acpu_vmcu0;
    struct addr_info tcpu_vmcu0;
    td_u32 tx_acpu_lock;
    td_u32 tx_tcpu_lock;
    struct addr_info acpu_dmcu0;
    td_u32 tx_dmcu0_lock;
    td_u32 dmcu0_irq;
};

static inline void mutex_lock(td_u32 *lock)
{
    LOS_MuxPend(*lock, LOS_WAIT_FOREVER);
    return;
}

static inline void mutex_unlock(td_u32 *lock)
{
    LOS_MuxPost(*lock);
    return;
}

static inline void spin_lock_irqsave(td_u32 *lock, td_ulong *flag)
{
    *flag = LOS_IntLock();
    LOS_TaskLock();
    return;
}

static inline void spin_unlock_irqrestore(td_u32 *lock, td_ulong *flag)
{
    LOS_TaskUnlock();
    LOS_IntRestore(*flag);
    return;
}

static inline td_u32 readl(const td_u32 *addr)
{
    if (addr == NULL) {
        return SOC_ERR_MAILBOX_INVALID_PTR;
    }

    __asm__ __volatile__("fence");
    return GET_UINT32(addr);
}

static inline void writel(td_u32 value, const td_u32 *addr)
{
    if (addr == NULL) {
        return;
    }

    WRITE_UINT32(value, addr);
    __asm__ __volatile__("fence");
}

#define MBX_ERR_PRINT              printf
#define MBX_WARN_PRINT             printf
#define MBX_INFO_PRINT             printf
#define MBX_DBG_PRINT              printf
#define MBX_WRITEL                 writel
#define MBX_READL                  readl
#define MBX_UDELAY                 LOS_Udelay
#define MBX_MSLEEP                 LOS_Msleep
#define MBX_MALLOC(size)           LOS_MemAlloc(m_aucSysMem0, size)
#define MBX_FREE(addr)             LOS_MemFree(m_aucSysMem0, addr)
#define MBX_MUTEX_INIT             LOS_MuxCreate
#define MBX_LIST_ADD(node, head)   LOS_ListAdd(head, node)
#define MBX_LIST_DEL(node)         LOS_ListDelete(node)
#define MBX_INIT_LIST_HEAD         LOS_ListInit
#define MBX_IRQ_RET                td_void
#define MBX_IRQ_HANDLED
#define MBX_LIST_FOR_EACH_ENTRY(pos, n, head, member) \
        LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(pos, n, head, struct session, member)

void init_mailbox_reg(struct session *session, td_u32 session_id, const struct mailbox *mailbox);
void mbx_polling_rx(void);

#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */

#endif /* _DRV_MAILBOX_H_ */