/**
 * @file drv_hdmi.h
 * @brief HDMI RX driver layer interface.
 * @verbatim
 * ==============================================================================
 *                        ##### How to use this driver #####
 * ==============================================================================
 * (+) Use Hv_Mw_HdmiHPDControl(...) to Init the HDMI RX Data.
 * (+) Use Hv_Mw_HdmiEdidPrepared(...) to Get the Cable Connection status.
 * (+) Use Hv_Mw_HdmiEdidUpdate(...) to register the Interrupt Call Back function. 
 * @endverbatim
 *
 * @author HiView SoC Software Team
 * @version 0.0.1
 * @date 2022-08-22
 */
#ifndef __SDK_MIDDLEWARE_HDMI_INC_HDMI_H__
#define __SDK_MIDDLEWARE_HDMI_INC_HDMI_H__

#include "hv_vos_Comm.h"
#include <string.h>
#include "hv_mw_InputPortManager.h"
#include "hv_comm_Event.h"
#include "hv_comm_Timer.h"
#include "hv_drv_HdmiRx.h"
#include "hv_cal_HdmiRx.h"
#include "hv_comm_SafeQueue.h"

#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_CTS)
#define HDMI_WAITSYNC_STATE_TIMER_LENGTH        0x400  /* ms */
#else
#define HDMI_WAITSYNC_STATE_TIMER_LENGTH        0x200   /* ms */
#endif
#define HDMI_SYNCOK_STATE_TIMER_LENGTH          0x400   /* ms */

#define HDMI_WAIT_HDCP_DONE_TIMER_LENGTH(n)      (128000/(n))/* Wait Hdcp Sync Timer ms */

#define HDMI_ENTER_ROBUST_RATIO_TIMER_LEN       300

#define HDMI_HOT_PLUG_DET_CTL_TIMER_LENTH       900     /* Plug Low Timer ms */
#define HDMI_HOT_PLUG_DET_SIG_TRGER_LENTH       150     /* HPD Tiggered Length */

#define HDMI_CED_ERR_INVALID_CNT                100     /* CED Error In 400ms */

#define HDMI_TRINING_DONE_CHECKING_LENTH        600      /* 按照最低24帧，3帧时间锁定计算 */

#define HDMI_FAST_LCKED_LENTH                   500     /* LANE LOCKED CHECKING LENGTH: 512MS */
#define HDMI_LANE_LCKED_TIMES                   22       /* LANE LOCKED CHECKING TIMES:10 */
#define HDMI_LANE_LCK_HPD_TIMES                 20       /* LANE LOCKED CHECKING TIMES:8 */

typedef enum _HdmiRxKeyEventTickPoint
{
    E_HDMI_CablePlugIn = 0,
    E_HDMI_TrainingDone,
    E_HDMI_TimingStable,
    E_HDMI_DPUGetPara,
    E_HDMI_TimingChange,
    E_HDMI_SignalLoss,
    E_HDMI_CablePlugOut,
    E_HDMI_TickPointNum
}HdmiRxKeyEventTickPoint;

DECLARE_HS_SAFE_QUEUE(HDMIRxQueue, 50, sizeof(HdmiRxIntStatus))

/**
 * @brief HDMI State Mashine for the first Idle state.
 * @param[in] pstHDMIManager : Key value of the HDMI Manager..
 * @return Status of the Operantion result.
 */
Status Hv_Mw_HDMI_Init(HDMIManager* pstHDMIManager);

/**
 * @brief  get pstPortData pointer of hdmi data.
 * @param[in] Port index of HDMI.
 * @return pstPortData pointer of hdmi data.
 */
HdmiCtrlData* HV_Mw_HdmiRx_GetHdmiData(UCHAR8 ucPortIndex);

/**
 * @brief  get pstPortData pointer of hdmi data.
 * @param[in] Link Port index of HDMI.
 * @return pstPortData pointer of hdmi data.
 */
HdmiCtrlData* HV_Mw_HdmiRx_GetHdmiLinkData(LinkPortIndex enLinkPortIndex);

/**
 * @brief HdmiVersion Changed handle.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status of the Operantion result.
 */
 Status Hv_Mw_HdmiRx_Sm_ChangeHdmiVersionHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief HDMI State Mashine for the first Idle state.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status of the Operantion result.
 */
