/* SPDX-License-Identifier: LGPL-2.1-only OR BSD-3-Clause */
/******************************************************************************
 *
 * This file is provided under a dual license.  When you use or
 * distribute this software, you may choose to be licensed under
 * version 2.1 of the GNU Lesser General Public License
 * ("LGPLv2.1 License") or BSD License.
 *
 * LGPLv2.1 License
 *
 * Copyright(C) 2019 MediaTek Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2.1 of the GNU Lesser General Public
 * License as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html for more
 * details.
 *
 * BSD LICENSE
 *
 * Copyright(C) 2019 MediaTek Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *****************************************************************************/


// === INCLUDE =============================================================================
#include "drv_tdtv_drvif.h"
#include "drv_video.h"
#include "x_gpio.h"
#include "x_pinmux.h"

// === HW INCLUDE =============================================================================

// === DEFINE =============================================================================
enum
{
    VDO_2D,
    VDO_3D_FS,
    VDO_3D_SBS,
    VDO_3D_TAB,
    VDO_3D_TTD, 
    VDO_3D_SS
};

// === FUNCTION PROTOTYPE =================================================================

// === EXTERN FUNCTION ====================================================================


// === GLOBAL VARIABLE ====================================================================

// === EXTERN VARIABLE ====================================================================
extern HANDLE_T h4k2kUnMuteTimer ;
extern HANDLE_T _hFrcUnmuteSema ;
// === STATIC VARIABLE ====================================================================
// === END OF STATIC VARIABLE =============================================================
// === BODY ===============================================================================
//#ifdef CC_SUPPORT_4K2K
#ifndef CC_CMI_MST_FRC_SUPPORT
#define CC_CMI_MST_FRC_SUPPORT	1
#endif
#ifndef CC_CMI_RTK_FRC_SUPPORT
#define CC_CMI_RTK_FRC_SUPPORT	1
#endif

#include "sif_if.h"
#include "drv_display.h"


r4k2kHandler *psCur4k2kHandler=NULL ;
static HANDLE_T _hFrcSetCmdSema=(HANDLE_T)(NULL);
void com4k2kSendPanelType(UINT32 u4PanelType);
void com4k2kSendPanelMode(UINT8 u1Mode);
void com4k2kSendCmd(UINT8 *pBuf, UINT16 u2Len);



#ifdef CC_CMI_MST_FRC_SUPPORT
#include "drv_cmiMst4k2k.c"
#endif
#ifdef CC_CMI_RTK_FRC_SUPPORT
#include "drv_cmiRtk4k2k.c"
#endif

#ifdef CC_CSOT_NTK_FRC_SUPPORT
#include "drv_csotNtk4k2k.c"
#endif


void com4k2kSendCmd(UINT8 *pBuf, UINT16 u2Len)
{
    UINT8 u1Checksum = 0, i, *pTmp, u1CmdLen, k ;
    UINT32 iret ;

	if(!psCur4k2kHandler)
	{
		return;
	}
	VERIFY (x_sema_lock(_hFrcSetCmdSema, X_SEMA_OPTION_WAIT) == OSR_OK);	

	pTmp = pBuf ;
	u1CmdLen = psCur4k2kHandler->u1CmdLen ;
	for(k=0; k < u2Len ; k=k+u1CmdLen)
	{
		u1Checksum = 0;
#ifdef CC_CMI_MST_FRC_SUPPORT		
		if(psCur4k2kHandler->u1Tag == E_4K2K_CMI_MST)
		{
		    for(  i=1 ; i< u1CmdLen ; i++)
		    {
				//skip data 0
					u1Checksum += pTmp[i] ;
		    }
		}    
#endif		
#ifndef NDEBUG			    
		Printf("\n[4k2k] I2c Data :");
#endif
#ifdef CC_CMI_MST_FRC_SUPPORT
		if(psCur4k2kHandler->u1Tag == E_4K2K_CMI_MST)
		{
	    	pTmp[0] = (pTmp[0] &0xF) + ((u1Checksum & 0xF) << 4) ; //upper 4 bit ;
	    }	
#endif	    
#ifndef NDEBUG			 
		 for(i=0 ; i < u1CmdLen ; i++)
		 {
			Printf("0x%x ", pTmp[i]);
		 }
		 Printf("\n");
#endif		 
	     iret = SIF_X_Write(psCur4k2kHandler->u1I2CChn, 0x100 , psCur4k2kHandler->u1I2cAddr, 0 ,0, pTmp, u1CmdLen);
	     if(iret <=0)
	     {
			LOG(0, "[4k2k] i2c send error\n");
	     }
	     pTmp = pTmp + u1CmdLen ;
	     //command delay
	     x_thread_delay(psCur4k2kHandler->u2CmdInterval);
     }
	x_sema_unlock(_hFrcSetCmdSema);
}

