/**
 * @file hv_mw_Dprx.c
 * @brief MiddleWare dp rx c file.
 * @details This file provides the following functions: \n
 *          (1) Initialization and reset functions \n
 *          (2) Write and read EDID functions \n
 *          (3) Write and read DPCD functions \n
 *          (4) Cable detect function \n
 *          (5) Irq related functions \n
 *          (6) Link related functions \n
 *          (7) Timing related functions \n
 *          (7) Event analyze functions \n *
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2022-08-23
 * @copyright Copyright(c),2022-8, Hiview Software. All rights reserved.
 * @par History:
 * <table>
 * <tr><th>Author         <th>Date        <th>Change Description
 * <tr><td>dp group      <td>2022-08-23   <td>init
 * </table>
*/
#include "hv_comm_Event.h"
#include "hv_comm_Assert.h"
#include "hv_vos_Comm.h"
#include "hv_chip_Config.h"

#include "FreeRTOS.h"
#include "timers.h"
#include "task.h"

#include "hv_drv_Ktx.h"
#include "hv_drv_DisplayPort.h"
#include "hv_drv_Physical.h"
#include "hv_drv_DpuCommon.h"
#include "hv_drv_DpuMainMute.h"

#include "hv_mw_Ddcci.h"
#include "hv_mw_InputPortManager.h"
#ifdef CONFIG_USER_TYPE_C_ON
#include "hv_mw_TypecTask.h"
#endif
#include "hv_mw_DisplayPort.h"
#include "hv_mw_Hdcp.h"
#include "hv_mw_SystemManager.h"
#include "hv_mw_Channel_Manager.h"
#include "hv_mw_Audio.h"
#include "hv_cal_Audio.h"

#define DP_HPD_PULSE                           800    /* HPD low last 800ms */
#define DP_TRAINING_NG_TIME                    3000   /* Training timeout thd is 3000 */
#define DP_TIMING_CHECK_CYCLE                  500    /* check for timing stable every 500ms */
#define DP_FREQ_THD                            200    /* KHz */
#define DP_Audio_CHECK_CYCLE                   10

#define DP_AUTO_LINK_TRAINING                  0x0
#define DP_FULL_LINK_TRAINING                  0x3

DEFINE_HS_SAFE_QUEUE(DpQueue, 20, sizeof(DpRxIntStatus));
static DpQueue s_stDpQueue;

static DisplayPortCtrlData *GetFromPortID(UCHAR8 ucPortId)
{
    InputPortManager* pstInputPortManager = Hv_Mw_InputPort_GetManagerPtr();
    HV_ASSERT_TRUE_RET(ucPortId <= HV_BOARD_CONFIG_MAX_DP_PORT_NUM, NULL);
    if(ucPortId == 0)
    {
        return &(pstInputPortManager->stDisplayPortManager.astDpCtrl[ucPortId]);
    }
    else
    {
        if (HV_BOARD_CONFIG_DISPLAYPORT_0 == PORT_VALID)
        {
            return &(pstInputPortManager->stDisplayPortManager.astDpCtrl[ucPortId]);
        }
        else
        {
            return &(pstInputPortManager->stDisplayPortManager.astDpCtrl[0]);
        }
    }
}

static DisplayPortCtrlData *GetFromLinkPort(LinkPortIndex enLinkPortIndex)
{
    InputPortManager* pstInputPortManager = Hv_Mw_InputPort_GetManagerPtr();
    UCHAR8 ucPortIndex = 0;

    for (ucPortIndex = 0; ucPortIndex < HV_BOARD_CONFIG_MAX_DP_PORT_NUM; ucPortIndex++)
    {
        if (pstInputPortManager->stDisplayPortManager.astDpCtrl[ucPortIndex].enPortIndex == enLinkPortIndex)
        {
            return &(pstInputPortManager->stDisplayPortManager.astDpCtrl[ucPortIndex]);
        }
    }

    return NULL;
}

static VOID FwInsertBlack(UCHAR8 ucPortId)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromPortID(ucPortId);
    HV_ASSERT_VALID_PTR_VOID_NO_LOG(pstDpCtrl);
    ChanelSignalState enChannelState = ChanelSignalState_Invalid;
    LinkPortIndex enLinkPortIndex = LINK_PORT_INDEX_INVALID;

    if(Hv_Mw_InputPort_GetChannelBindPortIndex(CHANNEL_TYPE_MAIN) == pstDpCtrl->enPortIndex)
    {
        Hv_Mw_Channel_GetSignalState(CHANNEL_TYPE_MAIN, &enLinkPortIndex, &enChannelState);
        if (ChanelSignalState_SignalSync == enChannelState)
        {
            Hv_Mw_Channel_MuteOn(CHANNEL_TYPE_MAIN);
        }
    }

#ifdef CONFIG_USER_DOUBLE_CHANNEL_ON
    if (Hv_Mw_InputPort_GetChannelBindPortIndex(CHANNEL_TYPE_SUB) == pstDpCtrl->enPortIndex)
    {
        Hv_Mw_Channel_GetSignalState(CHANNEL_TYPE_MAIN, &enLinkPortIndex, &enChannelState);
        if (ChanelSignalState_SignalSync == enChannelState)
        {
            Hv_Mw_Channel_MuteOn(CHANNEL_TYPE_SUB);
        }
    }
#endif

    return;
}

static VOID FwClrBlack(UCHAR8 ucPortId)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromPortID(ucPortId);
    HV_ASSERT_VALID_PTR_VOID_NO_LOG(pstDpCtrl);
    ChanelSignalState enChannelState = ChanelSignalState_Invalid;
    LinkPortIndex enLinkPortIndex = LINK_PORT_INDEX_INVALID;

    if (Hv_Mw_InputPort_GetChannelBindPortIndex(CHANNEL_TYPE_MAIN) == pstDpCtrl->enPortIndex)
    {
        Hv_Mw_Channel_GetSignalState(CHANNEL_TYPE_MAIN, &enLinkPortIndex, &enChannelState);
        if (ChanelSignalState_SignalSync == enChannelState)
        {
            Hv_Mw_Channel_MuteOff(CHANNEL_TYPE_MAIN);
        }
    }

#ifdef CONFIG_USER_DOUBLE_CHANNEL_ON
    if (Hv_Mw_InputPort_GetChannelBindPortIndex(CHANNEL_TYPE_SUB) == pstDpCtrl->enPortIndex)
    {
        Hv_Mw_Channel_GetSignalState(CHANNEL_TYPE_MAIN, &enLinkPortIndex, &enChannelState);
        if (ChanelSignalState_SignalSync == enChannelState)
        {
            Hv_Mw_Channel_MuteOff(CHANNEL_TYPE_SUB);
        }
    }
#endif

    return;
}

#ifdef HV_SCALER_DEBUG_VERSION
VOID Hv_Mw_DpRx_PrintTimingInfo(VideoTimingParam *pstVideoTiming)
{
    HV_ASSERT_VALID_PTR_VOID(pstVideoTiming);

    HV_LOG_INFO(DP,"****************DP Video Timing Info Start*********************");
    HV_LOG_INFO(DP,"@@ Timing info: HTotal    is %d", pstVideoTiming->usHTotal);
    HV_LOG_INFO(DP,"@@ Timing info: VTotal    is %d", pstVideoTiming->usVTotal);
    HV_LOG_INFO(DP,"@@ Timing info: HAct      is %d", pstVideoTiming->usHActive);
    HV_LOG_INFO(DP,"@@ Timing info: VAct      is %d", pstVideoTiming->usVActive);
    HV_LOG_INFO(DP,"@@ Timing info: PixelClk  is %d", pstVideoTiming->uiFreqKHz);
    HV_LOG_INFO(DP,"@@ Timing info: HFREQ     is %d", pstVideoTiming->uiHFreqHz);
    HV_LOG_INFO(DP,"@@ Timing info: FrameRate is %d", pstVideoTiming->usFrameRate);
    HV_LOG_INFO(DP,"@@ Timing info: Interlace is %d", pstVideoTiming->bInterlacedMode);
    HV_LOG_INFO(DP,"****************DP Video Timing Info END***********************");

    return;
}

VOID Hv_Mw_DpRx_PrintColorInfo(VideoColorParam *pstVideoColor)
{
    HV_ASSERT_VALID_PTR_VOID(pstVideoColor);

    HV_LOG_INFO(DP,"****************DP Video Color Info Start*******************");
    HV_LOG_INFO(DP,"@@ Color info: ColorDepth  is %d", pstVideoColor->eClrDepth);
    HV_LOG_INFO(DP,"@@ Color info: ColorFormat is %d", pstVideoColor->eClrFormat);
    HV_LOG_INFO(DP,"@@ Color info: ColorRange  is %d", pstVideoColor->eClrRange);
    HV_LOG_INFO(DP,"@@ Color info: ColorSpace  is %d", pstVideoColor->eClrSpace);
    HV_LOG_INFO(DP,"@@ Color info: ContentType is %d", pstVideoColor->eContent);
    HV_LOG_INFO(DP,"@@ Color info: PixelRepeat is %d", pstVideoColor->ucPixelRepe);
    HV_LOG_INFO(DP,"****************DP Video Color Info END*********************");

    return;
}

VOID Hv_Mw_DpRx_PrintHdrInfo(HDRParam *pstHDRPara)
{
    HV_ASSERT_VALID_PTR_VOID(pstHDRPara);

    HV_LOG_INFO(DP,"****************DP HDR Info Start**************************");
    HV_LOG_INFO(DP,"@@ HDR info: xType      is %d", pstHDRPara->xType);
    HV_LOG_INFO(DP,"@@ HDR info: MetaID     is %d", pstHDRPara->ucMetaID);
    HV_LOG_INFO(DP,"@@ HDR info: PrimX0     is %d", pstHDRPara->usPrimX0);
    HV_LOG_INFO(DP,"@@ HDR info: PrimY0     is %d", pstHDRPara->usPrimY0);
    HV_LOG_INFO(DP,"@@ HDR info: PrimX1     is %d", pstHDRPara->usPrimX1);
    HV_LOG_INFO(DP,"@@ HDR info: PrimY1     is %d", pstHDRPara->usPrimY1);
    HV_LOG_INFO(DP,"@@ HDR info: PrimX2     is %d", pstHDRPara->usPrimX2);
    HV_LOG_INFO(DP,"@@ HDR info: PrimY2     is %d", pstHDRPara->usPrimY2);
    HV_LOG_INFO(DP,"@@ HDR info: WhiteX     is %d", pstHDRPara->usWhtX);
    HV_LOG_INFO(DP,"@@ HDR info: WhiteY     is %d", pstHDRPara->usWhtY);
    HV_LOG_INFO(DP,"@@ HDR info: MaxLum     is %d", pstHDRPara->usMaxLum);
    HV_LOG_INFO(DP,"@@ HDR info: MinLum     is %d", pstHDRPara->usMinLum);
    HV_LOG_INFO(DP,"@@ HDR info: MaxContent is %d", pstHDRPara->usMaxCntn);
    HV_LOG_INFO(DP,"@@ HDR info: MaxFrmAvg  is %d", pstHDRPara->usMaxFrmAvg);
    HV_LOG_INFO(DP,"****************DP HDR Info END****************************");

    return;
}

VOID Hv_Mw_DpRx_PrintAMDInfo(VRRInfoParam *pstVrrInfo)
{
    HV_ASSERT_VALID_PTR_VOID(pstVrrInfo);

    HV_LOG_INFO(DP,"****************DP AMD Info Start**************************");
    HV_LOG_INFO(DP,"@@ VRR info: VendorType is %d", pstVrrInfo->eVendor);
    HV_LOG_INFO(DP,"@@ VRR info: Version    is %d", pstVrrInfo->uvsi.stAmdSpdInfPara.ucVersion);
    HV_LOG_INFO(DP,"@@ VRR info: MinReFresh is %d", pstVrrInfo->uvsi.stAmdSpdInfPara.ucFreeSyncMinReFresh);
    HV_LOG_INFO(DP,"@@ VRR info: MaxReFresh is %d", pstVrrInfo->uvsi.stAmdSpdInfPara.ucFreeSyncMaxReFresh);
    HV_LOG_INFO(DP,"@@ VRR info: Supported  is %d", pstVrrInfo->uvsi.stAmdSpdInfPara.bFreeSyncSupported);
    HV_LOG_INFO(DP,"@@ VRR info: Enabled    is %d", pstVrrInfo->uvsi.stAmdSpdInfPara.bFreeSyncEnabled);
    HV_LOG_INFO(DP,"@@ VRR info: Active     is %d", pstVrrInfo->uvsi.stAmdSpdInfPara.bFreeSyncActive);
    HV_LOG_INFO(DP,"****************DP AMD Info END****************************");

    return;
}

VOID Hv_Mw_DpRx_PrintNvidiaInfo(VRRInfoParam *pstVrrInfo)
{
    HV_ASSERT_VALID_PTR_VOID(pstVrrInfo);

    HV_LOG_INFO(DP,"*******************DP NVIDA Info Start**********************");
    HV_LOG_INFO(DP,"@@ VRR info: VendorType is %d", pstVrrInfo->eVendor);
    HV_LOG_INFO(DP,"@@ VRR info: ModuleName is %s", pstVrrInfo->uvsi.stNvidiaVSIPara.ucModeName);
    HV_LOG_INFO(DP,"@@ VRR info: SourceType is %d", pstVrrInfo->uvsi.stNvidiaVSIPara.eSourceInfoCode);
    HV_LOG_INFO(DP,"*******************DP NVIDA Info END***************** ******");

    return;
}
#endif

