/******************************************************************************
 *
 * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU 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 the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
 *
 *
 ******************************************************************************/

#include "mp_precomp.h"
#include "../phydm_precomp.h"

#if (RTL8814A_SUPPORT == 1)


/*---------------------------Define Local Constant---------------------------*/
// 2010/04/25 MH Define the max tx power tracking tx agc power.
#define		ODM_TXPWRTRACK_MAX_IDX_8814A		6

/*---------------------------Define Local Constant---------------------------*/

//3============================================================
//3 Tx Power Tracking
//3============================================================

// Add CheckRFGainOffset By YuChen to make sure that RF gain offset will not over upperbound 4'b1010

u1Byte
CheckRFGainOffset(
	PDM_ODM_T			pDM_Odm,
	u1Byte				RFPath
	)
{
	u1Byte	UpperBound = 10; // 4'b1010 = 10
	u1Byte	Final_RF_Index = 0;
	BOOLEAN	bPositive = FALSE;
	PODM_RF_CAL_T	pRFCalibrateInfo = &(pDM_Odm->RFCalibrateInfo);

	if( pRFCalibrateInfo->Absolute_OFDMSwingIdx[RFPath] >= 0)				// check if RF_Index is positive or not
	{
		Final_RF_Index = pRFCalibrateInfo->Absolute_OFDMSwingIdx[RFPath] >> 1;
		bPositive = TRUE;
		ODM_SetRFReg(pDM_Odm, (ODM_RF_RADIO_PATH_E)RFPath, rRF_TxGainOffset, BIT15, bPositive);
	}
	else
	{
		Final_RF_Index = (-1)*pRFCalibrateInfo->Absolute_OFDMSwingIdx[RFPath] >> 1;
		bPositive = FALSE;
		ODM_SetRFReg(pDM_Odm, (ODM_RF_RADIO_PATH_E)RFPath, rRF_TxGainOffset, BIT15, bPositive);
	}

	if(bPositive == TRUE)
	{
		if(Final_RF_Index >= UpperBound)
		{
			ODM_SetRFReg(pDM_Odm, (ODM_RF_RADIO_PATH_E)RFPath, rRF_TxGainOffset, 0xF0000, UpperBound);	//set RF Reg0x55 per path
			return UpperBound;
		}
		else
		{
			ODM_SetRFReg(pDM_Odm, (ODM_RF_RADIO_PATH_E)RFPath, rRF_TxGainOffset, 0xF0000, Final_RF_Index);	//set RF Reg0x55 per path
			return Final_RF_Index;
		}
	}
	else
	{
		ODM_SetRFReg(pDM_Odm, (ODM_RF_RADIO_PATH_E)RFPath, rRF_TxGainOffset, 0xF0000, Final_RF_Index);	//set RF Reg0x55 per path	
		return Final_RF_Index;
		
	}
		
	return FALSE;

}




