/**
 * @file hv_mw_Hdmi.c
 * @brief HDMI RX Midia ware
 * @details 该模块接口提供给Hiview-Madia-Ware及其他上层应用使用。
 * @author HiView SoC Software team
 * @version 0.0.1
 * @date 20220822
 * @copyright Copyright(c),2022-8, Hiview Software. All rights reserved.
 * @par History: 
 * <table>
 * <tr><th>作者                          <th>日期              <th>描述
 * <tr><td>HiView SoC Software team    <td>20220822        <td>Create and first Version.
 * </table>
**/
#include <string.h>
#include "hv_vos_Comm.h"
#include "hv_mw_Hdmi.h"
#include "hv_mw_Hdcp.h"
#include "hv_comm_Assert.h"
#include "hv_mw_SystemManager.h"
#include "hv_mw_Channel_Manager.h"
#include "hv_comm_Define.h"
#include "hv_drv_Physical.h"
#include "hv_drv_HdmiRx.h"
#include "hv_drv_DpuCommon.h"
#include "hv_drv_DpuMainMute.h"
#ifdef CONFIG_USER_DOUBLE_CHANNEL_ON
#include "hv_drv_DpuSubMute.h"
#endif
#include "hv_mw_Audio.h"
#include "hv_comm_DataBase.h"
#include "hv_mw_Ddcci.h"
#include "hv_drv_Eeprom.h"
#include "hv_drv_Ktx.h"
#include "hv_drv_Audio.h"
#include "hv_mw_PowerManager.h"
#include "hv_mw_Led.h"

#define HDMI_JIT_FOR_TIMING_H            20
#define HDMI_JIT_FOR_TIMING_V            1
#define HDMI_JIT_FOR_FRAME_RATE          2
#define HDMI_JIT_FOR_TIMING_FREQ         2000
#define HDMI_JIT_FOR_H_FREQ              5

#define HDMI_JIT_FOR_EQ_TMDS_FREQ        100

#if (HV_BOARD_CONFIG_HDMI_CABLE_DETECT == CABLE_DETECT_WITH_SOURCE_5V)
#define HDMI_ADAPT_NON_STANDARD          0
#else
#define HDMI_ADAPT_NON_STANDARD          1
#endif

#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_FRL)
#define HDMI_AUDIO_MANUAL_CLK_OPEN       1
#else
#define HDMI_AUDIO_MANUAL_CLK_OPEN       0
#endif

#ifdef HDMI_DEBUG_EVENT_TIC
UINT32  g_uiTickPointList[HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM][E_HDMI_TickPointNum] = {0,};
SHORT16 g_usEventStatstcs[HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM][InputPortEventId_HDMI_Max+1] = {0,};

#define HDMI_GET_TICK_COUNT(a,b) do{\
if ((a) < HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM && (b) < E_HDMI_TickPointNum)\
    {g_uiTickPointList[a][b]=Hv_Vos_GetTick();}\
}while(0)

#define HDMI_ADD_EVENT_STAT(a,b) do{\
if((a)<HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM && (b)<InputPortEventId_HDMI_Max+1)\
    {g_usEventStatstcs[a][b]++;}\
}while(0)
#else
#define HDMI_GET_TICK_COUNT(a,b)
#define HDMI_ADD_EVENT_STAT(a,b)
#endif

#define HV_MAX_HDMI_SW_EQ_TABLE_LENTH   17
static const USHORT16 g_ausSoftWareEqTable[HV_MAX_HDMI_SW_EQ_TABLE_LENTH] = {0x18, 0x20, 0x28, 0x30, 0x38, 0x78, 0xB8, 0xF8, 0x178, 0x1F8, 0x1F9, 0x1FA, 0x1FB, 0x1FC, 0x1FD, 0x1FE, 0x1FF};

DEFINE_HS_SAFE_QUEUE(HDMIRxQueue, 50, sizeof(HdmiRxIntStatus));
HDMIRxQueue g_stHdmiRxQueue;

HdmiCtrlData* HV_Mw_HdmiRx_GetHdmiData(UCHAR8 ucPortIndex)
{
    InputPortManager* pstInputPortManager = Hv_Mw_InputPort_GetManagerPtr();
    HV_ASSERT_VALID_PTR_RET(pstInputPortManager, NULL);
    HV_ASSERT_TRUE_RET_NO_LOG(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM, NULL);
    if(ucPortIndex == 0)
    {
        return &(pstInputPortManager->stHDMIManager.astHdmiData[ucPortIndex]);
    }
    else
    {
        if (HV_BOARD_CONFIG_HDMI_0 == PORT_VALID)
        {
            return &(pstInputPortManager->stHDMIManager.astHdmiData[ucPortIndex]);
        }
        else
        {
            return &(pstInputPortManager->stHDMIManager.astHdmiData[0]);
        }
    }
}

HdmiCtrlData* HV_Mw_HdmiRx_GetHdmiLinkData(LinkPortIndex enLinkPortIndex)
{
    UCHAR8 ucPortIndex = 0;
    InputPortManager* pstInputPortManager = Hv_Mw_InputPort_GetManagerPtr();

    HV_ASSERT_VALID_PTR_RET(pstInputPortManager, NULL);

    /* 查询linkportindex 对应的portindex */
    for(ucPortIndex = 0; ucPortIndex < HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM; ucPortIndex++)
    {
        /* 查找到返回Port Index */
        if (pstInputPortManager->stHDMIManager.astHdmiData[ucPortIndex].enPortIndex == enLinkPortIndex)
        {
            return &(pstInputPortManager->stHDMIManager.astHdmiData[ucPortIndex]);
        }
    }

    /* 未查找到返回NULL */
    return NULL;
}

static VOID HdmiSetChannelMuteOn(HdmiCtrlData* pstHdmiData)
{
    if(Hv_Mw_InputPort_GetChannelBindPortIndex(CHANNEL_TYPE_MAIN) == pstHdmiData->enPortIndex)
    {
        Hv_Mw_Channel_MuteOn(CHANNEL_TYPE_MAIN);
    }
#ifdef CONFIG_USER_DOUBLE_CHANNEL_ON        
    if(Hv_Mw_InputPort_GetChannelBindPortIndex(CHANNEL_TYPE_SUB) == pstHdmiData->enPortIndex)
    {
        Hv_Mw_Channel_MuteOn(CHANNEL_TYPE_SUB);
    }
#endif

    return;
}


static VOID PrintCommSPDInfo(SourceProductDesc *pstSPDInfo)
{
    HV_ASSERT_VALID_PTR_VOID(pstSPDInfo);

    HV_INPUT_LOG_DEBUG(HDMI,"*******************HDMI SPD Info Start**********************");

    HV_INPUT_LOG_DEBUG(HDMI,"@@  SPD info: eVendor Name is %x,%x,%x,%x,%x,%x,%x,%x" 
        ,pstSPDInfo->uclVendorName[0]
        ,pstSPDInfo->uclVendorName[1]
        ,pstSPDInfo->uclVendorName[2]
        ,pstSPDInfo->uclVendorName[3]
        ,pstSPDInfo->uclVendorName[4]
        ,pstSPDInfo->uclVendorName[5]
        ,pstSPDInfo->uclVendorName[6]
        ,pstSPDInfo->uclVendorName[7]
        );

    HV_INPUT_LOG_DEBUG(HDMI,"@@  SPD info: uclVendorDescript is %x,%x,%x,%x,%x,%x,%x,%x"
        , pstSPDInfo->uclVendorDescript[0]
        , pstSPDInfo->uclVendorDescript[1]
        , pstSPDInfo->uclVendorDescript[2]
        , pstSPDInfo->uclVendorDescript[3]
        , pstSPDInfo->uclVendorDescript[4]
        , pstSPDInfo->uclVendorDescript[5]
        , pstSPDInfo->uclVendorDescript[6]
        , pstSPDInfo->uclVendorDescript[7]
        );

    HV_INPUT_LOG_DEBUG(HDMI,"@@  SPD info: uclVendorDescript is %x,%x,%x,%x,%x,%x,%x,%x"
        , pstSPDInfo->uclVendorDescript[8]
        , pstSPDInfo->uclVendorDescript[9]
        , pstSPDInfo->uclVendorDescript[10]
        , pstSPDInfo->uclVendorDescript[11]
        , pstSPDInfo->uclVendorDescript[12]
        , pstSPDInfo->uclVendorDescript[13]
        , pstSPDInfo->uclVendorDescript[14]
        , pstSPDInfo->uclVendorDescript[15]
        );

    HV_INPUT_LOG_DEBUG(HDMI,"@@  SPD info: eSourceInfoCode is %d", pstSPDInfo->eSourceInfoCode);
    HV_INPUT_LOG_DEBUG(HDMI,"*******************HDMI SPD Info END***********************");

    return;
}
#ifdef HV_INPUT_DETAIL_OPEN
static VOID PrintAMDVSIFPara(VRRInfoParam *pstVendorSpceInfo)
{
    HV_ASSERT_VALID_PTR_VOID(pstVendorSpceInfo);

    HV_INPUT_LOG_DEBUG(HDMI,"*******************HDMI VSI Info Start**********************");
    HV_INPUT_LOG_DEBUG(HDMI,"@@ VSI info: eVendor Type is %d", pstVendorSpceInfo->eVendor);
    HV_INPUT_LOG_DEBUG(HDMI,"@@ VSI info: ucVersion is %d", pstVendorSpceInfo->uvsi.stAmdSpdInfPara.ucVersion);
    HV_INPUT_LOG_DEBUG(HDMI,"@@ VSI info: ucFreeSyncMinReFresh is %d", pstVendorSpceInfo->uvsi.stAmdSpdInfPara.ucFreeSyncMinReFresh);
    HV_INPUT_LOG_DEBUG(HDMI,"@@ VSI info: ucFreeSyncMaxReFresh is %d", pstVendorSpceInfo->uvsi.stAmdSpdInfPara.ucFreeSyncMaxReFresh);
    HV_INPUT_LOG_DEBUG(HDMI,"@@ VSI info: ucBrightneesControl is %d", pstVendorSpceInfo->uvsi.stAmdSpdInfPara.ucBrightneesControl);
    HV_INPUT_LOG_DEBUG(HDMI,"@@ VSI info: bFreeSyncSupported is %d", pstVendorSpceInfo->uvsi.stAmdSpdInfPara.bFreeSyncSupported);
    HV_INPUT_LOG_DEBUG(HDMI,"@@ VSI info: bFreeSyncEnabled is %d", pstVendorSpceInfo->uvsi.stAmdSpdInfPara.bFreeSyncEnabled);
    HV_INPUT_LOG_DEBUG(HDMI,"@@ VSI info: bFreeSyncActive is %d", pstVendorSpceInfo->uvsi.stAmdSpdInfPara.bFreeSyncActive);
    HV_INPUT_LOG_DEBUG(HDMI,"@@ VSI info: bBT709EOTFActive is %d", pstVendorSpceInfo->uvsi.stAmdSpdInfPara.bBT709EOTFActive);
    HV_INPUT_LOG_DEBUG(HDMI,"@@ VSI info: bGamma22EOTFActive is %d", pstVendorSpceInfo->uvsi.stAmdSpdInfPara.bGamma22EOTFActive);
    HV_INPUT_LOG_DEBUG(HDMI,"@@ VSI info: bGamma26EOTFActive is %d", pstVendorSpceInfo->uvsi.stAmdSpdInfPara.bGamma26EOTFActive);
    HV_INPUT_LOG_DEBUG(HDMI,"@@ VSI info: bLocalDimmingDisabled is %d", pstVendorSpceInfo->uvsi.stAmdSpdInfPara.bLocalDimmingDisabled);
    HV_INPUT_LOG_DEBUG(HDMI,"@@ VSI info: bNativeColorSpaceActive is %d", pstVendorSpceInfo->uvsi.stAmdSpdInfPara.bNativeColorSpaceActive);
    HV_INPUT_LOG_DEBUG(HDMI,"@@ VSI info: bSRGBEOTFActive is %d", pstVendorSpceInfo->uvsi.stAmdSpdInfPara.bSRGBEOTFActive);
    HV_INPUT_LOG_DEBUG(HDMI,"*******************HDMI VSI Info END***********************");

    return;
}
#endif
#ifdef HV_INPUT_DEBUG_OPEN
static VOID PrintEMPInfo(VRRMDContent* pstVrrMdPara)
{
    HV_ASSERT_VALID_PTR_VOID(pstVrrMdPara);

    HV_INPUT_LOG_DEBUG(HDMI,"*******************HDMI EMP Print Start**********************");
    HV_LOG_INFO(HDMI, "@@ EMP: VrrType %d  VRREnable %d", pstVrrMdPara->eVfrVrrType, pstVrrMdPara->bVRREnable);
    HV_INPUT_LOG_DEBUG(HDMI,"@@ EMP: ucBase_Vfront is %d", pstVrrMdPara->ucBase_Vfront);
    HV_INPUT_LOG_DEBUG(HDMI,"@@ EMP: ucNextTFR is %d", pstVrrMdPara->ucNextTFR);
    HV_INPUT_LOG_DEBUG(HDMI,"@@ EMP: ucFVAFactorM1 is %d", pstVrrMdPara->ucFVAFactorM1);
    HV_INPUT_LOG_DEBUG(HDMI,"@@ EMP: usBaseRefreshRate is %d", pstVrrMdPara->usBaseRefreshRate);
    HV_INPUT_LOG_DEBUG(HDMI,"*******************HDMI EMP Print END***********************");

    return;
}
#endif
VOID PrintHdmiTimingPara(VideoTimingParam *pstVideoTiming)
{
    HV_ASSERT_VALID_PTR_VOID(pstVideoTiming);

    HV_LOG_INFO(HDMI, "***HDMI Timing :HT%d VT%d HA%d VA%d,FQ%d FR%d I%d", 
        pstVideoTiming->usHTotal, pstVideoTiming->usVTotal, pstVideoTiming->usHActive, pstVideoTiming->usVActive,pstVideoTiming->uiFreqKHz, pstVideoTiming->usFrameRate, pstVideoTiming->bInterlacedMode);

    return;
}

VOID PrintHdmiAviColorPara(VideoColorParam *pstClorPara)
{
    HV_ASSERT_VALID_PTR_VOID(pstClorPara);

    HV_LOG_INFO(HDMI,"***HDMI Color Info : CF%d CS%d CD%d CR%d C%d PR%d ",
        pstClorPara->eClrFormat, pstClorPara->eClrSpace, pstClorPara->eClrDepth, pstClorPara->eClrRange, pstClorPara->eContent, pstClorPara->ucPixelRepe);

    return;
}

/**
 * @brief  Send Inner message for InputPort, Used the Inner Message to self-trigger handle.
 * @param[in] emInputEventId, message type to send.
 * @param[in] pstPortData, pointer to hdmi data.
 * @param[in] uiValue, Massage content to carry on this message
 * @return VOID, Without return value.
 */
static VOID SendInputportInnerMsg(HdmiCtrlData* pstHdmiData, InputPortEventId emInputEventId, UINT32 uiValue)
{
    InputPortEvent  stInputPortEvent = {0,};
    HV_ASSERT_VALID_PTR_VOID(pstHdmiData);

    /* 发送Input Port Message */
    stInputPortEvent.usEventId = emInputEventId;
    stInputPortEvent.enPortIndex = pstHdmiData->enPortIndex;
    stInputPortEvent.buffer = NULL;

    HV_ASSERT_SUCCESS_VOID(Hv_Mw_InputPort_SendInnerMsg(&stInputPortEvent));

    return;
}

static Status SendEventToOsd(LinkPortIndex enPortIndex, OsdEventId emOsdEventId)
{
    HV_VOS_QUEUE_S *pOsdQueue = Hv_Mw_System_GetOsdQueue();
    HV_ASSERT_VALID_PTR(pOsdQueue);
    OsdEvent stOsdEvent = {0};

    stOsdEvent.usEventId = emOsdEventId;

    /* 发送Channel Message */
    if(enPortIndex == Hv_Mw_InputPort_GetChannelBindPortIndex(CHANNEL_TYPE_MAIN) || emOsdEventId == OSD_EVENT_SIGNAL_PLUG_IN)
    {
        stOsdEvent.usValue = enPortIndex;
        stOsdEvent.usValue <<= 8;
        stOsdEvent.usValue |= (CHANNEL_TYPE_MAIN & 0x00FF);
        HV_ASSERT_PEEK_TRUE(Hv_Vos_QueueSend(pOsdQueue, &stOsdEvent));
        HV_INPUT_LOG_DEBUG(HDMI, "HDMI%d Finishend send Event to OSD:%d.", enPortIndex, emOsdEventId);
    }

#ifdef CONFIG_USER_DOUBLE_CHANNEL_ON
    else
    {
        if(enPortIndex == Hv_Mw_InputPort_GetChannelBindPortIndex(CHANNEL_TYPE_SUB))
        {
            stOsdEvent.usValue = enPortIndex;
            stOsdEvent.usValue <<= 8;
            stOsdEvent.usValue |= (CHANNEL_TYPE_SUB & 0x00FF);
            HV_ASSERT_PEEK_TRUE(Hv_Vos_QueueSend(pOsdQueue, &stOsdEvent));
        }
    }
#endif

    return HV_SUCCESS;
}

/**
 * @brief  Send Channel message for Channel manager.
 * @param[in] emChEventId, Channel message type to send.
 * @param[in] pstPortData, pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
static Status SendEventToChannel(HdmiCtrlData* pstHdmiData, ChanelEventId emChEventId)
{
    ChannelEvent stChannelEvent = {0,};
    HV_ASSERT_VALID_PTR(pstHdmiData);

    if((pstHdmiData->enCurrentPortState != INPUT_PORT_STATE_DISPLAY_RDY) 
        && (CHANNEL_EVENT_ID_PLUG_OUT != emChEventId))
    {
        return HV_SUCCESS;
    }

    /* 发送Channel Message */
    if(pstHdmiData->enPortIndex == Hv_Mw_InputPort_GetChannelBindPortIndex(CHANNEL_TYPE_MAIN))
    {
        stChannelEvent.usEventId = emChEventId;
        stChannelEvent.usValue = pstHdmiData->enPortIndex;/*RX 给Channel Managers发送消息portidex赋值给value*/
        stChannelEvent.enChannelType = CHANNEL_TYPE_MAIN;
        HV_ASSERT_SUCCESS(Hv_Mw_Channel_SendInnerMsg(&stChannelEvent));
    }

#ifdef CONFIG_USER_DOUBLE_CHANNEL_ON
    if(pstHdmiData->enPortIndex == Hv_Mw_InputPort_GetChannelBindPortIndex(CHANNEL_TYPE_SUB))
    {
        stChannelEvent.usEventId = emChEventId;
        stChannelEvent.usValue = pstHdmiData->enPortIndex;/*RX 给Channel Manager发送消息portidex赋值给value*/
        stChannelEvent.enChannelType = CHANNEL_TYPE_SUB;
        HV_ASSERT_SUCCESS(Hv_Mw_Channel_SendInnerMsg(&stChannelEvent));
    }
#endif

    return HV_SUCCESS;
}

/**
 * @brief  Send Channel message for Channel manager to notice timing changed etc.
 * @param[in] emChEventId, Channel message type to send.
 * @param[in] pstPortData, pointer to hdmi data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
static VOID NoticeChannelTimingChange(HdmiCtrlData* pstHdmiData, ChanelEventId emChEventId)
{
    HV_ASSERT_VALID_PTR_VOID(pstHdmiData);
    UCHAR8 ucPortIndex = pstHdmiData->ucDataPortIndex;

    /* 发送Channel Message */
    /*给Display 通知切timing*/
    SendEventToChannel(pstHdmiData, emChEventId);

    switch(emChEventId)
    {
        case CHANNEL_EVENT_ID_TIMING_CHANGE:
        {
            pstHdmiData->enLastPortUnSyncReason = LastPortUnSyncReason_TimingChange;
            HDMI_GET_TICK_COUNT(ucPortIndex, E_HDMI_TimingChange);
            break;
        }
        case CHANNEL_EVENT_ID_SIGNAL_LOSS:
        {
            pstHdmiData->enLastPortUnSyncReason = LastPortUnSyncReason_SignalLoss;
            HDMI_GET_TICK_COUNT(ucPortIndex, E_HDMI_SignalLoss);
            break;
        }
        case CHANNEL_EVENT_ID_COLOR_CHANGE:
        {
            pstHdmiData->enLastPortUnSyncReason = LastPortUnSyncReason_ColorChange;
            break;
        }
        case CHANNEL_EVENT_ID_PLUG_OUT:
        {
            pstHdmiData->enLastPortUnSyncReason = LastPortUnSyncReason_PlugOut;
            break;
        }
        default:
        {
            break;
        }
    }

    return ;
}

static BOOL IsHdmiEdidInvalid(HdmiCtrlData* pstHdmiData)
{
    HV_ASSERT_VALID_PTR_RET(pstHdmiData, HV_FALSE);

#if HV_PROJECT_CONFIG_EDID_EXTER_EEPROM
    if(pstHdmiData->enEdidConfiged == EDID_TYPE_INVALID)
    {
        return HV_FALSE;
    }
    else
    {
        return HV_TRUE;
    }
#else
    return Hv_Cal_HdmiRx_IsEdidInvalid(pstHdmiData->ucDataPortIndex);
#endif
}

static UINT32 GetLoadedEdidContent(UCHAR8 ucPortId, EDIDType eEdidType, UCHAR8* pucEdidUpdate)
{
    const UCHAR8 *pucEdidData   = NULL;
    UINT32 uiEdidLength         = 0;
    UINT32 uiEdidLabel          = 0;
    HdmiEdidDBRegion *pstEdidDb = ucPortId == 0 ? Hv_Common_Db_GetHdmiEdidDBRegionPtr() : Hv_Common_Db_GetHdmi1EdidDBRegionPtr();

    HV_ASSERT_VALID_PTR_RET(pucEdidUpdate, 0);

    Hv_Vos_TaskEnterCritical();
    for(uiEdidLabel = 0; uiEdidLabel < pstEdidDb->ucNumber && uiEdidLabel < EDID_DB_MAX_NUMBER; uiEdidLabel++)
    {
        if((eEdidType & 0x1F) == (pstEdidDb->astHdmiEdid[uiEdidLabel]).eEdidType)
        {
            uiEdidLength = (pstEdidDb->astHdmiEdid[uiEdidLabel]).uiEdidLen;

            if(uiEdidLength > HV_HDMI_MAX_EDID_LENTH)
            {
                return 0;
            }

            HV_MEMCPY(pucEdidUpdate, (pstEdidDb->astHdmiEdid[uiEdidLabel]).acEdid, uiEdidLength);
            break;
        }
    }
    Hv_Vos_TaskExitCritical();

    if(0 == uiEdidLength)
    {
        return 0;
    }

    if(((eEdidType & EDID_TYPE_CLOSE_HDR) != 0) || (eEdidType == EDID_TYPE_PIP))
    {
        Hv_Mw_InputPort_RmvEdidHdr(pucEdidUpdate, uiEdidLength);
    }

    return uiEdidLength;
}

#if HV_PROJECT_CONFIG_EDID_EXTER_EEPROM
static Status CheckWrittenExternEdid(UCHAR8 ucPortIndex, USHORT16 usLength, const UCHAR8 *pucEdidData)
{
    UCHAR8 aucEdidExtData[HV_EDID_SEGMENT_DATA_SIZE] = {0,};
    UINT32 uiEdidLabel                               = 0;

    if(HV_EDID_SEGMENT_DATA_SIZE < usLength)
    {
        HV_LOG_WARN(HDMI, "HDMI%d write the EDID length is over : %d.", ucPortIndex, usLength);
    }

    if(0 == ucPortIndex)
    {
        Hv_Drv_Eeprom_Read(I2CS0, 0, aucEdidExtData, usLength);
    }

    if(1 == ucPortIndex)
    {
        Hv_Drv_Eeprom_Read(SIMI2C0, 0, aucEdidExtData, usLength);
    }

    for(uiEdidLabel = 0; uiEdidLabel < HV_EDID_SEGMENT_DATA_SIZE; uiEdidLabel++, pucEdidData++)
    {
        if(aucEdidExtData[uiEdidLabel] != *pucEdidData)
        {
            return HV_FAILURE;
        }
    }

    HV_INPUT_LOG_INFO(HDMI, "HDMI%d write the EEPROM EDID SUCCESS.", ucPortIndex);

    return HV_SUCCESS;
}

static Status WriteHdmiExternEdid(UCHAR8 ucPortIndex, USHORT16 usLength, UCHAR8 *pucEdidData)
{
    //调用IIC接口进行外部EEPROM写入
    /* 写保护接口打开 */
    if(0 == ucPortIndex)
    {
        Hv_Drv_Eeprom_Write(I2CS0, 0, pucEdidData, usLength);
    }

    if(1 == ucPortIndex)
    {
        Hv_Drv_Eeprom_Write(SIMI2C0, 0, pucEdidData, usLength);
    }

    return CheckWrittenExternEdid(ucPortIndex, usLength, pucEdidData);
}
#endif

