/**
 * @file hv_mw_Video_TimingCheck.c
 * @brief  dpu TimingCheck middleware source file
 * @details This file provides the following functions: \n
 *          (1) dpu TimingCheck handle \n
 *          (2) Feed functions \n
 *
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2022-08-25
 * @copyright Copyright(c),2022-8, Hiview Software. All rights reserved.
 * @par History:
 * <table>
 * <tr><th>Author                         <th>Date         <th>Change Description
 * <tr><td>Hiview SoC Software Team       <td>2022-08-25   <td>init
 * </table>
*/

#include "hv_mw_Video_TimingCheck.h"
#include "hv_chip_Clk.h"
#include "hv_comm_Assert.h"
#include "hv_mw_InputPortManager.h"
#include "hv_mw_PanelManager.h"
#include "hv_comm_MemParser.h"
#include "hv_drv_DpuCommon.h"
#include "hv_mw_Video.h"

/*判断main frc模式下，ddr size是否够用*/
static BOOL MainFrcDdrSizeCompatible(ChannelData* pstChannelData)
{
    UINT32 uiStartAddress0  = 0;
    UINT32 uiStartAddress1  = 0;
    UINT32 uiEndAddress0    = 0;
    UINT32 uiEndAddress1    = 0;

    uiStartAddress0 = Hv_Board_Memory_FRCStart();
    UINT32 uiSubSize = Hv_Mw_Video_EstimateSubChannelMemSize(pstChannelData);
    uiStartAddress0 += uiSubSize;

    UINT32 uiLineOffsetAddr = pstChannelData->stVideoConfigParams.uiDdrOrWtrVideoWidth * 2 * 30 / 20;         // 20=除以8，再除以2.5倍压缩
    if(pstChannelData->stVideoConfigParams.bInterlacedMode)
    {
        /*hactive*vactive*1frame*(bit*3))/8/2最小压缩率*/
        uiStartAddress1 = uiStartAddress0 + pstChannelData->stVideoConfigParams.uiDdrOrWtrVideoWidth*pstChannelData->stVideoConfigParams.uiDdrOrWtrVideoHight * 30 / 20;
        /*interlace模式有第三帧,普通2帧配置上也无影响,未使用*/
        UINT32 uiStartAddress2 = uiStartAddress1 + pstChannelData->stVideoConfigParams.uiDdrOrWtrVideoWidth*pstChannelData->stVideoConfigParams.uiDdrOrWtrVideoHight * 30 / 20;
        uiEndAddress0 = uiStartAddress0 + (pstChannelData->stVideoConfigParams.uiDdrOrWtrVideoHight / 2) * uiLineOffsetAddr;
        uiEndAddress1 = uiStartAddress1 + (pstChannelData->stVideoConfigParams.uiDdrOrWtrVideoHight / 2) * uiLineOffsetAddr;
        UINT32 uiEndAddress2 = uiStartAddress2 + (pstChannelData->stVideoConfigParams.uiDdrOrWtrVideoHight / 2) * uiLineOffsetAddr;
        if((uiStartAddress2 >= (0x80000000 + HV_MEMORY_CONFIG_DDR_SIZE)) || (uiEndAddress2 >= (0x80000000 + HV_MEMORY_CONFIG_DDR_SIZE)))
        {
            HV_LOG_INFO(VIDEO,"Timing check Main Frc Interlace exceed ddr size. %ux%u", pstChannelData->stVideoConfigParams.uiDdrOrWtrVideoWidth, pstChannelData->stVideoConfigParams.uiDdrOrWtrVideoHight);
            return HV_FALSE;
        }
    }
    else
    {
        /*hactive*vactive*1frame*(bit*3))/8/2最小压缩率*/
        uiStartAddress1 = uiStartAddress0 + pstChannelData->stVideoConfigParams.uiDdrOrWtrVideoWidth*pstChannelData->stVideoConfigParams.uiDdrOrWtrVideoHight * 30 / 20;
        uiEndAddress0 = uiStartAddress0 + (pstChannelData->stVideoConfigParams.uiDdrOrWtrVideoHight / 2) * uiLineOffsetAddr;
        uiEndAddress1 = uiStartAddress1 + (pstChannelData->stVideoConfigParams.uiDdrOrWtrVideoHight / 2) * uiLineOffsetAddr;
        if((uiStartAddress1 >= (0x80000000 + HV_MEMORY_CONFIG_DDR_SIZE)) || (uiEndAddress1 >= (0x80000000 + HV_MEMORY_CONFIG_DDR_SIZE)))
        {
            HV_LOG_INFO(VIDEO,"Timing check Main Frc exceed ddr size. %ux%u", pstChannelData->stVideoConfigParams.uiDdrOrWtrVideoWidth, pstChannelData->stVideoConfigParams.uiDdrOrWtrVideoHight);;
            return HV_FALSE;
        }

    }
    return HV_TRUE;
}