VOID
ODM_TxPwrTrackSetPwr8814A(
	PDM_ODM_T			pDM_Odm,
	PWRTRACK_METHOD 	Method,
	u1Byte 				RFPath,
	u1Byte 				ChannelMappedIndex
	)
{
		u1Byte			Final_OFDM_Swing_Index = 0; 
		u1Byte			Final_CCK_Swing_Index = 0;
		u1Byte			Final_RF_Index = 0;
		u1Byte			UpperBound = 10, TxScalingUpperBound = 28; // Upperbound = 4'b1010, TxScalingUpperBound = +2 dB
		PODM_RF_CAL_T	pRFCalibrateInfo = &(pDM_Odm->RFCalibrateInfo);

		
		if (Method == MIX_MODE)
		{
			ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("pRFCalibrateInfo->DefaultOfdmIndex=%d, pRFCalibrateInfo->Absolute_OFDMSwingIdx[RFPath]=%d, RF_Path = %d\n",
				pRFCalibrateInfo->DefaultOfdmIndex, pRFCalibrateInfo->Absolute_OFDMSwingIdx[RFPath], RFPath));
			
			Final_CCK_Swing_Index = pRFCalibrateInfo->DefaultCckIndex + pRFCalibrateInfo->Absolute_OFDMSwingIdx[RFPath];	
			Final_OFDM_Swing_Index = pRFCalibrateInfo->DefaultOfdmIndex + (pRFCalibrateInfo->Absolute_OFDMSwingIdx[RFPath])%2;
	
			Final_RF_Index = CheckRFGainOffset(pDM_Odm, RFPath);		// check if Final_RF_Index >= 10

			if((Final_RF_Index == UpperBound) && (pRFCalibrateInfo->Absolute_OFDMSwingIdx[RFPath] >= 0))		// check BBSW is not over +2dB
			{
				Final_OFDM_Swing_Index = pRFCalibrateInfo->DefaultOfdmIndex + (pRFCalibrateInfo->Absolute_OFDMSwingIdx[RFPath] - (UpperBound << 1));
				if(Final_OFDM_Swing_Index > TxScalingUpperBound)
					Final_OFDM_Swing_Index = TxScalingUpperBound;
			}
			
		switch(RFPath)
				{
					case ODM_RF_PATH_A:
						
						ODM_SetBBReg(pDM_Odm, rA_TxScale_Jaguar, 0xFFE00000, TxScalingTable_Jaguar[Final_OFDM_Swing_Index]);	//set BBswing

						ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
							("******Path_A Compensate with BBSwing , Final_OFDM_Swing_Index = %d, Final_RF_Index = %d \n", Final_OFDM_Swing_Index, Final_RF_Index));
						break;

					case ODM_RF_PATH_B:
						
						ODM_SetBBReg(pDM_Odm, rB_TxScale_Jaguar, 0xFFE00000, TxScalingTable_Jaguar[Final_OFDM_Swing_Index]);	//set BBswing

						ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
							("******Path_B Compensate with BBSwing , Final_OFDM_Swing_Index = %d, Final_RF_Index = %d \n", Final_OFDM_Swing_Index, Final_RF_Index));
						break;

					case ODM_RF_PATH_C:
						
						ODM_SetBBReg(pDM_Odm, rC_TxScale_Jaguar2, 0xFFE00000, TxScalingTable_Jaguar[Final_OFDM_Swing_Index]);	//set BBswing

						ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
							("******Path_C Compensate with BBSwing , Final_OFDM_Swing_Index = %d, Final_RF_Index = %d \n", Final_OFDM_Swing_Index, Final_RF_Index));
				            	break;

					case ODM_RF_PATH_D:
						
						ODM_SetBBReg(pDM_Odm, rD_TxScale_Jaguar2, 0xFFE00000, TxScalingTable_Jaguar[Final_OFDM_Swing_Index]);	//set BBswing

						ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
							("******Path_D Compensate with BBSwing , Final_OFDM_Swing_Index = %d, Final_RF_Index = %d \n", Final_OFDM_Swing_Index, Final_RF_Index));
						break;

					default:
						ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
							("Wrong Path name!!!! \n"));

					break;
				}
		
			
			}

		return;
}	// ODM_TxPwrTrackSetPwr8814A