Status Hv_Mw_DpRx_ProcSystemMsg(InputPortEvent *pstEvent)
{
    UCHAR8 ucEventIdx = 0;
    UINT32 *puiIntFlag = NULL;
    UINT32 auiNoHdcpIntFlag[3] = {0};
    DpRxIntEventList stDpRxEventList = {0};
    HV_ASSERT_VALID_PTR(pstEvent);
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(pstEvent->enPortIndex);
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    HV_ASSERT_VALID_PTR(pstEvent->buffer);
    puiIntFlag = (UINT32 *)pstEvent->buffer;
    auiNoHdcpIntFlag[0] = puiIntFlag[0];
    auiNoHdcpIntFlag[1] = puiIntFlag[1];
    auiNoHdcpIntFlag[2] = puiIntFlag[2];
    HV_ASSERT_SUCCESS(Hv_Drv_DpRx_AlysIntEvent(pstDpCtrl->ucCurPort, auiNoHdcpIntFlag, &stDpRxEventList));
    HV_ASSERT_VALID_PTR(&stDpRxEventList);

    pstEvent->buffer = NULL;
    for (ucEventIdx = 0; (ucEventIdx < stDpRxEventList.ucSize) && (ucEventIdx < HV_DPRX_INT_EVENT_MAX_SIZE); ucEventIdx++)
    {
        pstEvent->usEventId = stDpRxEventList.usEventList[ucEventIdx];
        HV_ASSERT_SUCCESS(Hv_Mw_InputPort_SendInnerMsg(pstEvent));
    }

    return HV_SUCCESS;
}

Status Hv_Mw_DpRx_ProcCableMsg(InputPortEvent *pstEvent)
{
    BOOL bCableSta = HV_FALSE;
    HV_ASSERT_VALID_PTR(pstEvent);
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(pstEvent->enPortIndex);
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    bCableSta = Hv_Drv_DpRx_DetectCable(pstDpCtrl->ucCurPort);
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_DP_NOSTAND_CABLE_ENABLE)
    bCableSta |= Hv_Drv_DpRx_GetAuxState(pstDpCtrl->ucCurPort);
#endif

    if (bCableSta)
    {
        pstEvent->usEventId = InputPortEventId_DP_CableConnect;
    }
    else
    {
        pstEvent->usEventId = InputPortEventId_DP_CableDisconnect;
    }
    pstEvent->buffer = NULL;
    HV_ASSERT_SUCCESS(Hv_Mw_InputPort_SendInnerMsg(pstEvent));

    return HV_SUCCESS;
}

BOOL Hv_Mw_DpRx_GetPortStatus(LinkPortIndex enLinkPortIndex)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enLinkPortIndex);
    HV_ASSERT_VALID_PTR_RET(pstDpCtrl, HV_FALSE);

    return pstDpCtrl->bCableConnected;
}

BOOL Hv_Mw_DpRx_IsNoSignal(LinkPortIndex enLinkPortIndex)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enLinkPortIndex);
    HV_ASSERT_VALID_PTR_RET(pstDpCtrl, HV_TRUE);

    return pstDpCtrl->bIsNoSignal;
}

Status Hv_Mw_DpRx_GetVideoPara(LinkPortIndex enLinkPortIndex, ChannelData* pstChannelData)
{
    HV_ASSERT_VALID_PTR(pstChannelData);
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enLinkPortIndex);
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    if (pstDpCtrl->enCurrentPortState != INPUT_PORT_STATE_DISPLAY_RDY)
    {
        pstChannelData->stRxVideoTiming.bIsNoSignal = Hv_Mw_DpRx_IsNoSignal(enLinkPortIndex);
        return HV_FAILURE;
    }
    else
    {
        if (NULL != &pstChannelData->stRxVideoTiming)
        {
            HV_MEMCPY(&pstChannelData->stRxVideoTiming, &pstDpCtrl->stCurTiming, sizeof(VideoTimingParam));
        }

        if (NULL != &pstChannelData->stVideoConfigParams.stColor)
        {
            HV_MEMCPY(&pstChannelData->stVideoConfigParams.stColor, &pstDpCtrl->stCurColor, sizeof(VideoColorParam));
            /* Cut down to 12 bits */
            if(pstChannelData->stVideoConfigParams.stColor.eClrDepth == ColorDepthType_16Bit)
            {
                pstChannelData->stVideoConfigParams.stColor.eClrDepth = ColorDepthType_12Bit;
            }
        }

        if (NULL != &pstChannelData->stVideoConfigParams.stHdrParam)
        {
            HV_MEMCPY(&pstChannelData->stVideoConfigParams.stHdrParam, &pstDpCtrl->stCurHdr, sizeof(HDRParam));
        }

        if (NULL != &pstChannelData->stVideoConfigParams.stVRRInfoParam)
        {
            HV_MEMCPY(&pstChannelData->stVideoConfigParams.stVRRInfoParam, &pstDpCtrl->stCurVrr, sizeof(VRRInfoParam));
        }
        
        if (NULL != &pstChannelData->stRxAudioTiming)
        {
            HV_MEMCPY(&pstChannelData->stRxAudioTiming, &pstDpCtrl->stCurAudioTiming, sizeof(AudioTimingParam));
        }

        return HV_SUCCESS;
    }
}

Status Hv_Mw_DpRx_GetHdrPara(LinkPortIndex enLinkPortIndex, HDRParam *pstHdrPara)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enLinkPortIndex);
    HV_ASSERT_VALID_PTR(pstDpCtrl);
    HV_ASSERT_VALID_PTR(pstHdrPara);

    if (pstDpCtrl->enCurrentPortState != INPUT_PORT_STATE_DISPLAY_RDY)
    {
        return HV_FAILURE;
    }
    else
    {
        HV_MEMCPY(pstHdrPara, &pstDpCtrl->stCurHdr, sizeof(HDRParam));

        return HV_SUCCESS;
    }
}

Status Hv_Mw_DpRx_GetVrrPara(LinkPortIndex enLinkPortIndex, VRRInfoParam  *pstVrrInfo)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enLinkPortIndex);
    HV_ASSERT_VALID_PTR(pstDpCtrl);
    HV_ASSERT_VALID_PTR(pstVrrInfo);

    if (pstDpCtrl->enCurrentPortState != INPUT_PORT_STATE_DISPLAY_RDY)
    {
        return HV_FAILURE;
    }
    else
    {
        HV_MEMCPY(pstVrrInfo, &pstDpCtrl->stCurVrr, sizeof(VRRInfoParam));

        return HV_SUCCESS;
    }
}

Status Hv_Mw_DpRx_HpdLevel(LinkPortIndex enPortIndex, BOOL bHpdLevel)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enPortIndex);
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    if ((pstDpCtrl->ucCurPort == 0) && (HV_BOARD_CONFIG_DP0_TYPE == DP_PORT_ALTMODE))
    {
#ifdef CONFIG_USER_TYPE_C_ON
        Hv_Mw_Typec_AMESetDpHpd(HV_BOARD_CONFIG_DP0_TO_TYPEC, (BOOL)bHpdLevel);
#endif
    }
    else if ((pstDpCtrl->ucCurPort == 1) && (HV_BOARD_CONFIG_DP1_TYPE == DP_PORT_ALTMODE))
    {
#ifdef CONFIG_USER_TYPE_C_ON
        Hv_Mw_Typec_AMESetDpHpd(HV_BOARD_CONFIG_DP1_TO_TYPEC, (BOOL)bHpdLevel);
#endif
    }
    else
    {
        Hv_Drv_DpRx_EvtHpd(pstDpCtrl->ucCurPort, (BOOL)bHpdLevel);
    }
    pstDpCtrl->ucHpdLevel = bHpdLevel;
    Hv_Drv_DpRx_SetHPDStatus(pstDpCtrl->ucCurPort, bHpdLevel);

    return HV_SUCCESS;
}

Status Hv_Mw_DpRx_HpdToggle(LinkPortIndex enPortIndex)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enPortIndex);
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    if (pstDpCtrl->bCableConnected == HV_FALSE)
    {
        return HV_FAILURE;
    }

    HV_LOG_DEBUG(DP, "DP%d Hpd toggled", pstDpCtrl->ucCurPort);

    if ((pstDpCtrl->ucCurPort == 0) && (HV_BOARD_CONFIG_DP0_TYPE == DP_PORT_ALTMODE))
    {
#ifdef CONFIG_USER_TYPE_C_ON
        Hv_Mw_Typec_AMESetDpHpd(HV_BOARD_CONFIG_DP0_TO_TYPEC, (BOOL)DP_HPD_LOW);
#endif
    }
    else if ((pstDpCtrl->ucCurPort == 1) && (HV_BOARD_CONFIG_DP1_TYPE == DP_PORT_ALTMODE))
    {
#ifdef CONFIG_USER_TYPE_C_ON
        Hv_Mw_Typec_AMESetDpHpd(HV_BOARD_CONFIG_DP1_TO_TYPEC, (BOOL)DP_HPD_LOW);
#endif
    }
    else
    {
        Hv_Drv_DpRx_EvtHpd(pstDpCtrl->ucCurPort, (BOOL)DP_HPD_LOW);
    }
    pstDpCtrl->ucHpdLevel = DP_HPD_LOW;
    Hv_Drv_DpRx_SetHPDStatus(pstDpCtrl->ucCurPort, DP_HPD_LOW);
    if (pstDpCtrl->bDpHpdTimerStart == HV_TRUE)
    {
        Hv_Vos_Timer_Stop(pstDpCtrl->pstHpdTimer);
    }
    Hv_Vos_Timer_Start(pstDpCtrl->pstHpdTimer);
    pstDpCtrl->bDpHpdTimerStart = HV_TRUE;

    return HV_SUCCESS;
}

VOID Hv_Mw_DpRx_IrqHpd(LinkPortIndex enPortIndex)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enPortIndex);
    HV_ASSERT_VALID_PTR_VOID(pstDpCtrl);

    if (pstDpCtrl->ucHpdLevel == DP_HPD_LOW)
    {
        return;
    }

    if ((pstDpCtrl->ucCurPort == 0) && (HV_BOARD_CONFIG_DP0_TYPE == DP_PORT_ALTMODE))
    {
#ifdef CONFIG_USER_TYPE_C_ON
        Hv_Mw_Typec_AMESetDpIrqHpd(HV_BOARD_CONFIG_DP0_TO_TYPEC);
#endif
    }
    else if ((pstDpCtrl->ucCurPort == 1) && (HV_BOARD_CONFIG_DP1_TYPE == DP_PORT_ALTMODE))
    {
#ifdef CONFIG_USER_TYPE_C_ON
        Hv_Mw_Typec_AMESetDpIrqHpd(HV_BOARD_CONFIG_DP1_TO_TYPEC);
#endif
    }
    else
    {
        Hv_Drv_DpRx_IrqHpd(pstDpCtrl->ucCurPort);
    }

    return;
}

BOOL Hv_Mw_DpRx_GetAudioStatus(LinkPortIndex enPortIndex)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enPortIndex);
    HV_ASSERT_VALID_PTR_RET(pstDpCtrl, HV_FALSE);

    if (pstDpCtrl->enCurrentPortState != INPUT_PORT_STATE_DISPLAY_RDY)
    {
        return HV_FALSE;
    }

    return Hv_Drv_DpRx_GetAudioSta(pstDpCtrl->ucCurPort);
}

Status Hv_Mw_DpRx_SetEdid(LinkPortIndex enPortIndex, const UCHAR8 *pucEdidData, USHORT16 usLen)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enPortIndex);
    HV_ASSERT_VALID_PTR(pstDpCtrl);
    HV_ASSERT_VALID_PTR(pucEdidData);
    DpEdidDBRegion* pstDpEdid = NULL;

    if (LINK_PORT_INDEX_DP_RX0 == enPortIndex)
    {
        pstDpEdid = Hv_Common_Db_GetDpEdidDBRegionPtr();
    }
    else
    {
        pstDpEdid = Hv_Common_Db_GetDp1EdidDBRegionPtr();
    }
    pstDpEdid->astDpEdid[0].eEdidType = EDID_TYPE_DEFAULT;
    pstDpEdid->astDpEdid[0].uiEdidLen = usLen;
    HV_MEMCPY(pstDpEdid->astDpEdid[0].acEdid, pucEdidData, usLen);
    pstDpEdid->bModifyFlag = HV_TRUE;
    Hv_Mw_DataBase_Sync();
    Hv_Drv_DpRx_UpdtEdid(pstDpCtrl->ucCurPort, pucEdidData, usLen);
    Hv_Mw_DpRx_HpdToggle(pstDpCtrl->enPortIndex);

    return HV_SUCCESS;
}

UINT32 Hv_Mw_DpRx_GetEdid(LinkPortIndex enPortIndex, UCHAR8 *pucEdidData)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enPortIndex);
    HV_ASSERT_VALID_PTR_RET(pstDpCtrl, 0);
    HV_ASSERT_VALID_PTR_RET(pucEdidData, 0);
    const DpEdidDBRegion* pstDpEdid = NULL;
    const UCHAR8 *pucEdidTmp = NULL;
    UINT32 uiIndex = 0;
    EDIDType eEType = EDID_TYPE_DEFAULT;
    UINT32 uiLen = 0;

    eEType = pstDpCtrl->enCurEdidType & (~ EDID_TYPE_CLOSE_HDR);
    /* EDID default and VRR is the same */
    switch (eEType)
    {
        case EDID_TYPE_DEFAULT:
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_PXP)
        case EDID_TYPE_PBP:
        case EDID_TYPE_PIP:
