/**
 * @file hv_drv_HdmiRx.c
 * @brief HDMI RX 模块提供的驱动层
 * @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 "hv_comm_Assert.h"
#include "hv_comm_Define.h"
#include "hv_drv_HdmiRx.h"
#include "hv_drv_HdmiInc.h"
#include "hv_cal_HdmiInc.h"
#include "hv_comm_TimingDatabase.h"
#include "hv_chip_Clk.h"
#include "hv_comm_DataBase.h"

extern VOID Hv_Comm_SetHotfixRegister(UCHAR8 ucMain, UCHAR8 ucSub);

Status Hv_Drv_HdmiRx_TmdsInit(UCHAR8 ucPortIndex, UCHAR8 ucLaneSwap)
{
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);

    HV_ASSERT_SUCCESS(Hv_Cal_HdmiRx_SetHdmi21Enable(ucPortIndex, HV_FALSE));

    Hv_Cal_HdmiRx_TmdsCharacterAlignInit(ucPortIndex);

    Hv_Cal_HdmiRx_TmdsDeskewInit(ucPortIndex);

    //Hv_Cal_HdmiRx_TmdsLinkInit(ucPortIndex);

    Hv_Cal_HdmiRx_TmdsLaneClockInit(ucPortIndex);

    Hv_Cal_HdmiRx_Tmds4LaneMode(ucPortIndex, ucLaneSwap);

    Hv_Cal_HdmiRx_OpenTmdsAutoEq(ucPortIndex);

    return HV_SUCCESS;
}

Status Hv_Drv_HdmiRx_GetAVIPara(UCHAR8 ucPortIndex, VideoColorParam *pstVideoAVIPara, VideoTimingParam *pstTimingPara)
{
    /*检查入参*/
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);
    HV_ASSERT_VALID_PTR(pstVideoAVIPara);
    CalVideoColorParam stVideoPara = {0};

    Status uiResult = Hv_Cal_HdmiRx_GetAVIPara(ucPortIndex, &stVideoPara);

    HV_MEMCPY(pstVideoAVIPara, &stVideoPara, sizeof(VideoColorParam));

    return uiResult;
}

Status Hv_Drv_HdmiRx_GetTimingPara(UCHAR8 ucPortIndex, VideoTimingParam *pstTimingPara)
{
    /*检查入参*/
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);
    ColorDepthType ucColorDepth = ColorDepthType_8Bit;
    ColorFormatType ucColorFormat = ColorFormatType_RGB;
    CalVideoTimingParam stTimingInfo = {0};
    UINT32          uiPixelRep = 0;
    UCHAR8 ucLaneSwap = ((ucPortIndex == 0) ? HV_BOARD_CONFIG_HDMI0_LANE_SWP : HV_BOARD_CONFIG_HDMI1_LANE_SWP);
    HV_ASSERT_VALID_PTR(pstTimingPara);
    UINT32 uiResult = Hv_Cal_HdmiRx_GetTimingHVInfo(ucPortIndex, &stTimingInfo, ucLaneSwap);

    if(HV_SUCCESS != uiResult)
    {
        HV_LOG_INFO(HDMI, "HDMI%d Get Timing Failed Result: %d", ucPortIndex, uiResult);
        return HV_FAILURE;
    }

    HV_MEMCPY(pstTimingPara, &stTimingInfo, sizeof(VideoTimingParam));

    //pstTimingPara->uiRxDpllSetFreqKHz = 0;
    ucColorDepth = Hv_Cal_HdmiRx_GetColorDepth(ucPortIndex);
    switch (ucColorDepth)
    {
        case ColorDepthType_6Bit:
        case ColorDepthType_8Bit:
        {
            /*No need to do any*/
            break;
        }
        case ColorDepthType_10Bit:
        {
            pstTimingPara->usHTotal = (pstTimingPara->usHTotal << 2) / 5;
            pstTimingPara->usHActive = (pstTimingPara->usHActive << 2) / 5;
            pstTimingPara->uiRxDpllSetFreqKHz = (pstTimingPara->uiRxDpllSetFreqKHz << 2) / 5;
            break;
        }
        case ColorDepthType_12Bit:
        {
            pstTimingPara->usHTotal = (pstTimingPara->usHTotal << 1) / 3;
            pstTimingPara->usHActive = (pstTimingPara->usHActive << 1) / 3;
            pstTimingPara->uiRxDpllSetFreqKHz = (pstTimingPara->uiRxDpllSetFreqKHz << 1) / 3;
            break;
        }
        case ColorDepthType_16Bit:
        {
            pstTimingPara->usHTotal = (pstTimingPara->usHTotal) >> 1;
            pstTimingPara->usHActive = (pstTimingPara->usHActive) >> 1;
            pstTimingPara->uiRxDpllSetFreqKHz = (pstTimingPara->uiRxDpllSetFreqKHz) >> 1;
            break;
        }
        default:
        {
            HV_LOG_ERROR(HDMI, "Get HDMI%d Pixel Color Depth Error", ucPortIndex);
            break;
        }
    }

    ucColorFormat = Hv_Cal_HdmiRx_GetColorFormat(ucPortIndex);
    if (ucColorFormat == ColorFormatType_YCbCr420)
    {
        pstTimingPara->usHTotal = (pstTimingPara->usHTotal) << 1;
        pstTimingPara->usHActive = (pstTimingPara->usHActive) << 1;
        pstTimingPara->uiRxDpllSetFreqKHz = (pstTimingPara->uiRxDpllSetFreqKHz) << 1;
    }

    /* Pixel Repeation handle */
    uiPixelRep = Hv_Cal_HdmiRx_GetPixelRepeatFactor(ucPortIndex);
    if(uiPixelRep < 10)
    {
        pstTimingPara->usHTotal = (pstTimingPara->usHTotal) / (uiPixelRep + 1);
        pstTimingPara->usHActive = (pstTimingPara->usHActive) / (uiPixelRep + 1);
        pstTimingPara->uiRxDpllSetFreqKHz = (pstTimingPara->uiRxDpllSetFreqKHz) / (uiPixelRep + 1);
    }

    pstTimingPara->uiFreqKHz = (UINT32)((DOUBLE64)((DOUBLE64)(pstTimingPara->usHTotal) *  (DOUBLE64)(pstTimingPara->usVTotal)) * (pstTimingPara->fFrameRate) / 1000);

    pstTimingPara->uiHFreqHz = (UINT32)((FLOAT32)(pstTimingPara->usVTotal) * (pstTimingPara->fFrameRate));

    return HV_SUCCESS;
}