VOID
GetDeltaSwingTable_8814A(
	IN 	PDM_ODM_T			pDM_Odm,
	OUT pu1Byte 			*TemperatureUP_A,
	OUT pu1Byte 			*TemperatureDOWN_A,
	OUT pu1Byte 			*TemperatureUP_B,
	OUT pu1Byte 			*TemperatureDOWN_B	
	)
{
    PADAPTER        Adapter   		 = pDM_Odm->Adapter;
	PODM_RF_CAL_T  	pRFCalibrateInfo = &(pDM_Odm->RFCalibrateInfo);
	HAL_DATA_TYPE  	*pHalData  		 = GET_HAL_DATA(Adapter);
	u2Byte			rate			 = *(pDM_Odm->pForcedDataRate);
	u1Byte         	channel   		 = pHalData->CurrentChannel;

	if ( 1 <= channel && channel <= 14) {
		if (IS_CCK_RATE(rate)) {
	        *TemperatureUP_A   = pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKA_P;
	        *TemperatureDOWN_A = pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKA_N;
	        *TemperatureUP_B   = pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKB_P;
	        *TemperatureDOWN_B = pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKB_N;		
		} else {
	        *TemperatureUP_A   = pRFCalibrateInfo->DeltaSwingTableIdx_2GA_P;
	        *TemperatureDOWN_A = pRFCalibrateInfo->DeltaSwingTableIdx_2GA_N;
	        *TemperatureUP_B   = pRFCalibrateInfo->DeltaSwingTableIdx_2GB_P;
	        *TemperatureDOWN_B = pRFCalibrateInfo->DeltaSwingTableIdx_2GB_N;			
		}
 	} else if ( 36 <= channel && channel <= 64) {
        *TemperatureUP_A   = pRFCalibrateInfo->DeltaSwingTableIdx_5GA_P[0];
        *TemperatureDOWN_A = pRFCalibrateInfo->DeltaSwingTableIdx_5GA_N[0];
        *TemperatureUP_B   = pRFCalibrateInfo->DeltaSwingTableIdx_5GB_P[0];
        *TemperatureDOWN_B = pRFCalibrateInfo->DeltaSwingTableIdx_5GB_N[0];
    } else if ( 100 <= channel && channel <= 140) {
        *TemperatureUP_A   = pRFCalibrateInfo->DeltaSwingTableIdx_5GA_P[1];
        *TemperatureDOWN_A = pRFCalibrateInfo->DeltaSwingTableIdx_5GA_N[1];
        *TemperatureUP_B   = pRFCalibrateInfo->DeltaSwingTableIdx_5GB_P[1];
        *TemperatureDOWN_B = pRFCalibrateInfo->DeltaSwingTableIdx_5GB_N[1];
    } else if ( 149 <= channel && channel <= 173) {
        *TemperatureUP_A   = pRFCalibrateInfo->DeltaSwingTableIdx_5GA_P[2]; 
        *TemperatureDOWN_A = pRFCalibrateInfo->DeltaSwingTableIdx_5GA_N[2]; 
        *TemperatureUP_B   = pRFCalibrateInfo->DeltaSwingTableIdx_5GB_P[2]; 
        *TemperatureDOWN_B = pRFCalibrateInfo->DeltaSwingTableIdx_5GB_N[2]; 
    } else {
	    *TemperatureUP_A   = (pu1Byte)DeltaSwingTableIdx_2GA_P_8188E;
	    *TemperatureDOWN_A = (pu1Byte)DeltaSwingTableIdx_2GA_N_8188E;	
	    *TemperatureUP_B   = (pu1Byte)DeltaSwingTableIdx_2GA_P_8188E;
	    *TemperatureDOWN_B = (pu1Byte)DeltaSwingTableIdx_2GA_N_8188E;		
    }
	
	return;
}