/* 调用时，一定确认DATA的EDID Configured是配置好的。拉高拉低外部控制，这里只管写 */
static Status WriteHdmiInnerEdid(HdmiCtrlData* pstHdmiData)
{
    HV_ASSERT_VALID_PTR(pstHdmiData);

    pstHdmiData->uiEdidLength = GetLoadedEdidContent(pstHdmiData->ucDataPortIndex, pstHdmiData->enEdidConfiged, pstHdmiData->aucEdidData);

    if(pstHdmiData->uiEdidLength == 0 || pstHdmiData->uiEdidLength > HV_HDMI_MAX_EDID_LENTH)
    {
        return HV_FAILURE;
    }

/*
    if(pstHdmiData->ucDataPortIndex == 1)
    {
        UpdateHdmiEdidCecAddr(pstHdmiData);
    }
*/
#ifdef HDR_PARAM_DYNAMIC_UP
    Hv_Mw_InputPort_UpdateEdidHdrParam(pstHdmiData->aucEdidData, pstHdmiData->uiEdidLength);
#endif

#if HV_PROJECT_CONFIG_EDID_EXTER_EEPROM
    HV_ASSERT_SUCCESS(WriteHdmiExternEdid(pstHdmiData->ucDataPortIndex, pstHdmiData->uiEdidLength, pstHdmiData->aucEdidData));
#else
    HV_ASSERT_SUCCESS(Hv_Cal_HdmiRx_UpdateEdidData(pstHdmiData->ucDataPortIndex, pstHdmiData->uiEdidLength, pstHdmiData->aucEdidData));
#endif

    return HV_SUCCESS;
}


static VOID ClearHdmiTimingData(HdmiCtrlData* pstHdmiDataPtr)
{
    HV_ASSERT_VALID_PTR_VOID(pstHdmiDataPtr);

    pstHdmiDataPtr->bEnterAllm = HV_FALSE;
    pstHdmiDataPtr->bEnteredVRR = HV_FALSE;

    HV_MEMSET(&(pstHdmiDataPtr->stTimingPara), 0, sizeof(VideoTimingParam));
    HV_MEMSET(&(pstHdmiDataPtr->stColorPara), 0, sizeof(VideoColorParam));
    HV_MEMSET(&(pstHdmiDataPtr->stHdrPara), 0, sizeof(HDRParam));
    HV_MEMSET(&(pstHdmiDataPtr->stVrrInfo), 0, sizeof(VRRInfoParam));
    pstHdmiDataPtr->ucWaitSyncTimerOutCnt = 0x0;
    pstHdmiDataPtr->ucEQInitValue = 0x8;

    return ;
}

static VOID InitHdmiDataPara(HdmiCtrlData* pstHdmiDataPtr)
{
    HV_ASSERT_VALID_PTR_VOID(pstHdmiDataPtr);

    pstHdmiDataPtr->bEnteredVRR = HV_FALSE;
    pstHdmiDataPtr->stVrrInfo.bVRREnable = HV_FALSE;
    pstHdmiDataPtr->stVrrInfo.eVendor = VendorType_UnKnown;
    pstHdmiDataPtr->ucHdmiFRLRate = 0;
    pstHdmiDataPtr->ucGrearMode = E_UNLOCKED;
    pstHdmiDataPtr->enLastPortUnSyncReason = LastPortUnSyncReason_PlugOut;
    return ;
}

static Status GetHdmiAudioPara(USHORT16 usLinkPortIndex, AudioPara *pstAudioPara)
{
    HdmiCtrlData* pstHdmiData = HV_Mw_HdmiRx_GetHdmiLinkData(usLinkPortIndex);

    HV_ASSERT_VALID_PTR(pstHdmiData);
    HV_ASSERT_VALID_PTR(pstAudioPara);

    if(pstHdmiData->enCurrentPortState != INPUT_PORT_STATE_DISPLAY_RDY)
    {
        return HV_FAILURE;
    }

    return Hv_Drv_HdmiRx_GetAudioPara(pstHdmiData->ucDataPortIndex, pstAudioPara);
}

static BOOL IsAudioCarriedOnHdmi(USHORT16 usLinkPortIndex)
{
    AudioPara stAudioPara = {0};

    HV_ASSERT_SUCCESS_RET(GetHdmiAudioPara(usLinkPortIndex, &stAudioPara), HV_FALSE);

    /* 当 CTS N = 0时候，说明HDMI通道未携带Audio */
    return (stAudioPara.uiCtsValue != 0 && stAudioPara.uiNValue != 0);
}

static VOID CaculateTimingWithEMP(HdmiCtrlData* pstHdmiData)
{
    HV_ASSERT_VALID_PTR_VOID(pstHdmiData);
    USHORT16 usFreshFrameRate = pstHdmiData->stTimingPara.usFrameRate;
    USHORT16 usCaculateVTotal = 0;

    if(VendorType_HDMI_FORUM == pstHdmiData->stVrrInfo.eVendor)
    {
        usFreshFrameRate = pstHdmiData->stVrrInfo.uvsi.stCommVRRinMD.usBaseRefreshRate;
    }

    if(VendorType_AMD == pstHdmiData->stVrrInfo.eVendor 
        && pstHdmiData->stVrrInfo.uvsi.stAmdSpdInfPara.ucFreeSyncMaxReFresh != 0)
    {
        usFreshFrameRate = pstHdmiData->stVrrInfo.uvsi.stAmdSpdInfPara.ucFreeSyncMaxReFresh;
    }

    /* Specific indicate the Vic is not 0 should ignore the brr. */
    if(Hv_Cal_HdmiRx_GetVicForCurrentTiming(pstHdmiData->ucDataPortIndex) != 0)
    {
        return;
    }

    if(pstHdmiData->bEnteredVRR && (VendorType_HDMI_FORUM == pstHdmiData->stVrrInfo.eVendor || VendorType_AMD == pstHdmiData->stVrrInfo.eVendor))
    {
        if((usFreshFrameRate > pstHdmiData->stTimingPara.usFrameRate) && (usFreshFrameRate != 0) && pstHdmiData->stTimingPara.usHTotal > 0)
        {
            usCaculateVTotal = 
                pstHdmiData->stTimingPara.uiFreqKHz * 1000 / pstHdmiData->stTimingPara.usHTotal / usFreshFrameRate;

            /* Fix PS5 Base Frame is 120, But the actullay Frame rate is 60. */
            if(usCaculateVTotal <= pstHdmiData->stTimingPara.usVActive)
            {
                return ;
            }

            pstHdmiData->stTimingPara.usVTotal = usCaculateVTotal;

            pstHdmiData->stTimingPara.usFrameRate = usFreshFrameRate;
            pstHdmiData->stTimingPara.fFrameRate = (FLOAT32)((DOUBLE64)(pstHdmiData->stTimingPara.uiFreqKHz) * 1000 / pstHdmiData->stTimingPara.usHTotal / usCaculateVTotal);
        }
    }

    return;
}

static Status GetHdmiTimingData(HdmiCtrlData* pstHdmiDataPtr)
{
    HV_ASSERT_VALID_PTR(pstHdmiDataPtr);
    VideoTimingParam  stTimingPara = {0,};
    BOOL bAllmMode                 = HV_FALSE;
    UCHAR8 ucPortIndex             = pstHdmiDataPtr->ucDataPortIndex;

    UCHAR8 ucColorDepth            = Hv_Cal_HdmiRx_GetColorDepth(ucPortIndex);

    /* 该函数返回值表示HDMI指示ALLM，如果返回False，表示无指示，不需要处理 */
    if(Hv_Cal_HdmiRx_GetAllmModeInfo(ucPortIndex, &bAllmMode))
    {
        if(pstHdmiDataPtr->bEnterAllm != bAllmMode)
        {
            pstHdmiDataPtr->bEnterAllm = bAllmMode;
        }
    }

    if(HV_FAILURE == Hv_Drv_HdmiRx_GetTimingPara(ucPortIndex, &(stTimingPara)))
    {
        HV_LOG_ERROR(HDMI, "HDMI%d Get Timing Para Failed", ucPortIndex);
        return HV_FAILURE;
    }

    if(ucColorDepth == ColorDepthType_10Bit || ucColorDepth == ColorDepthType_12Bit)
    {
        Hv_Cal_HdmiRx_PhaseConfig(ucPortIndex, ucColorDepth);
    }

    /* TMDS VRR 采用Pixel Clock来进行Timing计算VTotal */
    if(pstHdmiDataPtr->bEnteredVRR && pstHdmiDataPtr->ucHdmiFRLRate == 0 && stTimingPara.usHTotal > 0 && stTimingPara.usFrameRate > 0)
    {
        stTimingPara.uiFreqKHz = stTimingPara.uiRxDpllSetFreqKHz + ((stTimingPara.usHTotal * stTimingPara.usFrameRate) / 1000);
        stTimingPara.usVTotal = ((stTimingPara.uiFreqKHz * 1000) / stTimingPara.usHTotal) / stTimingPara.usFrameRate;
        stTimingPara.fFrameRate = (FLOAT32)((DOUBLE64)(stTimingPara.uiFreqKHz) * 1000 / stTimingPara.usVTotal / stTimingPara.usHTotal);
    }

    HV_MEMCPY(&(pstHdmiDataPtr->stTimingPara), &stTimingPara, sizeof(VideoTimingParam));

    pstHdmiDataPtr->stTimingPara.bIsEnterALLM = pstHdmiDataPtr->bEnterAllm;

    /* HDMI VRR场景：重新计算V，根据EMP的Base Frame Rate */
    if((VendorType_HDMI_FORUM == pstHdmiDataPtr->stVrrInfo.eVendor || VendorType_AMD == pstHdmiDataPtr->stVrrInfo.eVendor) && pstHdmiDataPtr->bEnteredVRR)
    {
        CaculateTimingWithEMP(pstHdmiDataPtr);
    }

    return HV_SUCCESS;
}

static VOID AddInterruptEventOnStable(HdmiCtrlData* pstHdmiData)
{
    HdmiRxIntStatus stHdmiIntRxStatus = {0,0};

    HV_ASSERT_VALID_PTR_VOID(pstHdmiData);

    stHdmiIntRxStatus.uiIntrruptStatus1 = (HV_HDMIRX_INT_1_EVENT_PLL_CHG \
        |HV_HDMIRX_INT_1_EVENT_DECODE_ERROR\
        |HV_HDMIRX_INT_1_EVENT_AV_MUTE\
        );

    stHdmiIntRxStatus.uiIntrruptStatus2 = (HV_HDMIRX_INT_2_EVENT_AVI_CKS_CHG\
        |HV_HDMIRX_INT_2_EVENT_DRM_CKS_CHG\
        |HV_HDMIRX_INT_2_EVENT_TMDS_TIMING_CHG\
        |HV_HDMIRX_INT_2_EVENT_LANEFASTLOCK\
        |HV_HDMIRX_INT_2_EVENT_GCP_CD_CHG\
        );

    Hv_Cal_HdmiRx_AddInterruptEvent(pstHdmiData->ucDataPortIndex, &stHdmiIntRxStatus);

    return;
}

static Status DVIEnterSwEq(HdmiCtrlData* pstHdmiData)
{
    USHORT16 ausAutoEqValue[4] = {0x178, 0x178, 0x178, 0x00};

    Hv_Drv_HdmiRx_SetSwEqValue(pstHdmiData->ucDataPortIndex, ausAutoEqValue);
    Hv_Cal_HdmiRx_EnterTmdsSwEq(pstHdmiData->ucDataPortIndex);

    Hv_Cal_HdmiRx_FinishTmdsSwEq(pstHdmiData->ucDataPortIndex);

    return HV_SUCCESS;
}

static VOID SetupHdmiPathOnStable(HdmiCtrlData* pstHdmiData)
{
    ChannelType enChannelType          = CHANNEL_TYPE_MAIN;
    LinkPortIndex enAudioLinkPortIndex = LINK_PORT_INDEX_INVALID;
    USHORT16    usHBlankOffset         = 0;

    HV_ASSERT_VALID_PTR_VOID(pstHdmiData);

    Hv_Cal_HdmiRx_SetAutoVmute(pstHdmiData->ucDataPortIndex);

    pstHdmiData->bAudioAbnormal = HV_FALSE;
    pstHdmiData->bEnterLowBnd = HV_FALSE;

    pstHdmiData->bEnterManualAudClk = HV_FALSE;
    pstHdmiData->usLastUnderValue = 0;
    pstHdmiData->usLastOverValue = 0;
    Hv_Cal_HdmiRx_SwitchAudioManualClk(pstHdmiData->ucDataPortIndex, HV_FALSE);
    Hv_Cal_HdmiRx_SetCtsNMeasMode(pstHdmiData->ucDataPortIndex, 0x0);
    Hv_Cal_HdmiRx_SetCtsNMeasMode(pstHdmiData->ucDataPortIndex, 0x2);

    Hv_Cal_HdmiRx_ConfigureEqCheckValue(pstHdmiData->ucDataPortIndex, HV_FALSE);

    if(pstHdmiData->ucHdmiFRLRate != 0)
    {
        usHBlankOffset = (pstHdmiData->stTimingPara.usHTotal - pstHdmiData->stTimingPara.usHActive) >> 2;
        Hv_Cal_HdmiRx_ConfigureMinHtotal(pstHdmiData->ucDataPortIndex, 0x1, pstHdmiData->stTimingPara.usHTotal - usHBlankOffset);
    }

    if(HV_FALSE == Hv_Cal_HdmiRx_GetDviMode(pstHdmiData->ucDataPortIndex))
    {
        Hv_Cal_HdmiRx_SetHDCPHdmiMode(pstHdmiData->ucDataPortIndex, HV_TRUE);

        Hv_Cal_HdmiRx_SetHDCP1Xstatus(pstHdmiData->ucDataPortIndex, HV_TRUE);

        Hv_Mw_Hdcp_HdmiSetEessQstc(pstHdmiData->enPortIndex);
    }
    else
    {
#if (HV_PROJECT_CONFIG_CTS == HV_CONFIG_OFF)
        DVIEnterSwEq(pstHdmiData);
#endif
        Hv_Cal_HdmiRx_SetDviMode(pstHdmiData->ucDataPortIndex, HV_TRUE);
    }

#if (HV_PROJECT_CONFIG_CTS == HV_CONFIG_OFF)
    if((pstHdmiData->ucGrearMode != E_RATIOGEAR) && (pstHdmiData->ucGrearMode != E_FRLMODE) && 
        (!Hv_Cal_HdmiRx_IsTmdsSwEqCfgured(pstHdmiData->ucDataPortIndex)))
    {
        Hv_Cal_HdmiRx_SetSwEqFromHwValue(pstHdmiData->ucDataPortIndex);
        Hv_Cal_HdmiRx_EnterTmdsSwEq(pstHdmiData->ucDataPortIndex);
        Hv_Cal_HdmiRx_FinishTmdsSwEq(pstHdmiData->ucDataPortIndex);

        HV_INPUT_LOG_INFO(HDMI, "Copy HW EQ to SW");
    }
#endif

    pstHdmiData->ucEqStatus = HdmiEqStatus_EqStable;
    pstHdmiData->bSendTimeChange = HV_FALSE;

    return;
}

static Status SwitchHPDControlStatus(HdmiCtrlData* pstHdmiData, BOOL bHPDSwitch)
{
    HV_ASSERT_VALID_PTR(pstHdmiData);

    UCHAR8 ucPortIndex = pstHdmiData->ucDataPortIndex;

    HV_ASSERT_SUCCESS(Hv_Drv_HdmiRx_HPDCtrol(ucPortIndex, bHPDSwitch));

    HV_INPUT_LOG_DEBUG(HDMI,"HPD on the HDMI%d Switch to:%s", ucPortIndex, bHPDSwitch ? "HIGH" : "LOW");

    pstHdmiData->bHPDStatus = bHPDSwitch;

    return HV_SUCCESS;
}

static VOID ToggleHdmiHPD(USHORT16 usLinkPortIndex, UINT32 uiTimerLength)
{
    HdmiCtrlData* pstHdmiData = HV_Mw_HdmiRx_GetHdmiLinkData(usLinkPortIndex);

    HV_ASSERT_VALID_PTR_VOID(pstHdmiData);

    HV_INPUT_LOG_INFO(HDMI, "Toggle HPD on HDMI%d.", pstHdmiData->ucDataPortIndex);

    SwitchHPDControlStatus(pstHdmiData, HV_FALSE);

    /* 如果已经拉HPD，直接进入等待拉高即可TG */
    HV_ASSERT_VALID_PTR_VOID(pstHdmiData->pstHpdControlTimer);
    if (!Hv_Vos_Timer_IsTimerActive(pstHdmiData->pstHpdControlTimer))
    {
        Hv_Vos_Timer_Rstart(pstHdmiData->pstHpdControlTimer, uiTimerLength);
    }

    return;
}
static VOID ToggleHdmiHPDInterface(USHORT16 usLinkPortIndex)
{
    ToggleHdmiHPD(usLinkPortIndex, HDMI_HOT_PLUG_DET_SIG_TRGER_LENTH);
}

static Status SwitchPhyGearMode(HdmiCtrlData* pstHdmiData, HdmiRxGearMode emGearMode)
{
    HV_ASSERT_VALID_PTR(pstHdmiData);
    UCHAR8 ucPortIndex = pstHdmiData->ucDataPortIndex;

    pstHdmiData->ucGrearMode = emGearMode;

#if (HV_PROJECT_CONFIG_CTS == HV_CONFIG_OFF)
    if(E_RATIOGEAR != emGearMode && E_FRLMODE != emGearMode)
    {
        /* EQ Flag set to False */
        pstHdmiData->ucEqStatus = HdmiEqStatus_Init;

        Hv_Cal_HdmiRx_EnterTmdsSwEq(ucPortIndex);
    }
    else
#endif
    {
        /* EQ Flag set to False */
        pstHdmiData->ucEqStatus = HdmiEqStatus_HwEQDone;

        Hv_Cal_HdmiRx_EnterTmdsHwAutoEq(ucPortIndex);
    }

    Hv_Drv_HdmiRX_SwitchPhyGearMode(ucPortIndex, emGearMode);

    HV_INPUT_LOG_DEBUG(HDMI,"HDMI%d Change to Gear Mode %d.", ucPortIndex, emGearMode);

    return HV_SUCCESS;
}

static Status SwitchInRobustRatio(HdmiCtrlData* pstHdmiData)
{
    SwitchPhyGearMode(pstHdmiData, E_RATIOGEAR);

    pstHdmiData->bInRobustRatio = HV_TRUE;

    if(!Hv_Vos_Timer_IsTimerActive(pstHdmiData->pstRobustRatio))
    {
        Hv_Vos_Timer_Start(pstHdmiData->pstRobustRatio);
    }

    return HV_SUCCESS;
}

static BOOL CheckHdmiStatusIsValid(HdmiCtrlData* pstHdmiData)
{
    HV_ASSERT_VALID_PTR_RET(pstHdmiData, HV_FALSE);
    HdmiRxGearMode  emGearMode  = E_UNLOCKED;
    UCHAR8 ucPortIndex          = pstHdmiData->ucDataPortIndex;

    /* 首先检查HPD是否拉起 */
    if(!(pstHdmiData->bHPDStatus))
    {
        /* Toggle HPD 的话直接return 即可；等待超时后拉高HPD */
        HV_ASSERT_VALID_PTR(pstHdmiData->pstHpdControlTimer);

        if(!Hv_Vos_Timer_IsTimerActive(pstHdmiData->pstHpdControlTimer))
        {
            HV_LOG_ERROR(HDMI, "HDMI%d Set HPD LOW But Cable disconnected.", ucPortIndex);

            /* 拉高HPD PIN角 */
            SwitchHPDControlStatus(pstHdmiData, HV_TRUE);

            /* Toggle PHY Auto Eq. */
            Hv_Cal_HdmiRx_ResetPhy(ucPortIndex);
        }

        return HV_FALSE;
    }

#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_FRL)
    /* FRL TMDS 切换异常处理 */
    if(pstHdmiData->ucHdmiFRLRate != Hv_Cal_HdmiRx_GetFrlRate(ucPortIndex))
    {
        pstHdmiData->ucHdmiFRLRate = Hv_Drv_HdmiFRLRateChange(ucPortIndex);
        HV_INPUT_LOG_INFO(HDMI, "HDMI%d FRL Rate chaned to %d.", ucPortIndex, pstHdmiData->ucHdmiFRLRate);
        return HV_FALSE;
    }
#endif

    /* EDID 是否配置正确 */
    if(IsHdmiEdidInvalid(pstHdmiData))
    {
        ToggleHdmiHPD(pstHdmiData->enPortIndex, HDMI_HOT_PLUG_DET_CTL_TIMER_LENTH);
        WriteHdmiInnerEdid(pstHdmiData);
        return HV_FALSE;
    }

    /* 检查PHY相关参数 */
    emGearMode = Hv_Drv_HdmiRx_GetRatioType(ucPortIndex, pstHdmiData->ucGrearMode);
    if(emGearMode == E_UNLOCKED)
    {
        Hv_Cal_HdmiRx_ResetPhy(ucPortIndex);
    }

    if(pstHdmiData->ucGrearMode != emGearMode && emGearMode != E_FRLMODE && pstHdmiData->bEnterLowBnd == HV_FALSE)
    {
        if((E_RATIOGEAR != pstHdmiData->ucGrearMode) || (!Hv_Drv_HdmiRX_RobustCheckRatioMode(ucPortIndex)))
        {
            SwitchPhyGearMode(pstHdmiData, emGearMode);

            HV_INPUT_LOG_INFO(HDMI, "HDMI%d Gear Checked to %d.", ucPortIndex, pstHdmiData->ucGrearMode);

            return HV_FALSE;
        }
    }
    else
    {
        HV_INPUT_LOG_INFO(HDMI, "HDMI%d Gear Mode Keep %d.", ucPortIndex, pstHdmiData->ucGrearMode);
    }

    return HV_TRUE;
}

static BOOL CheckHdmiTimingStable(HdmiCtrlData* pstHdmiData)
{
    HV_ASSERT_VALID_PTR_RET(pstHdmiData, HV_FALSE);

    UCHAR8 ucPortIndex = pstHdmiData->ucDataPortIndex;
    HdmiRxLaneCED stLaneCed = {0,};
    VideoTimingParam  stTimingPara = {HDMI_CED_ERR_INVALID_CNT,};

    if(!Hv_Drv_HdmiRx_IsClockStable(ucPortIndex))
    {
        HV_INPUT_LOG_INFO(HDMI, "HDMI%d unlocked send PLL Change.", ucPortIndex);

        SendInputportInnerMsg(pstHdmiData, InputPortEventId_HDMI_PllChange, 0);

        return HV_TRUE;
    }

    if(HV_SUCCESS == Hv_Drv_HdmiRx_GetTimingPara(ucPortIndex, &(stTimingPara))
        && Hv_Drv_HdmiRx_IsTimingStable(ucPortIndex))
    {
        if (HV_SUCCESS != Hv_Drv_HdmiRx_GetAVIPara(ucPortIndex, &(pstHdmiData->stColorPara), &(stTimingPara)))
        {
            HV_LOG_ERROR(HDMI, "HDMI%d get avi err when chk timing", ucPortIndex);
            return HV_FALSE;
        }

        SendInputportInnerMsg(pstHdmiData, InputPortEventId_HDMI_TimingStable, 0);

        HV_INPUT_LOG_INFO(HDMI, "HDMI%d send Timing Stable.", ucPortIndex);

        return HV_TRUE;
    }

    return HV_FALSE;
}