#endif
        case EDID_TYPE_PRO_ESPORT:
        {
            break;
        }
        case EDID_TYPE_ADAPTIVESYNC:
        {
            eEType = EDID_TYPE_DEFAULT;
            break;
        }
        default:
        {
            return 0;
        }
    }

    if (LINK_PORT_INDEX_DP_RX0 == enPortIndex)
    {
        pstDpEdid = Hv_Common_Db_GetDpEdidDBRegionPtr();
    }
    else
    {
        pstDpEdid = Hv_Common_Db_GetDp1EdidDBRegionPtr();
    }

    if ((pstDpEdid->ucNumber == 0) || (pstDpEdid->ucNumber > 7))
    {
        return uiLen;
    }

    for (uiIndex = 0; uiIndex < pstDpEdid->ucNumber; uiIndex++)
    {
        if (eEType == pstDpEdid->astDpEdid[uiIndex].eEdidType)
        {
            pucEdidTmp = pstDpEdid->astDpEdid[uiIndex].acEdid;
            uiLen = pstDpEdid->astDpEdid[uiIndex].uiEdidLen;
            break;
        }
    }

    if ((uiLen > DP_EDID_MAX_LENGTH) || (pucEdidTmp == NULL))
    {
        return 0;
    }

    HV_MEMCPY(pucEdidData, pucEdidTmp, uiLen);

    if ((pstDpCtrl->enCurEdidType & EDID_TYPE_CLOSE_HDR) == BIT_5)
    {
       Hv_Mw_InputPort_RmvEdidHdr(pucEdidData, uiLen);
    }

#ifdef HDR_PARAM_DYNAMIC_UP
    Hv_Mw_InputPort_UpdateEdidHdrParam(pucEdidData, uiLen);
#endif

    return uiLen;
}

Status Hv_Mw_DpRx_UpdtEdid(LinkPortIndex enPortIndex, EDIDType enEdidConfigure)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enPortIndex);
    HV_ASSERT_VALID_PTR(pstDpCtrl);
    UCHAR8 aucEdidData[DP_EDID_MAX_LENGTH] = {0};
    UINT32 uiEdidLen = 0;

    if (enEdidConfigure == pstDpCtrl->enCurEdidType)
    {
        HV_LOG_DEBUG(DP, "EDID config is the same");
        return HV_FAILURE;
    }
    else
    {
        pstDpCtrl->enCurEdidType = enEdidConfigure;
    }

    uiEdidLen = Hv_Mw_DpRx_GetEdid(enPortIndex, aucEdidData);
    Hv_Drv_DpRx_UpdtEdid(pstDpCtrl->ucCurPort, aucEdidData, uiEdidLen);
    if ((pstDpCtrl->enCurEdidType & (~ EDID_TYPE_CLOSE_HDR)) == EDID_TYPE_ADAPTIVESYNC)
    {
        Hv_Drv_DpRx_SetTimingIgnore(pstDpCtrl->ucCurPort, HV_TRUE);
    }
    else
    {
        Hv_Drv_DpRx_SetTimingIgnore(pstDpCtrl->ucCurPort, HV_FALSE);
    }

    Hv_Mw_DpRx_HpdToggle(pstDpCtrl->enPortIndex);

    return HV_SUCCESS;
}

/* Used for Update EDID withou check Type and HPD */
Status Hv_Mw_DpRx_UpdtEdidRobust(LinkPortIndex enPortIndex)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enPortIndex);
    HV_ASSERT_VALID_PTR(pstDpCtrl);
    UCHAR8 aucEdidData[DP_EDID_MAX_LENGTH] = {0};
    UINT32 uiEdidLen = 0;

    uiEdidLen = Hv_Mw_DpRx_GetEdid(enPortIndex, aucEdidData);
    Hv_Drv_DpRx_UpdtEdid(pstDpCtrl->ucCurPort, aucEdidData, uiEdidLen);
    Hv_Mw_DpRx_HpdToggle(pstDpCtrl->enPortIndex);

    return HV_SUCCESS;
}

Status Hv_Mw_DpRx_SetDpVer(LinkPortIndex enPortIndex, UCHAR8 ucDpVer)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enPortIndex);
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    if (enPortIndex == LINK_PORT_INDEX_DP_RX0)
    {
        HV_COMMON_DATABASE_SET(UserData, ucDPVersion, ucDpVer);
    }
    if (enPortIndex == LINK_PORT_INDEX_DP_RX1)
    {
        HV_COMMON_DATABASE_SET(UserData, ucDP1Version, ucDpVer);
    }

    if (ucDpVer == Hv_Drv_DpRx_GetDpVer(pstDpCtrl->ucCurPort))
    {
        return HV_SUCCESS;
    }
    Hv_Drv_DpRx_SetDpVer(pstDpCtrl->ucCurPort, ucDpVer);
    Hv_Mw_DpRx_HpdToggle(pstDpCtrl->enPortIndex);

    return HV_SUCCESS;
}

Status Hv_Mw_DpRx_SetAllDpVer(UCHAR8 ucDpVer)
{
    Status stRet = HV_FAILURE;

#if (PORT_VALID == HV_BOARD_CONFIG_DISPLAYPORT_0)
    stRet = Hv_Mw_DpRx_SetDpVer(LINK_PORT_INDEX_DP_RX0, ucDpVer);
#endif

#if (PORT_VALID == HV_BOARD_CONFIG_DISPLAYPORT_1)
    stRet = Hv_Mw_DpRx_SetDpVer(LINK_PORT_INDEX_DP_RX1, ucDpVer);
#endif

    return stRet;
}

UCHAR8 Hv_Mw_DpRx_GetDpVer(LinkPortIndex enPortIndex)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enPortIndex);
    HV_ASSERT_VALID_PTR_RET(pstDpCtrl, 0);

    if (LINK_PORT_INDEX_DP_RX0 == enPortIndex)
    {
        return (HV_COMMON_DATABASE_GET(UserData, ucDPVersion));
    }
    else
    {
        return (HV_COMMON_DATABASE_GET(UserData, ucDP1Version));
    }
}

UCHAR8 Hv_Mw_DpRx_GetAllDpVer()
{
#if (PORT_VALID == HV_BOARD_CONFIG_DISPLAYPORT_0)
    return Hv_Mw_DpRx_GetDpVer(LINK_PORT_INDEX_DP_RX0);
#elif (PORT_VALID == HV_BOARD_CONFIG_DISPLAYPORT_1)
    return Hv_Mw_DpRx_GetDpVer(LINK_PORT_INDEX_DP_RX1);
#else
    return 0;
#endif
}

Status Hv_Mw_DpRx_SetMaxLaneCount(LinkPortIndex enPortIndex, UCHAR8 ucDpLaneCount)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enPortIndex);
    HV_ASSERT_VALID_PTR_RET(pstDpCtrl, 0);

    return Hv_Drv_DpRx_SetMaxLaneCount(pstDpCtrl->ucCurPort, ucDpLaneCount);
}

UINT32 Hv_Mw_DpRx_GetCurrentFrameRate(LinkPortIndex enPortIndex)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enPortIndex);
    HV_ASSERT_VALID_PTR_RET(pstDpCtrl, 0);

    return (UINT32)Hv_Drv_DpRx_GetFrameRate(pstDpCtrl->ucCurPort);
}

Status Hv_Mw_DpRx_Reset(LinkPortIndex enPortIndex)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enPortIndex);
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    Hv_Drv_DpRx_Reset(pstDpCtrl->ucCurPort, HV_TRUE);
    Hv_Drv_DpRx_Reset(pstDpCtrl->ucCurPort, HV_FALSE);

    return HV_SUCCESS;
}

VOID Hv_Mw_DpRx_EnableApbWr(BOOL bEn)
{
    Hv_Drv_DpRx_EnableApbWr(bEn);

    return;
}

VOID Hv_Mw_DpRx_MaskSdpInt(LinkPortIndex enPortIndex, BOOL bSwitch)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enPortIndex);
    HV_ASSERT_VALID_PTR_VOID_NO_LOG(pstDpCtrl);

    return Hv_Drv_DpRx_MaskSdpInt(pstDpCtrl->ucCurPort, bSwitch);
}

VOID Hv_Mw_DpRx_MaskRxHtotalInt(LinkPortIndex enPortIndex, BOOL bSwitch)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enPortIndex);
    HV_ASSERT_VALID_PTR_VOID_NO_LOG(pstDpCtrl);

    Hv_Drv_DpRx_MaskRxHtotalInt(pstDpCtrl->ucCurPort, bSwitch);

    return;
}

Status Hv_Mw_DpRx_GetPortErrorCode(LinkPortIndex enPortIndex)
{
    return HV_SUCCESS;
}

Status Hv_Mw_DpRx_Init(DisplayPortManager *pstDpRxManager)
{
    UCHAR8 ucPortId = 0;
    UCHAR8 aucEdid[DP_EDID_MAX_LENGTH] = {0};
    UINT32 uiEdidLen = 0;
    UCHAR8 ucDpVerSet = HV_DP_VER14;
    HV_ASSERT_VALID_PTR(pstDpRxManager);

    /* Init IRQ msg queue */
    DpQueueSafeQueueInit(&s_stDpQueue);

    /* HPD duration 800ms at low */
    HV_TIMER_INIT_PARAMS astHpdTmrInitParam[HV_BOARD_CONFIG_MAX_DP_PORT_NUM] =
    {
#if (HV_BOARD_CONFIG_DISPLAYPORT_0 == PORT_VALID)
        {"Dp0HpdTimer", DP_HPD_PULSE, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_DP0_HPD_TIMEOUT},
#endif
#if (HV_BOARD_CONFIG_DISPLAYPORT_1 == PORT_VALID)
        {"Dp1HpdTimer", DP_HPD_PULSE, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_DP1_HPD_TIMEOUT}
#endif
    };

    /* Training NG */
    HV_TIMER_INIT_PARAMS astTrainingTmrInitParam[HV_BOARD_CONFIG_MAX_DP_PORT_NUM] =
    {
#if (HV_BOARD_CONFIG_DISPLAYPORT_0 == PORT_VALID)
        {"Dp0TrainingNGTimer", DP_TRAINING_NG_TIME, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_DP0_TRAINING_NG},
#endif
#if (HV_BOARD_CONFIG_DISPLAYPORT_1 == PORT_VALID)
        {"Dp1TrainingNGTimer", DP_TRAINING_NG_TIME, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_DP1_TRAINING_NG}
#endif
    };

    /* Wait Timing Stable */
    HV_TIMER_INIT_PARAMS astTimChkTmrInitParam[HV_BOARD_CONFIG_MAX_DP_PORT_NUM] =
    {
#if (HV_BOARD_CONFIG_DISPLAYPORT_0 == PORT_VALID)
        {"Dp0TimingCheckTimer", DP_TIMING_CHECK_CYCLE, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_DP0_TIMING_CHECK},
#endif
#if (HV_BOARD_CONFIG_DISPLAYPORT_1 == PORT_VALID)
        {"Dp1TimingCheckTimer", DP_TIMING_CHECK_CYCLE, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_DP1_TIMING_CHECK}
#endif
    };

    HV_TIMER_INIT_PARAMS astAudioChkTmrInitParam[HV_BOARD_CONFIG_MAX_DP_PORT_NUM] =
    {
#if (HV_BOARD_CONFIG_DISPLAYPORT_0 == PORT_VALID)
        {"Dp0AudioCheckTimer", DP_Audio_CHECK_CYCLE, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_DP0_AUDIO_CHECK},
#endif
#if (HV_BOARD_CONFIG_DISPLAYPORT_1 == PORT_VALID)
        {"Dp1AudioCheckTimer", DP_Audio_CHECK_CYCLE, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_DP1_AUDIO_CHECK}
#endif
    };

    HV_MEMSET(&pstDpRxManager->astDpCtrl[0], 0, sizeof(pstDpRxManager->astDpCtrl));
    pstDpRxManager->pfGetVideoPara        = Hv_Mw_DpRx_GetVideoPara;
    pstDpRxManager->pfGetVrrPara          = Hv_Mw_DpRx_GetVrrPara;
    pstDpRxManager->pfHpdToggle           = Hv_Mw_DpRx_HpdToggle;
    pstDpRxManager->pfHPDAction           = Hv_Mw_DpRx_HpdLevel;
    pstDpRxManager->pfGetAudioStatus      = Hv_Mw_DpRx_GetAudioStatus;
    pstDpRxManager->pfUpdateEdid          = Hv_Mw_DpRx_UpdtEdid;
    pstDpRxManager->pfGetCurrentFrameRate = Hv_Mw_DpRx_GetCurrentFrameRate;
    pstDpRxManager->pfGetEdidData         = Hv_Mw_DpRx_GetEdid;
    pstDpRxManager->pfStartAudio          = Hv_Mw_DpRx_AudioStart;
    pstDpRxManager->pfStopAudio           = Hv_Mw_DpRx_AudioStop;
    pstDpRxManager->pfReset               = Hv_Mw_DpRx_Reset;
    pstDpRxManager->pfGetPortErrorCode    = Hv_Mw_DpRx_GetPortErrorCode;

#if (HV_BOARD_CONFIG_DISPLAYPORT_0 == PORT_VALID)
    pstDpRxManager->astDpCtrl[0].enPortIndex            = LINK_PORT_INDEX_DP_RX0;
    pstDpRxManager->astDpCtrl[0].pstHpdTimer            = Hv_Vos_Timer_Create(&astHpdTmrInitParam[0]);
    pstDpRxManager->astDpCtrl[0].pstTimingCheckTimer    = Hv_Vos_Timer_Create(&astTimChkTmrInitParam[0]);
    pstDpRxManager->astDpCtrl[0].pstTrainingTimer       = Hv_Vos_Timer_Create(&astTrainingTmrInitParam[0]);
    pstDpRxManager->astDpCtrl[0].pstAudioCheckTimer     = Hv_Vos_Timer_Create(&astAudioChkTmrInitParam[0]);
    pstDpRxManager->astDpCtrl[0].bDpHpdTimerStart       = HV_FALSE;
    pstDpRxManager->astDpCtrl[0].bDpChkTimerStart       = HV_FALSE;
    pstDpRxManager->astDpCtrl[0].bDpTrainingTimerStart  = HV_FALSE;
    pstDpRxManager->astDpCtrl[0].bDpAudioTimerStart     = HV_FALSE;
    pstDpRxManager->astDpCtrl[0].ucTimChkCnt            = 0;
    pstDpRxManager->astDpCtrl[0].ucCurPort              = 0;
    pstDpRxManager->astDpCtrl[0].enCurrentPortState     = INPUT_PORT_STATE_IDLE;
    pstDpRxManager->astDpCtrl[0].enCurEdidType          = EDID_TYPE_DEFAULT;
    pstDpRxManager->astDpCtrl[0].ucHpdLevel             = DP_HPD_LOW;
    pstDpRxManager->astDpCtrl[0].bCableConnected        = HV_FALSE;
    pstDpRxManager->astDpCtrl[0].bLinkSync              = HV_FALSE;
    pstDpRxManager->astDpCtrl[0].bLinkPeriod            = HV_FALSE;
    pstDpRxManager->astDpCtrl[0].bIsNoSignal            = HV_TRUE;
    pstDpRxManager->astDpCtrl[0].bAuxState              = HV_FALSE;
    pstDpRxManager->astDpCtrl[0].bAudioAbnormal         = HV_TRUE;
    pstDpRxManager->astDpCtrl[0].enLastPortUnSyncReason = LastPortUnSyncReason_None;
    pstDpRxManager->astDpCtrl[0].stCurColor.eClrDepth   = ColorDepthType_8Bit;

    HV_ASSERT_VALID_PTR(pstDpRxManager->astDpCtrl[0].pstHpdTimer);
    HV_ASSERT_VALID_PTR(pstDpRxManager->astDpCtrl[0].pstTimingCheckTimer);
    HV_ASSERT_VALID_PTR(pstDpRxManager->astDpCtrl[0].pstTrainingTimer);
    HV_ASSERT_VALID_PTR(pstDpRxManager->astDpCtrl[0].pstAudioCheckTimer);
    Hv_Drv_DpRx_Init(0);
    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_DP, HOTFIX_DP0_INIT);
    uiEdidLen = Hv_Mw_DpRx_GetEdid(pstDpRxManager->astDpCtrl[0].enPortIndex, aucEdid);
    Hv_Drv_DpRx_UpdtEdid(0, aucEdid, uiEdidLen);
    ucDpVerSet = HV_COMMON_DATABASE_GET(UserData, ucDPVersion);
    Hv_Drv_DpRx_SetDpVer(0, ucDpVerSet);