Status Hv_Mw_HdmiRx_Sm_EnterIdleHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief HDMI State Mashine for the first Idle Start Message Handle.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status of the Operantion result.
 */
Status Hv_Mw_HdmiRx_Sm_IdleStartHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief  Signal Loss handle.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_SignalLossHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief wait for clock stable and recv avi packet.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_EnterWaitSyncHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief  TMDS or FRL Training Done status. After this the Inputport enter sync Status.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_TrainingDoneHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief  Enter SyncOk Status handle.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_EnterSyncOkHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief  Enter Display Ready Status handle.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_EnterDisplayReadyHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief  WaitSync Time out.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_WaitSyncTimeOutHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief  SyncOk Time out.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_SyncOkTimeoutHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief Start or Restart the PHY EQ Training handler.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_EnterWaitEqDoneHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief Wait the PHY CR Done Training handler.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_EnterWaitLockHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief Check and save the PHY EQ handler.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_CheckEqCedHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief  Mack Lock Timer Out Handle.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_WaitEqDoneTimeOutHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief  Cable plug in handler.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_PlugInCableHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief   Cable plug out handler.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_PlugOutCableHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief  hpd set high after set low.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_SetHpdHighTimeoutHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief  Timing Stable interrupt handle.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_TimingStableHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief  timing change include pixel clock.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_TimingChangeHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief  PHY Fast Lock Status, with this we need to configure the PHY div.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_FastLockedHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief  hdmi ratio change need change phy para.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_RatioChangeHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief  Audio Over and Underflow handle to reset Audio fifo
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_ResetAudioFifoHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief  Audio Info Frame Changed handle to Do Fs Reconfigure.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_AIFChangeHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

#if (HV_PROJECT_CONFIG_FRL)
/**
 * @brief  FRL rate change indicate frl or tmds.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_FRLRateChangeHandle(const InputPortEvent* pstEvent, VOID* pstPortData);
#endif

/**
 * @brief  avi packet change handle.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_AVIPacketChangeHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief  SPD packet Received for Parser handle.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_SPDPacketChangeHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief  VSI Packet handle.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_RcvVSIPacketHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief  EMP Packet received handling.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_RcvEMPPacketHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief  HDR packet handle after received the DRM.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_RcvHDRPacketHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief  Packet Error interrupt for HDCP 2x to re-Auth.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_PacketErrorHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief Wait PHY PLL lock Timeout Handler.
 * @param[in] Link Port Index.
 * @param[out] The HDMI Edid Data Content .
 * @return The length of the EDID.
 */
Status Hv_Mw_HdmiRx_Sm_WaitFastLockTimeoutHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief  PHY Fast Lock Status, with this we need to configure the PHY div.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_LaneFastLockedHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief  HDCP Sync Timer out Handler.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_HdcpSyncTimerOutHandle(const InputPortEvent* pstEvent, VOID* pstPortData);

/**
 * @brief  Interface to get current HDMI Timing Vedio Mode.
 * @param[in] Link port index of the HDMI.
 * @return HV_TRUE:DVI Mode; HV_FALSE:HDMI Mode.
 */
BOOL Hv_Mw_HdmiRx_GetDviMode(LinkPortIndex enPortIndex);

/**
 * @brief  Interface to get current Frame rate for HDMI.
 * @param[in] Link port index of the HDMI.
 * @return FrameRate * 1000 of current Timing; 0 is for Invalid status.
 */
UINT32 Hv_Mw_HdmiRx_GetCurrentFrameRate(LinkPortIndex usLinkPortIndex);

/**
 * @brief Interface for the EDID Configure.
 * @param[in] Link Port Index and the EDID Type.
 * @return Status of the Operantion result.
 */
Status Hv_Mw_HdmiRx_UpdateEdid(LinkPortIndex enPortIndex, EDIDType eEdidConfigure);

/**
 * @brief Init The HDMI Interrupt Handling.
 * @param[in] Link Port Index and the EDID Type.
 * @return Status of the Operantion result.
 */
Status Hv_Mw_HdmiRx_InterruptInit(LinkPortIndex enPortIndex);