VOID
GetDeltaSwingTable_8814A_PathCD(
	IN 	PDM_ODM_T			pDM_Odm,
	OUT pu1Byte 			*TemperatureUP_C,
	OUT pu1Byte 			*TemperatureDOWN_C,
	OUT pu1Byte 			*TemperatureUP_D,
	OUT pu1Byte 			*TemperatureDOWN_D	
	)
{
    PADAPTER        Adapter   		 = pDM_Odm->Adapter;
	PODM_RF_CAL_T  	pRFCalibrateInfo = &(pDM_Odm->RFCalibrateInfo);
	HAL_DATA_TYPE  	*pHalData  		 = GET_HAL_DATA(Adapter);
	u2Byte			rate			 = *(pDM_Odm->pForcedDataRate);
	u1Byte         	channel   		 = pHalData->CurrentChannel;

	if ( 1 <= channel && channel <= 14) {
		if (IS_CCK_RATE(rate)) {
	        *TemperatureUP_C  = pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKC_P;
	        *TemperatureDOWN_C = pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKC_N;
	        *TemperatureUP_D   = pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKD_P;
	        *TemperatureDOWN_D = pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKD_N;		
		} else {
	        *TemperatureUP_C   = pRFCalibrateInfo->DeltaSwingTableIdx_2GC_P;
	        *TemperatureDOWN_C = pRFCalibrateInfo->DeltaSwingTableIdx_2GC_N;
	        *TemperatureUP_D   = pRFCalibrateInfo->DeltaSwingTableIdx_2GD_P;
	        *TemperatureDOWN_D = pRFCalibrateInfo->DeltaSwingTableIdx_2GD_N;			
		}
 	} else if ( 36 <= channel && channel <= 64) {
        *TemperatureUP_C   = pRFCalibrateInfo->DeltaSwingTableIdx_5GC_P[0];
        *TemperatureDOWN_C = pRFCalibrateInfo->DeltaSwingTableIdx_5GC_N[0];
        *TemperatureUP_D   = pRFCalibrateInfo->DeltaSwingTableIdx_5GD_P[0];
        *TemperatureDOWN_D = pRFCalibrateInfo->DeltaSwingTableIdx_5GD_N[0];
    } else if ( 100 <= channel && channel <= 140) {
        *TemperatureUP_C   = pRFCalibrateInfo->DeltaSwingTableIdx_5GC_P[1];
        *TemperatureDOWN_C = pRFCalibrateInfo->DeltaSwingTableIdx_5GC_N[1];
        *TemperatureUP_D   = pRFCalibrateInfo->DeltaSwingTableIdx_5GD_P[1];
        *TemperatureDOWN_D = pRFCalibrateInfo->DeltaSwingTableIdx_5GD_N[1];
    } else if ( 149 <= channel && channel <= 173) {
        *TemperatureUP_C   = pRFCalibrateInfo->DeltaSwingTableIdx_5GC_P[2]; 
        *TemperatureDOWN_C = pRFCalibrateInfo->DeltaSwingTableIdx_5GC_N[2]; 
        *TemperatureUP_D   = pRFCalibrateInfo->DeltaSwingTableIdx_5GD_P[2]; 
        *TemperatureDOWN_D = pRFCalibrateInfo->DeltaSwingTableIdx_5GD_N[2]; 
    } else {
	    *TemperatureUP_C   = (pu1Byte)DeltaSwingTableIdx_2GA_P_8188E;
	    *TemperatureDOWN_C = (pu1Byte)DeltaSwingTableIdx_2GA_N_8188E;	
	    *TemperatureUP_D   = (pu1Byte)DeltaSwingTableIdx_2GA_P_8188E;
	    *TemperatureDOWN_D = (pu1Byte)DeltaSwingTableIdx_2GA_N_8188E;		
    }
	
	return;
}

void ConfigureTxpowerTrack_8814A(
	PTXPWRTRACK_CFG	pConfig
	)
{
	pConfig->SwingTableSize_CCK = CCK_TABLE_SIZE;
	pConfig->SwingTableSize_OFDM = OFDM_TABLE_SIZE;
	pConfig->Threshold_IQK = 8;
	pConfig->AverageThermalNum = AVG_THERMAL_NUM_8814A;
	pConfig->RfPathCount = MAX_PATH_NUM_8814A;
	pConfig->ThermalRegAddr = RF_T_METER_88E;
		
	pConfig->ODM_TxPwrTrackSetPwr = ODM_TxPwrTrackSetPwr8814A;
	pConfig->DoIQK = DoIQK_8814A;
	pConfig->PHY_LCCalibrate = PHY_LCCalibrate_8814A;
	pConfig->GetDeltaSwingTable = GetDeltaSwingTable_8814A;
	pConfig->GetDeltaSwingTable8814only = GetDeltaSwingTable_8814A_PathCD;
}