#endif

#if (HV_BOARD_CONFIG_DISPLAYPORT_1 == PORT_VALID)
    if(HV_BOARD_CONFIG_DISPLAYPORT_0 == PORT_VALID)
    {
        ucPortId = 1;
    }
    else
    {
        ucPortId = 0;
    }
    pstDpRxManager->astDpCtrl[ucPortId].enPortIndex            = LINK_PORT_INDEX_DP_RX1;
    pstDpRxManager->astDpCtrl[ucPortId].pstHpdTimer            = Hv_Vos_Timer_Create(&astHpdTmrInitParam[ucPortId]);
    pstDpRxManager->astDpCtrl[ucPortId].pstTimingCheckTimer    = Hv_Vos_Timer_Create(&astTimChkTmrInitParam[ucPortId]);
    pstDpRxManager->astDpCtrl[ucPortId].pstTrainingTimer       = Hv_Vos_Timer_Create(&astTrainingTmrInitParam[ucPortId]);
    pstDpRxManager->astDpCtrl[ucPortId].pstAudioCheckTimer     = Hv_Vos_Timer_Create(&astAudioChkTmrInitParam[ucPortId]);
    pstDpRxManager->astDpCtrl[ucPortId].bDpHpdTimerStart       = HV_FALSE;
    pstDpRxManager->astDpCtrl[ucPortId].bDpChkTimerStart       = HV_FALSE;
    pstDpRxManager->astDpCtrl[ucPortId].bDpTrainingTimerStart  = HV_FALSE;
    pstDpRxManager->astDpCtrl[ucPortId].bDpAudioTimerStart     = HV_FALSE;
    pstDpRxManager->astDpCtrl[ucPortId].ucTimChkCnt            = 0;
    pstDpRxManager->astDpCtrl[ucPortId].ucCurPort              = 1;
    pstDpRxManager->astDpCtrl[ucPortId].enCurrentPortState     = INPUT_PORT_STATE_IDLE;
    pstDpRxManager->astDpCtrl[ucPortId].enCurEdidType          = EDID_TYPE_DEFAULT;
    pstDpRxManager->astDpCtrl[ucPortId].ucHpdLevel             = DP_HPD_LOW;
    pstDpRxManager->astDpCtrl[ucPortId].bCableConnected        = HV_FALSE;
    pstDpRxManager->astDpCtrl[ucPortId].bLinkSync              = HV_FALSE;
    pstDpRxManager->astDpCtrl[ucPortId].bLinkPeriod            = HV_FALSE;
    pstDpRxManager->astDpCtrl[ucPortId].bIsNoSignal            = HV_TRUE;
    pstDpRxManager->astDpCtrl[ucPortId].bAuxState              = HV_FALSE;
    pstDpRxManager->astDpCtrl[ucPortId].bAudioAbnormal         = HV_TRUE;
    pstDpRxManager->astDpCtrl[ucPortId].enLastPortUnSyncReason = LastPortUnSyncReason_None;
    pstDpRxManager->astDpCtrl[ucPortId].stCurColor.eClrDepth   = ColorDepthType_8Bit;

    HV_ASSERT_VALID_PTR(pstDpRxManager->astDpCtrl[ucPortId].pstHpdTimer);
    HV_ASSERT_VALID_PTR(pstDpRxManager->astDpCtrl[ucPortId].pstTimingCheckTimer);
    HV_ASSERT_VALID_PTR(pstDpRxManager->astDpCtrl[ucPortId].pstTrainingTimer);
    HV_ASSERT_VALID_PTR(pstDpRxManager->astDpCtrl[ucPortId].pstAudioCheckTimer);
    Hv_Drv_DpRx_Init(1);
    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_DP, HOTFIX_DP1_INIT);
    uiEdidLen = Hv_Mw_DpRx_GetEdid(pstDpRxManager->astDpCtrl[ucPortId].enPortIndex, aucEdid);
    Hv_Drv_DpRx_UpdtEdid(1, aucEdid, uiEdidLen);
    ucDpVerSet = HV_COMMON_DATABASE_GET(UserData, ucDP1Version);
    Hv_Drv_DpRx_SetDpVer(1, ucDpVerSet);
#endif

    HV_LOG_DEBUG(DP, "DP is Initialized!");

    return HV_SUCCESS;
}

HV_VOS_ISR_RESULT_E Hv_Mw_DpRx_CableIsrHandle(UINT32 uiIrqNum, VOID *arg)
{
    DisplayPortCtrlData* pstDpCtrl = (DisplayPortCtrlData*)arg;
    HV_ASSERT_VALID_PTR_RET_NO_LOG(pstDpCtrl, HV_VOS_ISR_NOT_HANDLED);
    UCHAR8 ucPortId  = pstDpCtrl->ucCurPort;
    SystemEvent stSystemEvent = {0};
    HV_VOS_QUEUE_S* pstSysQueue = Hv_Mw_System_GetSystemQueue();
    HV_ASSERT_VALID_PTR_RET_NO_LOG(pstSysQueue, HV_VOS_ISR_NOT_HANDLED);

    Hv_Drv_DpRx_ClrCableIntFlag(ucPortId);

    stSystemEvent.enEventType = SYSTEM_REV_EVENT_TYPE_INPUTPORT;
    stSystemEvent.usEventId   = InputPortEventId_DP_CableInt;
    stSystemEvent.ucPortIndex = pstDpCtrl->enPortIndex;
    stSystemEvent.buffer      = NULL;
    Hv_Vos_QueueSendFromISR(pstSysQueue, &stSystemEvent);

    return HV_VOS_ISR_HANDLED;
}

HV_VOS_ISR_RESULT_E Hv_Mw_DpRx_IsrHandle(UINT32 uiIrqNum, VOID *arg)
{
    DisplayPortCtrlData *pstDpCtrl  = (DisplayPortCtrlData *)arg;
    HV_ASSERT_VALID_PTR_RET_NO_LOG(pstDpCtrl, HV_VOS_ISR_NOT_HANDLED);
    UCHAR8 ucPortId = pstDpCtrl->ucCurPort;
    UINT32 auiDpRxIntFlag[3] = {0};
    UINT32 uiHdcpIntFlag = 0;

    Hv_Drv_DpRx_GetIntFlag(ucPortId, auiDpRxIntFlag, &uiHdcpIntFlag);
    Hv_Drv_DpRx_ClrIntFlag(ucPortId, auiDpRxIntFlag, &uiHdcpIntFlag);

    /* when Color change, insert black */
    if (auiDpRxIntFlag[0] & (1 << DPRX_COLOR_CHANGE))
    {
        FwInsertBlack(ucPortId);
        Hv_Drv_DpRx_MaskColorInt(ucPortId, HV_TRUE);
    }

    /* when Training Fail/timing change, disable timing change interrupt */
    if ((auiDpRxIntFlag[0] & (1 << O_DPRX_FT_IRQ_1))
     || (auiDpRxIntFlag[0] & (1 << DPRX_RESOLUTION_CHANGE))
     || (auiDpRxIntFlag[0] & (1 << DPRX_MNVID_CHANGE))
     || (auiDpRxIntFlag[2] & (1 << DPRX_RWTOTAL_CHG))
     || (auiDpRxIntFlag[2] & (1 << DPRX_MSATOTAL_CHG)))
    {
        FwInsertBlack(ucPortId);
        Hv_Drv_DpRx_MaskTimingInt(ucPortId, HV_TRUE);
        Hv_Drv_DpRx_MaskRxHtotalInt(ucPortId, HV_TRUE);
        Hv_Drv_DpRx_MaskAudioDepthInt(ucPortId, HV_TRUE);
        Hv_Drv_DpRx_MaskSdpInt(ucPortId, HV_TRUE);
        Hv_Drv_DpRx_MaskColorInt(ucPortId, HV_TRUE);
    }

    if (auiDpRxIntFlag[0] & (1 << DPRX_AUX_RD_DPCD_EN_6))
    {
        auiDpRxIntFlag[0] &= ~(1 << DPRX_AUX_RD_DPCD_EN_6);
    }

    /* set link rate */
    if (auiDpRxIntFlag[0] & (1 << DPRX_AUX_RD_DPCD_EN_7))
    {
        Hv_Drv_DpRx_LinkBwChanged(ucPortId);
        pstDpCtrl->bLinkPeriod = HV_TRUE;
        Hv_Drv_DpRx_SetTrainMode(ucPortId, DP_FULL_LINK_TRAINING);
        auiDpRxIntFlag[0] &= ~(1 << DPRX_AUX_RD_DPCD_EN_7);
    }
    /* set lane count */
    if (auiDpRxIntFlag[0] & (1 << DPRX_AUX_RD_DPCD_EN_17))
    {
        Hv_Drv_DpRx_LinkCountChanged(ucPortId);
        auiDpRxIntFlag[0] &= ~(1 << DPRX_AUX_RD_DPCD_EN_17);
    }
    /* audio mute change */
    if (auiDpRxIntFlag[0] & (1 << VB_ID_IRQ_3))
    {
        if (Hv_Drv_DpRx_DetectAudio(pstDpCtrl->ucCurPort) == HV_FALSE)
        {
            if (Hv_Mw_Channel_GetAudioSelInputPortIndex() == pstDpCtrl->enPortIndex)
            {
                Hv_Mw_Audio_ChannelMute(_AUDIO_MUTE_BIT_HW);
            }
            if (HV_SUCCESS == Hv_Drv_DpRx_AudioFifoOnOff(ucPortId, HV_FALSE))
            {
                pstDpCtrl->bAudioAbnormal = HV_TRUE;
            }
            auiDpRxIntFlag[0] &= ~(1 << VB_ID_IRQ_3);
        }
        else if (pstDpCtrl->bAudioAbnormal == HV_TRUE)
        {
            if (HV_SUCCESS == Hv_Drv_DpRx_AudioFifoOnOff(pstDpCtrl->ucCurPort, HV_TRUE))
            {
                pstDpCtrl->bAudioAbnormal = HV_FALSE;
            }
        }
        else
        {
            auiDpRxIntFlag[0] &= ~(1 << VB_ID_IRQ_3);
        }
    }

    if (auiDpRxIntFlag[2] & (1 << DPRX_AUDO_DEPTH_LOW))
    {
        if (pstDpCtrl->bAudioAbnormal == HV_FALSE)
        {
            if (Hv_Mw_Channel_GetAudioSelInputPortIndex() == pstDpCtrl->enPortIndex)
            {
                Hv_Mw_Audio_ChannelMute(_AUDIO_MUTE_BIT_HW);
            }
            if (HV_SUCCESS == Hv_Drv_DpRx_AudioFifoOnOff(ucPortId, HV_FALSE))
            {
                pstDpCtrl->bAudioAbnormal = HV_TRUE;
            }
        }

        auiDpRxIntFlag[2] &= ~(1 << DPRX_AUDO_DEPTH_LOW);
    }

    if (auiDpRxIntFlag[2] & (1 << DPRX_AUDO_DEPTH_HIGH))
    {
        if (pstDpCtrl->bAudioAbnormal == HV_FALSE)
        {
            auiDpRxIntFlag[2] &= ~(1 << DPRX_AUDO_DEPTH_HIGH);
        }
        else
        {
            Hv_Drv_DpRx_AudioFifoOnOff(pstDpCtrl->ucCurPort, HV_TRUE);
            pstDpCtrl->bAudioAbnormal = HV_FALSE;
        }
    }

    /* SW IRQ_HPD */
    if (auiDpRxIntFlag[1] & (1 << DPRX_SW_IRQ))
    {
        Hv_Drv_DpRx_SwIrq(ucPortId);
        auiDpRxIntFlag[1] &= ~(1 << DPRX_SW_IRQ);
    }

    /* Training failed */
    if (auiDpRxIntFlag[0] & (1 << O_DPRX_FT_IRQ_1))
    {
        Hv_Drv_DpRx_TrainingFail(ucPortId);
        if ((ucPortId == 0) && (pstDpCtrl->bCableConnected == HV_TRUE) && (pstDpCtrl->ucHpdLevel == DP_HPD_HIGH))
        {
            Hv_Drv_DpRx_IrqHpd(ucPortId);
        }
    }

    /* Training Done */
    if (auiDpRxIntFlag[0] & (1 << O_DPRX_FT_IRQ_0))
    {
        Hv_Drv_DpRx_TrainingDone(ucPortId);
        pstDpCtrl->bLinkPeriod = HV_FALSE;
    }

    /* SDP fifo */
    if (auiDpRxIntFlag[1] & (1 << SDP_IRQ_1))
    {
        Hv_Drv_DpRx_UpdateSdp(ucPortId);
        auiDpRxIntFlag[1] &= ~(1 << SDP_IRQ_1);
    }

    /* deskew change */
    if (auiDpRxIntFlag[0] & (1 << O_DPRX_FT_IRQ_7))
    {
        Hv_Drv_DpRx_ToggleDeskew(ucPortId);
        auiDpRxIntFlag[0] &= ~(1 << O_DPRX_FT_IRQ_7);
    }

#if (HV_PROJECT_CONFIG_CTS == HV_CONFIG_ON)
    if (auiDpRxIntFlag[1] & (1 << DPRX_AUX_RD_DPCD_EN_15))
    {
        auiDpRxIntFlag[1] &= ~(1 << DPRX_AUX_RD_DPCD_EN_15);
    }

    if (auiDpRxIntFlag[0] & (1 << DPRX_AUX_RD_DPCD_EN_1_4))
    {
        auiDpRxIntFlag[0] &= ~(1 << DPRX_AUX_RD_DPCD_EN_1_4);
    }
#endif

    if (auiDpRxIntFlag[1] & (1 << DPRX_AUX_RD_DPCD_EN_14))
    {
        auiDpRxIntFlag[1] &= ~(1 << DPRX_AUX_RD_DPCD_EN_14);
    }

    if (uiHdcpIntFlag != 0)
    {
        Hv_Mw_Hdcp_RxISRSndEvent(uiHdcpIntFlag, pstDpCtrl->enPortIndex, URGENT_REV_EVENT_TYPE_HDCP_DP);
    }

    if ((auiDpRxIntFlag[0] != 0) || (auiDpRxIntFlag[1] != 0) || (auiDpRxIntFlag[2] != 0))
    {
        HV_VOS_QUEUE_S *pstSysQueue = Hv_Mw_System_GetSystemQueue();
        HV_ASSERT_VALID_PTR_RET_NO_LOG(pstSysQueue, HV_VOS_ISR_NOT_HANDLED);
        SystemEvent stSystemEvent = {0};
        DpQueueElem *pstIntQueueElem;
        pstIntQueueElem = DpQueueSafeQueueEnqueue(&s_stDpQueue, (VOID*)&(auiDpRxIntFlag), sizeof(DpRxIntStatus));
        if (NULL == pstIntQueueElem)
        {
            return HV_VOS_ISR_NOT_HANDLED;
        }
        stSystemEvent.buffer      = pstIntQueueElem->ucBuffer;
        stSystemEvent.ucPortIndex = pstDpCtrl->enPortIndex;
        stSystemEvent.enEventType = SYSTEM_REV_EVENT_TYPE_INPUTPORT;
        stSystemEvent.usEventId   = InputPortEventId_DP_Interrupt;
        Hv_Vos_QueueSendFromISR(pstSysQueue, &stSystemEvent);
    }

    return HV_VOS_ISR_HANDLED;
}