static Status GetHdmiCurrentVideoPara(LinkPortIndex enLinkPortIndex, ChannelData* pstChannelData)
{
    HdmiCtrlData* pstHdmiDataPtr = HV_Mw_HdmiRx_GetHdmiLinkData(enLinkPortIndex);    
    AudioPara     stAudioPara    = {0};

    HV_ASSERT_VALID_PTR(pstHdmiDataPtr);
    HV_ASSERT_VALID_PTR(pstChannelData);

    /* Clock Stable and Recv gcp and avi packet */
    /* HPD Low will Not   the Vedio */
    if (pstHdmiDataPtr->enCurrentPortState != INPUT_PORT_STATE_DISPLAY_RDY
        || pstHdmiDataPtr->bHPDStatus == HV_FALSE
#if (HV_PROJECT_CONFIG_CTS == HV_CONFIG_OFF)
        || pstHdmiDataPtr->ucHdcpEncStatus == HdcpEncStatus_WaitSync
#endif
        )
    {
        pstChannelData->stRxVideoTiming.bIsNoSignal = !Hv_Drv_HdmiRx_IsClockStable(pstHdmiDataPtr->ucDataPortIndex);
        return HV_FAILURE;
    }

    if(HV_FALSE == pstHdmiDataPtr->bEnteredVRR)
    {
        if(HV_FAILURE == Hv_Drv_HdmiRx_GetTimingPara(pstHdmiDataPtr->ucDataPortIndex, &(pstHdmiDataPtr->stTimingPara)))
        {
            if(pstHdmiDataPtr->bSendTimeChange == HV_FALSE)
            {
                SendInputportInnerMsg(pstHdmiDataPtr, InputPortEventId_HDMI_TimingChange, 0);
                pstHdmiDataPtr->bSendTimeChange = HV_TRUE;
            }

            return HV_FAILURE;
        }
        else
        {
            pstHdmiDataPtr->bSendTimeChange = HV_FALSE;
        }
    }

    HV_MEMCPY(&pstChannelData->stRxVideoTiming, &(pstHdmiDataPtr->stTimingPara), sizeof(VideoTimingParam));

    if (HV_SUCCESS != Hv_Drv_HdmiRx_GetAVIPara(pstHdmiDataPtr->ucDataPortIndex, &(pstHdmiDataPtr->stColorPara), &(pstHdmiDataPtr->stTimingPara)))
    {
        HV_INPUT_LOG_DEBUG(HDMI, "The Link%d AVI Para Set to RGB.", enLinkPortIndex);
        pstHdmiDataPtr->stColorPara.eClrFormat = ColorFormatType_RGB;
        pstHdmiDataPtr->stColorPara.eClrSpace   = ColorSpaceType_SRGB;
        pstHdmiDataPtr->stColorPara.eClrDepth   = ColorDepthType_8Bit;
        pstHdmiDataPtr->stColorPara.eClrRange   = ColorRangeType_Full_Range;
        pstHdmiDataPtr->stColorPara.eContent    = CorlorContentType_NoDef;
        pstHdmiDataPtr->stColorPara.ucPixelRepe = 0;
    }
    HV_MEMCPY(&pstChannelData->stVideoConfigParams.stColor, &(pstHdmiDataPtr->stColorPara), sizeof(VideoColorParam));

    /* Channel 目前只支持 12Bit 位深，所以传给Channel Manager参数用12Bit参数，RX会自动转成12Bit位深 */
    if(pstChannelData->stVideoConfigParams.stColor.eClrDepth == ColorDepthType_16Bit 
        || pstChannelData->stVideoConfigParams.stColor.eClrFormat == ColorFormatType_YCbCr422)
    {
        pstChannelData->stVideoConfigParams.stColor.eClrDepth = ColorDepthType_12Bit;
    }

    HV_ASSERT_SUCCESS(Hv_Drv_HdmiRx_GetHDRPara(enLinkPortIndex, &(pstHdmiDataPtr->stHdrPara)));
    HV_MEMCPY(&pstChannelData->stVideoConfigParams.stHdrParam, &(pstHdmiDataPtr->stHdrPara), sizeof(HDRParam));

    HV_MEMCPY(&pstChannelData->stVideoConfigParams.stVRRInfoParam, &(pstHdmiDataPtr->stVrrInfo), sizeof(VRRInfoParam));

    if(HV_SUCCESS == GetHdmiAudioPara(enLinkPortIndex,&stAudioPara))
    {
        pstChannelData->stRxAudioTiming.uiCTS = stAudioPara.uiCtsValue;
        pstChannelData->stRxAudioTiming.uiN = stAudioPara.uiNValue;
    }

    HDMI_GET_TICK_COUNT(pstHdmiDataPtr->ucDataPortIndex, E_HDMI_DPUGetPara);

    return HV_SUCCESS;
}

static Status GetHdmiSourceVendorInfo(LinkPortIndex usLinkPortIndex, VRRInfoParam *pstVSIPara)
{
    HdmiCtrlData* pstHdmiData = HV_Mw_HdmiRx_GetHdmiLinkData(usLinkPortIndex);
    HV_ASSERT_VALID_PTR(pstHdmiData);
    HV_ASSERT_VALID_PTR(pstVSIPara);

    if(pstHdmiData->enCurrentPortState != INPUT_PORT_STATE_DISPLAY_RDY)
    {
        return HV_FAILURE;
    }

    HV_MEMCPY(pstVSIPara,&(pstHdmiData->stVrrInfo),sizeof(VRRInfoParam));

    return HV_SUCCESS;
}

static BOOL GetHdmiAudioCurrentStatus(LinkPortIndex enPortIndex)
{
    HdmiCtrlData* pstHdmiData = HV_Mw_HdmiRx_GetHdmiLinkData(enPortIndex);
    AudioPara stAudioPara = {0};

    HV_ASSERT_VALID_PTR_RET(pstHdmiData, HV_FALSE);

    if((pstHdmiData->enCurrentPortState != INPUT_PORT_STATE_DISPLAY_RDY) || (pstHdmiData->bAudioAbnormal == HV_TRUE))
    {
        return HV_FALSE;
    }

    Hv_Drv_HdmiRx_GetAudioPara(pstHdmiData->ucDataPortIndex, &stAudioPara);

    /* 根据Audio的时钟及CTS，N值判断Audio状态是否正常 */
    //bAudioStatus = Hv_Cal_HdmiRx_GetAudioStatus(pstHdmiData->ucDataPortIndex);

    if(stAudioPara.enCodingType > E_AUD_TYPE_L_PCM || stAudioPara.ucChnlCnt > 1)
    {
        HV_INPUT_LOG_INFO(HDMI, "HDMI%d Get Audio Status Failed with %d,%d", pstHdmiData->ucDataPortIndex, stAudioPara.enCodingType, stAudioPara.ucChnlCnt);
        return HV_FALSE;
    }

    if(stAudioPara.bAudClkStable == 0 || stAudioPara.uiCtsValue == 0 || stAudioPara.uiNValue == 0)
    {
        HV_INPUT_LOG_INFO(HDMI, "HDMI%d Get Audio Status Failed with CTS:%d, N:%d, S:%d",
            pstHdmiData->ucDataPortIndex, stAudioPara.uiCtsValue, stAudioPara.uiNValue, stAudioPara.bAudClkStable);

       return HV_FALSE;
    }

    return HV_TRUE;
}

void Hv_Mw_HdmiRx_RobustRatioHandle(VOID* pvArgument, USHORT16 usTimerId)
{
    InputPortManager* pstInputPortManager = Hv_Mw_InputPort_GetManagerPtr();

    if(usTimerId == SYS_EVENT_TIMER_HDMI0_RATIO)
    {
        (pstInputPortManager->stHDMIManager.astHdmiData)[0].bInRobustRatio = HV_FALSE;
    }
    else
    {
        if (HV_BOARD_CONFIG_HDMI_0 == PORT_VALID && HV_BOARD_CONFIG_HDMI_1 == PORT_VALID)
        {
            (pstInputPortManager->stHDMIManager.astHdmiData)[1].bInRobustRatio = HV_FALSE;
        }
        else
        {
            (pstInputPortManager->stHDMIManager.astHdmiData)[0].bInRobustRatio = HV_FALSE;
        }
    }

    return;
}

static VOID InitHdmiDataTimer(HdmiCtrlData* pstHdmiData)
{
    HV_ASSERT_VALID_PTR_VOID(pstHdmiData);
    if(pstHdmiData->enPortIndex == LINK_PORT_INDEX_HDMI_RX0)
    {
        HV_TIMER_INIT_PARAMS stWaitSyncTimerHdmi0 = \
        {"WaitSyncHdmi0", HDMI_WAITSYNC_STATE_TIMER_LENGTH, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_HDMI0_WAITSYNC};
        pstHdmiData->pstWaitSyncTimer = Hv_Vos_Timer_Create(&stWaitSyncTimerHdmi0);
        HV_ASSERT_VALID_PTR_VOID(pstHdmiData->pstWaitSyncTimer);

        HV_TIMER_INIT_PARAMS stSyncOkTimerHdmi0 = \
        {"SyncOkHdmi0", HDMI_SYNCOK_STATE_TIMER_LENGTH, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_HDMI0_SYNCOK};
        pstHdmiData->pstSyncOkTimer = Hv_Vos_Timer_Create(&stSyncOkTimerHdmi0);
        HV_ASSERT_VALID_PTR_VOID(pstHdmiData->pstSyncOkTimer);

        HV_TIMER_INIT_PARAMS stHpdControlTimerHdmi0 = \
        {"HPDControlHdmi0", HDMI_HOT_PLUG_DET_CTL_TIMER_LENTH, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_HDMI0_HPD_SET_HIGH};
        pstHdmiData->pstHpdControlTimer = Hv_Vos_Timer_Create(&stHpdControlTimerHdmi0);
        HV_ASSERT_VALID_PTR_VOID(pstHdmiData->pstHpdControlTimer);

        HV_TIMER_INIT_PARAMS stTrainDoneTimerHdmi0 = \
        {"TrainDoneHdmi0", HDMI_TRINING_DONE_CHECKING_LENTH, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_HDMI0_WAIT_EQ_DONE};
        pstHdmiData->pstEqCheckTimer = Hv_Vos_Timer_Create(&stTrainDoneTimerHdmi0);
        HV_ASSERT_VALID_PTR_VOID(pstHdmiData->pstEqCheckTimer);

        HV_TIMER_INIT_PARAMS stFastLckTimerHdmi0 = \
        {"FastLckHdmi0", HDMI_FAST_LCKED_LENTH, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_HDMI0_FASTLCK};
        pstHdmiData->pstLaneLockedTimer = Hv_Vos_Timer_Create(&stFastLckTimerHdmi0);
        HV_ASSERT_VALID_PTR_VOID(pstHdmiData->pstLaneLockedTimer);

        HV_TIMER_INIT_PARAMS stHdcpSyncTimerHdmi0 = \
        {"HdcpSyncHdmi0", 2400, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_HDMI0_HDCPSYNC};
        pstHdmiData->pstHdcpSyncTimer = Hv_Vos_Timer_Create(&stHdcpSyncTimerHdmi0);
        HV_ASSERT_VALID_PTR_VOID(pstHdmiData->pstHdcpSyncTimer);

        HV_TIMER_INIT_PARAMS stRobustRatioTimerHdmi0 = \
        {"RobustRatioHdmi0", HDMI_ENTER_ROBUST_RATIO_TIMER_LEN, HV_FALSE, NULL, Hv_Mw_HdmiRx_RobustRatioHandle, SYS_EVENT_TIMER_HDMI0_RATIO};
        pstHdmiData->pstRobustRatio = Hv_Vos_Timer_Create(&stRobustRatioTimerHdmi0);
        HV_ASSERT_VALID_PTR_VOID(pstHdmiData->pstRobustRatio);
    }

    if(pstHdmiData->enPortIndex == LINK_PORT_INDEX_HDMI_RX1)
    {
        HV_TIMER_INIT_PARAMS stWaitSyncTimerHdmi1 = \
        {"WaitSyncHdmi1", HDMI_WAITSYNC_STATE_TIMER_LENGTH, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_HDMI1_WAITSYNC};
        pstHdmiData->pstWaitSyncTimer = Hv_Vos_Timer_Create(&stWaitSyncTimerHdmi1);
        HV_ASSERT_VALID_PTR_VOID(pstHdmiData->pstWaitSyncTimer);

        HV_TIMER_INIT_PARAMS stSyncOkTimerHdmi1 = \
        {"SyncOkHdmi1", HDMI_SYNCOK_STATE_TIMER_LENGTH, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_HDMI1_SYNCOK};
        pstHdmiData->pstSyncOkTimer = Hv_Vos_Timer_Create(&stSyncOkTimerHdmi1);
        HV_ASSERT_VALID_PTR_VOID(pstHdmiData->pstSyncOkTimer);

        HV_TIMER_INIT_PARAMS stHpdControlTimerHdmi1 = \
        {"HPDControlHdmi1", HDMI_HOT_PLUG_DET_CTL_TIMER_LENTH, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_HDMI1_HPD_SET_HIGH};
        pstHdmiData->pstHpdControlTimer = Hv_Vos_Timer_Create(&stHpdControlTimerHdmi1);
        HV_ASSERT_VALID_PTR_VOID(pstHdmiData->pstHpdControlTimer);

        HV_TIMER_INIT_PARAMS stTrainDoneTimerHdmi1 = \
        {"TrainDoneHdmi1", HDMI_TRINING_DONE_CHECKING_LENTH, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_HDMI1_WAIT_EQ_DONE};
        pstHdmiData->pstEqCheckTimer = Hv_Vos_Timer_Create(&stTrainDoneTimerHdmi1);
        HV_ASSERT_VALID_PTR_VOID(pstHdmiData->pstEqCheckTimer);

        HV_TIMER_INIT_PARAMS stFastLckTimerHdmi1 = \
        {"FastLckHdmi1", HDMI_FAST_LCKED_LENTH, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_HDMI1_FASTLCK};
        pstHdmiData->pstLaneLockedTimer = Hv_Vos_Timer_Create(&stFastLckTimerHdmi1);
        HV_ASSERT_VALID_PTR_VOID(pstHdmiData->pstLaneLockedTimer);

        HV_TIMER_INIT_PARAMS stHdcpSyncTimerHdmi1 = \
        {"HdcpSyncHdmi1", 2400, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_HDMI1_HDCPSYNC};
        pstHdmiData->pstHdcpSyncTimer = Hv_Vos_Timer_Create(&stHdcpSyncTimerHdmi1);
        HV_ASSERT_VALID_PTR_VOID(pstHdmiData->pstHdcpSyncTimer);

        HV_TIMER_INIT_PARAMS stRobustRatioTimerHdmi1 = \
        {"RobustRatioHdmi1", HDMI_ENTER_ROBUST_RATIO_TIMER_LEN, HV_FALSE, NULL, Hv_Mw_HdmiRx_RobustRatioHandle, SYS_EVENT_TIMER_HDMI1_RATIO};
        pstHdmiData->pstRobustRatio = Hv_Vos_Timer_Create(&stRobustRatioTimerHdmi1);
        HV_ASSERT_VALID_PTR_VOID(pstHdmiData->pstRobustRatio);
    }

    return ;
}

static UINT32 GetHdmiEdidData(LinkPortIndex enPortIndex, UCHAR8 *pucEdidData)
{
    HdmiCtrlData* pstHdmiDataPtr = HV_Mw_HdmiRx_GetHdmiLinkData(enPortIndex);    

    HV_ASSERT_VALID_PTR(pstHdmiDataPtr);
    HV_ASSERT_VALID_PTR(pucEdidData);

    HV_ASSERT_TRUE_RET(pstHdmiDataPtr->uiEdidLength <= HV_HDMI_MAX_EDID_LENTH, 0);

    HV_MEMCPY(pucEdidData, pstHdmiDataPtr->aucEdidData, pstHdmiDataPtr->uiEdidLength);

    return (pstHdmiDataPtr->uiEdidLength);
}

static Status StartHdmiAudio(LinkPortIndex enPortIndex)
{
    HdmiCtrlData* pstHdmiData         = HV_Mw_HdmiRx_GetHdmiLinkData(enPortIndex);
    HdmiRxIntStatus stHdmiIntRxStatus = {0,0};
    UINT32 uiCts, uiN;

    HV_ASSERT_VALID_PTR(pstHdmiData);

    Hv_Cal_HdmiRx_GetAudioCurrentCTSN(pstHdmiData->ucDataPortIndex, &uiCts, &uiN);

    if (uiCts != 0 && uiN != 0)
    {
        /* cts/n有效，才允许放水，cts/n无效时放水会导致水位始终不涨或电流兹拉声 */

#if HDMI_AUDIO_MANUAL_CLK_OPEN
        Hv_Cal_HdmiRx_SetCtsNMeasMode(pstHdmiData->ucDataPortIndex, 0x2);
        if(Hv_Cal_HdmiRx_RobustCheckAudioManual(pstHdmiData->ucDataPortIndex))
        {
            HV_INPUT_LOG_INFO(HDMI, "HDMI%d Audio Start Manual Clock", pstHdmiData->ucDataPortIndex);
            pstHdmiData->bEnterManualAudClk = HV_TRUE;
            Hv_Cal_HdmiRx_SwitchAudioManualClk(pstHdmiData->ucDataPortIndex, HV_TRUE);
        }
#endif

        /* Reset Audio Fifo. */
        Hv_Cal_HdmiRx_ResetAudioFifo(pstHdmiData->ucDataPortIndex);
        /* Reset Sw Audio */
        Hv_Cal_HdmiRx_ResetSwAudio(pstHdmiData->ucDataPortIndex);

        /* Add Audio Fifo Inturrupt */
        stHdmiIntRxStatus.uiIntrruptStatus1 = (HV_HDMIRX_INT_1_EVENT_AUDIO_FIFO_OVERFLOW
#if HDMI_AUDIO_MANUAL_CLK_OPEN
            | HV_HDMIRX_INT_1_EVENT_AUDIO_FIFO_MAX
            | HV_HDMIRX_INT_1_EVENT_AUDIO_FIFO_MIN
#endif
            | HV_HDMIRX_INT_1_EVENT_AUDIO_FIFO_UNDERFLOW);
        stHdmiIntRxStatus.uiIntrruptStatus2 = HV_HDMIRX_INT_2_EVENT_AIF_CKS_CHG;

        Hv_Cal_HdmiRx_AddInterruptEvent(pstHdmiData->ucDataPortIndex, &stHdmiIntRxStatus);

        Hv_Cal_HdmiRx_GetHdmiAudioFsValue(pstHdmiData->ucDataPortIndex, &(pstHdmiData->uiAudioFsValue));

        HV_INPUT_LOG_INFO(HDMI, "HDMI%d Audio Fs:%d", pstHdmiData->ucDataPortIndex, pstHdmiData->uiAudioFsValue);
    }
    else
    {
        /* 
         * cts/n无效，开启cts/n中断，当cts/n更新时才放水；
         * 解决某些源show video后cts/n一直为0或一段时间仍为0的问题
         */
        stHdmiIntRxStatus.uiIntrruptStatus1 = HV_HDMIRX_INT_1_EVENT_AUDIO_CTS_CHG;
        stHdmiIntRxStatus.uiIntrruptStatus2 = HV_HDMIRX_INT_2_EVENT_AUDIO_N_CHG |
            HV_HDMIRX_INT_2_EVENT_ACR_RCV | HV_HDMIRX_INT_2_EVENT_AUDIO_TYPE_CHG;
        Hv_Cal_HdmiRx_AddInterruptEvent(pstHdmiData->ucDataPortIndex, &stHdmiIntRxStatus);
        HV_INPUT_LOG_INFO(HDMI, "hdmi%u wait audio cts/n", pstHdmiData->ucDataPortIndex);
    }

    return HV_SUCCESS;
}

Status StopHdmiAudio(LinkPortIndex enPortIndex)
{
    HdmiCtrlData* pstHdmiData         = HV_Mw_HdmiRx_GetHdmiLinkData(enPortIndex);
    HdmiRxIntStatus stHdmiIntRxStatus = {0,0};

    HV_ASSERT_VALID_PTR(pstHdmiData);

    stHdmiIntRxStatus.uiIntrruptStatus1 = (HV_HDMIRX_INT_1_EVENT_AUDIO_FIFO_OVERFLOW
        | HV_HDMIRX_INT_1_EVENT_AUDIO_FIFO_UNDERFLOW);

    Hv_Cal_HdmiRx_RemoveInterruptEvent(pstHdmiData->ucDataPortIndex, &stHdmiIntRxStatus);

    return HV_SUCCESS;
}

static VOID ResetHdmiMac(LinkPortIndex enPortIndex)
{
    HdmiCtrlData* pstHdmiData = HV_Mw_HdmiRx_GetHdmiLinkData(enPortIndex);

    HV_ASSERT_VALID_PTR_VOID(pstHdmiData);

    /* Reset Only the HDMI is Connected */
    if(pstHdmiData->bIsCableConnected)
    {
        CheckHdmiStatusIsValid(pstHdmiData);

        if(pstHdmiData->enCurrentPortState == INPUT_PORT_STATE_DISPLAY_RDY)
        {
            Hv_Cal_HdmiRx_PixelSwReset(pstHdmiData->ucDataPortIndex);
            Hv_Cal_HdmiRx_VidSwReset(pstHdmiData->ucDataPortIndex);
        }
        else
        {
            Hv_Drv_HdmiRx_TmdsPreReset(pstHdmiData->ucDataPortIndex);
        }

        HV_INPUT_LOG_INFO(HDMI, "Reset the HDMI%d.....", pstHdmiData->ucDataPortIndex);

        /* Realse the HDCP Resource */
        Hv_Mw_Hdcp_RealseHdcpCmStatus(pstHdmiData->enPortIndex);
    }

    return;
}

static Status GetHdmiCurrentCEDValue(LinkPortIndex enPortIndex)
{    
    HdmiCtrlData* pstHdmiData = HV_Mw_HdmiRx_GetHdmiLinkData(enPortIndex);
    HV_ASSERT_VALID_PTR(pstHdmiData);
    UCHAR8 ucPortIndex       = pstHdmiData->ucDataPortIndex;
    HdmiRxLaneCED stLaneCed  = {0};

    if(HV_SUCCESS != Hv_Drv_HdmiRx_GetLaneCEDValue(ucPortIndex, &stLaneCed))
    {
        HV_INPUT_LOG_INFO(HDMI, "HDMI%d unLocked", ucPortIndex);
        return HV_FAILURE;
    }

    if((stLaneCed.usLane0CED > HDMI_CED_ERR_INVALID_CNT) 
        || (stLaneCed.usLane1CED > HDMI_CED_ERR_INVALID_CNT)
        || (stLaneCed.usLane2CED > HDMI_CED_ERR_INVALID_CNT))
    {
        HV_INPUT_LOG_INFO(HDMI, "HDMI%d CED exceeds the threshold", ucPortIndex);
        
        return HV_FAILURE;
    }

    return HV_SUCCESS;
}

static Status SwitchHdmiHPDStatus(LinkPortIndex enPortIndex, BOOL bHpdSwitch)
{
    HdmiCtrlData* pstHdmiData = HV_Mw_HdmiRx_GetHdmiLinkData(enPortIndex);

    HV_ASSERT_VALID_PTR(pstHdmiData);

    return SwitchHPDControlStatus(pstHdmiData, bHpdSwitch);
}

static Status SaveHdmiConfigureEdidType(HdmiCtrlData* pstHdmiData)
{
    /* 将EDID写入到Flash里面 */
    HV_ASSERT_VALID_PTR(pstHdmiData);
    
#if (HV_BOARD_CONFIG_HDMI_0 == PORT_VALID)
    if(0 == pstHdmiData->ucDataPortIndex)
    {
        HV_COMMON_DATABASE_SET(UserData, ucHdmi0EdidCfg, pstHdmiData->enEdidConfiged);
    }
#endif
#if (HV_BOARD_CONFIG_HDMI_1 == PORT_VALID)
    if(1 == pstHdmiData->ucDataPortIndex)
    {
        HV_COMMON_DATABASE_SET(UserData, ucHdmi1EdidCfg, pstHdmiData->enEdidConfiged);
    }
#endif
    return HV_SUCCESS;
}

static EDIDType GetHdmiConfiguredEdidType(UCHAR8 ucDataPortIndex)
{
    EDIDType enEdidTypeCfg = EDID_TYPE_DEFAULT;

/* Cong Flash 里面获取 */
#if (HV_BOARD_CONFIG_HDMI_0 == PORT_VALID)
    if(0 == ucDataPortIndex)
    {
        enEdidTypeCfg = HV_COMMON_DATABASE_GET(UserData, ucHdmi0EdidCfg);
    }
#endif
#if (HV_BOARD_CONFIG_HDMI_1 == PORT_VALID)
    if(1 == ucDataPortIndex)
    {
        enEdidTypeCfg = HV_COMMON_DATABASE_GET(UserData, ucHdmi1EdidCfg);
    }
#endif
    return enEdidTypeCfg;
}

/*
 * Auto EQ 分为3档分别为2 4 8. 循环配置
 */
static UCHAR8 GetNextHdmiInitEqValue(UCHAR8 ucCurrentValue)
{
    if (ucCurrentValue == 8)
    {
        return 2;
    }

    if(ucCurrentValue == 2)
    {
        return 0;
    }

    if(ucCurrentValue == 0)
    {
        return 4;
    }

    if(ucCurrentValue == 4)
    {
        return 8;
    }

    return 8;
}

#define RECV_CACHE_NUM    50
static UCHAR8 s_aucRecvData[RECV_CACHE_NUM][DMAX_DDC_MSG_CACHE_NUM] = {0};
static UCHAR8 s_ucRecvDataIdx = 0;

static VOID HdmiSendDdcciMsg(UCHAR8 ucPortIndex, DDCCIEventId eDdcciEvent)
{
    SystemEvent stSystemEvent = {0};
    HV_VOS_QUEUE_S* pstSysQueue = Hv_Mw_System_GetSystemQueue();
    HV_ASSERT_VALID_PTR_VOID_NO_LOG(pstSysQueue);

    stSystemEvent.uiValue = Hv_Drv_HdmiRx_DdcRecv(ucPortIndex, s_aucRecvData[s_ucRecvDataIdx]);
    stSystemEvent.buffer = s_aucRecvData[s_ucRecvDataIdx];

    s_ucRecvDataIdx++;
    if(s_ucRecvDataIdx == RECV_CACHE_NUM)
    {
        s_ucRecvDataIdx = 0;
    }

    stSystemEvent.enEventType = SYSTEM_REV_EVENT_TYPE_DDCCI;
    stSystemEvent.usEventId = eDdcciEvent;
    stSystemEvent.ucPortIndex = (ucPortIndex != 0) ? DDCCI_PORT_HDMI1 : DDCCI_PORT_HDMI0;
    Hv_Vos_QueueSendFromISR(pstSysQueue, &stSystemEvent);

    return;
}