Status Hv_Drv_HdmiRx_InterruptInit(UCHAR8 ucPortIndex)
{
    /* 检查入参 */
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);
    HdmiRxIntStatus stHdmiIntRxStatus = {HV_HDMIRX_INT_1_EVENT_FRL_RATE_CHG, HV_HDMIRX_INT_2_EVENT_STANDBY_DDC};

    /* Set the Trigger mode as edge p */
    Hv_Cal_HdmiRx_SetInterruptTriggerRule(ucPortIndex);

    /* 初始化关闭所有中断 */
    HV_ASSERT_SUCCESS(Hv_Cal_HdmiRx_InterruptClearEvent(ucPortIndex, &stHdmiIntRxStatus));

    return HV_SUCCESS;
}

Status Hv_Drv_HdmiRx_PortInit(UCHAR8 ucPortIndex)
{
    /*检查入参*/
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);
    UCHAR8 ucLaneSwap = ((ucPortIndex == 0) ? HV_BOARD_CONFIG_HDMI0_LANE_SWP : HV_BOARD_CONFIG_HDMI1_LANE_SWP);
    USHORT16 ausAutoEqValue[4] = {0x178, 0x178, 0x178, 0x00};
    HV_ASSERT_SUCCESS(Hv_Cal_HdmiRx_Init(ucPortIndex, ucLaneSwap));

#if (HV_PROJECT_CONFIG_CTS == HV_CONFIG_ON)
    Hv_Cal_HdmiRx_InitWithCtsOn(ucPortIndex);