Status Hv_Mw_DpRx_InterruptInit(LinkPortIndex enPortIndex)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enPortIndex);
    HV_ASSERT_VALID_PTR(pstDpCtrl);
    UCHAR8 ucIrqId = 0;
    UCHAR8 ucCableIrqId = 0;

    ucIrqId = Hv_Drv_DpRx_GetIrqId(pstDpCtrl->ucCurPort);
    ucCableIrqId = Hv_Drv_DpRx_GetCableIrqId(pstDpCtrl->ucCurPort);

    if (ucCableIrqId != 0xFF)
    {
        if (((pstDpCtrl->ucCurPort == 0) && (HV_BOARD_CONFIG_DP0_TYPE == DP_PORT_NORM))
         || ((pstDpCtrl->ucCurPort == 1) && (HV_BOARD_CONFIG_DP1_TYPE == DP_PORT_NORM)))
        {
            Hv_Vos_AttachIsr(ucCableIrqId, Hv_Mw_DpRx_CableIsrHandle, (void *)pstDpCtrl);
        }
    }

    if (ucIrqId != 0xFF)
    {
        Hv_Vos_AttachIsr(ucIrqId, Hv_Mw_DpRx_IsrHandle, (void *)pstDpCtrl);
    }

    HV_LOG_DEBUG(DP, "DP%d Interrupt Initialized", pstDpCtrl->ucCurPort);

    return HV_SUCCESS;
}

static Status SendChannelMsg(LinkPortIndex enPortIndex, ChannelEvent *pstChannelEvent)
{
    Status uiRet = HV_FAILURE;
    HV_ASSERT_VALID_PTR(pstChannelEvent);
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enPortIndex);
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    if (Hv_Mw_InputPort_GetChannelBindPortIndex(CHANNEL_TYPE_MAIN) == enPortIndex)
    {
        pstChannelEvent->enChannelType = CHANNEL_TYPE_MAIN;
        uiRet = Hv_Mw_Channel_SendInnerMsg(pstChannelEvent);
    }

    if (Hv_Mw_InputPort_GetChannelBindPortIndex(CHANNEL_TYPE_SUB) == enPortIndex)
    {
        pstChannelEvent->enChannelType = CHANNEL_TYPE_SUB;
        uiRet = Hv_Mw_Channel_SendInnerMsg(pstChannelEvent);
    }

    if (HV_SUCCESS == uiRet )
    {
        switch (pstChannelEvent->usEventId)
        {
            case CHANNEL_EVENT_ID_TIMING_CHANGE:
            {
                HV_LOG_DEBUG(DP, "DP%d notify timing change", pstDpCtrl->ucCurPort);
                break;
            }
            case CHANNEL_EVENT_ID_COLOR_CHANGE:
            {
                HV_LOG_DEBUG(DP, "DP%d notify color change", pstDpCtrl->ucCurPort);
                break;
            }
            case CHANNEL_EVENT_ID_SIGNAL_LOSS:
            {
                HV_LOG_DEBUG(DP, "DP%d training failed and notify signalLoss", pstDpCtrl->ucCurPort);
                break;
            }
            case CHANNEL_EVENT_ID_PLUG_OUT:
            {
                HV_LOG_DEBUG(DP, "DP%d notify Plug-Out", pstDpCtrl->ucCurPort);
                break;
            }
            case CHANNEL_EVENT_ID_RCV_VRR_INFO:
            {
                HV_LOG_DEBUG(DP, "DP%d notify VRR change", pstDpCtrl->ucCurPort);
                break;
            }
            case CHANNEL_EVENT_ID_HDR_CHANGED:
            {
                HV_LOG_DEBUG(DP, "DP%d notify HDR change", pstDpCtrl->ucCurPort);
                break;
            }
            default:
            {
                break;
            }
        }
    }

    return uiRet;
}

BOOL Hv_Mw_DpRx_GetAuxState(LinkPortIndex enPortIndex)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enPortIndex);
    HV_ASSERT_VALID_PTR_RET(pstDpCtrl, HV_FALSE);

    return Hv_Drv_DpRx_GetAuxState(pstDpCtrl->ucCurPort);
}

/* Function is calling when state changed */
Status Hv_Mw_DpRx_Sm_FirstEnter(const InputPortEvent *pstEvent, VOID *pstPortData)
{
    BOOL bLinkSta = 0;
    DisplayPortCtrlData *pstDpCtrl = (DisplayPortCtrlData *)pstPortData;
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    if (pstDpCtrl->enCurrentPortState == INPUT_PORT_STATE_WAIT_SYNC)
    {
        HV_LOG_DEBUG(DP, "DP%d first enter WaitSync", pstDpCtrl->ucCurPort);

        bLinkSta = Hv_Drv_DpRx_DetectLink(pstDpCtrl->ucCurPort);

#ifdef CONFIG_USER_DP_AUDIO_RESHAPE_ON
        if (pstDpCtrl->bDpAudioTimerStart)
        {
            Hv_Vos_Timer_Stop(pstDpCtrl->pstAudioCheckTimer);
            pstDpCtrl->bDpAudioTimerStart = HV_FALSE;
        }
#endif

        if (pstDpCtrl->bDpChkTimerStart)
        {
            Hv_Vos_Timer_Stop(pstDpCtrl->pstTimingCheckTimer);
            pstDpCtrl->bDpChkTimerStart = HV_FALSE;
        }

        if (bLinkSta)
        {
            HV_LOG_DEBUG(DP, "DP%d link is already training done", pstDpCtrl->ucCurPort);

            pstDpCtrl->bLinkSync = HV_TRUE;
            /* Stop trainingNG timer if started */
            if (pstDpCtrl->bDpTrainingTimerStart)
            {
               Hv_Vos_Timer_Stop(pstDpCtrl->pstTrainingTimer);
               pstDpCtrl->bDpTrainingTimerStart = HV_FALSE;
               HV_LOG_DEBUG(DP, "Stop Training NG Timer");
            }

            Hv_Drv_DpRx_EqPermit(pstDpCtrl->ucCurPort);

            pstDpCtrl->bDpChkTimerStart = HV_TRUE;
            pstDpCtrl->ucTimChkCnt = 0;
            Hv_Vos_Timer_Start(pstDpCtrl->pstTimingCheckTimer);

            return HV_SUCCESS;
        }
        else
        {
            if (pstDpCtrl->bDpTrainingTimerStart == HV_TRUE)
            {
                Hv_Vos_Timer_Stop(pstDpCtrl->pstTrainingTimer);
            }
            Hv_Vos_Timer_Start(pstDpCtrl->pstTrainingTimer);
            pstDpCtrl->bDpTrainingTimerStart = HV_TRUE;
            HV_LOG_DEBUG(DP, "WaitSync Start Training NG Timer");

            return HV_FAILURE;
        }
    }

    return HV_FAILURE;
}

/* Start DP state-machine */
Status Hv_Mw_DpRx_Sm_IdleStart(const InputPortEvent *pstEvent, VOID *pstPortData)
{
    UCHAR8 ucIrqId = 0;
    UCHAR8 ucCableIrqId = 0;
    BOOL bCableConnect = HV_FALSE;
    DisplayPortCtrlData *pstDpCtrl  = (DisplayPortCtrlData *)pstPortData;
    HV_ASSERT_VALID_PTR(pstDpCtrl);
    UCHAR8 ucPortId = pstDpCtrl->ucCurPort;

    /* Whether already pluged in */
    if ((ucPortId == 0) && (HV_BOARD_CONFIG_DP0_TYPE == DP_PORT_ALTMODE))
    {
#ifdef CONFIG_USER_TYPE_C_ON
        bCableConnect = Hv_Mw_Typec_AMEGetStatus(HV_BOARD_CONFIG_DP0_TO_TYPEC);
#endif
    }
    else if ((ucPortId == 1) && (HV_BOARD_CONFIG_DP1_TYPE == DP_PORT_ALTMODE))
    {
#ifdef CONFIG_USER_TYPE_C_ON
        bCableConnect = Hv_Mw_Typec_AMEGetStatus(HV_BOARD_CONFIG_DP1_TO_TYPEC);
#endif
    }
    else
    {
        ucCableIrqId = Hv_Drv_DpRx_GetCableIrqId(ucPortId);
        Hv_Vos_UnmaskIrq(ucCableIrqId);
        bCableConnect = Hv_Drv_DpRx_DetectCable(ucPortId);
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_DP_NOSTAND_CABLE_ENABLE)
        bCableConnect |= Hv_Drv_DpRx_GetAuxState(pstDpCtrl->ucCurPort);
#endif
    }
    Hv_Drv_DpRx_SetCableStatus(pstDpCtrl->ucCurPort, bCableConnect);

    /* Init interrupts */
    ucIrqId = Hv_Drv_DpRx_GetIrqId(ucPortId);
    Hv_Drv_DpRx_SetIntEnable(ucPortId);
    Hv_Drv_DpRx_MaskColorInt(ucPortId, HV_TRUE);
    Hv_Drv_DpRx_MaskTimingInt(ucPortId, HV_TRUE);
    Hv_Drv_DpRx_MaskAudioDepthInt(ucPortId, HV_TRUE);
    Hv_Drv_DpRx_MaskRxHtotalInt(ucPortId, HV_TRUE);
    Hv_Drv_DpRx_MaskSdpInt(ucPortId, HV_TRUE);
    Hv_Drv_DpRx_AudioStop(ucPortId);
    Hv_Vos_UnmaskIrq(ucIrqId);
    Hv_Drv_DpRx_SetTrainMode(ucPortId, DP_AUTO_LINK_TRAINING);
    if (ucPortId == 0)
    {
        Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_DP, HOTFIX_DP0_IDLESTART);
    }
    else
    {
        Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_DP, HOTFIX_DP1_IDLESTART);
    }

    if (bCableConnect)
    {
        HV_LOG_DEBUG(DP, "DP%d cable is already Plug-In", ucPortId);
        Hv_Drv_DpRx_SetCableStatus(pstDpCtrl->ucCurPort, HV_TRUE);
        /* Release reset of phy and mac */
        Hv_Drv_DpRx_Reset(pstDpCtrl->ucCurPort, HV_FALSE);

        pstDpCtrl->bCableConnected = HV_TRUE;
        /* Pulling-up HDP */
        Hv_Mw_DpRx_HpdToggle(pstDpCtrl->enPortIndex);

        return HV_SUCCESS;
    }
    else
    {
        HV_LOG_DEBUG(DP, "DP%d cable is already Plug-Out", ucPortId);
        Hv_Drv_DpRx_SetHPDStatus(pstDpCtrl->ucCurPort, DP_HPD_LOW);

        return HV_FAILURE;
    }
}