void com4k2kSendPanelType(UINT32 u4PanelType)
{
    static UINT32 u4PrePanelType =0xff;
    UINT16 u2Len=0;
    UINT8 *pBuf;
    
	if(!psCur4k2kHandler)
	{
		return;
	}

    pBuf = NULL ;
#ifdef CC_CSOT_NTK_FRC_SUPPORT

	if(psCur4k2kHandler->u1Tag == E_4K2K_CSOT_NTK)
	{
		// NT previous mode=3D
	}
#endif    
    if(u4PanelType != u4PrePanelType)
    {
    	
        if ((u4PanelType == PANEL_4K2K_FHD120)||(u4PanelType == PANEL_4K2K_FHD60))
        {
#ifdef CC_CSOT_NTK_FRC_SUPPORT        
        	if(psCur4k2kHandler->u1Tag == E_4K2K_CSOT_NTK)
        	{
				if (u4PanelType == PANEL_4K2K_FHD60)  // 2D
				{
					App_SET_4K2K_TO_FHD();
				}
				else if (u4PanelType == PANEL_4K2K_FHD120)  // 3D
				{
					APP_FRC_Set_314_Skyworth_Enter3D();
					LOG(3, "[4K2K][NT]enter 3D\n");
				}
			}
			else
#endif			
			{
				if(psCur4k2kHandler->u13D2DTimingChg && (u4PanelType == PANEL_4K2K_FHD120))
				{
            		pBuf = psCur4k2kHandler->pu1Fhd3DBuf;            	
					u2Len = psCur4k2kHandler->u1Fhd3DBufSize;

				}
				else
				{
            		pBuf = psCur4k2kHandler->pu1FhdBuf;            	
					u2Len = psCur4k2kHandler->u1FhdBufSize;
				}
				
            }	
        	LOG(3, "[4K2K][LVDS]I2C send FHD mode\n");
        }
        else if (u4PanelType == PANEL_4K2K_30)
        { 
#ifdef CC_CSOT_NTK_FRC_SUPPORT         
        	if(psCur4k2kHandler->u1Tag == E_4K2K_CSOT_NTK)
        	{
					App_SET_FHD_TO_4K2K();				
        	}
        	else
#endif        	
        	{
				pBuf = psCur4k2kHandler->pu14k2kBuf; 	
				u2Len = psCur4k2kHandler->u14k2kBufSize;				
			}	
        	LOG(3, "[4K2K][LVDS]I2C send 4K2K30 mode\n");
        }
		else if (u4PanelType == PANEL_4K2K_60)
		{
			com4k2kSendCmd(_au1cmiMst4K2K60VB1Buf, sizeof(_au1cmiMst4K2K60VB1Buf));
		}
        if(psCur4k2kHandler && psCur4k2kHandler->frc_send_cmd)
        {
        	psCur4k2kHandler->frc_send_cmd(pBuf, u2Len);       
        }	
        
        u4PrePanelType = u4PanelType ;        
    }
}

void com4k2kSendPanelMode(UINT8 u1Mode)
{
    static UINT8 u1PreMode = 0xff ;
    UINT8 *pBuf ;
    UINT16 u2Len;
    BOOL fgSkipCmd=0;

	if(!psCur4k2kHandler)
	{
		return;
	}

    if((u1Mode == E_4K2K_NATIVE) || (u1Mode == E_4K2K_NORMAL_3D))
    {
		u1Mode = E_4K2K_NORMAL ;
		//mst use the default 60 or 120 panel as resume command , skip the resume command if 4k2k native mode
      	if(psCur4k2kHandler->u1Tag == E_4K2K_CMI_MST)
      	{
			fgSkipCmd = TRUE ;
      	}
    }    
    if(u1Mode != u1PreMode)
    {
        if (u1Mode == E_4K2K_SPLIT_PHOTO)
        {
        	pBuf = psCur4k2kHandler->pu1PhotoModeBuf;
        	u2Len = psCur4k2kHandler->u1PhotoBufSize;
        	LOG(3, "[4K2K][LVDS]I2C send split photo mode #2\n");
        }
        else if (u1Mode == E_4K2K_SPLIT_VDO)
        {
        	pBuf = psCur4k2kHandler->pu1VdoModeBuf;
        	u2Len = psCur4k2kHandler->u1VdoBufSize;        	
        	LOG(3, "[4K2K][LVDS]I2C send split vdo mode #2\n");
        }
        else // normal mode & native mode
        {        	
        	pBuf = psCur4k2kHandler->pu1ResumeBuf;
        	u2Len = psCur4k2kHandler->u1ResumeBufSize;        	        		
        	LOG(3, "[4K2K][LVDS]I2C send non-split normal mode #2\n");
        }
        
        
        if(!fgSkipCmd)
        {
        	psCur4k2kHandler->frc_send_cmd(pBuf , u2Len);
        }
        u1PreMode = u1Mode ;
    }
}