static BOOL FindPreEqResult(HdmiCtrlData* pstHdmiData, USHORT16 *pusAutoEqValue)
{
    HV_ASSERT_VALID_PTR_RET(pstHdmiData, HV_FALSE);

    if(pstHdmiData->usTmdsClkFreqEqLabel >= HV_HDMI_PRE_EQ_RESULT_TABLE_CONT)
    {
        return HV_FALSE;
    }

    if(pstHdmiData->ausPreEqTable[pstHdmiData->usTmdsClkFreqEqLabel][3] != 0)
    {
        pusAutoEqValue[0] = pstHdmiData->ausPreEqTable[pstHdmiData->usTmdsClkFreqEqLabel][0];
        pusAutoEqValue[1] = pstHdmiData->ausPreEqTable[pstHdmiData->usTmdsClkFreqEqLabel][1];
        pusAutoEqValue[2] = pstHdmiData->ausPreEqTable[pstHdmiData->usTmdsClkFreqEqLabel][2];

        return HV_TRUE;
    }
    else
    {
        return HV_FALSE;
    }
}

static Status SaveSwEqValue(HdmiCtrlData* pstHdmiData, USHORT16 *pusAutoEqValue)
{
    if(pstHdmiData->usTmdsClkFreqEqLabel >= HV_HDMI_PRE_EQ_RESULT_TABLE_CONT)
    {
        return HV_FAILURE;
    }

    pstHdmiData->ausPreEqTable[pstHdmiData->usTmdsClkFreqEqLabel][0] = pusAutoEqValue[0];
    pstHdmiData->ausPreEqTable[pstHdmiData->usTmdsClkFreqEqLabel][1] = pusAutoEqValue[1];
    pstHdmiData->ausPreEqTable[pstHdmiData->usTmdsClkFreqEqLabel][2] = pusAutoEqValue[2];
    pstHdmiData->ausPreEqTable[pstHdmiData->usTmdsClkFreqEqLabel][3] = 0x78;

    return HV_SUCCESS;
}

static Status FinishedEqWithDefaultValue(HdmiCtrlData* pstHdmiData)
{
    HV_ASSERT_VALID_PTR(pstHdmiData);

    HdmiRxIntStatus stPllChangeIntEn = {0, HV_HDMIRX_INT_2_EVENT_LANEFASTLOCK};
    USHORT16 ausAutoEqValue[4] = {0x178, 0x178, 0x178, 0x00};

    Hv_Drv_HdmiRx_SetSwEqValue(pstHdmiData->ucDataPortIndex, ausAutoEqValue);
    Hv_Cal_HdmiRx_FinishTmdsSwEq(pstHdmiData->ucDataPortIndex);
    pstHdmiData->ucEqStatus = HdmiEqStatus_EQLoopDone;
    pstHdmiData->ucEqSwTable = 0;

    Hv_Cal_HdmiRx_AddInterruptEvent(pstHdmiData->ucDataPortIndex, &stPllChangeIntEn);
    Hv_Cal_HdmiRx_ResetPhy(pstHdmiData->ucDataPortIndex);

    HV_INPUT_LOG_INFO(HDMI, "HDMI%d EQ Default.", pstHdmiData->ucDataPortIndex);

    return HV_SUCCESS;
}

static Status FinishEqCheckHandle(HdmiCtrlData* pstHdmiData)
{
    HV_ASSERT_VALID_PTR(pstHdmiData);
    HdmiRxIntStatus stPllChangeIntEn = {0, 0};
    USHORT16 ausAutoEqValue[4] = {0,0,0,0x00};

    /* 无法锁定直接切换到硬件EQ */
    if(((pstHdmiData->astSwEqResult)[0].usBestCedValue == 0x8000) 
        || ((pstHdmiData->astSwEqResult)[1].usBestCedValue == 0x8000)
        || ((pstHdmiData->astSwEqResult)[2].usBestCedValue == 0x8000))
    {
        if(pstHdmiData->ucEqSwTable >= (HV_MAX_HDMI_SW_EQ_TABLE_LENTH - 1))
        {
            HV_INPUT_LOG_INFO(HDMI, "HDMI%d EQ Failed, Switch to HW.", pstHdmiData->ucDataPortIndex);
            Hv_Cal_HdmiRx_EnterTmdsHwAutoEq(pstHdmiData->ucDataPortIndex);
            pstHdmiData->ucEqStatus = HdmiEqStatus_EQLoopDone;

            pstHdmiData->ucEqSwTable = 0;
        }
        else
        {
            pstHdmiData->ucEqSwTable++;
        }
    }
    else
    {
        if(pstHdmiData->ucEqSwTable > 10)
        {
            /* 配置软件EQ的内容数值 */
            ausAutoEqValue[0] = g_ausSoftWareEqTable[(((pstHdmiData->astSwEqResult)[0].ucBestStart + (pstHdmiData->astSwEqResult)[0].ucBestStop + 1) >> 1)];
            ausAutoEqValue[1] = g_ausSoftWareEqTable[(((pstHdmiData->astSwEqResult)[1].ucBestStart + (pstHdmiData->astSwEqResult)[1].ucBestStop + 1) >> 1)];
            ausAutoEqValue[2] = g_ausSoftWareEqTable[(((pstHdmiData->astSwEqResult)[2].ucBestStart + (pstHdmiData->astSwEqResult)[2].ucBestStop + 1) >> 1)];

            Hv_Drv_HdmiRx_SetSwEqValue(pstHdmiData->ucDataPortIndex, ausAutoEqValue);

            Hv_Cal_HdmiRx_FinishTmdsSwEq(pstHdmiData->ucDataPortIndex);

            pstHdmiData->ucEqStatus = HdmiEqStatus_EQLoopDone;

            pstHdmiData->ucEqSwTable = 0;

            SaveSwEqValue(pstHdmiData, ausAutoEqValue);

            HV_INPUT_LOG_INFO(HDMI, "Trainig done Table %d, %d, %d, %d, %d, %d .", (pstHdmiData->astSwEqResult)[0].ucBestStart, (pstHdmiData->astSwEqResult)[0].ucBestStop, 
                (pstHdmiData->astSwEqResult)[1].ucBestStart, (pstHdmiData->astSwEqResult)[1].ucBestStop,(pstHdmiData->astSwEqResult)[2].ucBestStart, (pstHdmiData->astSwEqResult)[2].ucBestStop);

            HV_INPUT_LOG_INFO(HDMI, "Success the Training with By Value with %x, %x, %x .", ausAutoEqValue[0], ausAutoEqValue[1], ausAutoEqValue[2]);
        }
        else
        {
            pstHdmiData->ucEqSwTable++;
        }
    }

    stPllChangeIntEn.uiIntrruptStatus2 = HV_HDMIRX_INT_2_EVENT_LANEFASTLOCK;

    Hv_Cal_HdmiRx_AddInterruptEvent(pstHdmiData->ucDataPortIndex, &stPllChangeIntEn);

    Hv_Cal_HdmiRx_ResetPhy(pstHdmiData->ucDataPortIndex);

    return HV_SUCCESS;
}

static VOID InitParaWithEqtart(HdmiCtrlData* pstHdmiData)
{
    UCHAR8 ucPortIndex = pstHdmiData->ucDataPortIndex;

    /* HDMI Packet Fifo Closed */
    Hv_Cal_HdmiRx_ClosedPdFifo(ucPortIndex);
    Hv_Cal_HdmiRx_ClrDviMode(ucPortIndex);

    pstHdmiData->bEnterManualAudClk = HV_FALSE;
    pstHdmiData->usLastUnderValue = 0;
    pstHdmiData->usLastOverValue = 0;
    Hv_Cal_HdmiRx_SwitchAudioManualClk(ucPortIndex, HV_FALSE);

#if (HV_PROJECT_CONFIG_CTS == HV_CONFIG_OFF)
    /* HDCP重新认证 */
    Hv_Mw_Hdcp_RealseHdcpCmStatus(pstHdmiData->enPortIndex);
#endif
    /* 关闭Timing Stable 上报 */
    Hv_Cal_HdmiRx_ChangeFrameTh(ucPortIndex, 0x0);

    Hv_Drv_HdmiRx_Hdcp1XInitForAuth(ucPortIndex);
    Hv_Cal_HdmiRx_ConfigureEqCheckValue(ucPortIndex, HV_TRUE);

    /* EQ Table Init */
    pstHdmiData->ucEqSwTable = 0;

    pstHdmiData->bAudioAbnormal = HV_FALSE;
    pstHdmiData->bEnterLowBnd = HV_FALSE;

    if(pstHdmiData->bEnterEQBypassMode || pstHdmiData->bEnterLowBnd)
    {
        Hv_Cal_HdmiRx_SetEqByPass(ucPortIndex, 0x0);
        pstHdmiData->bEnterEQBypassMode = HV_FALSE;
        pstHdmiData->bEnterLowBnd = HV_FALSE;
    }

    return;
}

Status Hv_Mw_HdmiRx_Sm_AudioFifoStartHandle(const InputPortEvent *pstEvent, VOID *pstPortData)
{
    HdmiCtrlData* pstHdmiData = (HdmiCtrlData *)pstPortData;
    HV_ASSERT_VALID_PTR_RET(pstHdmiData, HV_FALSE);

    if (HV_TRUE == pstHdmiData->bAudioAbnormal)
    {
        pstHdmiData->bAudioAbnormal = HV_FALSE;
        SendEventToChannel(pstHdmiData, CHANNEL_EVENT_ID_AUDIO_MUTE_STATE_CHANGE);
    }

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_Sm_ChangeHdmiVersionHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HdmiCtrlData* pstHdmiData = (HdmiCtrlData*)pstPortData;
    HV_ASSERT_VALID_PTR(pstHdmiData);

    if(HdmiVesion_HD14 == HV_COMMON_DATABASE_GET(UserData, ucHDMIVersion))
    {
        /* 关闭SCDC */
        Hv_Cal_HdmiRx_EnableScdcBySwitch(pstHdmiData->ucDataPortIndex, HV_FALSE);
    }
    else
    {
        /* 打开SCDC */
        Hv_Cal_HdmiRx_EnableScdcBySwitch(pstHdmiData->ucDataPortIndex, HV_TRUE);
    }

    return HV_CONTINUE;
}

Status Hv_Mw_HdmiRx_Sm_EnterIdleHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HdmiCtrlData* pstHdmiData = (HdmiCtrlData*)pstPortData;

    HV_ASSERT_VALID_PTR(pstHdmiData);

    /* 检查HPD及CableDetect 状态是否符合，如果失败，需要恢复 */
    /* 获取Cable值确认是插入还是拔出, True表示插入 */
    //Hv_Mw_HdmiRx_CableDetCheck(pstHdmiData->ucDataPortIndex);
    Hv_Cal_HdmiRx_InterruptRmHdcpEvent(pstHdmiData->ucDataPortIndex);
    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + pstHdmiData->ucDataPortIndex, HOTFIX_HDMI_IDLE);

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_Sm_IdleStartHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HV_ASSERT_VALID_PTR(pstPortData);
    HdmiCtrlData* pstHdmiData = (HdmiCtrlData*)pstPortData;
    UINT32 uiCableIrqIndex    = HV_CHIP_IRQ_RX_CABLE2;
    UINT32 uiHdmiIrqIndex     = HV_CHIP_IRQ_RX_HDMI_0;
    Status uiResult           = HV_SUCCESS;
    UCHAR8 ucPortIndex        = pstHdmiData->ucDataPortIndex;

#if(HV_PROJECT_CONFIG_EDID_EXTER_EEPROM == HV_CONFIG_OFF)
    Hv_Cal_HdmiRx_EdidReadEnable(ucPortIndex);
#endif

    /* 拉高HPD */
    SwitchHPDControlStatus(pstHdmiData, HV_TRUE);
    pstHdmiData->bIdleStart = HV_TRUE;

    if(ucPortIndex == 1)
    {
        uiCableIrqIndex = HV_CHIP_IRQ_RX_CABLE3;
        uiHdmiIrqIndex = HV_CHIP_IRQ_RX_HDMI_1;
    }

    /* 开启 Cable Detect 中断 */
    Hv_Vos_UnmaskIrq(uiCableIrqIndex);

    /* 第一次 Cable 发现 */
    Hv_Mw_HdmiRx_CableDetCheck(ucPortIndex);

    Hv_Cal_HdmiRx_InterruptRmHdcpEvent(ucPortIndex);

    /* 开启HDMI中断 */
    Hv_Vos_UnmaskIrq(uiHdmiIrqIndex);

#ifdef HDMI_DEFAULT_CLOSED
    Hv_Cal_HdmiRx_SwitchCECFunc(ucPortIndex, HV_FALSE);
#else
    Hv_Cal_HdmiRx_StartRcvCecMsg(ucPortIndex);
#endif

    /* HDMI Reset */
    Hv_Cal_HdmiRx_Reset(ucPortIndex);

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_Sm_SignalLossHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HdmiCtrlData* pstHdmiData = (HdmiCtrlData*)pstPortData;
    HV_ASSERT_VALID_PTR(pstHdmiData);

    NoticeChannelTimingChange(pstHdmiData, CHANNEL_EVENT_ID_SIGNAL_LOSS);

    /* Pre Reset */
    Hv_Drv_HdmiRx_TmdsPreReset(pstHdmiData->ucDataPortIndex);

    /* HDCP CM Status Release */
    Hv_Mw_Hdcp_RealseHdcpCmStatus(pstHdmiData->enPortIndex);

    HDMI_ADD_EVENT_STAT(pstHdmiData->ucDataPortIndex, InputPortEventId_HDMI_PllChange);
    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + pstHdmiData->ucDataPortIndex, HOTFIX_HDMI_SIGNAL_LOSS);

    HV_INPUT_LOG_INFO(HDMI, "HDMI%d Received PLL Change.", pstHdmiData->ucDataPortIndex);

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_Sm_EnterWaitSyncHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HV_ASSERT_VALID_PTR(pstPortData);
    HdmiCtrlData* pstHdmiData = (HdmiCtrlData*)pstPortData;
    UCHAR8 ucPortIndex        = pstHdmiData->ucDataPortIndex;

    /* 修改到UnSync状态提供给Channel Manager 使用 */
    pstHdmiData->enLastPortUnSyncReason = LastPortUnSyncReason_TimingChange;

    Hv_Cal_HdmiRx_SetHDCPHdmiMode(ucPortIndex, HV_FALSE);

    /* 清空Phase Configuration */
    Hv_Cal_HdmiRx_ReleasePhaseConfig(ucPortIndex);

    /* HDMI Packet Fifo Closed */
    Hv_Cal_HdmiRx_ClosedPdFifo(ucPortIndex);

    /* Init Interrupt */
    Hv_Cal_HdmiRx_InterruptInitEvent(ucPortIndex);

    /* Min Htotal only used for FRL */
    Hv_Cal_HdmiRx_ConfigureMinHtotal(ucPortIndex, 0x0, 0x0);

    ClearHdmiTimingData(pstHdmiData);

    /* 关闭Auto VMute，用遮黑方案来遮黑 */
    Hv_Cal_HdmiRx_ClearAutoVmute(ucPortIndex);

    /* 开启Timing Change VTotal 变化上报 */
    Hv_Cal_HdmiRx_SetFrameRateTimingChange(ucPortIndex, HV_FALSE);

    /* 关闭Timing Stable 上报 */
    Hv_Cal_HdmiRx_ChangeFrameTh(ucPortIndex, 0x0);

    if(pstHdmiData->ucHdmiFRLRate == 0)
    {
        Hv_Cal_HdmiRx_ClrAlnDeskew(pstHdmiData->ucDataPortIndex);
    }

    /* Clock Stable */
    if(Hv_Drv_HdmiRx_IsClockStable(ucPortIndex))
    {
        SendInputportInnerMsg(pstHdmiData, InputPortEventId_HDMI_TrainDone, 0);

        /* 设置Timing 解析的位置 */
        Hv_Cal_HdmiRx_ConfigureFrmTrigPos(ucPortIndex, pstHdmiData->ucGrearMode);

        HV_INPUT_LOG_INFO(HDMI, "HDMI%d Still On Sync.", ucPortIndex);

        return HV_SUCCESS;
    }
    else
    {
        Hv_Vos_Timer_Rstart(pstHdmiData->pstWaitSyncTimer, HDMI_WAITSYNC_STATE_TIMER_LENGTH);

        HV_INPUT_LOG_INFO(HDMI, "HDMI%u Start waitsync timer", ucPortIndex);
    }

    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + ucPortIndex, HOTFIX_HDMI_WAIT_SYNC);

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_Sm_TrainingDoneHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HV_ASSERT_VALID_PTR(pstPortData);

    /* FRL TMDS 同一个Training Done 处理 */
    HdmiCtrlData* pstHdmiData = (HdmiCtrlData*)pstPortData;
    UCHAR8 ucPortIndex        = pstHdmiData->ucDataPortIndex;

    /* Check Sync is OK or Not */
    if(!Hv_Drv_HdmiRx_IsClockStable(ucPortIndex))
    {
        UCHAR8 ucGearToCfg = Hv_Drv_HdmiRx_GetRatioType(ucPortIndex, pstHdmiData->ucGrearMode);

        if(ucGearToCfg != pstHdmiData->ucGrearMode)
        {
            SwitchPhyGearMode(pstHdmiData, ucGearToCfg);

            HV_INPUT_LOG_INFO(HDMI, "HDMI%d Training Abnormal Gear to %d.", ucPortIndex, ucGearToCfg);
        }
        else
        {
            HV_INPUT_LOG_INFO(HDMI, "HDMI%d Training Done Abnormal.", ucPortIndex);
        }

        /* 重新触发 Training Done */
        Hv_Drv_HdmiRx_TmdsPreReset(ucPortIndex);

        /* 开WaitSync Timer */
        Hv_Vos_Timer_Rstart(pstHdmiData->pstWaitSyncTimer, 0);

        return HV_FAILURE;
    }

    if(pstHdmiData->bEnterLowBnd == HV_TRUE)
    {
        Hv_Cal_HdmiRx_ReBackTmdsLockInLowBnd(ucPortIndex);
    }

#if (HV_PROJECT_CONFIG_CTS == HV_CONFIG_OFF)
    /* 清空HDMI解析内容；重新获取进行内容解析 */
    Hv_Cal_HdmiRx_SWCfgReset(ucPortIndex);

    /* 等待1帧的时间 */
    Hv_Vos_MSleep(30);
#endif

    /* 设置Timing 解析的位置 */
    Hv_Cal_HdmiRx_ConfigureFrmTrigPos(ucPortIndex, pstHdmiData->ucGrearMode);

    /* 确保收到T   iming  Stable */
    Hv_Cal_HdmiRx_ClrMrTiming(ucPortIndex);

    HDMI_ADD_EVENT_STAT(ucPortIndex, InputPortEventId_HDMI_TrainDone);

    HDMI_GET_TICK_COUNT(ucPortIndex, E_HDMI_TrainingDone);

    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + pstHdmiData->ucDataPortIndex, HOTFIX_HDMI_TRAINING_DONE);

    HV_INPUT_LOG_INFO(HDMI, "HDMI%d Enter SyncOk.", ucPortIndex);

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_Sm_EnterSyncOkHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HdmiCtrlData* pstHdmiData = (HdmiCtrlData*)pstPortData;
    HV_ASSERT_VALID_PTR(pstHdmiData);
    HdmiRxIntStatus stPllChangeIntEn = {0, 0};

    UCHAR8 ucPortIndex = pstHdmiData->ucDataPortIndex;

#if (HV_PROJECT_CONFIG_CTS == HV_CONFIG_OFF)
    Hv_Mw_Hdcp_HdmiReAtherOnSync(pstHdmiData->enPortIndex, HV_FALSE);
#endif

    /* 打开Timing   Stable 上报 */
    Hv_Cal_HdmiRx_ChangeFrameTh(ucPortIndex, 0x800);

    /* 打开Packet报文收集 */
    Hv_Cal_HdmiRx_OpenPdFifo(ucPortIndex);

    Hv_Vos_Timer_Rstop(pstHdmiData->pstWaitSyncTimer);

    /* 保证PLL Change 会上报中断 */
    stPllChangeIntEn.uiIntrruptStatus1 = HV_HDMIRX_INT_1_EVENT_PLL_CHG;
    stPllChangeIntEn.uiIntrruptStatus2 = HV_HDMIRX_INT_2_EVENT_LANEFASTLOCK | HV_HDMIRX_INT_2_EVENT_AVI_RCVED;
    Hv_Cal_HdmiRx_AddInterruptEvent(ucPortIndex, &stPllChangeIntEn);

#if (HV_PROJECT_CONFIG_CTS == HV_CONFIG_OFF)
    Hv_Cal_HdmiRx_ClearCEDValue(ucPortIndex);
#endif

    Hv_Vos_Timer_Rstart(pstHdmiData->pstSyncOkTimer, HDMI_SYNCOK_STATE_TIMER_LENGTH);
    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + ucPortIndex, HOTFIX_HDMI_SYNC_OK);

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_Sm_EnterDisplayReadyHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HdmiCtrlData* pstHdmiData = (HdmiCtrlData*)pstPortData;

    HV_ASSERT_VALID_PTR(pstHdmiData);

    /* 告知Channel Manager现在可以正常显示 */
    pstHdmiData->enLastPortUnSyncReason = LastPortUnSyncReason_None;
    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + pstHdmiData->ucDataPortIndex, HOTFIX_HDMI_DISPLAY_RDY);

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_Sm_WaitSyncTimeOutHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HV_ASSERT_VALID_PTR(pstPortData);
    HdmiCtrlData* pstHdmiData        = (HdmiCtrlData*)pstPortData;
    HdmiRxIntStatus stPllChangeIntEn = {0, 0};
    UCHAR8 ucPortIndex               = pstHdmiData->ucDataPortIndex;

    /* check 当前状态是否已经处于Sync OK状态 */
    if(Hv_Drv_HdmiRx_IsClockStable(ucPortIndex))
    {
        HV_INPUT_LOG_INFO(HDMI, "HDMI%d Have Synced.", ucPortIndex);

        /* 设置Timing 解析的位置 */
        Hv_Cal_HdmiRx_ConfigureFrmTrigPos(ucPortIndex, pstHdmiData->ucGrearMode);

        SendInputportInnerMsg(pstHdmiData, InputPortEventId_HDMI_TrainDone, 0);

        return HV_SUCCESS;
    }

    if(CheckHdmiStatusIsValid(pstHdmiData))
    {
        pstHdmiData->ucWaitSyncTimerOutCnt++;

        if(Hv_Cal_HdmiRX_IsPhyLocked(ucPortIndex))
        {
            Hv_Drv_HdmiRx_TmdsPreReset(ucPortIndex);
            Hv_Cal_HdmiRx_PhyCfgSwTrig(ucPortIndex);
        }
        else
        {
            if((pstHdmiData->ucWaitSyncTimerOutCnt & 0x3) == 0)
            {
                ToggleHdmiHPDInterface(pstHdmiData->enPortIndex);

                Hv_Cal_HdmiRx_Reset(ucPortIndex);
            }
            else
            {
                if(Hv_Cal_HdmiRx_CheckTmdsSignal(ucPortIndex))
                {
                    if((E_RATIOGEAR != pstHdmiData->ucGrearMode) && Hv_Drv_HdmiRX_RobustCheckRatioMode(ucPortIndex))
                    {
                        SwitchInRobustRatio(pstHdmiData);

                        HV_INPUT_LOG_INFO(HDMI, "HDMI%d Gear Robust Ratio", ucPortIndex);
                    }
                    else 
                    {
                        if((pstHdmiData->ucGrearMode == E_RATIOGEAR) || (pstHdmiData->ucGrearMode == E_FRLMODE))
                        {
                            pstHdmiData->ucEQInitValue = GetNextHdmiInitEqValue(pstHdmiData->ucEQInitValue);

                            Hv_Cal_HdmiRx_CfgHdmiAutoEQInitValue(ucPortIndex, pstHdmiData->ucEQInitValue);
                        }

                        /* 更新EQ档位后，复位PHY */
                        Hv_Cal_HdmiRx_ResetPhy(ucPortIndex);
                    }
                }
            }
        }
    }

    /* 开WaitSync Timer */
    Hv_Vos_Timer_Rstart(pstHdmiData->pstWaitSyncTimer,HDMI_WAITSYNC_STATE_TIMER_LENGTH << 3);
    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + pstHdmiData->ucDataPortIndex, HOTFIX_HDMI_WAITSYNC_TIMEOUT);

    return HV_CONTINUE;
}