Status Hv_Mw_DpRx_Sm_CableDet(const InputPortEvent *pstEvent, VOID *pstPortData)
{
    BOOL bCableConnect = HV_FALSE;
    ChannelEvent stChannelEvent = {0};
    DisplayPortCtrlData *pstDpCtrl  = (DisplayPortCtrlData *)pstPortData;
    HV_ASSERT_VALID_PTR(pstEvent);
    HV_ASSERT_VALID_PTR(pstDpCtrl);
    UCHAR8 ucPortId = pstDpCtrl->ucCurPort;

    if (((ucPortId == 0) && (HV_BOARD_CONFIG_DP0_TYPE == DP_PORT_ALTMODE))
     || ((ucPortId == 1) && (HV_BOARD_CONFIG_DP1_TYPE == DP_PORT_ALTMODE)))
    {
        if (pstEvent->usEventId == InputPortEventId_DP_CableConnect)
        {
            bCableConnect = HV_TRUE;
        }
        else
        {
            bCableConnect = HV_FALSE;
        }
    }
    else
    {
        bCableConnect = Hv_Drv_DpRx_DetectCable(ucPortId);
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_DP_NOSTAND_CABLE_ENABLE)
        bCableConnect |= Hv_Drv_DpRx_GetAuxState(pstDpCtrl->ucCurPort);
#endif
        if (pstDpCtrl->bCableConnected && bCableConnect)
        {
            HV_LOG_DEBUG(DP, "DP%d cable state is not changed", ucPortId);

            /* should clear mute when turbulence in link sync */
            if (pstDpCtrl->enCurrentPortState == INPUT_PORT_STATE_DISPLAY_RDY)
            {
                FwClrBlack(ucPortId);
            }

            return HV_FAILURE;
        }
    }

    /* plugin --> plugout */
    if (pstDpCtrl->bDpChkTimerStart)
    {
        Hv_Vos_Timer_Stop(pstDpCtrl->pstTimingCheckTimer);
        pstDpCtrl->bDpChkTimerStart = HV_FALSE;
    }

    if (pstDpCtrl->bDpTrainingTimerStart)
    {
        Hv_Vos_Timer_Stop(pstDpCtrl->pstTrainingTimer);
        pstDpCtrl->bDpTrainingTimerStart = HV_FALSE;
    }

    if (pstDpCtrl->bDpHpdTimerStart)
    {
        Hv_Vos_Timer_Stop(pstDpCtrl->pstHpdTimer);
        pstDpCtrl->bDpHpdTimerStart = HV_FALSE;
    }

#ifdef CONFIG_USER_DP_AUDIO_RESHAPE_ON
    if (pstDpCtrl->bDpAudioTimerStart)
    {
        Hv_Vos_Timer_Stop(pstDpCtrl->pstAudioCheckTimer);
        pstDpCtrl->bDpAudioTimerStart = HV_FALSE;
    }
#endif

    if (bCableConnect)
    {
        /* plugout --> plugin */
        HV_LOG_INFO(DP, "DP%d cable is Plug-In", ucPortId);
        Hv_Drv_DpRx_SetCableStatus(pstDpCtrl->ucCurPort, HV_TRUE);
        /* Release reset of phy and mac */
        Hv_Drv_DpRx_Reset(pstDpCtrl->ucCurPort, HV_FALSE);

        /* Pull-up HDP */
        if ((ucPortId == 0) && (HV_BOARD_CONFIG_DP0_TYPE == DP_PORT_ALTMODE))
        {
#ifdef CONFIG_USER_TYPE_C_ON
            Hv_Mw_Typec_AMESetDpHpd(HV_BOARD_CONFIG_DP0_TO_TYPEC, (BOOL)DP_HPD_HIGH);
#endif
        }
        else if ((ucPortId == 1) && (HV_BOARD_CONFIG_DP1_TYPE == DP_PORT_ALTMODE))
        {
#ifdef CONFIG_USER_TYPE_C_ON
            Hv_Mw_Typec_AMESetDpHpd(HV_BOARD_CONFIG_DP1_TO_TYPEC, (BOOL)DP_HPD_HIGH);
#endif
        }
        else
        {
            Hv_Drv_DpRx_EvtHpd(ucPortId, (BOOL)DP_HPD_HIGH);
        }
        pstDpCtrl->ucHpdLevel = DP_HPD_HIGH;
        Hv_Drv_DpRx_SetHPDStatus(pstDpCtrl->ucCurPort, DP_HPD_HIGH);
        pstDpCtrl->bCableConnected = HV_TRUE;
        pstDpCtrl->bAuxState = HV_FALSE;

        return HV_SUCCESS;
    }
    else
    {
        /* plugin/plugout --> plugout */
        HV_LOG_INFO(DP, "DP%d cable is Plug-Out", ucPortId);
        Hv_Drv_DpRx_SetCableStatus(pstDpCtrl->ucCurPort, HV_FALSE);

        /* Pullin-dwon HDP */
        if ((ucPortId == 0) && (HV_BOARD_CONFIG_DP0_TYPE == DP_PORT_ALTMODE))
        {
            /* Do Nothing */
        }
        else if ((ucPortId == 1) && (HV_BOARD_CONFIG_DP1_TYPE == DP_PORT_ALTMODE))
        {
            /* Do Nothing */
        }
        else
        {
            Hv_Drv_DpRx_EvtHpd(ucPortId, (BOOL)DP_HPD_LOW);
        }

        /* Disable interrupts */
        Hv_Drv_DpRx_MaskSdpInt(ucPortId, HV_TRUE);
        Hv_Drv_DpRx_MaskColorInt(ucPortId, HV_TRUE);
        Hv_Drv_DpRx_MaskTimingInt(ucPortId, HV_TRUE);
        Hv_Drv_DpRx_MaskAudioDepthInt(ucPortId, HV_TRUE);
        Hv_Drv_DpRx_MaskRxHtotalInt(ucPortId, HV_TRUE);

        /* Clear status and timing infos */
        pstDpCtrl->ucHpdLevel = DP_HPD_LOW;
        Hv_Drv_DpRx_SetHPDStatus(pstDpCtrl->ucCurPort, DP_HPD_LOW);
        pstDpCtrl->bCableConnected = HV_FALSE;
        pstDpCtrl->bLinkSync = HV_FALSE;
        pstDpCtrl->bLinkPeriod = HV_FALSE;
        pstDpCtrl->bIsNoSignal = HV_TRUE;
        pstDpCtrl->enLastPortUnSyncReason = LastPortUnSyncReason_PlugOut;
        HV_MEMSET(&pstDpCtrl->stCurVrr, 0, sizeof(VRRInfoParam));
        HV_MEMSET(&pstDpCtrl->stCurHdr, 0, sizeof(HDRParam));
        Hv_Drv_DpRx_ClrHdr(ucPortId);
        Hv_Drv_DpRx_ClrVrr(ucPortId);
        Hv_Mw_Hdcp_ReleaseHdcpBinding(pstDpCtrl->enPortIndex);

        /* Reset phy and mac */
        Hv_Drv_DpRx_ResetDpcd(ucPortId);
        Hv_Drv_DpRx_SetTrainMode(ucPortId, DP_AUTO_LINK_TRAINING);
        Hv_Drv_DpRx_Reset(pstDpCtrl->ucCurPort, HV_TRUE);

        stChannelEvent.usEventId = CHANNEL_EVENT_ID_PLUG_OUT;
        stChannelEvent.usValue = pstDpCtrl->enPortIndex;
        SendChannelMsg(pstDpCtrl->enPortIndex, &stChannelEvent);

        return HV_SUCCESS;
    }
}

Status Hv_Mw_DpRx_Sm_TrainingDone(const InputPortEvent *pstEvent, VOID *pstPortData)
{
    BOOL bLinkSta = HV_FALSE;
    DisplayPortCtrlData *pstDpCtrl = (DisplayPortCtrlData *)pstPortData;
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    bLinkSta = Hv_Drv_DpRx_DetectLink(pstDpCtrl->ucCurPort);

    if (bLinkSta)
    {
        HV_LOG_DEBUG(DP, "DP%d is training done", pstDpCtrl->ucCurPort);
        pstDpCtrl->bLinkSync = HV_TRUE;

        /* Stop trainingNG timer if started */
        if (pstDpCtrl->bDpTrainingTimerStart)
        {
           Hv_Vos_Timer_Stop(pstDpCtrl->pstTrainingTimer);
           pstDpCtrl->bDpTrainingTimerStart = HV_FALSE;
           HV_LOG_DEBUG(DP, "Stop Training NG Timer");
        }

        Hv_Drv_DpRx_EqPermit(pstDpCtrl->ucCurPort);
        Hv_Vos_TaskEnterCritical();
        Hv_Drv_DpRx_ClrHdr(pstDpCtrl->ucCurPort);
        Hv_Drv_DpRx_ClrVrr(pstDpCtrl->ucCurPort);
        Hv_Vos_TaskExitCritical();
        /* Wait for timing stable */
        if (!pstDpCtrl->bDpChkTimerStart)
        {
            pstDpCtrl->bDpChkTimerStart = HV_TRUE;
            pstDpCtrl->ucTimChkCnt = 0;
            Hv_Vos_Timer_Start(pstDpCtrl->pstTimingCheckTimer);
        }
        if (pstDpCtrl->ucCurPort == 0)
        {
            Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_DP, HOTFIX_DP0_TRAININGDONE);
        }
        else
        {
            Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_DP, HOTFIX_DP1_TRAININGDONE);
        }

        return HV_SUCCESS;
    }
    else
    {
        HV_LOG_DEBUG(DP, "DP%d is still training failed", pstDpCtrl->ucCurPort);

        return HV_FAILURE;
    }
}

/* Training falling fail */
Status Hv_Mw_DpRx_Sm_TrainingFail(const InputPortEvent *pstEvent, VOID *pstPortData)
{
    ChannelEvent stChannelEvent = {0};
    DisplayPortCtrlData *pstDpCtrl = (DisplayPortCtrlData *)pstPortData;
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    HV_LOG_DEBUG(DP, "DP%d is training failed", pstDpCtrl->ucCurPort);
    if (pstDpCtrl->bDpChkTimerStart)
    {
        Hv_Vos_Timer_Stop(pstDpCtrl->pstTimingCheckTimer);
        pstDpCtrl->bDpChkTimerStart = HV_FALSE;
    }

#ifdef CONFIG_USER_DP_AUDIO_RESHAPE_ON
    if (pstDpCtrl->bDpAudioTimerStart)
    {
        Hv_Vos_Timer_Stop(pstDpCtrl->pstAudioCheckTimer);
        pstDpCtrl->bDpAudioTimerStart = HV_FALSE;
    }
#endif

    /* Clear timing infos */
    pstDpCtrl->bLinkSync = HV_FALSE;
    if (HV_FALSE == pstDpCtrl->bIsNoSignal)
    {
        ChannelEvent stChannelEvent = {0};
        stChannelEvent.usEventId = CHANNEL_EVENT_ID_SIGNAL_LOSS;
        stChannelEvent.usValue = pstDpCtrl->enPortIndex;
        pstDpCtrl->enLastPortUnSyncReason = LastPortUnSyncReason_SignalLoss;
        SendChannelMsg(pstDpCtrl->enPortIndex, &stChannelEvent);
    }
    pstDpCtrl->bIsNoSignal= HV_TRUE;
    pstDpCtrl->enLastPortUnSyncReason = LastPortUnSyncReason_SignalLoss;
    HV_MEMSET(&pstDpCtrl->stCurTiming , 0, sizeof(VideoTimingParam));
    HV_MEMSET(&pstDpCtrl->stCurVrr, 0, sizeof(VRRInfoParam));
    HV_MEMSET(&pstDpCtrl->stCurHdr, 0, sizeof(HDRParam));
    Hv_Vos_TaskEnterCritical();
    Hv_Drv_DpRx_ClrHdr(pstDpCtrl->ucCurPort);
    Hv_Drv_DpRx_ClrVrr(pstDpCtrl->ucCurPort);
    Hv_Vos_TaskExitCritical();
    Hv_Mw_Hdcp_DpResetLinkIntegrityFailure(pstDpCtrl->ucCurPort);

    /* Generate IRQ_HPD */
    if ((pstDpCtrl->ucCurPort == 0) && (HV_BOARD_CONFIG_DP0_TYPE == DP_PORT_ALTMODE) && (pstDpCtrl->ucHpdLevel == DP_HPD_HIGH))
    {
#ifdef CONFIG_USER_TYPE_C_ON
        Hv_Mw_Typec_AMESetDpIrqHpd(HV_BOARD_CONFIG_DP0_TO_TYPEC);
#endif
    }
    else if ((pstDpCtrl->ucCurPort == 1) && (HV_BOARD_CONFIG_DP1_TYPE == DP_PORT_ALTMODE) && (pstDpCtrl->ucHpdLevel == DP_HPD_HIGH))
    {
#ifdef CONFIG_USER_TYPE_C_ON
        Hv_Mw_Typec_AMESetDpIrqHpd(HV_BOARD_CONFIG_DP1_TO_TYPEC);
#endif
    }

    if (pstDpCtrl->enCurrentPortState >= INPUT_PORT_STATE_DISPLAY_RDY)
    {
        stChannelEvent.usEventId = CHANNEL_EVENT_ID_SIGNAL_LOSS;
        stChannelEvent.usValue = pstDpCtrl->enPortIndex;
        SendChannelMsg(pstDpCtrl->enPortIndex, &stChannelEvent);
    }
    if (pstDpCtrl->ucCurPort == 0)
    {
        Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_DP, HOTFIX_DP0_TRAININGFAIL);
    }
    else
    {
        Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_DP, HOTFIX_DP1_TRAININGFAIL);
    }

    return HV_SUCCESS;
}