//==============================================================================
/* Init function pointer table via panel id  */

void vExt4k2kFrcInit(void)
{

	switch(GetCurrentPanelIndex())
	{
#ifdef CC_CMI_RTK_FRC_SUPPORT		
	case PANEL_CMI_4K2K_FHD120:
		psCur4k2kHandler = &cmiRtk4k2kHandler;	
		LOG(0, "[4k2k]CMI+RTK 4k2k FRC handler Init\n");
		break;
#endif		
#ifdef CC_CMI_MST_FRC_SUPPORT			
	case PANEL_CMO_V580DK1_LS1_INX:
		psCur4k2kHandler = &cmiMst1204k2kHandler;
		LOG(0, "[4k2k]CMI+MST 4k2k FRC 120 handler Init\n");
		break;
	case PANEL_CMO_V580DK1_LS1_INX_VB1:		
		psCur4k2kHandler = &cmiMst120VB14k2kHandler;
		LOG(0, "[4k2k]CMI+MST 4k2k FRC 120 VB1 handler Init\n");
		break;
	case PANEL_AUO_4K2K_FHD60:
		psCur4k2kHandler = &cmiMst4k2kHandler;
		LOG(0, "[4k2k]CMI+MST 4k2k FRC 60 handler Init\n");		
		break;
	case PANEL_CMO_V580DK1_LS1_INX_60_VB1:		
		psCur4k2kHandler = &cmiMst60VB14k2kHandler;
		LOG(0, "[4k2k]CMI+MST 4k2k FRC 60 VB1 handler Init\n");		
		break;
	case PANEL_CMO_V580DK1_LS1_INX_60_VB1_TEST:
		psCur4k2kHandler = &cmiMst60VB14k2kHandler;
		LOG(0, "[4k2k]CMI+MST 4k2k FRC 60 VB1 handler Init\n");	
		break;
	case PANEL_VB1_4K2KDD_GRAPH:
	case PANEL_4K2KDD:
		psCur4k2kHandler = &cmiMstVB14k2kHandler;
		LOG(0, "[4k2k]CMI+MST 4k2k FRC VB1 handler Init\n");
		break;
#endif		
#ifdef CC_CSOT_NTK_FRC_SUPPORT
	case PANEL_CSOT_4K2K_FHD60:
		psCur4k2kHandler = &csotNtk4k2kHandler;
		LOG(0, "[4k2k]CSOT+NTK 4k2k FRC 60 handler Init\n");
		break;
#endif
	default:
		psCur4k2kHandler = NULL ;
		LOG(0, "[4k2k]none handler Init\n");
		break;
	}
	if(psCur4k2kHandler && psCur4k2kHandler->frc_init)
	{
		if(!_hFrcSetCmdSema)
		{
			VERIFY(x_sema_create(&_hFrcSetCmdSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK) == OSR_OK);
		}	
		psCur4k2kHandler->frc_init();
	}
	
	if (GetCurrentPanelIndex()==PANEL_VB1_4K2KDD_GRAPH)
	{
		//com4k2kSendCmd(_au1cmiMstOSD60VB1Buf, sizeof(_au1cmiMstOSD60VB1Buf));
	}
	
	if (GetCurrentPanelIndex()==PANEL_4K2KDD)
	{
		com4k2kSendCmd(_au1cmiMstVB1AutoMuteOff, sizeof(_au1cmiMstVB1AutoMuteOff));
	}
}

/* Dispatch the function handler */

void vSend4k2kFrcCmd(UINT8 *pBuf, UINT16 u2Len)
{
	if(psCur4k2kHandler && psCur4k2kHandler->frc_send_cmd)
	{
		psCur4k2kHandler->frc_send_cmd(pBuf, u2Len);
	}	
}
void vSend4k2kFrcPanelTypeCmd(UINT32 u4PanelType) 
{
	if(psCur4k2kHandler && psCur4k2kHandler->frc_snd_pnl_type)
	{
		psCur4k2kHandler->frc_snd_pnl_type(u4PanelType);
	}	
}    