Status Hv_Mw_HdmiRx_Sm_SyncOkTimeoutHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HV_ASSERT_VALID_PTR(pstPortData);

    HdmiRxIntStatus stPllChangeIntEn = {0, 0};
    HdmiCtrlData* pstHdmiData        = (HdmiCtrlData*)pstPortData;
    UCHAR8 ucPortIndex               = pstHdmiData->ucDataPortIndex;

    /* 异常处理，检查超时原因，并且尝试恢复 */
    if(CheckHdmiTimingStable(pstHdmiData))
    {
        Hv_Vos_Timer_Rstop(pstHdmiData->pstSyncOkTimer);

        HV_INPUT_LOG_DEBUG(HDMI, "HDMI%d Check Timing Gen TRUE", ucPortIndex);

        return HV_SUCCESS;
    }

    /* Clr Timing 会触发上报Timing Stable */
    Hv_Cal_HdmiRx_ClrMrTiming(ucPortIndex);

    Hv_Cal_HdmiRx_OpenPdFifo(ucPortIndex);
/*
    if(pstHdmiData->ucHdmiFRLRate != 0)
    {
        Hv_Cal_HdmiRx_SetFrlFltUpdate(ucPortIndex);
    }
*/
    Hv_Vos_Timer_Rstart(pstHdmiData->pstSyncOkTimer, (HDMI_SYNCOK_STATE_TIMER_LENGTH + HDMI_HOT_PLUG_DET_CTL_TIMER_LENTH));

    stPllChangeIntEn.uiIntrruptStatus1 = HV_HDMIRX_INT_1_EVENT_PLL_CHG;
    stPllChangeIntEn.uiIntrruptStatus2 = HV_HDMIRX_INT_2_EVENT_LANEFASTLOCK;
    Hv_Cal_HdmiRx_AddInterruptEvent(ucPortIndex, &stPllChangeIntEn);
    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + pstHdmiData->ucDataPortIndex, HOTFIX_HDMI_SYNCOK_TIMEOUT);

    HV_INPUT_LOG_INFO(HDMI, "HDMI%d SynkOk Timerout.", ucPortIndex);

    return HV_SUCCESS;
}

/*
 * 0. HV_FAILURE ==> WaitEqDone
 * 1. HV_SUCCESS ==> WaitSync
 * 2. HV_CONTINUE ==> AnyState.
 */
Status Hv_Mw_HdmiRx_Sm_LaneFastLockedHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HV_ASSERT_VALID_PTR(pstEvent);
    HV_ASSERT_VALID_PTR(pstPortData);

    HdmiCtrlData* pstHdmiData = (HdmiCtrlData*)pstPortData;
    UCHAR8 ucPortIndex        = pstHdmiData->ucDataPortIndex;
    UCHAR8 ucGearToCfg        = E_MIDDLEGEAR;
    HdmiRxIntStatus stHdmiIntRxStatus = {0,0};

    HDMI_ADD_EVENT_STAT(ucPortIndex, InputPortEventId_HDMI_FastLocked);

    /* 获取PHY的频率状态 */
    ucGearToCfg = Hv_Drv_HdmiRx_GetRatioType(ucPortIndex, pstHdmiData->ucGrearMode);

    if(pstHdmiData->ucGrearMode != ucGearToCfg)
    {
        if((pstHdmiData->ucGrearMode == E_RATIOGEAR) && pstHdmiData->bInRobustRatio)
        {
            HV_INPUT_LOG_INFO(HDMI, "HDMI%d Robust Ratio Locked.", ucPortIndex);
            pstHdmiData->ucEqStatus = HdmiEqStatus_HwEQDone;
            Hv_Vos_Timer_Rstop(pstHdmiData->pstLaneLockedTimer);
            return HV_SUCCESS;
        }

        /* Fast Lock 中断上报 */
        stHdmiIntRxStatus.uiIntrruptStatus2 = HV_HDMIRX_INT_2_EVENT_LANEFASTLOCK;
        Hv_Cal_HdmiRx_AddInterruptEvent(ucPortIndex, &stHdmiIntRxStatus);

        pstHdmiData->ucEqSwTable = 0;

        /* 对PHY进行分频比配置 */
        SwitchPhyGearMode(pstHdmiData, ucGearToCfg);

        HV_INPUT_LOG_INFO(HDMI, "HDMI%d FastLock Switch Gear to %d.", ucPortIndex, ucGearToCfg);

        Hv_Vos_Timer_Rstart(pstHdmiData->pstLaneLockedTimer, 0);

        return HV_CONTINUE;
    }
    else
    {
#if (HV_PROJECT_CONFIG_CTS == HV_CONFIG_OFF)
        if(ucGearToCfg == E_FRLMODE || ucGearToCfg == E_RATIOGEAR)
#endif
        {
            HV_INPUT_LOG_DEBUG(HDMI, "HW EQ Locked %d:%d.", ucGearToCfg, pstHdmiData->ucEqStatus);
            pstHdmiData->ucEqStatus = HdmiEqStatus_HwEQDone;
            Hv_Vos_Timer_Rstop(pstHdmiData->pstLaneLockedTimer);

            /* MAC 开始准备接收PHY的时钟及数据 */
            Hv_Drv_HdmiRx_TmdsPreReset(ucPortIndex);

            return HV_SUCCESS;
        }
#if (HV_PROJECT_CONFIG_CTS == HV_CONFIG_OFF)
        else
        {
            if(Hv_Drv_HdmiRx_CheckTmdsClockAbnormal(ucPortIndex))
            {
                Hv_Cal_HdmiRx_SetEqByPass(ucPortIndex, 0x2);
                Hv_Cal_HdmiRx_EnterTmdsSwEq(ucPortIndex);
                FinishedEqWithDefaultValue(pstHdmiData);
                Hv_Cal_HdmiRx_PhyCfgSwTrig(ucPortIndex);
                pstHdmiData->bEnterEQBypassMode = HV_TRUE;

                Hv_Vos_Timer_Rstop(pstHdmiData->pstLaneLockedTimer);
                pstHdmiData->ucEqSwTable = 0;

                return HV_SUCCESS;
            }

            if(Hv_Drv_HdmiRX_IsPhyFastLocked(ucPortIndex) == HV_FALSE)
            {
                Hv_Vos_Timer_Rstart(pstHdmiData->pstLaneLockedTimer, 0);
                HV_INPUT_LOG_DEBUG(HDMI, "HDMI TMDSCLK = HDMI%d PHY Lock Status Abnormal", ucPortIndex);
                return HV_CONTINUE;
            }

            if(((pstHdmiData->ucEqStatus) & BIT_0) != 0)
            {
                HV_INPUT_LOG_DEBUG(HDMI, "SW EQ Locked %d:%d.", ucGearToCfg, pstHdmiData->ucEqStatus);
                Hv_Vos_Timer_Rstop(pstHdmiData->pstLaneLockedTimer);
                pstHdmiData->ucEqSwTable = 0;

                return HV_SUCCESS;
            }

            USHORT16 ausAutoEqValue[4]  = {0, 0, 0, 0x00};
            pstHdmiData->usTmdsClkFreqEqLabel = (Hv_Cal_HdmiRx_GetTmdsClkFreq(ucPortIndex)) >> 7;
            if(FindPreEqResult(pstHdmiData, ausAutoEqValue))
            {
                Hv_Drv_HdmiRx_SetSwEqValue(pstHdmiData->ucDataPortIndex, ausAutoEqValue);
                Hv_Cal_HdmiRx_FinishTmdsSwEq(pstHdmiData->ucDataPortIndex);
                Hv_Cal_HdmiRx_ResetPhy(pstHdmiData->ucDataPortIndex);

                pstHdmiData->ucEqStatus = HdmiEqStatus_SwEQDone;
                pstHdmiData->ucEqSwTable = 0;

                Hv_Vos_Timer_Rstop(pstHdmiData->pstLaneLockedTimer);

                HV_INPUT_LOG_INFO(HDMI, "Sw EQ Cfg %d : %x,%x,%x.", ucGearToCfg, ausAutoEqValue[0], ausAutoEqValue[1], ausAutoEqValue[2]);

                return HV_SUCCESS;
            }
        }
#endif
    }

    Hv_Vos_Timer_Rstop(pstHdmiData->pstLaneLockedTimer);

    HV_INPUT_LOG_DEBUG(HDMI, "SW EQ Not Done %d : %d.", ucGearToCfg, pstHdmiData->ucEqStatus);
    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + pstHdmiData->ucDataPortIndex, HOTFIX_HDMI_FAST_LOCKED);

    return HV_FAILURE;
}

Status Hv_Mw_HdmiRx_Sm_EnterWaitLockHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HV_ASSERT_VALID_PTR(pstPortData);
    HV_ASSERT_VALID_PTR(pstEvent);
    HdmiCtrlData* pstHdmiData    = (HdmiCtrlData*)pstPortData;   
    HdmiRxGearMode  emGearMode   = E_UNLOCKED;
    HdmiRxIntStatus stInitStatus = {(HV_HDMIRX_INT_1_EVENT_RATIO_CHG | HV_HDMIRX_INT_1_EVENT_FRL_RATE_CHG), (HV_HDMIRX_INT_2_EVENT_STANDBY_DDC | HV_HDMIRX_INT_2_EVENT_LANEFASTLOCK)};

    /* 关闭中断 */
    Hv_Cal_HdmiRx_InterruptClearEvent(pstHdmiData->ucDataPortIndex, &stInitStatus);

    Hv_Vos_Timer_Rstop(pstHdmiData->pstEqCheckTimer);
    if((pstHdmiData->ucEqStatus == HdmiEqStatus_EqStable))
    {
        InitParaWithEqtart(pstHdmiData);
    }

#if (HV_PROJECT_CONFIG_CTS == HV_CONFIG_OFF)
    if(pstHdmiData->ucHdcpEncStatus == HdcpEncStatus_1XDone)
    {
        USHORT16 usFrameRate = pstHdmiData->stTimingPara.usFrameRate;

        if(usFrameRate < 23)
        {
            usFrameRate = 60;
        }

        Hv_Vos_Timer_Rstart(pstHdmiData->pstHdcpSyncTimer, HDMI_WAIT_HDCP_DONE_TIMER_LENGTH(usFrameRate));

        pstHdmiData->ucHdcpEncStatus = HdcpEncStatus_WaitSync;
    }
#endif

    /* EQ Loop Done */
    if(pstHdmiData->ucEqStatus == HdmiEqStatus_EQLoopDone)
    {
        pstHdmiData->ucEqStatus = HdmiEqStatus_SwEQDone;
    }
    else
    {
        pstHdmiData->ucEqStatus = HdmiEqStatus_Init;
    }

    /* PHY Reset */
    Hv_Cal_HdmiRx_ResetPhy(pstHdmiData->ucDataPortIndex);

    Hv_Vos_Timer_Rstart(pstHdmiData->pstLaneLockedTimer, HDMI_FAST_LCKED_LENTH);

    pstHdmiData->ucLaneLockTimes = 0;

    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + pstHdmiData->ucDataPortIndex, HOTFIX_HDMI_WAIT_FAST_LOCK);

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_Sm_EnterWaitEqDoneHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HdmiCtrlData*   pstHdmiData = (HdmiCtrlData*)pstPortData;   
    HV_ASSERT_VALID_PTR(pstHdmiData);
    UCHAR8          ucPortIndex = pstHdmiData->ucDataPortIndex;
    USHORT16 ausAutoEqValue[4]  = {0,0,0,0x00};
    HdmiRxIntStatus stPllChangeIntEn = {0, 0};

    Hv_Vos_Timer_Rstop(pstHdmiData->pstLaneLockedTimer);

    if(pstHdmiData->ucEqSwTable == 0)
    {
        (pstHdmiData->astSwEqResult)[0].ucBestStart = 8;
        (pstHdmiData->astSwEqResult)[0].ucBestStop = 8;
        (pstHdmiData->astSwEqResult)[0].usBestCedValue = 0x8000;
        (pstHdmiData->astSwEqResult)[1].ucBestStart = 8;
        (pstHdmiData->astSwEqResult)[1].ucBestStop = 8;
        (pstHdmiData->astSwEqResult)[1].usBestCedValue = 0x8000;
        (pstHdmiData->astSwEqResult)[2].ucBestStart = 8;
        (pstHdmiData->astSwEqResult)[2].ucBestStop = 8;
        (pstHdmiData->astSwEqResult)[2].usBestCedValue = 0x8000;

        Hv_Cal_HdmiRx_EnterTmdsSwEq(ucPortIndex);
    }

    if(pstHdmiData->ucEqSwTable < HV_MAX_HDMI_SW_EQ_TABLE_LENTH)
    {
        ausAutoEqValue[0] = g_ausSoftWareEqTable[pstHdmiData->ucEqSwTable];
        ausAutoEqValue[1] = g_ausSoftWareEqTable[pstHdmiData->ucEqSwTable];
        ausAutoEqValue[2] = g_ausSoftWareEqTable[pstHdmiData->ucEqSwTable];

        Hv_Drv_HdmiRx_SetSwEqValue(ucPortIndex, ausAutoEqValue);
    }

    stPllChangeIntEn.uiIntrruptStatus1 = HV_HDMIRX_INT_1_EVENT_TMDS_DESKEW_LOCK;
    stPllChangeIntEn.uiIntrruptStatus2 = HV_HDMIRX_INT_2_EVENT_LANEFASTLOCK;

    Hv_Cal_HdmiRx_AddInterruptEvent(ucPortIndex, &stPllChangeIntEn);

    Hv_Drv_HdmiRx_TmdsPreReset(ucPortIndex);

    Hv_Vos_Timer_Rstart(pstHdmiData->pstEqCheckTimer, 0);
    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + pstHdmiData->ucDataPortIndex, HOTFIX_HDMI_WAIT_EQ_DONE);

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_Sm_WaitEqDoneTimeOutHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HdmiCtrlData* pstHdmiData = (HdmiCtrlData*)pstPortData;   
    HV_ASSERT_VALID_PTR(pstHdmiData);

    /* 一致无法锁定，进行Robust Ratio check. */
    if((E_RATIOGEAR != pstHdmiData->ucGrearMode) && Hv_Drv_HdmiRX_RobustCheckRatioMode(pstHdmiData->ucDataPortIndex))
    {
        SwitchInRobustRatio(pstHdmiData);
        HV_INPUT_LOG_INFO(HDMI, "HDMI%d EQ Done Gear Robust Ratio", pstHdmiData->ucDataPortIndex);
        Hv_Vos_Timer_Rstart(pstHdmiData->pstEqCheckTimer, 0);
    }
    else
    {
        FinishEqCheckHandle(pstHdmiData);
    }

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_Sm_CheckEqCedHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HdmiCtrlData* pstHdmiData   = (HdmiCtrlData*)pstPortData;   
    HV_ASSERT_VALID_PTR(pstHdmiData);
    UCHAR8          ucPortIndex = pstHdmiData->ucDataPortIndex;
    USHORT16      ausLaneCed[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
    UCHAR8           ucLaneLoop = 0;

    Hv_Vos_Timer_Rstop(pstHdmiData->pstEqCheckTimer);

    /* EQ Table */
    HV_INPUT_LOG_DEBUG(HDMI, "Check HDMI%d EQ calculate with table %d", ucPortIndex, pstHdmiData->ucEqSwTable);

    while(pstHdmiData->ucEqSwTable < HV_MAX_HDMI_SW_EQ_TABLE_LENTH)
    {
        Hv_Cal_HdmiRx_ClearCEDValue(pstHdmiData->ucDataPortIndex);

        Hv_Vos_Delayus(30000);

        if(HV_SUCCESS != Hv_Drv_HdmiRx_GetLaneCEDValue(pstHdmiData->ucDataPortIndex, (HdmiRxLaneCED*)ausLaneCed))
        {
            HV_INPUT_LOG_DEBUG(HDMI, "1:CED unlocked EQ Value:%x on table:%d ", g_ausSoftWareEqTable[pstHdmiData->ucEqSwTable], pstHdmiData->ucEqSwTable);

            if(pstHdmiData->ucEqSwTable < 10)
            {
                for(ucLaneLoop = 0; ucLaneLoop < 3; ucLaneLoop++)
                {
                    if((pstHdmiData->astSwEqResult)[ucLaneLoop].usBestCedValue == 0x0)
                    {
                        (pstHdmiData->astSwEqResult)[ucLaneLoop].usBestCedValue = 0x1;
                    }
                }
            }

            if(Hv_Cal_HdmiRx_GetDviMode(ucPortIndex))
            {
                FinishedEqWithDefaultValue(pstHdmiData);
            }
            else
            {
                FinishEqCheckHandle(pstHdmiData);
            }

            return HV_FAILURE;
        }

        for(ucLaneLoop = 0; ucLaneLoop < 3; ucLaneLoop++)
        {
            if(ausLaneCed[ucLaneLoop] <= (pstHdmiData->astSwEqResult)[ucLaneLoop].usBestCedValue)
            {
                if((pstHdmiData->astSwEqResult)[ucLaneLoop].usBestCedValue == 0)
                {
                    if((pstHdmiData->astSwEqResult)[ucLaneLoop].ucBestStop + 3 > pstHdmiData->ucEqSwTable)
                    {
                        (pstHdmiData->astSwEqResult)[ucLaneLoop].ucBestStop = pstHdmiData->ucEqSwTable;
                    }
                }
                else
                {
                    (pstHdmiData->astSwEqResult)[ucLaneLoop].ucBestStart = pstHdmiData->ucEqSwTable;
                    (pstHdmiData->astSwEqResult)[ucLaneLoop].ucBestStop = pstHdmiData->ucEqSwTable;
                    (pstHdmiData->astSwEqResult)[ucLaneLoop].usBestCedValue = ausLaneCed[ucLaneLoop];
                }
            }
            else
            {
                /* 优化Fake 锁定问题，下一次非0且仅连 */
                if((pstHdmiData->astSwEqResult)[ucLaneLoop].usBestCedValue == 0
                    && (pstHdmiData->astSwEqResult)[ucLaneLoop].ucBestStart + 1 == pstHdmiData->ucEqSwTable)
                {
                    (pstHdmiData->astSwEqResult)[ucLaneLoop].usBestCedValue = ausLaneCed[ucLaneLoop];
                    (pstHdmiData->astSwEqResult)[ucLaneLoop].ucBestStop = pstHdmiData->ucEqSwTable;
                }
            }
        }

        HV_INPUT_LOG_DEBUG(HDMI, "CED of Table%d is:%d, %d, %d", pstHdmiData->ucEqSwTable, 
          ausLaneCed[0], ausLaneCed[1], ausLaneCed[2]);

        if(pstHdmiData->ucEqSwTable >= (HV_MAX_HDMI_SW_EQ_TABLE_LENTH - 1))
        {
            FinishEqCheckHandle(pstHdmiData);
            return HV_FAILURE;
        }

        (pstHdmiData->ucEqSwTable)++;

        if(pstHdmiData->ucEqSwTable < HV_MAX_HDMI_SW_EQ_TABLE_LENTH)
        {
            USHORT16 ausAutoEqValue[4]  = {0,0,0,0x00};

            ausAutoEqValue[0] = g_ausSoftWareEqTable[pstHdmiData->ucEqSwTable];
            ausAutoEqValue[1] = g_ausSoftWareEqTable[pstHdmiData->ucEqSwTable];
            ausAutoEqValue[2] = g_ausSoftWareEqTable[pstHdmiData->ucEqSwTable];
        
            Hv_Drv_HdmiRx_SetSwEqValue(ucPortIndex, ausAutoEqValue);
        }
    }

    FinishEqCheckHandle(pstHdmiData);

    return HV_FAILURE;
}

Status Hv_Mw_HdmiRx_Sm_WaitFastLockTimeoutHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HV_ASSERT_VALID_PTR(pstPortData);

    HdmiCtrlData* pstHdmiData = (HdmiCtrlData*)pstPortData;
    UCHAR8 ucPortIndex = pstHdmiData->ucDataPortIndex;
    HdmiRxGearMode emGearMode = E_UNLOCKED;

    if(Hv_Drv_HdmiRX_IsPhyFastLocked(ucPortIndex))
    {
        HV_INPUT_LOG_INFO(HDMI, "HDMI%d PHY Is locke with Timer", ucPortIndex);

        SendInputportInnerMsg(pstHdmiData, InputPortEventId_HDMI_FastLocked, 0);
        Hv_Vos_Timer_Rstart(pstHdmiData->pstLaneLockedTimer, 0);

        return HV_CONTINUE;
    }

    /* 超时拉HPD，复位PHY，然后继续FAST LOCK中断 */
    pstHdmiData->ucLaneLockTimes++;

    if (pstHdmiData->ucLaneLockTimes == HDMI_LANE_LCK_HPD_TIMES)
    {
        ToggleHdmiHPDInterface(pstHdmiData->enPortIndex);
        Hv_Vos_Timer_Rstart(pstHdmiData->pstLaneLockedTimer, (HDMI_FAST_LCKED_LENTH + HDMI_HOT_PLUG_DET_CTL_TIMER_LENTH));
    }
    else
    {
    
//        if(Hv_Drv_HdmiRX_IsTMDSClockOverFlow(ucPortIndex) && Hv_Cal_HdmiRx_GetSourceCfgRatioMode(ucPortIndex))
        if(Hv_Cal_HdmiRx_GetSourceCfgRatioMode(ucPortIndex))
        {
            if(pstHdmiData->ucGrearMode != E_RATIOGEAR)
            {
                SwitchPhyGearMode(pstHdmiData, E_RATIOGEAR);
                HV_INPUT_LOG_INFO(HDMI, "HDMI%d Gear to Cfg Ratio", ucPortIndex);
            }

            if(Hv_Drv_HdmiRX_IsTMDSClockOverFlow(ucPortIndex))
            {
                Hv_Cal_HdmiRx_RobustTmdsLockInLowBnd(ucPortIndex);
                pstHdmiData->bEnterLowBnd = HV_TRUE;
                HV_INPUT_LOG_INFO(HDMI, "HDMI%d Robust TMDS Low Bnd.", ucPortIndex);
            }
            else
            {
                pstHdmiData->ucEQInitValue = GetNextHdmiInitEqValue(pstHdmiData->ucEQInitValue);
                Hv_Cal_HdmiRx_CfgHdmiAutoEQInitValue(ucPortIndex, pstHdmiData->ucEQInitValue);
                Hv_Cal_HdmiRx_PhyCfgSwTrig(ucPortIndex);
                HV_INPUT_LOG_INFO(HDMI, "HDMI%d TMDS Change Eq to %d.", ucPortIndex, pstHdmiData->ucEQInitValue);
            }
        }
        else
        {
            if(Hv_Drv_HdmiRx_CheckTmdsClockAbnormal(ucPortIndex))
            {
                Hv_Cal_HdmiRx_SetEqByPass(ucPortIndex, 0x2);
                Hv_Cal_HdmiRx_EnterTmdsSwEq(ucPortIndex);
                FinishedEqWithDefaultValue(pstHdmiData);
                Hv_Cal_HdmiRx_PhyCfgSwTrig(ucPortIndex);
                pstHdmiData->bEnterEQBypassMode = HV_TRUE;
            }

            {
                emGearMode = Hv_Drv_HdmiRx_GetRatioType(ucPortIndex, pstHdmiData->ucGrearMode);

                if(pstHdmiData->ucGrearMode != emGearMode)
                {
                    /* 对PHY进行分频比配置 */
                    SwitchPhyGearMode(pstHdmiData, emGearMode);

                    HV_INPUT_LOG_INFO(HDMI, "HDMI%d LockTimer Switch Gear to %d.", ucPortIndex, emGearMode);
                }
                else
                {
                    if((E_RATIOGEAR != pstHdmiData->ucGrearMode) && Hv_Drv_HdmiRX_RobustCheckRatioMode(ucPortIndex))
                    {
                        SwitchInRobustRatio(pstHdmiData);
                        HV_INPUT_LOG_INFO(HDMI, "HDMI%d Gear to RobustRatio", ucPortIndex);
                    }
                    else
                    {
                        Hv_Cal_HdmiRx_ResetPhy(ucPortIndex);
                    }
                }
            }
        }

        Hv_Vos_Timer_Rstart(pstHdmiData->pstLaneLockedTimer, HDMI_FAST_LCKED_LENTH);
    }

    if (pstHdmiData->ucLaneLockTimes == HDMI_LANE_LCKED_TIMES)
    {
        HV_INPUT_LOG_INFO(HDMI, "HDMI%d NO LOCKED ON EQ Gear Mode:%d", ucPortIndex, pstHdmiData->ucGrearMode);

        pstHdmiData->ucEqSwTable = 0;

        return HV_FAILURE;
    }

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_Sm_PlugInCableHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HdmiCtrlData* pstHdmiData = (HdmiCtrlData*)pstPortData;   

    HV_ASSERT_VALID_PTR(pstHdmiData);
    SendEventToOsd(pstHdmiData->enPortIndex, OSD_EVENT_SIGNAL_PLUG_IN);

    /* 清空HDMI寄存器中之前残留数据 */
    Hv_Cal_HdmiRx_SWCfgReset(pstHdmiData->ucDataPortIndex);

    /* EQ Flag set to False */
    pstHdmiData->ucEqStatus = HdmiEqStatus_Init;

    /* 检查配置EDID */
    if (IsHdmiEdidInvalid(pstHdmiData))
    {
        HV_INPUT_LOG_DEBUG(HDMI, "HDMI%d Check EDID Invalid at Cable PlugIn.", pstHdmiData->ucDataPortIndex);
        WriteHdmiInnerEdid(pstHdmiData);
    }

    HV_MEMSET(pstHdmiData->ausPreEqTable, 0x0, sizeof(pstHdmiData->ausPreEqTable));

    HDMI_ADD_EVENT_STAT(pstHdmiData->ucDataPortIndex, InputPortEventId_HDMI_5VPlugIn);
    HDMI_GET_TICK_COUNT(pstHdmiData->ucDataPortIndex, E_HDMI_CablePlugIn);

    HV_LOG_WARN(HDMI, "HDMI%d Received Cable PlugIn.", pstHdmiData->ucDataPortIndex);

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_Sm_PlugOutCableHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HV_ASSERT_VALID_PTR(pstPortData);

    HdmiCtrlData* pstHdmiData = (HdmiCtrlData*)pstPortData;
    UCHAR8 ucPortIndex        = (pstHdmiData->ucDataPortIndex);
    USHORT16 ausAutoEqValue[4] = {0x178, 0x178, 0x178, 0x00};

    NoticeChannelTimingChange(pstHdmiData, CHANNEL_EVENT_ID_PLUG_OUT);

    Hv_Vos_Timer_Rstop(pstHdmiData->pstWaitSyncTimer);
    Hv_Vos_Timer_Rstop(pstHdmiData->pstSyncOkTimer);
    Hv_Vos_Timer_Rstop(pstHdmiData->pstEqCheckTimer);
    Hv_Vos_Timer_Rstop(pstHdmiData->pstLaneLockedTimer);
    Hv_Vos_Timer_Rstop(pstHdmiData->pstHdcpSyncTimer);

    pstHdmiData->ucHdcpEncStatus = HdcpEncStatus_NoneEnc;
    pstHdmiData->ucEqStatus = HdmiEqStatus_Init;

    /* 恢复默认 TMDS模式 */
    Hv_Cal_HdmiRx_SetFrlModeOn(ucPortIndex, 0);

    /* 配置恢复MinHtotal到默认值 */
    Hv_Cal_HdmiRx_ConfigureMinHtotal(ucPortIndex, 0x0, 0x0);

    /* 清除恢复 */
    ClearHdmiTimingData(pstHdmiData);

    Hv_Mw_Hdcp_ReleaseHdcpBinding(pstHdmiData->enPortIndex);
    Hv_Drv_Hdcp2x_HdmiResetLinkIntegrityFailure(ucPortIndex);
    Hv_Drv_HdmiRx_SetSwEqValue(ucPortIndex, ausAutoEqValue);

    HDMI_ADD_EVENT_STAT(ucPortIndex, InputPortEventId_HDMI_5VPlugOut);
    HDMI_GET_TICK_COUNT(ucPortIndex, E_HDMI_CablePlugOut);

    HV_LOG_WARN(HDMI, "HDMI%d Cable PlugOut.", ucPortIndex);

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_Sm_SetHpdHighTimeoutHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HV_ASSERT_VALID_PTR(pstPortData);
    HdmiCtrlData* pstHdmiData = (HdmiCtrlData*)pstPortData;
    UCHAR8 ucPortIndex        = (pstHdmiData->ucDataPortIndex);

    Hv_Vos_Timer_Rstop(pstHdmiData->pstHpdControlTimer);

    /* 检查配置EDID */
    if (IsHdmiEdidInvalid(pstHdmiData))
    {
        WriteHdmiInnerEdid(pstHdmiData);
    }

    /* 拉高HPD PIN角 */
    SwitchHPDControlStatus(pstHdmiData, HV_TRUE);

    /* Toggle PHY Auto Eq. */
    Hv_Cal_HdmiRx_ResetPhy(ucPortIndex);

    HV_LOG_WARN(HDMI, "Set HPD High HDMI%d.", ucPortIndex);

    return HV_CONTINUE;
}