Status Hv_Mw_DpRx_Sm_CheckTiming(const InputPortEvent *pstEvent, VOID *pstPortData)
{
    VideoTimingParam stTempTiming = {0};
    DisplayPortCtrlData *pstDpCtrl = (DisplayPortCtrlData *)pstPortData;
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    pstDpCtrl->bDpChkTimerStart = HV_FALSE;

    if (pstDpCtrl->bCableConnected && pstDpCtrl->bLinkSync)
    {
        HV_LOG_DEBUG(DP, "DP%d check timing", pstDpCtrl->ucCurPort);

        /* Timing is valid or not */
        if ((Hv_Drv_DpRx_GetTiming(pstDpCtrl->ucCurPort, &stTempTiming, &pstDpCtrl->stCurAudioTiming) == HV_FAILURE)
         || (Hv_Drv_DpRx_DetectVideo(pstDpCtrl->ucCurPort) == HV_FALSE)
         || (Hv_Drv_DpRx_GetPowerState(pstDpCtrl->ucCurPort) != 0x1))
        {
            HV_LOG_DEBUG(DP, "DP%d get timing failed", pstDpCtrl->ucCurPort);

            pstDpCtrl->bDpChkTimerStart = HV_TRUE;
            pstDpCtrl->ucTimChkCnt++;
            Hv_Vos_Timer_Start(pstDpCtrl->pstTimingCheckTimer);
            if ((pstDpCtrl->ucTimChkCnt > 5) && (Hv_Drv_DpRx_DetectVideo(pstDpCtrl->ucCurPort) == HV_TRUE) && (Hv_Drv_DpRx_GetPowerState(pstDpCtrl->ucCurPort) == 0x1))
            {
                pstDpCtrl->bIsNoSignal= HV_FALSE;
            }

            return HV_FAILURE;
        }

        /* Get Freesync status */
        Hv_Drv_DpRx_GetVrr(pstDpCtrl->ucCurPort, &pstDpCtrl->stCurVrr);
        Hv_Drv_DpRx_CheckOui(pstDpCtrl->ucCurPort, &pstDpCtrl->stCurVrr);

        /* Timing is stable or not */
        if (pstDpCtrl->stCurTiming.usHTotal  != stTempTiming.usHTotal
         || (pstDpCtrl->stCurTiming.usVTotal != stTempTiming.usVTotal && !pstDpCtrl->stCurVrr.bVRREnable)
         || (pstDpCtrl->stCurTiming.usHActive != stTempTiming.usHActive)
         || (pstDpCtrl->stCurTiming.usVActive != stTempTiming.usVActive)
         || (ABS(pstDpCtrl->stCurTiming.uiFreqKHz, stTempTiming.uiFreqKHz) > DP_FREQ_THD)
         || (HV_FALSE == Hv_Drv_DpRx_GetSdpStatus(pstDpCtrl->ucCurPort)))
        {
            HV_LOG_DEBUG(DP, "DP%d timing is unstable", pstDpCtrl->ucCurPort);

            HV_MEMCPY(&pstDpCtrl->stCurTiming, &stTempTiming, sizeof(VideoTimingParam));
            pstDpCtrl->bDpChkTimerStart = HV_TRUE;
            pstDpCtrl->ucTimChkCnt++;
            Hv_Vos_Timer_Start(pstDpCtrl->pstTimingCheckTimer);
            if ((pstDpCtrl->ucTimChkCnt > 5) && (Hv_Drv_DpRx_DetectVideo(pstDpCtrl->ucCurPort) == HV_TRUE) && (Hv_Drv_DpRx_GetPowerState(pstDpCtrl->ucCurPort) == 0x1))
            {
                pstDpCtrl->bIsNoSignal= HV_FALSE;
            }

            return HV_FAILURE;
        }

        /* Enable timing relative interrupt */
        Hv_Drv_DpRx_MaskTimingInt(pstDpCtrl->ucCurPort, HV_FALSE);
        Hv_Drv_DpRx_MaskAudioDepthInt(pstDpCtrl->ucCurPort, HV_FALSE);
        Hv_Drv_DpRx_MaskSdpInt(pstDpCtrl->ucCurPort, HV_FALSE);
        Hv_Drv_DpRx_MaskColorInt(pstDpCtrl->ucCurPort, HV_FALSE);

        /* Get Color and HDR info */
        Hv_Drv_DpRx_GetColor(pstDpCtrl->ucCurPort, &pstDpCtrl->stCurColor);
        Hv_Drv_DpRx_GetHdr(pstDpCtrl->ucCurPort, &pstDpCtrl->stCurHdr);
        if (((pstDpCtrl->enCurEdidType & EDID_TYPE_CLOSE_HDR) == BIT_5)
          || (pstDpCtrl->enCurEdidType == EDID_TYPE_PBP)
          || (pstDpCtrl->enCurEdidType == EDID_TYPE_PIP))
        {
            pstDpCtrl->stCurHdr.xType = 0;
        }
#ifdef CONFIG_USER_DP_AUDIO_RESHAPE_ON
        if ((pstDpCtrl->stCurVrr.eVendor == VendorType_NVIDIA) &&
            (pstDpCtrl->stCurTiming.usHActive <= 800) &&
            (pstDpCtrl->stCurTiming.usVActive <= 600))
        {
            if(!pstDpCtrl->bDpAudioTimerStart)
            {
                Hv_Vos_Timer_Start(pstDpCtrl->pstAudioCheckTimer);
                pstDpCtrl->bDpAudioTimerStart = HV_TRUE;
            }
        }
#endif
        if (pstDpCtrl->ucCurPort == 0)
        {
            Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_DP, HOTFIX_DP0_DISPLAYREADY);
        }
        else
        {
            Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_DP, HOTFIX_DP1_DISPLAYREADY);
        }

        HV_LOG_INFO(DP, "\nDP%d TimingInfo: %dx%d@%dHz Total %dx%d Format %d Depth %d Space %d Range %d HDR %d VRR %d\n",
                        pstDpCtrl->ucCurPort,
                        pstDpCtrl->stCurTiming.usHActive,
                        pstDpCtrl->stCurTiming.usVActive,
                        pstDpCtrl->stCurTiming.usFrameRate,
                        pstDpCtrl->stCurTiming.usHTotal,
                        pstDpCtrl->stCurTiming.usVTotal,
                        pstDpCtrl->stCurColor.eClrFormat,
                        pstDpCtrl->stCurColor.eClrDepth,
                        pstDpCtrl->stCurColor.eClrSpace,
                        pstDpCtrl->stCurColor.eClrRange,
                        pstDpCtrl->stCurHdr.xType,
                        pstDpCtrl->stCurVrr.bVRREnable);

        return HV_SUCCESS;
    }
    else
    {
        return HV_FAILURE;
    }
}

/* Generate IRQ_HPD after training fail directly */
Status Hv_Mw_DpRx_Sm_TrainingNG(const InputPortEvent *pstEvent, VOID *pstPortData)
{
    DisplayPortCtrlData *pstDpCtrl = (DisplayPortCtrlData *)pstPortData;
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    pstDpCtrl->bDpTrainingTimerStart = HV_FALSE;
    Hv_Drv_DpRx_DumpFailStatus(pstDpCtrl->ucCurPort);

    if (pstDpCtrl->bLinkPeriod)
    {
#if (HV_PROJECT_CONFIG_CTS == HV_OFF)
        Hv_Mw_DpRx_IrqHpd(pstDpCtrl->enPortIndex);
#endif
        HV_LOG_DEBUG(DP, "NG IRQ HPD");
    }
#ifdef CONFIG_USER_TYPE_C_ON
    /**
    * Fix the issue where the Red Magic 6 Pro phone etc occasionally fails to display after the motherboard
    * restarts when connected via type-c
     */
    else if (Hv_Drv_DpRx_GetPowerState(pstDpCtrl->ucCurPort) == 1)
    {
        if ((pstDpCtrl->ucCurPort == 0) && (HV_BOARD_CONFIG_DP0_TYPE == DP_PORT_ALTMODE))
        {
            Hv_Mw_Typec_AMESetDpHpd(HV_BOARD_CONFIG_DP0_TO_TYPEC, (BOOL)DP_HPD_HIGH);
        }
        else if ((pstDpCtrl->ucCurPort == 1) && (HV_BOARD_CONFIG_DP1_TYPE == DP_PORT_ALTMODE))
        {
            Hv_Mw_Typec_AMESetDpHpd(HV_BOARD_CONFIG_DP1_TO_TYPEC, (BOOL)DP_HPD_HIGH);
        }
    }
#endif

    return HV_SUCCESS;
}

/* Pull up HPD after pulling down for a while */
Status Hv_Mw_DpRx_Sm_HpdTimeOut(const InputPortEvent *pstEvent, VOID *pstPortData)
{
    DisplayPortCtrlData *pstDpCtrl = (DisplayPortCtrlData *)pstPortData;
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    HV_LOG_DEBUG(DP, "D%d HPD timer-out", pstDpCtrl->ucCurPort);

    pstDpCtrl->bDpHpdTimerStart = HV_FALSE;
    if ((pstDpCtrl->ucCurPort == 0) && (HV_BOARD_CONFIG_DP0_TYPE == DP_PORT_ALTMODE))
    {
#ifdef CONFIG_USER_TYPE_C_ON
        Hv_Mw_Typec_AMESetDpHpd(HV_BOARD_CONFIG_DP0_TO_TYPEC, (BOOL)DP_HPD_HIGH);
#endif
    }
    else if ((pstDpCtrl->ucCurPort == 1) && (HV_BOARD_CONFIG_DP1_TYPE == DP_PORT_ALTMODE))
    {
#ifdef CONFIG_USER_TYPE_C_ON
        Hv_Mw_Typec_AMESetDpHpd(HV_BOARD_CONFIG_DP1_TO_TYPEC, (BOOL)DP_HPD_HIGH);
#endif
    }
    else
    {
        Hv_Drv_DpRx_EvtHpd(pstDpCtrl->ucCurPort, (BOOL)DP_HPD_HIGH);
    }
    pstDpCtrl->ucHpdLevel = DP_HPD_HIGH;
    Hv_Drv_DpRx_SetHPDStatus(pstDpCtrl->ucCurPort, DP_HPD_HIGH);

    return HV_CONTINUE;
}

Status Hv_Mw_DpRx_Sm_TimingChange(const InputPortEvent *pstEvent, VOID *pstPortData)
{
    DisplayPortCtrlData *pstDpCtrl = (DisplayPortCtrlData *)pstPortData;
    ChannelEvent stChannelEvent = {0};
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    HV_LOG_DEBUG(DP, "DP%d timing is changed", pstDpCtrl->ucCurPort);
    HV_MEMSET(&pstDpCtrl->stCurVrr, 0, sizeof(VRRInfoParam));
    HV_MEMSET(&pstDpCtrl->stCurHdr, 0, sizeof(HDRParam));
    Hv_Vos_TaskEnterCritical();
    Hv_Drv_DpRx_ClrHdr(pstDpCtrl->ucCurPort);
    Hv_Drv_DpRx_ClrVrr(pstDpCtrl->ucCurPort);
    Hv_Vos_TaskExitCritical();
    Hv_Mw_Hdcp_RealseHdcpCmStatus(pstDpCtrl->enPortIndex);

    stChannelEvent.usEventId = CHANNEL_EVENT_ID_TIMING_CHANGE;
    stChannelEvent.usValue = pstDpCtrl->enPortIndex;
    pstDpCtrl->enLastPortUnSyncReason = LastPortUnSyncReason_TimingChange;
    SendChannelMsg(pstDpCtrl->enPortIndex, &stChannelEvent);

    pstDpCtrl->bLinkSync = HV_FALSE;

    return HV_SUCCESS;
}