static VOID SetChannelVideoConfigParams(ChannelData* pstChannelData)
{
    const ChannelManager* pstChannelManager =  Hv_Mw_Channel_GetManager();
    pstChannelData->stVideoConfigParams.enAspectRatio = pstChannelManager->astChannelData[CHANNEL_TYPE_MAIN].pfPQCallback(PQCALLBACK_RATIOMAPPING, &(pstChannelData->stVideoConfigParams));
    pstChannelData->stVideoConfigParams.bInterlacedMode    = pstChannelData->stRxVideoTiming.bInterlacedMode;
    pstChannelData->stVideoConfigParams.uiInputFrameRate   = pstChannelData->stRxVideoTiming.usFrameRate;
    pstChannelData->stVideoConfigParams.uiInputVideoWidth  = pstChannelData->stRxVideoTiming.usHActive;
    pstChannelData->stVideoConfigParams.uiInputVideoHight  = pstChannelData->stRxVideoTiming.usVActive;
    pstChannelData->stVideoConfigParams.uiInputVideoHtotal = pstChannelData->stRxVideoTiming.usHTotal;
    pstChannelData->stVideoConfigParams.uiInputVideoVtotal = pstChannelData->stRxVideoTiming.usVTotal;
    pstChannelData->stVideoConfigParams.enPxpMode          = pstChannelManager->stChannelFlashConfig.enFlashPxPMode;
    return;
}

Status Hv_Mw_Video_TimingCheck(LinkPortIndex stPortIndex,ChannelData* pstChannelData)
{
    HV_ASSERT_VALID_PTR(pstChannelData);
    #if 0
    const InputPortManager* pstInputPortManager = Hv_Mw_InputPort_GetManagerPtr();
    if(HV_FAILURE ==  pstInputPortManager->pfGetPortErrorCode(stPortIndex))
    {
        pstInputPortManager->pfReset(stPortIndex);
        HV_LOG_INFO(HDMI, "The Error Code of RX %u exceeds the threshold", stPortIndex);
        return ERROR_RX_AUTOEQ_ABNORMAL;
    }
    #endif
    if ((0 == pstChannelData->stRxVideoTiming.usHTotal)
     || (0 == pstChannelData->stRxVideoTiming.usHActive)
     || (0 == pstChannelData->stRxVideoTiming.usVTotal)
     || (0 == pstChannelData->stRxVideoTiming.usVActive)
     || (0 == pstChannelData->stRxVideoTiming.usFrameRate))
    {
        return ERROR_RX_TIMING_UNSUPPORT;
    }
    
    SetChannelVideoConfigParams(pstChannelData);
    if ((CHANNEL_TYPE_MAIN == pstChannelData->enChannelType)
    && (HV_FALSE == Hv_Mw_Video_CheckUseFrameSync(pstChannelData->stVideoConfigParams.bVflipEnable, &pstChannelData->stRxVideoTiming, &pstChannelData->stVideoConfigParams)))
    {
        if (HV_FALSE == MainFrcDdrSizeCompatible(pstChannelData))
        {
            return ERROR_RX_TIMING_UNSUPPORT;
        }
    }

    if (ColorDepthType_16Bit == pstChannelData->stVideoConfigParams.stColor.eClrDepth)
    {
        return ERROR_RX_TIMING_COLOR_DEPTH_NOT_SUPPORT;
    }
    /*2200*1125*297HZ = 735,075 khz*/
    if ((0 == pstChannelData->stRxVideoTiming.uiFreqKHz) || (pstChannelData->stRxVideoTiming.uiFreqKHz > HV_CHIP_CLK_DATAPATH_MAX))
    {
        return ERROR_RX_TIMING_FREQ_OUT_OF_RANGE;
    }
    
    return HV_SUCCESS;
}