/**
 * @brief  Interface to Control the HDMI Interface of HDMI.
 * @param[in] Link port index of the HDMI; 
 * @param[in] HPD Control Switch: HV_FALSE - PULL DOWN The HPD; HV_TRUE - PULL UP the HPD 
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_DDCCIHPDControl(USHORT16 usLinkPortIndex, BOOL bHPDSwitch);

/**
 * @brief Get the HDMI Version Current.
 * @param[in] Link Port Index.
 * @return The HDMI Version, details see define of HdmiVersion.
 */
UCHAR8 Hv_Mw_HdmiRx_GetHdmiVersion(LinkPortIndex enPortIndex);

/**
 * @brief Modify the HDMI Version.
 * @param[in] Link Port Index.
 * @param[in] The HDMI Version, details see define of HdmiVersion.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_ModifyHdmiVersion(LinkPortIndex enPortIndex, HdmiVersion eHdmiVersion);

/**
 * @brief Set the EDID for the Port of HDMI; set the length with 0 indecate remove the configured EDID Before.
 * @param[in] Link Port Index.
 * @param[in] The HDMI Edid Data Content and Length.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_SetHdmiEdid(LinkPortIndex enPortIndex, const UCHAR8 *paucHdmiEdid, USHORT16 usLen);

/**
 * @brief Get the EDID for the Port of HDMI.
 * @param[in] Link Port Index.
 * @param[out] The HDMI Edid Data Content .
 * @return The length of the EDID.
 */
USHORT16 Hv_Mw_HdmiRx_GetHdmiEdid(LinkPortIndex enPortIndex, UCHAR8 *paucHdmiEdid);

/**
 * @brief Check HDMI Cable Status.
 * @param[in] Link Port Index.
 * @param[out] The HDMI Edid Data Content .
 * @return The length of the EDID.
 */
Status Hv_Mw_HdmiRx_CableDetCheck(UCHAR8 ucPortIndex);

/**
 * @brief Set HDMI Hdcp Status.
 * @param[in] Link Port Index; 
 * @param[in] Hdcp Encrypt status;
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_SetHdcpStatus(LinkPortIndex enPortIndex, HdcpEncStatus enHdcpStatus);

/**
 * @brief Set HDMI AMD FreeSync MCCS Configuration.
 * @param[in] Link Port Index; 
 * @param[in] AMD FreeSync Configure Value;
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_SetFreeSyncMccsCfg(LinkPortIndex enPortIndex, UCHAR8 ucMccsFreeSyncCfg);

/**
 * @brief check and restore audio fifo
 * @param[in] Link Port Index; 
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_AudioCheck(LinkPortIndex enPortIndex);

/**
 * @brief start audio when cts/n changed.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_AudioStartHandle(const InputPortEvent *pstEvent, VOID *pstPortData);

/**
 * @brief get hdmi audio cts/n
 * @param[in] Link Port Index; 
 */
VOID Hv_Mw_HdmiRx_GetAudioCurrentCTSN(LinkPortIndex enPortIndex, UINT32 *puiCTS, UINT32 *puiN);

/**
 * @brief  Hdmi Fifo Open Handle.
 * @param[in] pstEvent pointer to message to process.
 * @param[in] pstPortData pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_Sm_AudioFifoStartHandle(const InputPortEvent *pstEvent, VOID *pstPortData);

/* Used for Update EDID withou check Type and HPD, Used for Factory ParaUpdte */

/**
 * @brief Update EDID Content Robust.
 * @param[in] Link Port Index; 
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
Status Hv_Mw_HdmiRx_UpdateEdidRobust(LinkPortIndex enPortIndex);

/**
 * @brief Get HDMI Current ALLM Mode is Open or Not Open.
 * @param[in] Link Port Index; 
 * @return BOOL, Enter ALLM - HV_TRUE, Not Entered ALLM -HV_FALSE.
 */
BOOL Hv_Mw_HdmiRx_GetAllmMode(LinkPortIndex enPortIndex);

Status Hv_Mw_HdmiRx_DdcciSend(LinkPortIndex enPortIndex, UCHAR8 *pucData, UINT32 uiLen, BOOL bInIrq);

#endif