#endif

    /* HPD 初始化 */
    //HV_ASSERT_SUCCESS(Hv_Cal_HdmiRx_HPDIOInit(ucPortIndex));

    /* 5V 检测初始化 */
    HV_ASSERT_SUCCESS(Hv_Cal_HdmiRx_CableConnectInit(ucPortIndex));

    /* 中断初始化 */
    HV_ASSERT_SUCCESS(Hv_Drv_HdmiRx_InterruptInit(ucPortIndex));

    Hv_Drv_HdmiRx_CecInit(ucPortIndex);

    Hv_Cal_HdmiRx_DdcInit(ucPortIndex);

    /* TMDS init */
    HV_ASSERT_SUCCESS(Hv_Drv_HdmiRx_TmdsInit(ucPortIndex, ucLaneSwap));

    Hv_Cal_HdmiRx_FrlInit(ucPortIndex);

    Hv_Cal_HdmiRx_OpenFrlAutoEq(ucPortIndex);

    HV_ASSERT_SUCCESS(Hv_Cal_HdmiRx_PhyInit(ucPortIndex, ((ucPortIndex == 0) ? HV_BOARD_CONFIG_HDMI0_INV_PN : HV_BOARD_CONFIG_HDMI1_INV_PN)));

    HV_ASSERT_PEEK_SUCCESS(Hv_Cal_HdmiRx_AudioInit(ucPortIndex));

    Hv_Cal_HdmiRx_SetSwEqValue(ucPortIndex, ausAutoEqValue, ucLaneSwap);
    Hv_Cal_HdmiRX_SwitchAutoEqTable(ucPortIndex, HV_TRUE);

#if (HV_PROJECT_CONFIG_CTS == HV_CONFIG_ON)
    Hv_Cal_HdmiRx_ConfigurePhyRterm(ucPortIndex, 0xF);
#else
    Hv_Cal_HdmiRx_SetHdcp1XRiSel(ucPortIndex, 0x1);
#endif

    HV_LOG_DEBUG(HDMI, "Hv_Drv_HdmiRx_PortInit SUCCESS with Port:%d.",ucPortIndex);

    return HV_SUCCESS;
}

Status Hv_Drv_HdmiRx_HPDCtrol(UCHAR8 ucPortIndex, BOOL bSwitch)
{
    /*检查入参*/
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);

    /* 对HPD进行配置 */
    if (bSwitch == HV_TRUE)
    {
        Hv_Drv_HdmiRx_TmdsPreReset(ucPortIndex);
        Hv_Cal_HdmiRx_ClrMrTiming(ucPortIndex);
        Hv_Cal_HdmiRx_ControlScdcByHPDSwitch(ucPortIndex, bSwitch);
        Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + ucPortIndex, HOTFIX_HDMI_SET_HPD_HIGH);

#if (HV_BOARD_CONFIG_HDMI_HPD_SOURCE_5V == 1)
        return Hv_Cal_HdmiRx_HPDOnWithSource5V(ucPortIndex);
#else
        return Hv_Cal_HdmiRx_HPDOn(ucPortIndex);
#endif
    }
    else
    {
        /* 协议里面规定HPD拉低的时候SCDC需要恢复到默认状态 */
        Hv_Drv_HdmiRx_TmdsPreReset(ucPortIndex);
        Hv_Cal_HdmiRx_ClrMrTiming(ucPortIndex);
        Hv_Cal_HdmiRx_ControlScdcByHPDSwitch(ucPortIndex, bSwitch);
        Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + ucPortIndex, HOTFIX_HDMI_SET_HPD_LOW);

#if (HV_BOARD_CONFIG_HDMI_HPD_SOURCE_5V == 1)
        return Hv_Cal_HdmiRx_HPDOffWithSource5V(ucPortIndex);
#else
        return Hv_Cal_HdmiRx_HPDOff(ucPortIndex);
#endif
    }
}

#if (HV_PROJECT_CONFIG_FRL)
/**
 * @brief frl rate change indicate frl or tmds
 * 
 * FRL Rate 4 Bit
 * 0 : No FRL, TMDS Only
 * 1 :  3G @ 3Lane
 * 2 :  6G @ 3Lane
 * 3 :  6G @ 4Lane
 * 4 :  8G @ 4Lane
 * 5 : 10G @ 4Lane
 * 6 : 12G @ 4Lane
 * 7 - 15 :reserved 
 */