Status Hv_Mw_HdmiRx_Sm_TimingStableHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HV_ASSERT_VALID_PTR(pstPortData);

    HdmiCtrlData* pstHdmiData = (HdmiCtrlData*)pstPortData;
    UCHAR8 ucPortIndex        = pstHdmiData->ucDataPortIndex;

    HDMI_ADD_EVENT_STAT(ucPortIndex, InputPortEventId_HDMI_TimingStable);

    /* HDMI Packet Fifo Closed */
    Hv_Cal_HdmiRx_ClosedPdFifo(ucPortIndex);

    /* 获取color depth之前等待寄存器就绪 */
    // Hv_Drv_HdmiRx_ReloadColorDepth(ucPortIndex);

    /* 获取Timing信息 */
    if(HV_SUCCESS != GetHdmiTimingData(pstHdmiData))
    {
        HV_LOG_ERROR(HDMI, "HDMI%d Get AVI or Timing Failed", ucPortIndex);
        Hv_Vos_Timer_Rstop(pstHdmiData->pstSyncOkTimer);

        return HV_FAILURE;
    }

    /* 获取HDR信息，包含TYPE及MetaData */
    Hv_Drv_HdmiRx_GetHDRPara(ucPortIndex, &(pstHdmiData->stHdrPara));

    /* 保证PLL Change 会上报中断 */
    Hv_Cal_HdmiRx_ClrAlnChangFlag(ucPortIndex);

    /* 开启Timing change等中断 */
    AddInterruptEventOnStable(pstHdmiData);

    /* 获取AVI信息 */
    if(HV_SUCCESS != Hv_Drv_HdmiRx_GetAVIPara(ucPortIndex, &(pstHdmiData->stColorPara), &(pstHdmiData->stTimingPara)))
    {
#if 1
        Hv_Vos_MSleep(200);

        if(HV_SUCCESS != Hv_Drv_HdmiRx_GetAVIPara(ucPortIndex, &(pstHdmiData->stColorPara), &(pstHdmiData->stTimingPara)))
        {
            pstHdmiData->stColorPara.eClrFormat  = ColorFormatType_RGB;

            pstHdmiData->stColorPara.eClrSpace   = ColorSpaceType_SRGB;

            pstHdmiData->stColorPara.eClrDepth   = ColorDepthType_8Bit;

            pstHdmiData->stColorPara.eClrRange   = ColorRangeType_Full_Range;

            pstHdmiData->stColorPara.eContent    = CorlorContentType_NoDef;

            pstHdmiData->stColorPara.ucPixelRepe = 0;
        }
#else
        HV_INPUT_LOG_INFO(HDMI, "HDMI%d Wait AVI on SyncOK.", ucPortIndex);
        Hv_Vos_Timer_Rstart(pstHdmiData->pstSyncOkTimer, 0);

        return HV_CONTINUE;
#endif
    }

    /* 配置其他RX Data Path相关参数 */
    SetupHdmiPathOnStable(pstHdmiData);

    /* 输出Timing等信息用于debug */
    PrintHdmiTimingPara(&(pstHdmiData->stTimingPara));    
    PrintHdmiAviColorPara(&(pstHdmiData->stColorPara));

    HV_INPUT_LOG_INFO(HDMI,"@@ HDR info: Type %d", pstHdmiData->stHdrPara.xType);

    if(Hv_Cal_HdmiRx_GetDviMode(ucPortIndex))
    {
        Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + pstHdmiData->ucDataPortIndex, HOTFIX_HDMI_DVI_MODE);
        HV_INPUT_LOG_INFO(HDMI, "HDMI%d is DVI Mode.",ucPortIndex);
    }

    if(pstHdmiData->bEnteredVRR)
    {
        HV_INPUT_LOG_INFO(HDMI, "HDMI%d VRR Opened with Vendor : %d.", ucPortIndex, pstHdmiData->stVrrInfo.eVendor);
    }

    Hv_Vos_Timer_Rstop(pstHdmiData->pstSyncOkTimer);

    HDMI_GET_TICK_COUNT(ucPortIndex, E_HDMI_TimingStable);

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_Sm_TimingChangeHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HV_ASSERT_VALID_PTR(pstPortData);
    HdmiCtrlData* pstHdmiData           = (HdmiCtrlData*)pstPortData;
    VideoTimingParam  stTimingPara      = {0,};
    HdmiRxIntStatus stTimingChangIntrEn = {0, 0};
    UCHAR8 ucPortIndex                  = pstHdmiData->ucDataPortIndex;

    HDMI_ADD_EVENT_STAT(ucPortIndex, InputPortEventId_HDMI_TimingChange);

    if(HV_SUCCESS != Hv_Drv_HdmiRx_GetTimingPara( ucPortIndex, &stTimingPara))
    {
        /* Timing Lost and Notice to Channel Manager */
        NoticeChannelTimingChange(pstHdmiData, CHANNEL_EVENT_ID_TIMING_CHANGE);
        Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + pstHdmiData->ucDataPortIndex, HOTFIX_HDMI_TIMING_CHG);

        HV_LOG_WARN(HDMI, "HDMI%d Timing is Lost.", ucPortIndex);

        return HV_SUCCESS;
    }

    /* Checking Timing and Sent to Channel Manager */
    if (ABS(pstHdmiData->stTimingPara.usHTotal, stTimingPara.usHTotal) > HDMI_JIT_FOR_TIMING_H
        || ABS(pstHdmiData->stTimingPara.usHActive, stTimingPara.usHActive) > HDMI_JIT_FOR_TIMING_H/2
        || ABS(pstHdmiData->stTimingPara.usVActive, stTimingPara.usVActive) > HDMI_JIT_FOR_TIMING_V
        || (ABS(pstHdmiData->stTimingPara.usFrameRate, stTimingPara.usFrameRate) > HDMI_JIT_FOR_FRAME_RATE
            && pstHdmiData->bEnteredVRR == HV_FALSE)
        || (ABS(pstHdmiData->stTimingPara.uiFreqKHz, stTimingPara.uiFreqKHz) > HDMI_JIT_FOR_TIMING_FREQ)
        || (ABS(pstHdmiData->stTimingPara.usVTotal * pstHdmiData->stTimingPara.usFrameRate, stTimingPara.usVTotal * stTimingPara.usFrameRate) > HDMI_JIT_FOR_H_FREQ))
    {
        /* Timing Changed */
        NoticeChannelTimingChange(pstHdmiData, CHANNEL_EVENT_ID_TIMING_CHANGE);
        Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + pstHdmiData->ucDataPortIndex, HOTFIX_HDMI_TIMING_CHG);

        HV_LOG_WARN(HDMI, "HDMI%d Timing is Lost.", ucPortIndex);

        return HV_SUCCESS;
    }

    /* Check Channel Status and Trigger Reconfigure the Timing */
#ifdef CONFIG_USER_DOUBLE_CHANNEL_ON
    if(HV_FAILURE == Hv_Mw_Channel_MuteOff(CHANNEL_TYPE_SUB) || HV_FAILURE == Hv_Mw_Channel_MuteOff(CHANNEL_TYPE_MAIN))
#else
    if(HV_FAILURE == Hv_Mw_Channel_MuteOff(CHANNEL_TYPE_MAIN))
#endif
    {
        /* Timing Changed */
        NoticeChannelTimingChange(pstHdmiData, CHANNEL_EVENT_ID_TIMING_CHANGE);

        HV_INPUT_LOG_INFO(HDMI, "HDMI%d mute or dtc abnormal.", ucPortIndex);

        return HV_SUCCESS;
    }

    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + pstHdmiData->ucDataPortIndex, HOTFIX_HDMI_TIMING_CHG_STILL);
    HV_INPUT_LOG_INFO(HDMI, "Timing still stable.");

    return HV_FAILURE;
}

Status Hv_Mw_HdmiRx_Sm_FastLockedHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    //HV_ASSERT_VALID_PTR(pstEvent);
    HV_ASSERT_VALID_PTR(pstPortData);

    HdmiCtrlData* pstHdmiData = (HdmiCtrlData*)pstPortData;
    UCHAR8 ucPortIndex        = pstHdmiData->ucDataPortIndex;
    UCHAR8 ucGearToCfg        = E_MIDDLEGEAR;
    HdmiRxIntStatus stHdmiIntRxStatus = {0,0};

    HDMI_ADD_EVENT_STAT(ucPortIndex, InputPortEventId_HDMI_FastLocked);

    /* Fast Lock 中断上报 */
    stHdmiIntRxStatus.uiIntrruptStatus2 = HV_HDMIRX_INT_2_EVENT_LANEFASTLOCK;
    Hv_Cal_HdmiRx_AddInterruptEvent(ucPortIndex, &stHdmiIntRxStatus);

    /* 获取PHY的频率状态 */
    ucGearToCfg = Hv_Drv_HdmiRx_GetRatioType(ucPortIndex, pstHdmiData->ucGrearMode);
    if(pstHdmiData->ucGrearMode != ucGearToCfg)
    {
        if((E_RATIOGEAR == pstHdmiData->ucGrearMode) && pstHdmiData->bInRobustRatio)
        {
            return HV_SUCCESS;
        }

        /* 对PHY进行分频比配置 */
        SwitchPhyGearMode(pstHdmiData, ucGearToCfg);
        pstHdmiData->ucEqSwTable = 0;

        HV_INPUT_LOG_INFO(HDMI, "HDMI%d LaneLock Switch Gear to %d.", ucPortIndex, ucGearToCfg);

        return HV_FAILURE;
    }
    else
    {
        if((pstHdmiData->ucGrearMode != E_RATIOGEAR) && Hv_Drv_HdmiRX_RobustCheckRatioMode(ucPortIndex))
        {
            SwitchInRobustRatio(pstHdmiData);
            pstHdmiData->ucEqSwTable = 0;
            HV_INPUT_LOG_INFO(HDMI, "Hdmi%d Gear the Robust Ratio", ucPortIndex);
            return HV_FAILURE;
        }
    }

    return HV_SUCCESS;
}

/* Scramble change will Notice too; Then need to ignore it. */
Status Hv_Mw_HdmiRx_Sm_RatioChangeHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HV_ASSERT_VALID_PTR(pstPortData);
    HdmiCtrlData* pstHdmiData   = (HdmiCtrlData*)pstPortData;
    HdmiRxGearMode eNewGearMode = E_HIGHGEAR;
    UCHAR8 ucPortIndex          = pstHdmiData->ucDataPortIndex;

    HDMI_ADD_EVENT_STAT(ucPortIndex, InputPortEventId_HDMI_RatioChange);

    /* 获取目前PHY状态 */
    eNewGearMode = Hv_Drv_HdmiRx_GetRatioType(ucPortIndex, pstHdmiData->ucGrearMode);

    if((eNewGearMode == E_FRLMODE) || (pstHdmiData->ucGrearMode == eNewGearMode))
    {
        return HV_CONTINUE;
    }

    /* 先配置到 Middle 模式，便于PHY锁定信号 */
    if(eNewGearMode == E_UNLOCKED)
    {
        eNewGearMode = E_MIDDLEGEAR;
    }

    /* 设置phy */
    if(pstHdmiData->ucGrearMode != eNewGearMode)
    {
        /* 对PHY进行分频比配置 */
        SwitchPhyGearMode(pstHdmiData, eNewGearMode);
        pstHdmiData->ucEqSwTable = 0;

        /* Timing Change Noticed. */
        NoticeChannelTimingChange(pstHdmiData, CHANNEL_EVENT_ID_TIMING_CHANGE);
        InitParaWithEqtart(pstHdmiData);

        HV_INPUT_LOG_INFO(HDMI, "HDMI%d Ratio Gear to : %d RC", ucPortIndex, pstHdmiData->ucGrearMode);
    }

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_Sm_ResetAudioFifoHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HdmiCtrlData* pstHdmiData = (HdmiCtrlData*)pstPortData;

    HV_ASSERT_VALID_PTR(pstHdmiData);

    pstHdmiData->bEnterManualAudClk = HV_FALSE;
    pstHdmiData->usLastUnderValue = 0;
    pstHdmiData->usLastOverValue = 0;
    Hv_Cal_HdmiRx_SwitchAudioManualClk(pstHdmiData->ucDataPortIndex, HV_FALSE);

    /* Timing Change But Not Notice HDMI */
    if(Hv_Drv_HdmiRx_IsTimingStable(pstHdmiData->ucDataPortIndex))
    {
        /* 检查HDMI通路上是否有声音 */
        if(IsAudioCarriedOnHdmi(pstHdmiData->enPortIndex))
        {
            UINT32 uiHdmiFs = 0;
            Hv_Cal_HdmiRx_GetHdmiAudioFsValue(pstHdmiData->ucDataPortIndex, &(uiHdmiFs));

            HV_INPUT_LOG_INFO(HDMI, "HDMI%d Audio Fs:%d and %d", pstHdmiData->ucDataPortIndex, uiHdmiFs, pstHdmiData->uiAudioFsValue);

            if(ABS(pstHdmiData->uiAudioFsValue, uiHdmiFs) < 3)
            {
                HV_ASSERT_SUCCESS(Hv_Cal_HdmiRx_ResetAudioFifo(pstHdmiData->ucDataPortIndex));
            }
            else
            {
                /* FS Change Checked ON Audio Moudle */
                SendEventToChannel(pstHdmiData, CHANNEL_EVENT_ID_AUDIO_FS_CHANGE);

                pstHdmiData->bAudioAbnormal = HV_FALSE;
            }

            Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + pstHdmiData->ucDataPortIndex, HOTFIX_HDMI_RESET_AUDIO_FIFO);
        }
        else
        {
            /* FS Change Checked ON Audio Moudle */
            SendEventToChannel(pstHdmiData, CHANNEL_EVENT_ID_AUDIO_FS_CHANGE);
        }
    }
    else
    {
        /* Timing Change with No timing */
        SendInputportInnerMsg(pstHdmiData, InputPortEventId_HDMI_TimingChange, 0);
        HV_INPUT_LOG_INFO(HDMI, "HDMI%d Timing Changed.", pstHdmiData->ucDataPortIndex);
    }

    HDMI_ADD_EVENT_STAT(pstHdmiData->ucDataPortIndex, InputPortEventId_HDMI_AudioResetFifo);

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_Sm_AIFChangeHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HdmiCtrlData* pstHdmiData = (HdmiCtrlData*)pstPortData;

    HV_ASSERT_VALID_PTR(pstHdmiData);

    /* FS Change Checked ON Audio Moudle */
    SendEventToChannel(pstHdmiData, CHANNEL_EVENT_ID_AUDIO_FS_CHANGE);

    HV_INPUT_LOG_INFO(HDMI, "HDMI%d AIF Changed.", pstHdmiData->ucDataPortIndex);

    HDMI_ADD_EVENT_STAT(pstHdmiData->ucDataPortIndex, InputPortEventId_HDMI_AudioPacketChange);

    return HV_SUCCESS;
}

#if (HV_PROJECT_CONFIG_FRL)
Status Hv_Mw_HdmiRx_Sm_FRLRateChangeHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HdmiCtrlData* pstHdmiData = (HdmiCtrlData*)pstPortData;
    HV_ASSERT_VALID_PTR(pstHdmiData);

    /* FRL Rate Change后通知Channel Manager信号丢失 */
    NoticeChannelTimingChange(pstHdmiData, CHANNEL_EVENT_ID_SIGNAL_LOSS);

    UCHAR8 ucGearToCfg = Hv_Drv_HdmiRx_GetRatioType(pstHdmiData->ucDataPortIndex, pstHdmiData->ucGrearMode);

    SwitchPhyGearMode(pstHdmiData, ucGearToCfg);
    pstHdmiData->ucEqSwTable = 0;
    InitParaWithEqtart(pstHdmiData);

    HV_INPUT_LOG_INFO(HDMI, "HDMI%d Rate %d, Gear to : %d FRL RC", pstHdmiData->ucDataPortIndex, pstHdmiData->ucHdmiFRLRate, pstHdmiData->ucGrearMode);

    HDMI_ADD_EVENT_STAT(pstHdmiData->ucDataPortIndex, InputPortEventId_HDMI_FRLRateChange);

    return HV_SUCCESS;
}
#endif

Status Hv_Mw_HdmiRx_Sm_AVIPacketChangeHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HV_ASSERT_VALID_PTR(pstPortData);
    HV_ASSERT_VALID_PTR(pstEvent);
    HdmiCtrlData* pstHdmiData       = (HdmiCtrlData*)pstPortData;
    VideoTimingParam stTimingPara   = {0,};
    VideoColorParam stVideoAVIPara  = {0,};
    UCHAR8 ucPortIndex              = (pstHdmiData->ucDataPortIndex);

    /* 发生Timing Change的时候，会产生AVI Change */
    if(HV_SUCCESS != Hv_Drv_HdmiRx_GetTimingPara( ucPortIndex, &stTimingPara))
    {
        /* Timing Changed */
        NoticeChannelTimingChange(pstHdmiData, CHANNEL_EVENT_ID_TIMING_CHANGE);

        HV_LOG_WARN(HDMI, "HDMI%d Timing Lost AVI.",ucPortIndex);

        return HV_SUCCESS;
    }

    /* Checking Timing and Sent to Channel Manager */
    if (ABS(pstHdmiData->stTimingPara.usHTotal, stTimingPara.usHTotal) > HDMI_JIT_FOR_TIMING_H
        || ABS(pstHdmiData->stTimingPara.usHActive, stTimingPara.usHActive) > HDMI_JIT_FOR_TIMING_H/2
        || ABS(pstHdmiData->stTimingPara.usVActive, stTimingPara.usVActive) > HDMI_JIT_FOR_TIMING_V
        || (ABS(pstHdmiData->stTimingPara.usFrameRate, stTimingPara.usFrameRate) > HDMI_JIT_FOR_FRAME_RATE
           && pstHdmiData->bEnteredVRR == HV_FALSE) 
        || (ABS(pstHdmiData->stTimingPara.uiFreqKHz, stTimingPara.uiFreqKHz) > HDMI_JIT_FOR_TIMING_FREQ))
    {
        /* Timing Changed */
        NoticeChannelTimingChange(pstHdmiData, CHANNEL_EVENT_ID_TIMING_CHANGE);

        HV_LOG_WARN(HDMI, "HDMI%d Timing Lost.",ucPortIndex);

        return HV_SUCCESS;
    }

    /* Get AVI Para and GCP */
    Hv_Drv_HdmiRx_GetAVIPara(ucPortIndex, &stVideoAVIPara, &pstHdmiData->stTimingPara);
    HDMI_ADD_EVENT_STAT(ucPortIndex, pstEvent->usEventId);

    /* Checking the Color Format and NotiFy Channel Manager */
    if(pstHdmiData->stColorPara.eClrFormat    != stVideoAVIPara.eClrFormat
        || pstHdmiData->stColorPara.eClrDepth != stVideoAVIPara.eClrDepth
        || pstHdmiData->stColorPara.eClrSpace != stVideoAVIPara.eClrSpace
        || pstHdmiData->stColorPara.eClrRange != stVideoAVIPara.eClrRange
        || pstHdmiData->stColorPara.eContent  != stVideoAVIPara.eContent)
    {
        /* Color Changed */
        HV_MEMCPY(&(pstHdmiData->stColorPara), &stVideoAVIPara, sizeof(VideoColorParam));

        NoticeChannelTimingChange(pstHdmiData, CHANNEL_EVENT_ID_COLOR_CHANGE);
        HV_INPUT_LOG_INFO(HDMI, "ColorFormat to %d with AVI", stVideoAVIPara.eClrFormat);
        Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + pstHdmiData->ucDataPortIndex, HOTFIX_HDMI_COLOR_CHG);

        return HV_FAILURE;
    }

    HV_INPUT_LOG_INFO(HDMI, "HDMI%d AVI Still.", ucPortIndex);

    return HV_FAILURE;
} 

