/* Copyright (C) 2018 RDA Technologies Limited and/or its affiliates("RDA").
 * All rights reserved.
 *
 * This software is supplied "AS IS" without any warranties.
 * RDA assumes no responsibility or liability for the use of the software,
 * conveys no license or title under any patent, copyright, or mask work
 * right to the product. RDA reserves the right to make changes in the
 * software without notification.  RDA also make no representation or
 * warranty that such application will be suitable for the specified use
 * without further testing or modification.
 */

#ifndef _DRV_MD_IPC_H_
#define _DRV_MD_IPC_H_

#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "hal_config.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief IPC channel ID
 */
enum smd_ch_id
{
    SMD_CH_AT = 1,       ///< alias for SMD_CH_AT1
    SMD_CH_AT1 = 1,      ///< AT1, stream type
    SMD_CH_AT2 = 2,      ///< AT2, stream type
    SMD_CH_PS = 3,       ///< PS, packet type
    SMD_CH_A2C_CTRL = 4, ///< A2C_CTRL, queue type
#ifdef CONFIG_SOC_8850
    SMD_CH_GNSS_LOW = 5,  ///< GNSS LowPro, stream type
    SMD_CH_GNSS_HIGH = 6, ///< GNSS HighPro, stream type
    SMD_CH_WIFI_SCAN = 7, ///< WIFI SCAN, stream type
#else
    SMD_CH_AUD_CTRL = 5, ///< AUD_CTRL, command type
#endif
    SMD_CH_MAX ///< placeholder for count
};

/**
 * @brief channel Event
 */
enum smd_ch_flag
{
    CH_READ_AVAIL = 0x1,                          ///< indicate read available
    CH_WRITE_AVAIL = 0x2,                         ///< indicate write available
    CH_OPENED = 0x4,                              ///< flag for channel opened
    CH_RW_MASK = (CH_READ_AVAIL | CH_WRITE_AVAIL) ///< read and write mask
};

/**
 * PS uplink buffer maximum size
 *
 * When write to PS IPC channel, the maximum packet size can't exceed
 * this.
 */
#define IPC_PS_BUF_UL_LEN_B 1568

/**
 * PS uplink buffer header size
 *
 * When copy data to PC uplink buffer, the payload should be copied
 * to the allocated buffer with is offset.
 */
#define IPC_PS_UL_HDR_LEN 40

/**
 * IPC command header
 */
struct ipc_cmd
{
    uint32_t id;    ///< command id
    uint32_t para0; ///< 1st parameter
    uint32_t para1; ///< 2nd parameter
    uint32_t para2; ///< 3rd parameter
};

/**
 * IPC PS buf header
 */
struct ps_header
{
    uint32_t next;          ///< next offset (from shared memory) in the chain
    uint8_t cid;            ///< CID
    uint8_t simid;          ///< SIM number
    uint16_t len;           ///< data length
    uint8_t rai;            ///< NAS RAI Release assistance indication 0 1 2
    uint8_t exception_data; ///<
    uint16_t flag;          ///< BUF_IN_USR or BUF_IN_IDLE
    uint32_t buf_size;      ///< 300B or 1600B
    uint32_t data_off;      ///< data offset in buffer
    uint32_t id;            ///< only for debug
};

struct smd_ch;

/**
 * @brief IPC module initialization
 */
void ipcInit(void);

/**
 * @brief open an IPC channel
 *
 * Each IPC channel can be opened only once.
 *
 * It is permitted \p notify to be NULL.
 *
 * \p notify will be called in ISR context. So, it should follow ISR
 * programming guide. In the notify itself, it is not permitted to
 * read or write the channel
 *
 * @param ch_id     channel ID
 * @param ch        output channel pointer
 * @param priv      channel notify callback first argument
 * @param notify    channel notify callback
 * @return
 *      - 0 on success
 *      - -ENODEV/-EPERM on error
 */
int ipc_ch_open(int ch_id, struct smd_ch **ch, void *priv,
                void (*notify)(void *, uint32_t));