UCHAR8 Hv_Drv_HdmiFRLRateChange(UCHAR8 ucPortIndex)
{
    UCHAR8 ucFRLRate = 0;
    UCHAR8 ucLaneSwap = ((ucPortIndex == 0) ? HV_BOARD_CONFIG_HDMI0_LANE_SWP : HV_BOARD_CONFIG_HDMI1_LANE_SWP);

    /*检查入参*/
    HV_ASSERT_TRUE_RET_NO_LOG(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM,HV_FAILURE);

    ucFRLRate = Hv_Cal_HdmiRx_GetFrlRate(ucPortIndex);

    if (ucFRLRate == 0)
    {
        /* TMDS mode */
        Hv_Cal_HdmiRx_SWCfgReset(ucPortIndex);
        Hv_Cal_HdmiRx_SetHdmi21Enable(ucPortIndex, HV_FALSE);
        Hv_Cal_HdmiRX_PhyClockInit(ucPortIndex, E_D4LANETMDS, ucLaneSwap);
    }
    else
    {
        Hv_Cal_HdmiRx_SWCfgReset(ucPortIndex);
        Hv_Cal_HdmiRX_SwitchAutoEqTable(ucPortIndex, HV_FALSE);

        /* FRL mode */
        Hv_Cal_HdmiRx_SetHdmi21Enable(ucPortIndex, HV_TRUE);

        if ((ucFRLRate == 1) || (ucFRLRate == 2))
        {
            Hv_Cal_HdmiRX_PhyClockInit(ucPortIndex, E_D3LANEFRL, ucLaneSwap);
        }
        else
        {
            Hv_Cal_HdmiRX_PhyClockInit(ucPortIndex, E_D4LANEFRL, ucLaneSwap);
        }
    }
    //Hv_Cal_HdmiRx_SetFrlRateFreq(ucPortIndex,ucFRLRate);

    return ucFRLRate;
}
#endif

HdmiRxGearMode Hv_Drv_HdmiRx_GetRatioType(UCHAR8 ucPortIndex, HdmiRxGearMode emGearModeCfg)
{
    /*检查入参*/
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);
    UCHAR8 ucLaneSwap = ((ucPortIndex == 0) ? HV_BOARD_CONFIG_HDMI0_LANE_SWP : HV_BOARD_CONFIG_HDMI1_LANE_SWP);

#if (HV_PROJECT_CONFIG_FRL == HV_CONFIG_ON)
    if(Hv_Cal_HdmiRx_GetFrlRate(ucPortIndex) != 0)
    {
        return E_FRLMODE;
    }
#endif

    if (Hv_Cal_HdmiRx_GetScdcTmdsBitClkRatio(ucPortIndex, ucLaneSwap))
    {
        return E_RATIOGEAR;
    }
    else
    {
        return Hv_Cal_HdmiRx_GetGearMode(ucPortIndex, emGearModeCfg, ucLaneSwap);
    }
}

UINT32 Hv_Drv_HdmiRx_InterruptEnPrint(UCHAR8 ucPortIndex, UCHAR8 ucIntr)
{
    /*检查入参*/
    HV_ASSERT_TRUE_RET(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM, 0);
    HV_ASSERT_TRUE_RET(ucIntr < 2, 0);

    return Hv_Cal_HdmiRx_InterruptEnPrint(ucPortIndex, ucIntr);
}

VOID HV_Drv_HdmirRx_ResetScdcWith5V(UCHAR8 ucPortIndex)
{
    if(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM)
    {
#if (HV_PROJECT_CONFIG_CTS == HV_CONFIG_OFF)
        HV_Cal_HdmirRx_ResetScdcWith5V(ucPortIndex);
#else
        HV_Cal_HdmirRx_ResetScdcWith5VCtsOn(ucPortIndex);
#endif
    }

    return;
}

Status Hv_Drv_HdmiRx_EnterStandby(UCHAR8 ucPortIndex, BOOL bEnterStandby)
{
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);

    return Hv_Cal_HdmiRx_EnterStandby(ucPortIndex, bEnterStandby);
}

Status Hv_Drv_HdmiRx_DdcSend(UCHAR8 ucPortIndex, UCHAR8 *data, UINT32 len)
{
    HV_ASSERT_TRUE_RET_NO_LOG(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM, HV_FAILURE);

    return Hv_Cal_HdmiRx_SendDdcMsg(ucPortIndex, len, data);
}