Status Hv_Mw_HdmiRx_Sm_SPDPacketChangeHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HV_ASSERT_VALID_PTR(pstPortData);
    HdmiCtrlData* pstHdmiData = (HdmiCtrlData*)pstPortData;
    VRRInfoParam stVRRInfo    = {0,};
    UCHAR8 ucPortIndex        = (pstHdmiData->ucDataPortIndex);
    stVRRInfo.eVendor         = VendorType_UnKnown;

    HDMI_ADD_EVENT_STAT(ucPortIndex, InputPortEventId_HDMI_SPDChsChanged);

    /* 获取 SPD 内容*/
    HV_ASSERT_SUCCESS(Hv_Drv_HdmiRx_GetAMDVendSpecInfoPara(ucPortIndex, &stVRRInfo));
    if(stVRRInfo.eVendor == VendorType_AMD)
    {
        HV_MEMCPY(&(pstHdmiData->stVrrInfo), &stVRRInfo, sizeof(VRRInfoParam));
        pstHdmiData->bEnteredVRR = stVRRInfo.bVRREnable;

        SendEventToChannel(pstHdmiData, CHANNEL_EVENT_ID_RCV_VRR_INFO);

        HV_INPUT_LOG_INFO(HDMI,"##bEnteredVRR = %u,bVRREnable =%u", pstHdmiData->bEnteredVRR,stVRRInfo.bVRREnable);
#ifdef HV_INPUT_DETAIL_OPEN
        PrintAMDVSIFPara(&stVRRInfo);
#endif

        /* 延迟关闭VRR Timing Change Mode */
        if(pstHdmiData->bEnteredVRR)
        {
            Hv_Cal_HdmiRx_SetFrameRateTimingChange(ucPortIndex, pstHdmiData->bEnteredVRR);
            
            Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + pstHdmiData->ucDataPortIndex, HOTFIX_HDMI_VRR_ENTER);
        }
        else
        {
            Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + pstHdmiData->ucDataPortIndex, HOTFIX_HDMI_VRR_EXIT);
            if(0 == HV_COMMON_DATABASE_GET(UserData, ucFreeSync))
            {
                Hv_Cal_HdmiRx_SetFrameRateTimingChange(ucPortIndex, pstHdmiData->bEnteredVRR);
            }
        }

        return HV_CONTINUE;
    }
#if 0
    /* Nvdia GPU Card to check*/
    HV_ASSERT_SUCCESS(Hv_Cal_HdmiRx_GetSPDInfoPara(ucPortIndex, &stVRRInfo));
   
    if(stVRRInfo.eVendor == VendorType_NVIDIA)
    {
        HV_MEMCPY(&(pstHdmiData->stVrrInfo), &stVRRInfo, sizeof(VRRInfoParam));
    }
#endif
    return HV_CONTINUE;
} 

Status Hv_Mw_HdmiRx_Sm_RcvVSIPacketHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HdmiCtrlData* pstHdmiData   = (HdmiCtrlData*)pstPortData;
    BOOL bAllmMode              = HV_FALSE;

    HV_ASSERT_VALID_PTR(pstHdmiData);

    /* 检查是否为ALLM MODE指示 */
    if(Hv_Cal_HdmiRx_GetAllmModeInfo(pstHdmiData->ucDataPortIndex, &bAllmMode))
    {
        if(pstHdmiData->bEnterAllm != bAllmMode)
        {
            pstHdmiData->bEnterAllm = bAllmMode;
            SendEventToChannel(pstHdmiData, CHANNEL_EVENT_ID_ALLM_MODE_CHANGE);
        }

        HV_INPUT_LOG_INFO(HDMI, "HDMI%d ALLM Changed to: %d", pstHdmiData->ucDataPortIndex, bAllmMode);
    }

    HDMI_ADD_EVENT_STAT(pstHdmiData->ucDataPortIndex, InputPortEventId_HDMI_VSIPacketChange);

    return HV_CONTINUE;
}

Status Hv_Mw_HdmiRx_Sm_RcvEMPPacketHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HdmiCtrlData* pstHdmiData = (HdmiCtrlData*)pstPortData;
    HV_ASSERT_VALID_PTR(pstHdmiData);

    VRRInfoParam stVrrMdPara = {0,};
    UCHAR8 ucPortIndex = (pstHdmiData->ucDataPortIndex);

    /* 获取HDMI EMP */
    HV_ASSERT_SUCCESS(Hv_Drv_HdmiRx_GetMDVrrPara(ucPortIndex, &stVrrMdPara));

    if(stVrrMdPara.eVendor == VendorType_UnKnown)
    {
        return HV_SUCCESS;
    }

    if(pstHdmiData->bEnteredVRR != stVrrMdPara.bVRREnable)
    {
        pstHdmiData->bEnteredVRR = stVrrMdPara.bVRREnable;
        Hv_Cal_HdmiRx_SetFrameRateTimingChange(ucPortIndex, pstHdmiData->bEnteredVRR);
        SendEventToChannel(pstHdmiData, CHANNEL_EVENT_ID_RCV_VRR_INFO);

        if(pstHdmiData->bEnteredVRR)
        {
            Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + pstHdmiData->ucDataPortIndex, HOTFIX_HDMI_VRR_ENTER);
        }
        else
        {
            Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + pstHdmiData->ucDataPortIndex, HOTFIX_HDMI_VRR_EXIT);
        }

        HV_INPUT_LOG_INFO(HDMI,"EMP ##bEnteredVRR = %u,bVRREnable =%u", pstHdmiData->bEnteredVRR,stVrrMdPara.bVRREnable);
    }

    HV_MEMCPY(&(pstHdmiData->stVrrInfo), &stVrrMdPara, sizeof(VRRInfoParam));

    /* Timing Ready 后收到才会重新计算 */
    if(stVrrMdPara.bVRREnable && pstHdmiData->enCurrentPortState == INPUT_PORT_STATE_DISPLAY_RDY)
    {
        CaculateTimingWithEMP(pstHdmiData);
    }
#ifdef HV_INPUT_DEBUG_OPEN
    PrintEMPInfo(&(stVrrMdPara.uvsi.stCommVRRinMD));
#endif
    HDMI_ADD_EVENT_STAT(ucPortIndex, InputPortEventId_HDMI_EMPPacketRcv);

    return HV_CONTINUE;
}

Status Hv_Mw_HdmiRx_Sm_AudioPacketChangeHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HdmiCtrlData* pstHdmiData = (HdmiCtrlData*)pstPortData;
    HV_ASSERT_VALID_PTR(pstHdmiData);
    AudioPara stAudioPara     = {0,};

    Hv_Drv_HdmiRx_GetAudioPara(pstHdmiData->ucDataPortIndex, &stAudioPara);

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_Sm_RcvHDRPacketHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HdmiCtrlData* pstHdmiData   = (HdmiCtrlData*)pstPortData;
    HV_ASSERT_VALID_PTR(pstHdmiData);

    HDRParam stHDRPara          = {0};
    UCHAR8 ucPortIndex          = pstHdmiData->ucDataPortIndex;

    /* 获取HDR Type etc */
    Hv_Drv_HdmiRx_GetHDRPara(ucPortIndex, &stHDRPara);

    SendEventToChannel(pstHdmiData, CHANNEL_EVENT_ID_HDR_CHANGED);
    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + pstHdmiData->ucDataPortIndex, HOTFIX_HDMI_HDR_CHG);

    HV_MEMCPY(&(pstHdmiData->stHdrPara), &stHDRPara, sizeof(HDRParam));

    HV_INPUT_LOG_INFO(HDMI, "Have Received the HDR Type = %d for HDMI%d", stHDRPara.xType, ucPortIndex);

    HDMI_ADD_EVENT_STAT(ucPortIndex, InputPortEventId_HDMI_DRMPacketChange);

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_Sm_PacketErrorHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HdmiCtrlData* pstHdmiData = (HdmiCtrlData*)pstPortData;
    HV_ASSERT_VALID_PTR(pstHdmiData);

    UCHAR8 ucPortIndex = pstHdmiData->ucDataPortIndex;

    if(pstHdmiData->enCurrentPortState == INPUT_PORT_STATE_DISPLAY_RDY 
        || pstHdmiData->enCurrentPortState == INPUT_PORT_STATE_SYNC_OK)
    {
        /* 软件遮黑 */
        HdmiSetChannelMuteOn(pstHdmiData);

        /* 释放HDCP资源 */
        Hv_Mw_Hdcp_HdmiReAtherOnSync(pstHdmiData->enPortIndex, HV_TRUE);

        /* HDCP解密已近失败，直接通知Channel Manger遮黑然后推到Sync状态 */
        NoticeChannelTimingChange(pstHdmiData, CHANNEL_EVENT_ID_TIMING_CHANGE);
    }

    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + pstHdmiData->ucDataPortIndex, HOTFIX_HDMI_PKT_ERR);

    HV_LOG_WARN(HDMI, "HDMI%d RCV PE For HDCP.", ucPortIndex);

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_Sm_HdcpSyncTimerOutHandle(const InputPortEvent* pstEvent, VOID* pstPortData)
{
    HdmiCtrlData* pstHdmiData = (HdmiCtrlData*)pstPortData;
    HV_ASSERT_VALID_PTR(pstHdmiData);

    if(pstHdmiData->ucHdcpEncStatus == HdcpEncStatus_WaitSync)
    {
        pstHdmiData->ucHdcpEncStatus = HdcpEncStatus_NoneEnc;
    }

    HV_INPUT_LOG_INFO(HDMI, "HDMI%d RCV SyncTimerOut for HDCP.", pstHdmiData->ucDataPortIndex);

    return HV_SUCCESS;
}

BOOL Hv_Mw_HdmiRx_GetDviMode(LinkPortIndex enPortIndex)
{
    HdmiCtrlData* pstHdmiData = HV_Mw_HdmiRx_GetHdmiLinkData(enPortIndex);
    HV_ASSERT_VALID_PTR_RET(pstHdmiData, HV_FALSE);

    return Hv_Cal_HdmiRx_GetDviMode(pstHdmiData->ucDataPortIndex);
}

UINT32 Hv_Mw_HdmiRx_GetCurrentFrameRate(LinkPortIndex usLinkPortIndex)
{
    HdmiCtrlData* pstHdmiDataPtr = HV_Mw_HdmiRx_GetHdmiLinkData(usLinkPortIndex);

    HV_ASSERT_VALID_PTR(pstHdmiDataPtr);

    return Hv_Cal_HdmiRx_GetFrameRate(pstHdmiDataPtr->ucDataPortIndex);
}

Status Hv_Mw_HdmiRx_UpdateEdid(LinkPortIndex enPortIndex, EDIDType eEdidConfigure)
{
    HdmiCtrlData* pstHdmiDataPtr = HV_Mw_HdmiRx_GetHdmiLinkData(enPortIndex);    

    HV_ASSERT_VALID_PTR(pstHdmiDataPtr);

    if(EDID_TYPE_END <= (eEdidConfigure & (~EDID_TYPE_CLOSE_HDR)))
    {
        HV_LOG_ERROR(HDMI, "HDMI%d Configure a Invalid EDID Type.", pstHdmiDataPtr->ucDataPortIndex);

        return HV_FAILURE;
    }

    /* 使用用户自定义类型，不进行EDID更新 */
    if(pstHdmiDataPtr->enEdidConfiged == EDID_TYPE_USR_DEF && eEdidConfigure != EDID_TYPE_DEFAULT)
    {
        HV_INPUT_LOG_DEBUG(HDMI, "Use the definfed edid without any Update for HDMI%d.", pstHdmiDataPtr->ucDataPortIndex);

        return HV_FAILURE;
    }

    if(eEdidConfigure != pstHdmiDataPtr->enEdidConfiged || IsHdmiEdidInvalid(pstHdmiDataPtr))
    {
        pstHdmiDataPtr->enEdidConfiged = eEdidConfigure;

        if (HV_SUCCESS == WriteHdmiInnerEdid(pstHdmiDataPtr))
        {
            HV_LOG_WARN(HDMI, "Edid Update Success on HDMI%d type: %d.", pstHdmiDataPtr->ucDataPortIndex, eEdidConfigure);

            HdmiSetChannelMuteOn(pstHdmiDataPtr);

            /*更新完EDID，然后Toggle HPD*/
            ToggleHdmiHPD(enPortIndex, HDMI_HOT_PLUG_DET_CTL_TIMER_LENTH);

            HV_ASSERT_SUCCESS(SaveHdmiConfigureEdidType(pstHdmiDataPtr));

            Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + pstHdmiDataPtr->ucDataPortIndex, HOTFIX_HDMI_HDCP_EDID_UPDATE);

            return HV_SUCCESS;
        }
        else
        {
            pstHdmiDataPtr->enEdidConfiged = EDID_TYPE_DEFAULT;

            WriteHdmiInnerEdid(pstHdmiDataPtr);

            HV_LOG_ERROR(HDMI, "Edid Update Failed on HDMI%d type: %d.", pstHdmiDataPtr->ucDataPortIndex, eEdidConfigure);

            return HV_FAILURE;
        }
    }
    else
    {
        HV_INPUT_LOG_DEBUG(HDMI, "HDMI%d reconfigured same edid.", pstHdmiDataPtr->ucDataPortIndex);

        return HV_FAILURE;
    }
}

/* Used for Update EDID withou check Type and HPD, Used for Factory ParaUpdte */
Status Hv_Mw_HdmiRx_UpdateEdidRobust(LinkPortIndex enPortIndex)
{
    HdmiCtrlData* pstHdmiDataPtr = HV_Mw_HdmiRx_GetHdmiLinkData(enPortIndex);    

    HV_ASSERT_VALID_PTR(pstHdmiDataPtr);

    HV_ASSERT_SUCCESS(WriteHdmiInnerEdid(pstHdmiDataPtr));

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_CableDetCheck(UCHAR8 ucPortIndex)
{
    HdmiCtrlData*   pstHdmiData     = HV_Mw_HdmiRx_GetHdmiData(ucPortIndex);
    HV_VOS_QUEUE_S* xSystembQueue   = Hv_Mw_System_GetSystemQueue();
    BOOL            bCableDetect    = HV_FALSE;
    SystemEvent     stHdmiEvent     = {0,};

    HV_ASSERT_VALID_PTR(xSystembQueue);
    HV_ASSERT_VALID_PTR(pstHdmiData);

    if(pstHdmiData->bIdleStart == HV_FALSE)
    {
        return HV_SUCCESS;
    }

#if HDMI_ADAPT_NON_STANDARD
    bCableDetect = Hv_Cal_HdmiRx_GetCableConnectStatus(ucPortIndex);
#else
    bCableDetect = Hv_Drv_HdmiRx_GetCableStatus(ucPortIndex);
#endif

    if(bCableDetect != pstHdmiData->bIsCableConnected)
    {
        if(HV_SUCCESS != Hv_Drv_HdmiRx_CableConnectAction(ucPortIndex, bCableDetect))
        {
            return HV_FAILURE;
        }

        if(bCableDetect)
        {
            Hv_Cal_HdmiRx_InterruptInitEvent(ucPortIndex);

            stHdmiEvent.usEventId = InputPortEventId_HDMI_5VPlugIn;
            pstHdmiData->bIsCableConnected = HV_TRUE;
            InitHdmiDataPara(pstHdmiData);
        }
        else
        {
            HdmiRxIntStatus stInitStatus = {0x0, HV_HDMIRX_INT_2_EVENT_STANDBY_DDC};
            Hv_Cal_HdmiRx_InterruptClearEvent(ucPortIndex, &stInitStatus);

            stHdmiEvent.usEventId = InputPortEventId_HDMI_5VPlugOut;
            pstHdmiData->bIsCableConnected = HV_FALSE;
            InitHdmiDataPara(pstHdmiData);
        }

        stHdmiEvent.enEventType = SYSTEM_REV_EVENT_TYPE_INPUTPORT;
        stHdmiEvent.ucPortIndex = pstHdmiData->enPortIndex;

        Hv_Vos_QueueSendFromISR(xSystembQueue, (void *)&stHdmiEvent);
    }

    return HV_SUCCESS;
}

HV_VOS_ISR_RESULT_E Hv_Mw_HdmiRx_CableDetectISRHandle(UINT32 irqNum, void *arg)
{
    HdmiCtrlData*   pstHdmiDataPtr = (HdmiCtrlData*)arg;
    HV_VOS_QUEUE_S* xSystembQueue   = Hv_Mw_System_GetSystemQueue();
    SystemEvent     stHdmiEvent     = {0,};
    BOOL            bCableDetect    = HV_FALSE;
    UCHAR8          ucPortIndex     = 0;

    Hv_Vos_WClrMiscInt(irqNum - HV_CHIP_IRQ_BASE);

    HV_ASSERT_VALID_PTR_RET_NO_LOG(pstHdmiDataPtr, HV_VOS_ISR_HANDLED);
    HV_ASSERT_VALID_PTR_RET_NO_LOG(xSystembQueue, HV_VOS_ISR_HANDLED);

    ucPortIndex = pstHdmiDataPtr->ucDataPortIndex;

    /* 获取Cable值确认是插入还是拔出, True表示插入 */
    bCableDetect = Hv_Drv_HdmiRx_GetCableStatus(ucPortIndex);

    if(HV_SUCCESS != Hv_Drv_HdmiRx_CableConnectAction(ucPortIndex, bCableDetect))
    {
        return HV_VOS_ISR_HANDLED;
    }

    if(bCableDetect)
    {
        Hv_Cal_HdmiRx_InterruptInitEvent(ucPortIndex);

        stHdmiEvent.usEventId = InputPortEventId_HDMI_5VPlugIn;
        pstHdmiDataPtr->bIsCableConnected = HV_TRUE;

        Hv_Drv_HdmiRx_HPDCtrol(ucPortIndex, HV_TRUE);
        pstHdmiDataPtr->bHPDStatus = HV_TRUE;

        InitHdmiDataPara(pstHdmiDataPtr);
        
        Hv_Mw_Led_SetBlueLedNoData(HV_FALSE);  //led on
        Hv_Mw_Led_SetRedLedMode(HV_TRUE);      //led off
    }
    else
    {
        HdmiRxIntStatus stInitStatus = {0x0, HV_HDMIRX_INT_2_EVENT_STANDBY_DDC};
        Hv_Cal_HdmiRx_InterruptClearEvent(ucPortIndex, &stInitStatus);

        stHdmiEvent.usEventId = InputPortEventId_HDMI_5VPlugOut;
        pstHdmiDataPtr->bIsCableConnected = HV_FALSE;

        InitHdmiDataPara(pstHdmiDataPtr);
        
        Hv_Mw_Led_SetBlueLedNoData(HV_TRUE);  //led off
        Hv_Mw_Led_SetRedLedMode(HV_FALSE);    //led on
    }

    stHdmiEvent.enEventType = SYSTEM_REV_EVENT_TYPE_INPUTPORT;
    stHdmiEvent.ucPortIndex = pstHdmiDataPtr->enPortIndex;

    Hv_Vos_QueueSendFromISR(xSystembQueue, (void *)&stHdmiEvent);

    HDMI_ADD_EVENT_STAT(pstHdmiDataPtr->ucDataPortIndex, InputPortEventId_HDMI_Max);

    return HV_VOS_ISR_HANDLED;
}

HV_ATTR_ISR_SECTION HV_VOS_ISR_RESULT_E Hv_Mw_HdmiRx_IRQ_Handler(UINT32 irqNum, void *arg)
{
    HdmiRxInterruptEvent stIntEvent = {0,};
    HdmiCtrlData* pstHdmiDataPtr    = (HdmiCtrlData*)arg;
    UINT32 uiHdcpInterruptValue     = 0;
    UCHAR8 ucPortIndex              = 0;

    if(NULL == pstHdmiDataPtr)
    {
        Hv_Vos_WClrMiscInt(irqNum - HV_CHIP_IRQ_BASE);
        return HV_VOS_ISR_HANDLED;
    }

    ucPortIndex = pstHdmiDataPtr->ucDataPortIndex;

    if(Hv_Cal_HdmiRx_GetAviChangeEvent(ucPortIndex))
    {
        VideoColorParam stVideoAVIPara  = {0,};

        Hv_Drv_HdmiRx_GetAVIPara(ucPortIndex, &stVideoAVIPara, &(pstHdmiDataPtr->stTimingPara));

        if(pstHdmiDataPtr->stColorPara.eClrFormat != stVideoAVIPara.eClrFormat
            || pstHdmiDataPtr->stColorPara.eClrDepth != stVideoAVIPara.eClrDepth
            || pstHdmiDataPtr->stColorPara.eClrSpace != stVideoAVIPara.eClrSpace
            || pstHdmiDataPtr->stColorPara.eClrRange != stVideoAVIPara.eClrRange
            || pstHdmiDataPtr->stColorPara.eContent != stVideoAVIPara.eContent)
        {
            HdmiSetChannelMuteOn(pstHdmiDataPtr);
        }
    }

#if (HV_PROJECT_CONFIG_ESEGMENT == HV_CONFIG_ON)
    if(Hv_Cal_HdmiRx_IsEsegmentIsrRcved(ucPortIndex))
    {
        Hv_Cal_HdmiRx_UpdateEdidData(ucPortIndex, pstHdmiDataPtr->uiEdidLength, pstHdmiDataPtr->aucEdidData);
    }
#endif

    /*HDCP*/
    uiHdcpInterruptValue = Hv_Cal_HdmiRx_GetHdcpIsrStatus(ucPortIndex);
    if(0 != (uiHdcpInterruptValue & (BIT_13 | BIT_14)))
    {
        Hv_Cal_HdmiRx_ClearHDCPRxStatus(ucPortIndex);
    }

    if(0 != uiHdcpInterruptValue)
    {
        Hv_Mw_Hdcp_RxISRSndEvent(uiHdcpInterruptValue, pstHdmiDataPtr->enPortIndex, URGENT_REV_EVENT_TYPE_HDCP_HDMI);
    }

    /* HDMI */
    stIntEvent.ucPortIndex = pstHdmiDataPtr->ucDataPortIndex;

    Hv_Cal_HdmiRx_GetInterruptEvent(stIntEvent.ucPortIndex, &stIntEvent);

    Hv_Vos_WClrMiscInt(irqNum - HV_CHIP_IRQ_BASE);

    if ((stIntEvent.stHdmiIntRxStatus.uiIntrruptStatus1 & (HV_HDMIRX_INT_1_CHECK)) != 0
     || (stIntEvent.stHdmiIntRxStatus.uiIntrruptStatus2 & (HV_HDMIRX_INT_2_CHECK)) != 0)
    {
        if(stIntEvent.stHdmiIntRxStatus.uiIntrruptStatus2 & HV_HDMIRX_INT_2_EVENT_AVI_RCVED)
        {
            Hv_Cal_HdmiRx_SetHDCPHdmiMode(ucPortIndex, HV_TRUE);

            Hv_Cal_HdmiRx_SetHDCP1Xstatus(ucPortIndex, HV_TRUE);

            stIntEvent.stHdmiIntRxStatus.uiIntrruptStatus2 &= (~HV_HDMIRX_INT_2_EVENT_AVI_RCVED);
        }

        if(stIntEvent.stHdmiIntRxStatus.uiIntrruptStatus2 & HV_HDMIRX_INT_2_EVENT_STANDBY_DDC)
        {
            if (stIntEvent.usStbyIntrStatus & HV_HDMI_INT_3_EVENT_WRDATA_VALID)
            {
                HdmiSendDdcciMsg(ucPortIndex, DDCCI_EVENT_RCV);
            }

            if (stIntEvent.usStbyIntrStatus & HV_HDMI_INT_3_EVENT_READ_REQUEST)
            {
                Hv_Mw_HdmiRx_DdcciSend(ucPortIndex, NULL, 0, HV_TRUE);
            }

            if(stIntEvent.usStbyIntrStatus & HV_HDMI_INT_3_EVENT_CEC_RCV)
            {
                /*CEC Handle*/
                Hv_Drv_HdmiRx_CecRecvData(ucPortIndex);
            }

            stIntEvent.stHdmiIntRxStatus.uiIntrruptStatus2 &= (~HV_HDMIRX_INT_2_EVENT_STANDBY_DDC);
        }

#if (HV_PROJECT_CONFIG_FRL)
        if(stIntEvent.stHdmiIntRxStatus.uiIntrruptStatus1 & HV_HDMIRX_INT_1_EVENT_FRL_RATE_CHG)
        {
            pstHdmiDataPtr->ucHdmiFRLRate = Hv_Drv_HdmiFRLRateChange(ucPortIndex);
        }
#endif

        if (stIntEvent.stHdmiIntRxStatus.uiIntrruptStatus2 & HV_HDMIRX_INT_2_EVENT_TMDS_TIMING_CHG)
        {
            HdmiSetChannelMuteOn(pstHdmiDataPtr);
        }

        if(stIntEvent.stHdmiIntRxStatus.uiIntrruptStatus1 & HV_HDMIRX_INT_1_EVENT_AV_MUTE)
        {
            Hv_Cal_HdmiRx_SetAutoVmute(ucPortIndex);
            stIntEvent.stHdmiIntRxStatus.uiIntrruptStatus1 &= (~HV_HDMIRX_INT_1_EVENT_AV_MUTE);
        }

        if(stIntEvent.stHdmiIntRxStatus.uiIntrruptStatus1 & HV_HDMIRX_INT_1_EVENT_AUDIO_FIFO_UNDERFLOW)
        {
            pstHdmiDataPtr->bAudioAbnormal = HV_TRUE;

            //打开audio fifo start中断
            HdmiRxIntStatus stAudioPassIntEn = {HV_HDMIRX_INT_1_EVENT_AUDIO_FIFO_PASS, 0};

            Hv_Cal_HdmiRx_AddInterruptEvent(pstHdmiDataPtr->ucDataPortIndex, &stAudioPassIntEn);
        }

#if HDMI_AUDIO_MANUAL_CLK_OPEN
        if(stIntEvent.stHdmiIntRxStatus.uiIntrruptStatus1 & HV_HDMIRX_INT_1_EVENT_AUDIO_FIFO_MAX)
        {
            if(pstHdmiDataPtr->bEnterManualAudClk == HV_FALSE)
            {
                pstHdmiDataPtr->bEnterManualAudClk = HV_TRUE;
                Hv_Cal_HdmiRx_SwitchAudioManualClk(ucPortIndex, HV_TRUE);
            }

            pstHdmiDataPtr->usLastOverValue = HV_Cal_HdmiRx_ManualCtsValueSet(ucPortIndex, HV_FALSE, pstHdmiDataPtr->usLastOverValue, pstHdmiDataPtr->usLastUnderValue);
            pstHdmiDataPtr->usLastUnderValue = 0;
            stIntEvent.stHdmiIntRxStatus.uiIntrruptStatus1 &= (~HV_HDMIRX_INT_1_EVENT_AUDIO_FIFO_MAX);
        }

        if(stIntEvent.stHdmiIntRxStatus.uiIntrruptStatus1 & HV_HDMIRX_INT_1_EVENT_AUDIO_FIFO_MIN)
        {
            if(pstHdmiDataPtr->bEnterManualAudClk == HV_FALSE)
            {
                pstHdmiDataPtr->bEnterManualAudClk = HV_TRUE;
                Hv_Cal_HdmiRx_SwitchAudioManualClk(ucPortIndex, HV_TRUE);
            }

            pstHdmiDataPtr->usLastUnderValue = HV_Cal_HdmiRx_ManualCtsValueSet(ucPortIndex, HV_TRUE, pstHdmiDataPtr->usLastOverValue, pstHdmiDataPtr->usLastUnderValue);
            pstHdmiDataPtr->usLastOverValue = 0;
            stIntEvent.stHdmiIntRxStatus.uiIntrruptStatus1 &= (~HV_HDMIRX_INT_1_EVENT_AUDIO_FIFO_MIN);
        }
#endif
        /*检查是否有Rx Interrupt 事件上报*/
        if((stIntEvent.stHdmiIntRxStatus.uiIntrruptStatus1 == 0)
        && (stIntEvent.stHdmiIntRxStatus.uiIntrruptStatus2 == 0))
        {
            return HV_VOS_ISR_HANDLED;
        }
        else
        {
            SystemEvent stHdmiEvent = {0};
            HDMIRxQueueElem *pstIntQueueElem;
            HV_VOS_QUEUE_S* xSystembQueue = Hv_Mw_System_GetSystemQueue();

            stHdmiEvent.ucPortIndex = ucPortIndex;
            stHdmiEvent.enEventType = SYSTEM_REV_EVENT_TYPE_INPUTPORT;
            stHdmiEvent.usEventId = InputPortEventId_HDMI_IntGen;
        
            /*HDMI 中断事件分发*/
            pstIntQueueElem = HDMIRxQueueSafeQueueEnqueue(&g_stHdmiRxQueue, 
                                (VOID*)&(stIntEvent.stHdmiIntRxStatus), sizeof(HdmiRxIntStatus));
            if (NULL == pstIntQueueElem)
            {
                return HV_VOS_ISR_NOT_HANDLED;
            }

            stHdmiEvent.buffer = pstIntQueueElem->ucBuffer;
            if (NULL == xSystembQueue || HV_TRUE != Hv_Vos_QueueSendFromISR(xSystembQueue, (void *)&stHdmiEvent))
            {
                return HV_VOS_ISR_NOT_HANDLED;
            }
        }
    }

    HDMI_ADD_EVENT_STAT(pstHdmiDataPtr->ucDataPortIndex, InputPortEventId_HDMI_IntGen);

    return HV_VOS_ISR_HANDLED;
}

Status Hv_Mw_HdmiRx_InterruptInit(LinkPortIndex enPortIndex)
{
    UINT32 uiCableIrqIndex       = HV_CHIP_IRQ_RX_CABLE2;
    UINT32 uiHdmiIrqIndex        = HV_CHIP_IRQ_RX_HDMI_0;
    HdmiCtrlData* pstHdmiDataPtr = HV_Mw_HdmiRx_GetHdmiLinkData(enPortIndex);

    HV_ASSERT_VALID_PTR(pstHdmiDataPtr);

    if(pstHdmiDataPtr->ucDataPortIndex == 1)
    {
        uiCableIrqIndex = HV_CHIP_IRQ_RX_CABLE3;
        uiHdmiIrqIndex = HV_CHIP_IRQ_RX_HDMI_1;
    }

    /* 初始化HDMI Cable中断 */
    Hv_Vos_ConfigIrq(uiCableIrqIndex , HV_TRUE, 0);
    Hv_Vos_AttachIsr(uiCableIrqIndex, Hv_Mw_HdmiRx_CableDetectISRHandle, (void*)(pstHdmiDataPtr));
    HV_INPUT_LOG_DEBUG(HDMI, "Now Hv_Mw_HdmiCableDetectISRHandle attach HDMI%d Success.",pstHdmiDataPtr->ucDataPortIndex);

    /* 初始化HDMI中断 */
    Hv_Vos_ConfigIrq(uiHdmiIrqIndex , HV_TRUE, 0);
    Hv_Vos_AttachIsr(uiHdmiIrqIndex, Hv_Mw_HdmiRx_IRQ_Handler, (void*)(pstHdmiDataPtr));
    HV_INPUT_LOG_DEBUG(HDMI, "Now Hv_Mw_HdmiISRHandle attach HDMI%d Success.", pstHdmiDataPtr->ucDataPortIndex);

    return HV_SUCCESS;
}

Status Hv_Mw_HDMI_Init(HDMIManager* pstHDMIManager)
{
    UCHAR8        ucPortIndex = 0;
    HdmiCtrlData* pstHdmiData = NULL;
    CHAR8  acManufactStr[8] = {HV_PROJECT_CONFIG_HDMI_SCDC_DEVICE_STR};

    HV_ASSERT_VALID_PTR(pstHDMIManager);
    /*初始化消息队列*/
    HDMIRxQueueSafeQueueInit(&g_stHdmiRxQueue);

    /* 初始化接口函数 */
    pstHDMIManager->pfHPDToggle                 = ToggleHdmiHPDInterface;
    pstHDMIManager->pfGetVideoPara              = GetHdmiCurrentVideoPara;
    pstHDMIManager->pfGetSourceVendorInfo       = GetHdmiSourceVendorInfo;
    pstHDMIManager->pfGetAudioStatus            = GetHdmiAudioCurrentStatus;
    pstHDMIManager->pfUpdateEdid                = Hv_Mw_HdmiRx_UpdateEdid;
    pstHDMIManager->pfGetCurrentFrameRate       = Hv_Mw_HdmiRx_GetCurrentFrameRate;
    pstHDMIManager->pfGetEdidData               = GetHdmiEdidData;
    pstHDMIManager->pfStartAudio                = StartHdmiAudio;
    pstHDMIManager->pfStopAudio                 = StopHdmiAudio;
    pstHDMIManager->pfReset                     = ResetHdmiMac;
    pstHDMIManager->pfGetPortErrorCode          = GetHdmiCurrentCEDValue;
    pstHDMIManager->pfHPDAction                 = SwitchHdmiHPDStatus;
    
#if (HV_BOARD_CONFIG_HDMI_0 == PORT_VALID)
    pstHDMIManager->astHdmiData[0].enPortIndex = LINK_PORT_INDEX_HDMI_RX0;
    pstHdmiData = &((pstHDMIManager->astHdmiData)[0]);
    /* 配置 portindex 与 linkportindex 的映射 */
    pstHdmiData->ucDataPortIndex = 0;
    InitHdmiDataTimer(pstHdmiData);
    pstHdmiData->bIsCableConnected = HV_FALSE;
    pstHdmiData->bIdleStart = HV_FALSE;
    pstHdmiData->bEnterManualAudClk = HV_FALSE;
    pstHdmiData->bAudioAbnormal = HV_FALSE;
    pstHdmiData->bEnterEQBypassMode = HV_FALSE;
    pstHdmiData->usLastUnderValue = 0;
    pstHdmiData->usLastOverValue = 0;
    pstHdmiData->bEnterLowBnd = HV_FALSE;
    pstHdmiData->bInRobustRatio = HV_FALSE;
    pstHdmiData->ucEqStatus = HdmiEqStatus_Init;

    pstHdmiData->ucWaitSyncTimerOutCnt = 0x0;
    pstHdmiData->ucEQInitValue = 0x8;
    pstHdmiData->ucLaneLockTimes = 0;
    pstHdmiData->ucEqSwTable = 0;
    HV_MEMSET(pstHdmiData->ausPreEqTable, 0x0, sizeof(pstHdmiData->ausPreEqTable));
    pstHdmiData->ucGrearMode = E_UNLOCKED;

    InitHdmiDataPara(pstHdmiData);
    /* 初始化各个端口状态为IDLE态 */
    pstHdmiData->enCurrentPortState = INPUT_PORT_STATE_IDLE;
    /* 每个口的初始化 */
    Hv_Drv_HdmiRx_PortInit(0);

    Hv_Cal_HdmiRx_InitSCDCManuFactor(0, acManufactStr, HV_PROJECT_CONFIG_MANUFACT_OUI);
    pstHdmiData->enEdidConfiged = GetHdmiConfiguredEdidType(0);
    /* 检查配置EDID */
    if ((pstHdmiData->enEdidConfiged & (~EDID_TYPE_CLOSE_HDR)) >= EDID_TYPE_END)
    {
        pstHdmiData->enEdidConfiged = EDID_TYPE_DEFAULT;
        SaveHdmiConfigureEdidType(pstHdmiData);
    }
    WriteHdmiInnerEdid(pstHdmiData);

    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0, HOTFIX_HDMI_INIT);
#endif
#if (HV_BOARD_CONFIG_HDMI_1 == PORT_VALID)
    if(HV_BOARD_CONFIG_HDMI_0 == PORT_VALID)
    {
        ucPortIndex = 1;
    }
    else
    {
        ucPortIndex = 0;
    }
    pstHDMIManager->astHdmiData[ucPortIndex].enPortIndex = LINK_PORT_INDEX_HDMI_RX1;
    pstHdmiData = &((pstHDMIManager->astHdmiData)[ucPortIndex]);
    
    /* 配置 portindex 与 linkportindex 的映射 */
    pstHdmiData->ucDataPortIndex = 1;

    InitHdmiDataTimer(pstHdmiData);

    pstHdmiData->bIsCableConnected = HV_FALSE;
    pstHdmiData->bIdleStart = HV_FALSE;
    pstHdmiData->bEnterManualAudClk = HV_FALSE;
    pstHdmiData->bAudioAbnormal = HV_FALSE;
    pstHdmiData->usLastUnderValue = 0;
    pstHdmiData->usLastOverValue = 0;
    pstHdmiData->bEnterLowBnd = HV_FALSE;
    pstHdmiData->bInRobustRatio = HV_FALSE;
    pstHdmiData->ucEqStatus = HdmiEqStatus_Init;

    pstHdmiData->ucWaitSyncTimerOutCnt = 0x0;
    pstHdmiData->ucEQInitValue = 0x8;
    pstHdmiData->ucLaneLockTimes = 0;
    pstHdmiData->ucEqSwTable = 0;
    HV_MEMSET(pstHdmiData->ausPreEqTable, 0x0, sizeof(pstHdmiData->ausPreEqTable));

    pstHdmiData->ucGrearMode = E_UNLOCKED;

    InitHdmiDataPara(pstHdmiData);

    /* 初始化各个端口状态为IDLE态 */
    pstHdmiData->enCurrentPortState = INPUT_PORT_STATE_IDLE;

    /* 每个口的初始化 */
    Hv_Drv_HdmiRx_PortInit(1);

    Hv_Cal_HdmiRx_InitSCDCManuFactor(1, acManufactStr, HV_PROJECT_CONFIG_MANUFACT_OUI);

    pstHdmiData->enEdidConfiged = GetHdmiConfiguredEdidType(1);

    /* 检查配置EDID */
    if ((pstHdmiData->enEdidConfiged & (~EDID_TYPE_CLOSE_HDR)) >= EDID_TYPE_END)
    {
        pstHdmiData->enEdidConfiged = EDID_TYPE_DEFAULT;
        SaveHdmiConfigureEdidType(pstHdmiData);
    }

    WriteHdmiInnerEdid(pstHdmiData);

    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + ucPortIndex, HOTFIX_HDMI_INIT);