/**
 * @brief set IPC channel event mask
 *
 * Only masked event will invoke the registered \p notify callback.
 *
 * The default event mask is 0. That is the callback won't be invoked.
 *
 * @param ch        IPC channel, must be valid
 * @param event_mask    event mask to be set
 */
void ipc_ch_set_event_mask(struct smd_ch *ch, uint32_t event_mask);

/**
 * @brief read from IPC channel
 *
 * The read content depends on channel type:
 * - stream: read data. The return value is the actual read bytes,
 *   and may be less than \p len.
 * - packet: \p data is the packet offset, \p len is the offset count
 *   rather than size of \p data. However, the return value is the
 *   read bytes.
 * - command: \p data is the command including header and data,
 *   the return value is the actual read bytes.
 * - queue: \p data is \p ipc_cmd, \p len is the count of \p ipc_cmd,
 *   the return value is the actual read bytes
 *
 * @param ch        IPC channel, must be valid
 * @param data      data to be read
 * @param len       data length
 * @return
 *      - actual read
 *      - -EINVAL, -EAGAIN on fail
 */
int ipc_ch_read(struct smd_ch *ch, void *data, uint32_t len);

/**
 * @brief write to IPC channel
 *
 * The write content depends on channel type:
 * - stream: write data. The return value is the actual written bytes,
 *   and may be less than \p len.
 * - packet: \p data is the packet offset, \p len is the offset count
 *   rather than size of \p data. However, the return value is the
 *   written bytes.
 * - command: write content is command (includes header and data).
 *   When \p size is 0, the control fifo will be cleared.
 * - queue: \p data is \p ipc_cmd, \p len is the count of \p ipc_cmd,
 *   the return value is the actual read bytes
 *
 * After write, even partial write, it will set peer's interrupt.
 *
 * @param ch        IPC channel, must be valid
 * @param data      data to be written
 * @param len       data length
 * @return
 *      - actual written
 *      - 0 for no space, and won't set peer's interrupt
 *      - -ENODEV if the uplink channel is not openned
 *      - -EINVAL for invalid parameters
 */
int ipc_ch_write(struct smd_ch *ch, const void *data, uint32_t len);

/**
 * @brief channel available read space
 *
 * The meaning of the return unit depends on channel type:
 * - stream: available bytes
 * - packet: available offset count
 * - command: available bytes including command header
 * - queue: available count of \p ipc_cmd
 *
 * @param ch        IPC channel, must be valid
 * @return
 *      - available
 *      - 0 for unavailable
 */
int ipc_ch_read_avail(struct smd_ch *ch);

/**
 * @brief channel available write space
 *
 * The meaning of return unit depends on channel type:
 * - stream: available write bytes
 * - packet: available offset write count
 * - command: available write bytes of command data (except command header)
 * - queue: available count of \p ipc_cmd
 *
 * @param ch        IPC channel, must be valid
 * @return
 *      - available
 *      - 0 for no space
 */
int ipc_ch_write_avail(struct smd_ch *ch);

/**
 * @brief free downlink PS buf
 *
 * Even if the downlink PS buf is in a chain, this will free the
 * specified downlink PS buf only. Other buf in the chain is
 * untouched.
 *
 * @param ch        the PS IPC channel, must be valid
 * @param offset    the offset from share memory of the downlink buf
 * @return
 *      - 0 in success, it will never fail
 */
int ipc_free_dl_ps_buf(struct smd_ch *ch, uint32_t offset);

/**
 * @brief allocate uplink PS buf
 *
 * The size will be used to decide big buffer or little buffer. It doesn't
 * mean that the allocated buffer is large enough for requested \p size.
 *
 * @param ch    the PS IPC channel, must be valid
 * @param size  request size
 * @return
 *      - uplink buf offset in shared memory
 *      - -ENOMEM if no available buffer
 */
int ipc_alloc_ul_ps_buf(struct smd_ch *ch, uint32_t size);

/**
 * @brief notify AP panic to CP
 *
 * It should be called after AP panic.
 */