UCHAR8 Hv_Drv_HdmiRx_DdcRecv(UCHAR8 ucPortIndex, UCHAR8 *ucBuf)
{
    UCHAR8 aucFreesyncData[5] = {0x51, 0x82, 0x01, 0xE6, 0x5A};
    UCHAR8 aucReplyData[11]   = {0x6E, 0x88, 0x02, 0x00, 0xE6, 0x01, 0x00, 0x01, 0x00, 0x00, 0x53};

    HV_ASSERT_TRUE_RET_NO_LOG(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM, HV_FAILURE);

    UCHAR8 ucRecvLen = Hv_Cal_HdmiRx_RecvDdcMsg(ucPortIndex, ucBuf);

    if(ucRecvLen == 5)
    {
        if (0 == HV_MEMCMP(aucFreesyncData, ucBuf, 5))
        {
            if (HV_ON == HV_COMMON_DATABASE_GET(UserData, ucFreeSync))
            {
                aucReplyData[9] = 0x01;
                aucReplyData[10] = 0x52;
            }
            else
            {
                aucReplyData[9] = 0x00;
                aucReplyData[10] = 0x53;
            }

            Hv_Cal_HdmiRx_SendDdcMsg(ucPortIndex, sizeof(aucReplyData), aucReplyData);
        }
    }

    return ucRecvLen;
}

Status Hv_Drv_HdmiRx_InitEdidConf(UCHAR8 ucPortIndex)
{
    /*检查入参*/
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);

#if (HV_PROJECT_CONFIG_EDID_EXTER_EEPROM == HV_CONFIG_ON)
    /* 关闭 EDID on Register. */
    Hv_Cal_HdmiRx_CloseRegisterEdid(ucPortIndex);
#else
    /* 开启 EDID on Register. */
#if (HV_PROJECT_CONFIG_ESEGMENT == HV_CONFIG_ON)
    Hv_Cal_HdmiRx_OpenRegisterEdid(ucPortIndex, 1);
#else
    Hv_Cal_HdmiRx_OpenRegisterEdid(ucPortIndex, 0);
#endif
#endif

    return HV_SUCCESS;
}

Status Hv_Drv_HdmiRx_TmdsPreReset(UCHAR8 ucPortIndex)
{
    /*检查入参*/
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);

    Hv_Cal_HdmiRx_BusSwReset(ucPortIndex);
    Hv_Cal_HdmiRx_TmdsSwReset(ucPortIndex);

    return HV_SUCCESS;
}

VOID Hv_Drv_HdmiRx_AudioCheck(UCHAR8 ucPortId)
{
    HV_ASSERT_TRUE_VOID(ucPortId <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);

    Hv_Cal_HdmiRx_AudioCheck(ucPortId);

    return;
}

VOID Hv_Drv_HdmiRx_ReloadColorDepth(UCHAR8 ucPortIndex)
{
    HV_ASSERT_TRUE_VOID(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);
    Hv_Cal_HdmiRx_ReloadColorDepth(ucPortIndex);
    return;
}

Status Hv_Drv_HdmiRx_GetMDVrrPara(UCHAR8 ucPortIndex, VRRInfoParam* pstVrrMdPara)
{
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);
    HV_ASSERT_VALID_PTR(pstVrrMdPara);
    CalVRRInfoParam stMDPara = {0};
    HV_ASSERT_SUCCESS(Hv_Cal_HdmiRx_GetMDVrrPara(ucPortIndex, &stMDPara));
    HV_MEMCPY(pstVrrMdPara, &stMDPara, sizeof(VRRInfoParam));
    return HV_SUCCESS;
}

Status Hv_Drv_HdmiRx_GetAMDVendSpecInfoPara(UCHAR8 ucPortIndex, VRRInfoParam *pstVendSpecInfoPara)
{
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);
    HV_ASSERT_VALID_PTR(pstVendSpecInfoPara);
    CalVRRInfoParam stVSIPara = {0};

    HV_ASSERT_SUCCESS(Hv_Cal_HdmiRx_GetAMDVendSpecInfoPara(ucPortIndex, &stVSIPara));
    HV_MEMCPY(pstVendSpecInfoPara, &stVSIPara, sizeof(VRRInfoParam));

    return HV_SUCCESS;
}

Status Hv_Drv_HdmiRx_GetAudioPara(UCHAR8 ucPortIndex, AudioPara *pstAudioPara)
{
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);
    HV_ASSERT_VALID_PTR(pstAudioPara);
    CalAudioPara stAudioInfo = {0};

    Hv_Cal_HdmiRx_GetAudioPara(ucPortIndex, &stAudioInfo);

    HV_MEMCPY(pstAudioPara, &stAudioInfo, sizeof(AudioPara));

    return HV_SUCCESS;
}