void vSend4k2kFrcModeCmd(UINT8 u1Mode)
{
	if(psCur4k2kHandler && psCur4k2kHandler->frc_snd_pnl_mode)
	{
		psCur4k2kHandler->frc_snd_pnl_mode(u1Mode);
	}	
}
void vExt4k2kFrcMute(UINT8 bOn)    
{
	if(psCur4k2kHandler && psCur4k2kHandler->frc_snd_mute)
	{
		x_timer_stop(h4k2kUnMuteTimer);
		psCur4k2kHandler->frc_snd_mute(bOn);
	}	
}	
static VOID _FRCUnMuteTimeout(HANDLE_T  pt_tm_handle, VOID *pv_tag)
{
	x_sema_unlock(_hFrcUnmuteSema);
}
void vExt4k2kFrcUmMuteTimer(UINT16 u2Timer)    
{	
	//u2Timer ms 
	if(psCur4k2kHandler && psCur4k2kHandler->frc_snd_mute)
	{
	VERIFY(x_timer_start(h4k2kUnMuteTimer, u2Timer, X_TIMER_FLAG_ONCE,
            _FRCUnMuteTimeout, NULL) == OSR_OK);		
    }        
}	

BOOL fgExt4k2k2D3DTimingChg(void)
{
	if(psCur4k2kHandler)
	{
		return (BOOL) psCur4k2kHandler->u13D2DTimingChg;
	}
	return FALSE ;
}

void  DRVCUST_SetExtFrcBypassWindow(UINT8 bWId, UINT16 u2Width, UINT16 u2Height,  UINT16 u2StartX,  UINT16 u2StartY)
{
	if(psCur4k2kHandler && psCur4k2kHandler->frc_snd_protect_window)
	{
		psCur4k2kHandler->frc_snd_protect_window(bWId, u2Width, u2Height, u2StartX, u2StartY);
	}	
}

void DRVCUST_SplitPotoGpioSet(BOOL bOnOff)
{
	INT32 i4Val = 0;
	
	BSP_PinSet(PIN_GPIO53, PINMUX_FUNCTION0); //GPIO, org is L/R
	GPIO_Output(GPIO(53), &i4Val);
}
UINT16 u2Ext4k2kGetMuteTime(void)
{
	if(psCur4k2kHandler)
	{
		return psCur4k2kHandler->u2MuteTime ;
	}
	return 0 ;
}
//#endif //CC_SUPPORT_4K2K


VOID DRVCUST_SetExtFrc3DFormat(E_TDTV_UI_3D_PACKING eUIPackingSel)
{
	 UINT32 u4Ext3DEnableGPIO, u4Ext3DLRPin, u4Ext3DLRPinFunc;
	//static UINT8 u1PreVdo3DFmt=VDO_2D ;

    //UINT8 u1ErrMsg;

    if(bDrvVideoSignalStatus(SV_VP_MAIN)!=SV_VDO_STABLE)
    {
        eUIPackingSel=E_TDTV_UI_3D_MODE_OFF;
    }
    

	if( (E_TDTV_UI_3D_MODE_OFF!=eUIPackingSel) && 
			bDrvVideoSignalStatus(SV_VP_MAIN)==SV_VDO_STABLE)
	{	
		//Enable 3D Enable Signal
		if (DRVCUST_OptQuery(e3DEnableGPIO,&u4Ext3DEnableGPIO)==0)
		{
			LOG(3, "[3D]3D_EN: GPIO%d output 1\n", u4Ext3DEnableGPIO);
			GPIO_SetOut(u4Ext3DEnableGPIO, 1);	
		}
		//Enable 3D LR Signal
		if ((DRVCUST_OptQuery(e3DLRPin,&u4Ext3DLRPin)==0)&&(DRVCUST_OptQuery(e3DLRPinFunc,&u4Ext3DLRPinFunc)==0))
		{
			LOG(3, "[3D]3D_LR: 0x%x set to FUNCTION%d\n", u4Ext3DLRPin, u4Ext3DLRPinFunc);
			BSP_PinSet(u4Ext3DLRPin, u4Ext3DLRPinFunc);
		}
	}
	else
	{
		//Disable 3D LR Signal
		if (DRVCUST_OptQuery(e3DLRPin,&u4Ext3DLRPin)==0)
		{
			LOG(3, "[3D]3D_LR: 0x%x set to FUNCTION0\n", u4Ext3DLRPin);
			BSP_PinSet(u4Ext3DLRPin, 0);
		}
		//Disable 3D Enable Signal
		if (DRVCUST_OptQuery(e3DEnableGPIO,&u4Ext3DEnableGPIO)==0)
		{
			LOG(3, "[3D]3D_EN: GPIO%d output 0\n", u4Ext3DEnableGPIO);
			GPIO_SetOut(u4Ext3DEnableGPIO, 0);	
		}
	}
}

void DRVCUST_INXMsAutoMuteDisable(void)
{
	cmiMstFrcAutoMuteOff();
}