void ipc_notify_cp_assert(void);

/**
 * @brief show CP assert information
 */
void ipc_show_cp_assert(void);

/**
 * @brief get CP assert information address
 */
void *ipc_get_cp_assert_cause(void);

/**
 * @brief switch cp trace
 *
 * @param en    enable cp trace or not
 */
void ipc_switch_cp_trace(bool en);

/**
 * @brief notify sim plug in/out to CP
 *
 * @param num       sim number (1/2)
 * @param connect   true indicate the sim plug in otherwise plug out
 */
void ipc_notify_sim_detect(int num, bool connect);

/**
 * @brief zsp audio request notify.
 *
 * @param handler    the notify handler
 */
void ipc_register_audio_notify(void (*handler)(void));

/**
 * @brief modem trace request notify.
 *
 * @param handler    the notify handler
 * @param param      caller private data
 */
void ipc_register_trace_notify(void (*handler)(uint32_t, void *), void *param);

/**
 * @brief modem MOS request notify
 *
 * @param handler    the notify handler
 * @param param     caller private data
 */
void ipc_register_mos_notify(void (*handler)(void *), void *param);

/**
 * @brief bt riscv log request notify
 *
 * @param handler    the notify handler
 * @param param     caller private data
 */
void ipc_register_bt_log_notify(void (*handler)(uint32_t, void *), void *param);

/**
 * @brief bt riscv sleep request notify
 *
 * @param handler    the notify handler
 */
void ipc_register_bt_sleep_notify(void (*handler)(uint32_t));

/**
 * @brief bt riscv assert request notify
 *
 * @param handler    the notify handler
 */
void ipc_register_bt_assert_notify(void (*handler)(void));

/**
 * @brief update shared memory MMU properties
 */
void ipc_update_buf_access(void);

/**
 * @brief disable ipc channel interrupt
 *
 * @param ch  the smd channel
 */
void ipc_disable_ch_irq(struct smd_ch *ch);

/**
 * @brief enable ipc channel interrupt
 *
 * @param ch  the smd channel
 */
void ipc_enable_ch_irq(struct smd_ch *ch);

/**
 * @brief notify function type to be called
 *
 * It will be called when cp need notify ap to update rf param
 */
typedef void (*rfParamNotify_t)(void *ctx1, uint32_t v0, uint32_t v1, uint32_t v2, uint32_t v3, uint32_t v4);

/**
 * @brief modem rf param request notify
 *
 * @param notify    notify callback
 * @param param     caller private data
 */
void ipc_register_rfParam_notify(rfParamNotify_t notify, void *param);

/**
 * @brief cp rf param init function
 *
 * @param v0        parameter 0
 * @param v1        parameter 1
 * @param v2        parameter 2
 * @param v3        parameter 3
 * @param v4        parameter 4
 */
void ipc_cpRfParamInit(uint32_t v0, uint32_t v1, uint32_t v2, uint32_t v3, uint32_t v4);

/**
 * @brief ipc get delta nv addr
 *
 * @return deltanv address
 */
uint8_t *ipc_get_deltanv_addr(void);

/**
 * @brief ipc get ims nv addr and send sysmail
 *
 * @return ims nv address
 */
uint8_t *ipc_get_ims_nv_addr(void);

/**
 * @brief ipc set delta addr and size send sysmail
 *
 * @param addr      address
 * @param len       length
 */
void ipc_set_deltanv_bin(uint32_t addr, uint32_t len);

/**
 * @brief cp wake lock (not permit sleep)
 */
void ipc_cp_wake_lock(void);

/**
 * @brief set rpc patch ctx --> IPC interrupt lost patch for rpc function.
 */
void osiRPCPatchCTX(void *ctx);

/**
 * @brief EXE rpc patch --> IPC interrupt lost patch for rpc function.
 */
void osiRPCPatchHandler(void *ctx);
#if defined(CONFIG_SOC_8850)
void ipc_notify_volte_data(void);
#endif

#ifdef __cplusplus
}
#endif
#endif