Status Hv_Drv_HdmiRx_GetHDRPara(UCHAR8 ucPortIndex, HDRParam *pstHDRPara)
{
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);
    HV_ASSERT_VALID_PTR(pstHDRPara);
    CalHDRParam stHdrInfo = {0};

    Hv_Cal_HdmiRx_GetHDRPara(ucPortIndex, &stHdrInfo);

    HV_MEMCPY(pstHDRPara, &stHdrInfo, sizeof(HDRParam));

    return HV_SUCCESS;
}

BOOL Hv_Drv_HdmiRX_RobustCheckRatioMode(UCHAR8 ucPortIndex)
{
    HV_ASSERT_TRUE_RET(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM, HV_FALSE);
    UCHAR8 ucLaneSwap = ((ucPortIndex == 0) ? HV_BOARD_CONFIG_HDMI0_LANE_SWP : HV_BOARD_CONFIG_HDMI1_LANE_SWP);

    return Hv_Cal_HdmiRX_RobustCheckRatioMode(ucPortIndex, ucLaneSwap);
}

BOOL Hv_Drv_HdmiRx_IsClockStable(UCHAR8 ucPortIndex)
{
    HV_ASSERT_TRUE_RET(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM, HV_FALSE);
    UCHAR8 ucLaneSwap = ((ucPortIndex == 0) ? HV_BOARD_CONFIG_HDMI0_LANE_SWP : HV_BOARD_CONFIG_HDMI1_LANE_SWP);

    return Hv_Cal_HdmiRx_IsClockStable(ucPortIndex, ucLaneSwap);
}

Status Hv_Drv_HdmiRx_GetLaneCEDValue(UCHAR8 ucPortIndex, HdmiRxLaneCED *pstLaneCedValue)
{
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);
    HV_ASSERT_VALID_PTR(pstLaneCedValue);
    UCHAR8 ucLaneSwap = ((ucPortIndex == 0) ? HV_BOARD_CONFIG_HDMI0_LANE_SWP : HV_BOARD_CONFIG_HDMI1_LANE_SWP);

    return Hv_Cal_HdmiRx_GetLaneCEDValue(ucPortIndex, pstLaneCedValue, ucLaneSwap);
}

Status Hv_Drv_HdmiRx_SetSwEqValue(UCHAR8 ucPortIndex, const USHORT16 *pusSwEqValue)
{
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);
    HV_ASSERT_VALID_PTR(pusSwEqValue);
    UCHAR8 ucLaneSwap = ((ucPortIndex == 0) ? HV_BOARD_CONFIG_HDMI0_LANE_SWP : HV_BOARD_CONFIG_HDMI1_LANE_SWP);

    return Hv_Cal_HdmiRx_SetSwEqValue(ucPortIndex, pusSwEqValue, ucLaneSwap);
}

BOOL Hv_Drv_HdmiRx_IsTimingStable(UCHAR8 ucPortIndex)
{
    HV_ASSERT_TRUE_RET(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM, HV_FALSE);
    UCHAR8 ucLaneSwap = ((ucPortIndex == 0) ? HV_BOARD_CONFIG_HDMI0_LANE_SWP : HV_BOARD_CONFIG_HDMI1_LANE_SWP);

    return Hv_Cal_HdmiRx_IsTimingStable(ucPortIndex, ucLaneSwap);
}

Status Hv_Drv_HdmiRx_CableConnectAction(UCHAR8 ucPortIndex, BOOL bCableSta)
{
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);
    UCHAR8 ucLaneSwap = ((ucPortIndex == 0) ? HV_BOARD_CONFIG_HDMI0_LANE_SWP : HV_BOARD_CONFIG_HDMI1_LANE_SWP);

    return Hv_Cal_HdmiRx_CableConnectAction(ucPortIndex, bCableSta, ucLaneSwap);
}

VOID Hv_Drv_HdmiRX_SwitchPhyGearMode(UCHAR8 ucPortIndex, HdmiRxGearMode ucGrearMode)
{
    HV_ASSERT_TRUE_VOID(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);
    UCHAR8 ucLaneSwap = ((ucPortIndex == 0) ? HV_BOARD_CONFIG_HDMI0_LANE_SWP : HV_BOARD_CONFIG_HDMI1_LANE_SWP);

#if (HV_PROJECT_CONFIG_CTS == HV_CONFIG_OFF)
    if(ucGrearMode < E_HIGHGEAR || ucGrearMode == E_UNLOCKED)
    {
        Hv_Cal_HdmiRX_SwitchAutoEqTable(ucPortIndex, HV_TRUE);
    }
    else
    {
        Hv_Cal_HdmiRX_SwitchAutoEqTable(ucPortIndex, HV_FALSE);
    }
#endif

    return Hv_Cal_HdmiRX_SwitchPhyGearMode(ucPortIndex, ucGrearMode, ucLaneSwap);
}