VOID	
phy_LCCalibrate_8814A(
	IN PDM_ODM_T		pDM_Odm,
	IN	BOOLEAN		is2T
	)
{
	u4Byte	LC_Cal = 0;
	
	//Check continuous TX and Packet TX
	u4Byte	reg0x914 = ODM_Read4Byte(pDM_Odm, rSingleTone_ContTx_Jaguar);;

	// Backup RF reg18.
	LC_Cal = ODM_GetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask);

	if((reg0x914 & 0x70000) == 0)
		ODM_Write1Byte(pDM_Odm, REG_TXPAUSE_8812A, 0xFF);			

	//3 3. Read RF reg18
	LC_Cal = ODM_GetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask);
	
	//3 4. Set LC calibration begin bit15
	ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, LC_Cal|0x08000);

	ODM_delay_ms(100);		

	//3 Restore original situation
	if((reg0x914 & 70000) == 0)
		ODM_Write1Byte(pDM_Odm, REG_TXPAUSE_8812A, 0x00);	

	// Recover channel number
	ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, LC_Cal);

	DbgPrint("Call %s\n", __FUNCTION__);
}


VOID	
phy_APCalibrate_8814A(
#if (DM_ODM_SUPPORT_TYPE & ODM_AP)
	IN PDM_ODM_T		pDM_Odm,
#else
	IN	PADAPTER	pAdapter,
#endif
	IN	s1Byte 		delta,
	IN	BOOLEAN		is2T
	)
{
}


VOID
PHY_LCCalibrate_8814A(
	IN PDM_ODM_T		pDM_Odm
	)
{
	
#if !(DM_ODM_SUPPORT_TYPE & ODM_AP)
	PADAPTER 		pAdapter = pDM_Odm->Adapter;
	
#if (MP_DRIVER == 1)
#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)	
	PMPT_CONTEXT	pMptCtx = &(pAdapter->MptCtx);
#else
	PMPT_CONTEXT	pMptCtx = &(pAdapter->mppriv.MptCtx);		
#endif	
#endif
#endif	

	ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("===> PHY_LCCalibrate_8814A\n"));

//#if (MP_DRIVER == 1)	
	phy_LCCalibrate_8814A(pDM_Odm, TRUE);
//#endif 

	ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("<=== PHY_LCCalibrate_8814A\n"));

}

VOID
PHY_APCalibrate_8814A(
#if (DM_ODM_SUPPORT_TYPE & ODM_AP)
	IN PDM_ODM_T		pDM_Odm,
#else
	IN	PADAPTER	pAdapter,
#endif
	IN	s1Byte 		delta	
	)
{

}


VOID	                                                 
PHY_DPCalibrate_8814A(                                   
	IN 	PDM_ODM_T	pDM_Odm                             
	)
{
}


BOOLEAN 
phy_QueryRFPathSwitch_8814A(
	IN	PADAPTER	pAdapter
	)
{
	return TRUE;
}


BOOLEAN PHY_QueryRFPathSwitch_8814A(	
	IN	PADAPTER	pAdapter
	)
{

#if DISABLE_BB_RF
	return TRUE;
#endif

	return phy_QueryRFPathSwitch_8814A(pAdapter);
}


VOID phy_SetRFPathSwitch_8814A(
#if (DM_ODM_SUPPORT_TYPE & ODM_AP)
	IN PDM_ODM_T		pDM_Odm,
#else
	IN	PADAPTER	pAdapter,
#endif
	IN	BOOLEAN		bMain,
	IN	BOOLEAN		is2T
	)
{
}
VOID PHY_SetRFPathSwitch_8814A(
#if (DM_ODM_SUPPORT_TYPE & ODM_AP)
	IN PDM_ODM_T		pDM_Odm,
#else
	IN	PADAPTER	pAdapter,
#endif
	IN	BOOLEAN		bMain
	)
{
}




#else	/* (RTL8814A_SUPPORT == 0)*/
VOID
PHY_LCCalibrate_8814A(
	IN PDM_ODM_T		pDM_Odm
	){}

VOID
PHY_IQCalibrate_8814A(
	IN	PDM_ODM_T	pDM_Odm,
	IN	BOOLEAN bReCovery
	){}
#endif	/* (RTL8814A_SUPPORT == 0)*/