#endif

    HV_INPUT_LOG_DEBUG(HDMI,"Hv_Mw_InputPortHDMIInit SUCCESS.");

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_DdcciSend(LinkPortIndex enPortIndex, UCHAR8 *pucData, UINT32 uiLen, BOOL bInIrq)
{
    static UINT32 uiRemainLen;
    static UINT32 uiOffset;
    static UCHAR8 *pucSendData;
    UCHAR8 ucPort;
    UCHAR8 ucCurSendLen;

    if (enPortIndex != LINK_PORT_INDEX_HDMI_RX0 && enPortIndex != LINK_PORT_INDEX_HDMI_RX1)
    {
        HV_LOG_ERROR(HDMI, "HDMI port %d error when send ddc", enPortIndex);
        return HV_FAILURE;
    }
    ucPort = enPortIndex == LINK_PORT_INDEX_HDMI_RX0 ? 0 : 1;

    if (!bInIrq)
    {
        // 上位机意外退出时，释放上一次的buffer
        if (pucSendData)
        {
            HV_FREE(pucSendData);
            pucSendData = NULL;
        }
        
        uiRemainLen = uiLen;
        uiOffset = 0;
        pucSendData = HV_MALLOC(uiRemainLen);
        if (!pucSendData)
        {
            HV_LOG_ERROR(HDMI, "HDMI alloc %u error when send ddc", uiRemainLen);
            return HV_FAILURE;
        }
        HV_MEMCPY(pucSendData, pucData, uiRemainLen);
    }
    else
    {
        if (!uiRemainLen)
        {
            // send over
            if (pucSendData)
            {
                HV_FREE(pucSendData);
                pucSendData = NULL;
            }

            // clear reg
            Hv_Cal_HdmiRx_ClrDdcSendReg(ucPort);
            return HV_SUCCESS;
        }
    }

    ucCurSendLen = uiRemainLen <= DMAX_DDC_MSG_CACHE_NUM ? uiRemainLen : DMAX_DDC_MSG_CACHE_NUM;

    Hv_Drv_HdmiRx_DdcSend(ucPort, pucSendData + uiOffset, ucCurSendLen);
    uiRemainLen -= ucCurSendLen;
    uiOffset += ucCurSendLen;
    
    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_DDCCIHPDControl(USHORT16 usLinkPortIndex, BOOL bHPDSwitch)
{
    HdmiCtrlData* pstHdmiData = HV_Mw_HdmiRx_GetHdmiLinkData(usLinkPortIndex);
    HV_ASSERT_VALID_PTR(pstHdmiData);
    UCHAR8 ucPortIndex        = pstHdmiData->ucDataPortIndex;

    HV_INPUT_LOG_INFO(HDMI,"HPD DDCCI On HDMI%d Switch to:%s", ucPortIndex, bHPDSwitch ? "ON" : "OFF");

    HV_ASSERT_SUCCESS(SwitchHPDControlStatus(pstHdmiData, bHPDSwitch));

    pstHdmiData->bHPDStatus = bHPDSwitch;

    return HV_SUCCESS;
}

UCHAR8 Hv_Mw_HdmiRx_GetHdmiVersion(LinkPortIndex enPortIndex)
{
    UCHAR8 ucHdmiVersion = HV_COMMON_DATABASE_GET(UserData, ucHDMIVersion);

    return ucHdmiVersion;
}

Status Hv_Mw_HdmiRx_ModifyHdmiVersion(LinkPortIndex enPortIndex, HdmiVersion eHdmiVersion)
{
    HdmiCtrlData* pstHdmiData = HV_Mw_HdmiRx_GetHdmiLinkData(enPortIndex);
    HV_ASSERT_VALID_PTR_RET(pstHdmiData, HV_FALSE);

    UCHAR8 ucHdmiVersion = eHdmiVersion;

    HV_COMMON_DATABASE_SET(UserData, ucHDMIVersion, ucHdmiVersion);

    Hv_Mw_HdmiRx_Sm_ChangeHdmiVersionHandle(NULL, pstHdmiData);

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_SetHdmiEdid(LinkPortIndex enPortIndex, const UCHAR8 *paucHdmiEdid, USHORT16 usLen)
{
    HdmiCtrlData* pstHdmiData   = HV_Mw_HdmiRx_GetHdmiLinkData(enPortIndex);
    HdmiEdidDBRegion *pstEdidDb = enPortIndex == LINK_PORT_INDEX_HDMI_RX0 ? Hv_Common_Db_GetHdmiEdidDBRegionPtr() : Hv_Common_Db_GetHdmi1EdidDBRegionPtr();

    HV_ASSERT_VALID_PTR(pstHdmiData);
    HV_ASSERT_VALID_PTR(pstEdidDb);
    HV_ASSERT_VALID_PTR(paucHdmiEdid);

    if(usLen > HV_HDMI_MAX_EDID_LENTH)
    {
        return HV_FAILURE;
    }

    if(0 == usLen)
    {
        /* 关闭用户自定义EDID，重启后，正常使用配置分区内EDID */
        Hv_Vos_TaskEnterCritical();
        (pstEdidDb->astHdmiEdid[0]).eEdidType = EDID_TYPE_DEFAULT;
        Hv_Vos_TaskExitCritical();

        Hv_Mw_HdmiRx_UpdateEdid(enPortIndex, EDID_TYPE_DEFAULT);
    }
    else
    {
        /* 使用用户自定义EDID，配置后，不在进行其他EDID更新，自动忽略掉所有更新 */
        Hv_Vos_TaskEnterCritical();
        (pstEdidDb->astHdmiEdid[0]).eEdidType = EDID_TYPE_USR_DEF;
        (pstEdidDb->astHdmiEdid[0]).uiEdidLen = usLen;

        HV_MEMCPY((pstEdidDb->astHdmiEdid[0]).acEdid, paucHdmiEdid, usLen);

        pstEdidDb->bModifyFlag = HV_TRUE;

        Hv_Vos_TaskExitCritical();

        /* 更新到EDID分区 */
        Hv_Mw_DataBase_Sync();

        Hv_Mw_HdmiRx_UpdateEdid(enPortIndex, EDID_TYPE_USR_DEF);
    }

    return HV_SUCCESS;
}

USHORT16 Hv_Mw_HdmiRx_GetHdmiEdid(LinkPortIndex enPortIndex, UCHAR8 *paucHdmiEdid)
{
    HdmiCtrlData* pstHdmiData = HV_Mw_HdmiRx_GetHdmiLinkData(enPortIndex);

    HV_ASSERT_VALID_PTR_RET(pstHdmiData, HV_FALSE);
    HV_ASSERT_VALID_PTR_RET(paucHdmiEdid, HV_FALSE);

    HV_MEMCPY(paucHdmiEdid, pstHdmiData->aucEdidData, pstHdmiData->uiEdidLength);

    return (USHORT16)(pstHdmiData->uiEdidLength);
}

Status Hv_Mw_HdmiRx_SwitchAllmMode(BOOL bAllmSwitch)
{
    HV_INPUT_LOG_INFO(HDMI, "Switch the Allm Mode to:%s.", bAllmSwitch ? "Open" : "Close");
    HV_COMMON_DATABASE_SET(UserData, bHdmiAllmEn, bAllmSwitch);
    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_SwitchQmsMode(BOOL bQmsSwitch)
{
    HV_INPUT_LOG_INFO(HDMI, "Switch the QMS Mode to:%s.", bQmsSwitch ? "Open" : "Close");
    HV_COMMON_DATABASE_SET(UserData, bQms, bQmsSwitch);
    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_SetHdcpStatus(LinkPortIndex enPortIndex, HdcpEncStatus enHdcpStatus)
{
    HdmiCtrlData* pstHdmiData = HV_Mw_HdmiRx_GetHdmiLinkData(enPortIndex);

    HV_ASSERT_VALID_PTR_RET(pstHdmiData, HV_FALSE);

    pstHdmiData->ucHdcpEncStatus = enHdcpStatus;

    Hv_Vos_Timer_Rstop(pstHdmiData->pstHdcpSyncTimer);
    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + pstHdmiData->ucDataPortIndex, HOTFIX_HDMI_HDCP_SYNC);

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_SetFreeSyncMccsCfg(LinkPortIndex enPortIndex, UCHAR8 ucMccsFreeSyncCfg)
{
    HdmiCtrlData* pstHdmiData = HV_Mw_HdmiRx_GetHdmiLinkData(enPortIndex);

    HV_ASSERT_VALID_PTR_RET(pstHdmiData, HV_FALSE);

    if(pstHdmiData->ucMccsFreeSyncStatus != ucMccsFreeSyncCfg)
    {
        pstHdmiData->ucMccsFreeSyncStatus = ucMccsFreeSyncCfg;

        if(ucMccsFreeSyncCfg == 0)
        {
            pstHdmiData->bEnteredVRR = HV_FALSE;
        }
        else
        {
            pstHdmiData->bEnteredVRR = HV_TRUE;
        }

        SendEventToChannel(pstHdmiData, CHANNEL_EVENT_ID_RCV_VRR_INFO);
    }

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_AudioCheck(LinkPortIndex enPortIndex)
{
    HdmiCtrlData *pstHdmiData = HV_Mw_HdmiRx_GetHdmiLinkData(enPortIndex);

    HV_ASSERT_VALID_PTR(pstHdmiData);

    Hv_Drv_HdmiRx_AudioCheck(pstHdmiData->ucDataPortIndex);

    return HV_SUCCESS;
}

Status Hv_Mw_HdmiRx_Sm_AudioStartHandle(const InputPortEvent *pstEvent, VOID *pstPortData)
{
    HdmiCtrlData *pstHdmiData = (HdmiCtrlData *)pstPortData;
    UINT32 uiCts, uiN;
    HdmiRxIntStatus stHdmiIntRxStatus = { 0, 0};

    HV_ASSERT_VALID_PTR(pstHdmiData);

    Hv_Cal_HdmiRx_GetAudioCurrentCTSN(pstHdmiData->ucDataPortIndex, &uiCts, &uiN);
    if (uiCts != 0 && uiN != 0)
    {
        SendEventToChannel(pstHdmiData, CHANNEL_EVENT_ID_AUDIO_FS_CHANGE);
        HV_INPUT_LOG_INFO(HDMI, "hdmi%u cts/n valid, audio unmute", pstHdmiData->ucDataPortIndex);
    }
    else
    {
        HV_LOG_WARN(HDMI, "hdmi%u cts/n int occur, but val invalid", pstHdmiData->ucDataPortIndex);
    }
    
    return HV_SUCCESS;
}

VOID Hv_Mw_HdmiRx_GetAudioCurrentCTSN(LinkPortIndex enPortIndex, UINT32 *puiCTS, UINT32 *puiN)
{
    HdmiCtrlData *pstHdmiData = HV_Mw_HdmiRx_GetHdmiLinkData(enPortIndex);
    HV_ASSERT_VALID_PTR_VOID(pstHdmiData);
    HV_ASSERT_VALID_PTR_VOID(puiCTS);
    HV_ASSERT_VALID_PTR_VOID(puiN);

    return Hv_Cal_HdmiRx_GetAudioCurrentCTSN(pstHdmiData->ucDataPortIndex, puiCTS, puiN);
}

BOOL Hv_Mw_HdmiRx_GetAllmMode(LinkPortIndex enPortIndex)
{
    BOOL bAllmMode = HV_FALSE;
    HdmiCtrlData *pstHdmiData = HV_Mw_HdmiRx_GetHdmiLinkData(enPortIndex);
    HV_ASSERT_VALID_PTR_RET(pstHdmiData, HV_FALSE);

    if(pstHdmiData->enCurrentPortState != INPUT_PORT_STATE_DISPLAY_RDY)
    {
        HV_INPUT_LOG_INFO(HDMI, "HDMI%d Current Status is not Ready.", pstHdmiData->ucDataPortIndex);
        return HV_FALSE;
    }

    /* 该函数返回值表示HDMI指示ALLM，如果返回False，表示无指示，不需要处理 */
    return Hv_Cal_HdmiRx_GetAllmModeInfo(pstHdmiData->ucDataPortIndex, &bAllmMode);
}

Status Hv_Mw_HdmiRx_SwitchCECFunc(LinkPortIndex enPortIndex, BOOL bCecSwitch)
{
    HdmiCtrlData *pstHdmiData = HV_Mw_HdmiRx_GetHdmiLinkData(enPortIndex);
    HV_ASSERT_VALID_PTR(pstHdmiData);

    if(bCecSwitch)
    {
        Hv_Cal_HdmiRx_StartRcvCecMsg(pstHdmiData->ucDataPortIndex);
        Hv_Cal_HdmiRx_SwitchCECFunc(pstHdmiData->ucDataPortIndex, HV_TRUE);
    }
    else
    {
        Hv_Cal_HdmiRx_SwitchCECFunc(pstHdmiData->ucDataPortIndex, HV_FALSE);
    }

    return HV_SUCCESS;
}