Status Hv_Mw_DpRx_Sm_AudioReshape(const InputPortEvent *pstEvent, VOID *pstPortData)
{
    DisplayPortCtrlData *pstDpCtrl = (DisplayPortCtrlData *)pstPortData;
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    Hv_Drv_DpRx_AudioReshape(pstDpCtrl->ucCurPort);
    Hv_Vos_Timer_Start(pstDpCtrl->pstAudioCheckTimer);

    return HV_SUCCESS;
}

Status Hv_Mw_DpRx_Sm_ColorChange(const InputPortEvent *pstEvent, VOID *pstPortData)
{
    VideoColorParam stNewColor = {0};
    ChannelEvent stChannelEvent = {0};
    DisplayPortCtrlData *pstDpCtrl = (DisplayPortCtrlData *)pstPortData;
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    Hv_Drv_DpRx_GetColor(pstDpCtrl->ucCurPort, &stNewColor);

    if (HV_MEMCMP(&stNewColor, &pstDpCtrl->stCurColor, sizeof(VideoColorParam)) != 0)
    {
        HV_LOG_DEBUG(DP, "DP%d color is changed", pstDpCtrl->ucCurPort);
        HV_MEMCPY(&pstDpCtrl->stCurColor, &stNewColor, sizeof(VideoColorParam));

        stChannelEvent.usEventId = CHANNEL_EVENT_ID_COLOR_CHANGE;
        stChannelEvent.usValue = pstDpCtrl->enPortIndex;
        pstDpCtrl->enLastPortUnSyncReason = LastPortUnSyncReason_ColorChange;
        SendChannelMsg(pstDpCtrl->enPortIndex, &stChannelEvent);

        return HV_SUCCESS;
    }
    else
    {
        HV_LOG_DEBUG(DP, "DP%d color is not changed", pstDpCtrl->ucCurPort);
        FwClrBlack(pstDpCtrl->ucCurPort);
        Hv_Drv_DpRx_MaskColorInt(pstDpCtrl->ucCurPort, HV_FALSE);

        return HV_FAILURE;
    }
}

Status Hv_Mw_DpRx_Sm_HdrChange(const InputPortEvent *pstEvent, VOID *pstPortData)
{
    HDRParam stNewHdr = {0};
    ChannelEvent stChannelEvent = {0};
    DisplayPortCtrlData *pstDpCtrl = (DisplayPortCtrlData *)pstPortData;
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    Hv_Drv_DpRx_GetHdr(pstDpCtrl->ucCurPort, &stNewHdr);
    if (((pstDpCtrl->enCurEdidType & EDID_TYPE_CLOSE_HDR) == BIT_5)
      || (pstDpCtrl->enCurEdidType == EDID_TYPE_PBP)
      || (pstDpCtrl->enCurEdidType == EDID_TYPE_PIP))
    {
        stNewHdr.xType = 0;
    }

    if (stNewHdr.xType != pstDpCtrl->stCurHdr.xType)
    {
        HV_MEMCPY(&pstDpCtrl->stCurHdr, &stNewHdr, sizeof(HDRParam));

        HV_LOG_DEBUG(DP, "DP%d HDR Type is changed", pstDpCtrl->ucCurPort);
        if (pstDpCtrl->enCurrentPortState == INPUT_PORT_STATE_DISPLAY_RDY)
        {
            stChannelEvent.usEventId = CHANNEL_EVENT_ID_HDR_CHANGED;
            stChannelEvent.usValue = pstDpCtrl->enPortIndex;
            SendChannelMsg(pstDpCtrl->enPortIndex, &stChannelEvent);
        }
    }
    else if (stNewHdr.xType > 0)
    {
        HV_MEMCPY(&pstDpCtrl->stCurHdr, &stNewHdr, sizeof(HDRParam));

        HV_LOG_DEBUG(DP, "DP%d HDR is changed", pstDpCtrl->ucCurPort);
        if (pstDpCtrl->enCurrentPortState == INPUT_PORT_STATE_DISPLAY_RDY)
        {
            stChannelEvent.usEventId = CHANNEL_EVENT_ID_HDR_CHANGED;
            stChannelEvent.usValue = pstDpCtrl->enPortIndex;
            SendChannelMsg(pstDpCtrl->enPortIndex, &stChannelEvent);
        }
    }
    else
    {
        HV_LOG_DEBUG(DP, "DP%d HDR is not changed", pstDpCtrl->ucCurPort);
    }

    return HV_CONTINUE;
}

/* Get FreeSync Status */
Status Hv_Mw_DpRx_Sm_VrrChange(const InputPortEvent *pstEvent, VOID *pstPortData)
{
    VRRInfoParam stNewVrr = {0};
    DisplayPortCtrlData *pstDpCtrl = (DisplayPortCtrlData *)pstPortData;
    HV_ASSERT_VALID_PTR(pstDpCtrl);
    ChannelEvent stChannelEvent = {0};

    Hv_Drv_DpRx_GetVrr(pstDpCtrl->ucCurPort, &stNewVrr);

    if (HV_MEMCMP(&stNewVrr, &pstDpCtrl->stCurVrr, sizeof(VRRInfoParam)) != 0)
    {
        HV_MEMCPY(&pstDpCtrl->stCurVrr, &stNewVrr, sizeof(VRRInfoParam));
        stChannelEvent.usEventId = CHANNEL_EVENT_ID_RCV_VRR_INFO;
        stChannelEvent.usValue = pstDpCtrl->enPortIndex;
        SendChannelMsg(pstDpCtrl->enPortIndex, &stChannelEvent);

        HV_LOG_DEBUG(DP, "DP%d VRR is change", pstDpCtrl->ucCurPort);
    }
    else
    {
        HV_LOG_DEBUG(DP, "DP%d VRR is not changed", pstDpCtrl->ucCurPort);
    }

    return HV_CONTINUE;
}

/* Get Gsync Status */
Status Hv_Mw_DpRx_Sm_TimingIgnoreChange(const InputPortEvent *pstEvent, VOID *pstPortData)
{
    VRRInfoParam stNewVrr = {0};
    DisplayPortCtrlData *pstDpCtrl = (DisplayPortCtrlData *)pstPortData;
    ChannelEvent stChannelEvent = {0};
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    HV_LOG_DEBUG(DP, "DP%d checkoui", pstDpCtrl->ucCurPort);
    Hv_Drv_DpRx_CheckOui(pstDpCtrl->ucCurPort, &stNewVrr);

    if (pstDpCtrl->stCurVrr.bVRREnable != stNewVrr.bVRREnable)
    {
        HV_MEMCPY(&pstDpCtrl->stCurVrr, &stNewVrr, sizeof(VRRInfoParam));
        stChannelEvent.usEventId = CHANNEL_EVENT_ID_RCV_VRR_INFO;
        stChannelEvent.usValue = pstDpCtrl->enPortIndex;
        SendChannelMsg(pstDpCtrl->enPortIndex, &stChannelEvent);
    }

    return HV_CONTINUE;
}

Status Hv_Mw_DpRx_Sm_AdaptSyncStart(const InputPortEvent *pstEvent, VOID *pstPortData)
{
    DisplayPortCtrlData *pstDpCtrl = (DisplayPortCtrlData *)pstPortData;
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    pstDpCtrl->stCurVrr.bVRREnable = HV_TRUE;
    pstDpCtrl->stCurVrr.eVendor = VendorType_AMD_AdaptSync;

    HV_LOG_DEBUG(DP, "DP%d Adaptive-Sync start", pstDpCtrl->ucCurPort);

    return HV_CONTINUE;
}

Status Hv_Mw_DpRx_Sm_AdaptSyncEnd(const InputPortEvent *pstEvent, VOID *pstPortData)
{
    DisplayPortCtrlData *pstDpCtrl = (DisplayPortCtrlData *)pstPortData;
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    pstDpCtrl->stCurVrr.bVRREnable = HV_FALSE;
    pstDpCtrl->stCurVrr.eVendor = VendorType_AMD_AdaptSync;

    HV_LOG_DEBUG(DP, "DP%d Adaptive-Sycn end", pstDpCtrl->ucCurPort);

    return HV_CONTINUE;
}

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

/* Receive Mccs Cmds */
Status Hv_Mw_DpRx_Sm_MccsProc(const InputPortEvent *pstEvent, VOID *pstPortData)
{
    SystemEvent stSystemEvent = {0};
    HV_VOS_QUEUE_S* pstSysQueue = Hv_Mw_System_GetSystemQueue();
    HV_ASSERT_VALID_PTR_RET_NO_LOG(pstSysQueue, HV_VOS_ISR_NOT_HANDLED);

    DisplayPortCtrlData *pstDpCtrl = (DisplayPortCtrlData *)pstPortData;
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    Hv_Drv_DpRx_GetMccsCmd(pstDpCtrl->ucCurPort, s_aucRecvData[s_ucRecvDataIdx], DP_MCCS_CMD_LENGTH);
    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.ucPortIndex = DDCCI_PORT_DP0 + pstDpCtrl->ucCurPort;
    Hv_Vos_QueueSendFromISR(pstSysQueue, &stSystemEvent);

    return HV_CONTINUE;
}

/* Reconfig lane swap and polarity when type-c flips */
VOID Hv_Mw_DpRx_SetTypecOrientation(LinkPortIndex enPortIndex, UCHAR8 ucOrientation, UCHAR8 ucPinAssignment)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enPortIndex);
    HV_ASSERT_VALID_PTR_VOID(pstDpCtrl);

    Hv_Drv_DpRx_SetTypecOrientation(pstDpCtrl->ucCurPort, ucOrientation, ucPinAssignment);

    return;
}

/* Mute audio, no use any more */
Status Hv_Mw_DpRx_AudioStop(LinkPortIndex enPortIndex)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enPortIndex);
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    Hv_Drv_DpRx_AudioStop(pstDpCtrl->ucCurPort);
    pstDpCtrl->bAudioAbnormal = HV_TRUE;

    return HV_SUCCESS;
}

/* Unmute audio, no use any more */
Status Hv_Mw_DpRx_AudioStart(LinkPortIndex enPortIndex)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enPortIndex);
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    Hv_Drv_DpRx_AudioStart(pstDpCtrl->ucCurPort);

    return HV_SUCCESS;
}

/* Clear audio fifo until stable when audio unmute */
Status Hv_Mw_DpRx_AudioCheck(LinkPortIndex enPortIndex)
{
    DisplayPortCtrlData *pstDpCtrl = GetFromLinkPort(enPortIndex);
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    Hv_Drv_DpRx_AudioCheck(pstDpCtrl->ucCurPort);

    return HV_SUCCESS;
}

/* Exit going to standby when receive DPCD 00600 = 0x1 */
Status Hv_Mw_DpRx_Sm_WakeUp(const InputPortEvent *pstEvent, VOID *pstPortData)
{
    ChannelEvent stChannelEvent = {0};
    DisplayPortCtrlData *pstDpCtrl = (DisplayPortCtrlData *)pstPortData;
    HV_ASSERT_VALID_PTR(pstDpCtrl);
    UCHAR8 ucPowerState = 0;

    ucPowerState = Hv_Drv_DpRx_GetPowerState(pstDpCtrl->ucCurPort);
    if (ucPowerState == 0x1)
    {
        stChannelEvent.usEventId = CHANNEL_EVENT_ID_NO_SIGNAL_TO_SEARCH;
        stChannelEvent.usValue = pstDpCtrl->enPortIndex;
        pstDpCtrl->enLastPortUnSyncReason = LastPortUnSyncReason_None;
        SendChannelMsg(pstDpCtrl->enPortIndex, &stChannelEvent);
        HV_LOG_DEBUG(DP, "DP%d Wake Up", pstDpCtrl->ucCurPort);
#ifdef CONFIG_USER_TYPE_C_ON
        if (pstDpCtrl->ucHpdLevel != DP_HPD_HIGH)
        {
            if ((pstDpCtrl->ucCurPort == 0) && (HV_BOARD_CONFIG_DP0_TYPE == DP_PORT_ALTMODE))
            {
                Hv_Mw_Typec_AMESetDpHpd(HV_BOARD_CONFIG_DP0_TO_TYPEC, (BOOL)DP_HPD_HIGH);
            }
            else if ((pstDpCtrl->ucCurPort == 1) && (HV_BOARD_CONFIG_DP1_TYPE == DP_PORT_ALTMODE))
            {
                Hv_Mw_Typec_AMESetDpHpd(HV_BOARD_CONFIG_DP1_TO_TYPEC, (BOOL)DP_HPD_HIGH);
            }
        }
#endif
        if (pstDpCtrl->ucCurPort == 0)
        {
            Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_DP, HOTFIX_DP0_POWERON);
        }
        else
        {
            Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_DP, HOTFIX_DP1_POWERON);
        }
    }
    else
    {
        pstDpCtrl->bLinkPeriod = HV_FALSE;
    }

    return HV_SUCCESS;
}

Status Hv_Mw_DpRx_Sm_AudioMuteChgHandler(const InputPortEvent *pstEvent, VOID *pstPortData)
{
    ChannelEvent stChannelEvent = {0};
    DisplayPortCtrlData *pstDpCtrl = (DisplayPortCtrlData *)pstPortData;
    HV_ASSERT_VALID_PTR(pstDpCtrl);

    stChannelEvent.usEventId = CHANNEL_EVENT_ID_AUDIO_MUTE_STATE_CHANGE;
    stChannelEvent.usValue = pstDpCtrl->enPortIndex;
    SendChannelMsg(pstDpCtrl->enPortIndex, &stChannelEvent);

    return HV_SUCCESS;
}