/**
 * @brief If the PHY is fast locked.
 * @param[in] Port Number used for the HDMI RX.
 * @return TRUE is Loced False is unlocked.
 */
BOOL Hv_Drv_HdmiRX_IsPhyFastLocked(UCHAR8 ucPortIndex)
{
    HV_ASSERT_TRUE_RET(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM, HV_FALSE);
    UCHAR8 ucLaneSwap = ((ucPortIndex == 0) ? HV_BOARD_CONFIG_HDMI0_LANE_SWP : HV_BOARD_CONFIG_HDMI1_LANE_SWP);

    return Hv_Cal_HdmiRX_IsPhyFastLocked(ucPortIndex, ucLaneSwap);
}
/**
 * @brief If the PHY TMDS Clock Is OverFlow.
 * @param[in] Port Number used for the HDMI RX.
 * @return TRUE is OverFlow False is not OverFlow.
 */
BOOL Hv_Drv_HdmiRX_IsTMDSClockOverFlow(UCHAR8 ucPortIndex)
{
    HV_ASSERT_TRUE_RET(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM, HV_FALSE);
    UCHAR8 ucLaneSwap = ((ucPortIndex == 0) ? HV_BOARD_CONFIG_HDMI0_LANE_SWP : HV_BOARD_CONFIG_HDMI1_LANE_SWP);

    return Hv_Cal_HdmiRX_IsTMDSClockOverFlow(ucPortIndex, ucLaneSwap);
}

Status Hv_Drv_HdmiRx_Hdcp1XInitForAuth(UCHAR8 ucPortIndex)
{
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);
    UCHAR8 ucTryCnt = 10;

    Hv_Cal_HdmiRx_SetHDCPHdmiMode(ucPortIndex, HV_FALSE);

    do
    {
        if(Hv_Cal_HdmiRx_DdcCurStateIsIdle(ucPortIndex))
        {
#if (HV_PROJECT_CONFIG_CTS == HV_CONFIG_ON)
            Hv_Cal_HdmiRx_SetHdcp1XRiSel(ucPortIndex, 0x0);
#endif
            /* 配置到HDMI模式到非HDMI模式 */
            Hv_Cal_HdmiRx_SetHDCP1Xstatus(ucPortIndex, HV_FALSE);

            if(Hv_Cal_HdmiRx_DdcCurStateIsIdle(ucPortIndex))
            {
                break;
            }
        }

        Hv_Vos_Delayus(500);

    } while (ucTryCnt--);

    if (!ucTryCnt)
    {
        HV_LOG_ERROR(HDMI, "ddc busy when proc hdcp 1x, %u", ucPortIndex);
#if (HV_PROJECT_CONFIG_CTS == HV_CONFIG_ON)
        Hv_Cal_HdmiRx_SetHdcp1XRiSel(ucPortIndex, 0x0);
#endif
        /* 配置到HDMI模式到非HDMI模式 */
        Hv_Cal_HdmiRx_SetHDCP1Xstatus(ucPortIndex, HV_FALSE);
    }

    return HV_SUCCESS;
}

BOOL Hv_Drv_HdmiRx_CheckTmdsClockAbnormal(UCHAR8 ucPortIndex)
{
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);
    
    UCHAR8 ucLaneSwap = ((ucPortIndex == 0) ? HV_BOARD_CONFIG_HDMI0_LANE_SWP : HV_BOARD_CONFIG_HDMI1_LANE_SWP);

    return Hv_Cal_HdmiRx_CheckTmdsClockAbnormal(ucPortIndex, ucLaneSwap);
}

BOOL Hv_Drv_HdmiRx_GetCableStatus(UCHAR8 ucPortIndex)
{
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);

#if (HV_BOARD_CONFIG_HDMI_CABLE_DETECT == CABLE_DETECT_WITH_SOURCE_5V)
    return (!Hv_Cal_HdmiRx_GetCableStatus(ucPortIndex));
#else
    return Hv_Cal_HdmiRx_GetCableStatus(ucPortIndex);
#endif
}


