Contributors: 2
Author Tokens Token Proportion Commits Commit Proportion
Hans de Goede 2419 99.92% 1 50.00%
Nathan Chancellor 2 0.08% 1 50.00%
Total 2421 2


// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
 *
 * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
 *
 ******************************************************************************/

/* include "Mp_Precomp.h" */
#include "odm_precomp.h"


#define CALCULATE_SWINGTALBE_OFFSET(_offset, _direction, _size, _deltaThermal) \
	do {\
		for (_offset = 0; _offset < _size; _offset++) {\
			if (_deltaThermal < thermalThreshold[_direction][_offset]) {\
				if (_offset != 0)\
					_offset--;\
				break;\
			} \
		} \
		if (_offset >= _size)\
			_offset = _size-1;\
	} while (0)


void ConfigureTxpowerTrack(PDM_ODM_T pDM_Odm, PTXPWRTRACK_CFG pConfig)
{
	ConfigureTxpowerTrack_8723B(pConfig);
}

/*  */
/*  <20121113, Kordan> This function should be called when TxAGC changed. */
/*  Otherwise the previous compensation is gone, because we record the */
/*  delta of temperature between two TxPowerTracking watch dogs. */
/*  */
/*  NOTE: If Tx BB swing or Tx scaling is varified during run-time, still */
/*        need to call this function. */
/*  */
void ODM_ClearTxPowerTrackingState(PDM_ODM_T pDM_Odm)
{
	struct hal_com_data *pHalData = GET_HAL_DATA(pDM_Odm->Adapter);
	u8 p = 0;

	pDM_Odm->BbSwingIdxCckBase = pDM_Odm->DefaultCckIndex;
	pDM_Odm->BbSwingIdxCck = pDM_Odm->DefaultCckIndex;
	pDM_Odm->RFCalibrateInfo.CCK_index = 0;

	for (p = ODM_RF_PATH_A; p < MAX_RF_PATH; ++p) {
		pDM_Odm->BbSwingIdxOfdmBase[p] = pDM_Odm->DefaultOfdmIndex;
		pDM_Odm->BbSwingIdxOfdm[p] = pDM_Odm->DefaultOfdmIndex;
		pDM_Odm->RFCalibrateInfo.OFDM_index[p] = pDM_Odm->DefaultOfdmIndex;

		pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = 0;
		pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[p] = 0;
		pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[p] = 0;
		pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = 0;

		/*  Initial Mix mode power tracking */
		pDM_Odm->Absolute_OFDMSwingIdx[p] = 0;
		pDM_Odm->Remnant_OFDMSwingIdx[p] = 0;
	}

	/* Initial at Modify Tx Scaling Mode */
	pDM_Odm->Modify_TxAGC_Flag_PathA = false;
	/* Initial at Modify Tx Scaling Mode */
	pDM_Odm->Modify_TxAGC_Flag_PathB = false;
	pDM_Odm->Remnant_CCKSwingIdx = 0;
	pDM_Odm->RFCalibrateInfo.ThermalValue = pHalData->EEPROMThermalMeter;
	pDM_Odm->RFCalibrateInfo.ThermalValue_IQK = pHalData->EEPROMThermalMeter;
	pDM_Odm->RFCalibrateInfo.ThermalValue_LCK = pHalData->EEPROMThermalMeter;
}

void ODM_TXPowerTrackingCallback_ThermalMeter(struct adapter *Adapter)
{

	struct hal_com_data *pHalData = GET_HAL_DATA(Adapter);
	PDM_ODM_T pDM_Odm = &pHalData->odmpriv;

	u8 ThermalValue = 0, delta, delta_LCK, delta_IQK, p = 0, i = 0;
	u8 ThermalValue_AVG_count = 0;
	u32 ThermalValue_AVG = 0;

	u8 OFDM_min_index = 0;  /*  OFDM BB Swing should be less than +3.0dB, which is required by Arthur */
	u8 Indexforchannel = 0; /*  GetRightChnlPlaceforIQK(pHalData->CurrentChannel) */

	TXPWRTRACK_CFG c;


	/* 4 1. The following TWO tables decide the final index of OFDM/CCK swing table. */
	u8 *deltaSwingTableIdx_TUP_A;
	u8 *deltaSwingTableIdx_TDOWN_A;
	u8 *deltaSwingTableIdx_TUP_B;
	u8 *deltaSwingTableIdx_TDOWN_B;

	/* 4 2. Initilization (7 steps in total) */

	ConfigureTxpowerTrack(pDM_Odm, &c);

	(*c.GetDeltaSwingTable)(
		pDM_Odm,
		(u8 **)&deltaSwingTableIdx_TUP_A,
		(u8 **)&deltaSwingTableIdx_TDOWN_A,
		(u8 **)&deltaSwingTableIdx_TUP_B,
		(u8 **)&deltaSwingTableIdx_TDOWN_B
	);

	/* cosa add for debug */
	pDM_Odm->RFCalibrateInfo.TXPowerTrackingCallbackCnt++;
	pDM_Odm->RFCalibrateInfo.bTXPowerTrackingInit = true;

	ODM_RT_TRACE(
		pDM_Odm,
		ODM_COMP_TX_PWR_TRACK,
		ODM_DBG_LOUD,
		(
			"===>ODM_TXPowerTrackingCallback_ThermalMeter,\npDM_Odm->BbSwingIdxCckBase: %d, pDM_Odm->BbSwingIdxOfdmBase[A]: %d, pDM_Odm->DefaultOfdmIndex: %d\n",
			pDM_Odm->BbSwingIdxCckBase,
			pDM_Odm->BbSwingIdxOfdmBase[ODM_RF_PATH_A],
			pDM_Odm->DefaultOfdmIndex
		)
	);

	ThermalValue = (u8)PHY_QueryRFReg(pDM_Odm->Adapter, ODM_RF_PATH_A, c.ThermalRegAddr, 0xfc00);	/* 0x42: RF Reg[15:10] 88E */
	if (
		!pDM_Odm->RFCalibrateInfo.TxPowerTrackControl ||
		pHalData->EEPROMThermalMeter == 0 ||
		pHalData->EEPROMThermalMeter == 0xFF
	)
		return;

	/* 4 3. Initialize ThermalValues of RFCalibrateInfo */

	if (pDM_Odm->RFCalibrateInfo.bReloadtxpowerindex)
		ODM_RT_TRACE(
			pDM_Odm,
			ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
			("reload ofdm index for band switch\n")
		);

	/* 4 4. Calculate average thermal meter */

	pDM_Odm->RFCalibrateInfo.ThermalValue_AVG[pDM_Odm->RFCalibrateInfo.ThermalValue_AVG_index] = ThermalValue;
	pDM_Odm->RFCalibrateInfo.ThermalValue_AVG_index++;
	if (pDM_Odm->RFCalibrateInfo.ThermalValue_AVG_index == c.AverageThermalNum)   /* Average times =  c.AverageThermalNum */
		pDM_Odm->RFCalibrateInfo.ThermalValue_AVG_index = 0;

	for (i = 0; i < c.AverageThermalNum; i++) {
		if (pDM_Odm->RFCalibrateInfo.ThermalValue_AVG[i]) {
			ThermalValue_AVG += pDM_Odm->RFCalibrateInfo.ThermalValue_AVG[i];
			ThermalValue_AVG_count++;
		}
	}

	/* Calculate Average ThermalValue after average enough times */
	if (ThermalValue_AVG_count) {
		ThermalValue = (u8)(ThermalValue_AVG / ThermalValue_AVG_count);
		ODM_RT_TRACE(
			pDM_Odm,
			ODM_COMP_TX_PWR_TRACK,
			ODM_DBG_LOUD,
			(
				"AVG Thermal Meter = 0x%X, EFUSE Thermal Base = 0x%X\n",
				ThermalValue,
				pHalData->EEPROMThermalMeter
			)
		);
	}

	/* 4 5. Calculate delta, delta_LCK, delta_IQK. */
	/* delta" here is used to determine whether thermal value changes or not. */
	delta =
		(ThermalValue > pDM_Odm->RFCalibrateInfo.ThermalValue) ?
		(ThermalValue - pDM_Odm->RFCalibrateInfo.ThermalValue) :
		(pDM_Odm->RFCalibrateInfo.ThermalValue - ThermalValue);
	delta_LCK =
		(ThermalValue > pDM_Odm->RFCalibrateInfo.ThermalValue_LCK) ?
		(ThermalValue - pDM_Odm->RFCalibrateInfo.ThermalValue_LCK) :
		(pDM_Odm->RFCalibrateInfo.ThermalValue_LCK - ThermalValue);
	delta_IQK =
		(ThermalValue > pDM_Odm->RFCalibrateInfo.ThermalValue_IQK) ?
		(ThermalValue - pDM_Odm->RFCalibrateInfo.ThermalValue_IQK) :
		(pDM_Odm->RFCalibrateInfo.ThermalValue_IQK - ThermalValue);

	ODM_RT_TRACE(
		pDM_Odm,
		ODM_COMP_TX_PWR_TRACK,
		ODM_DBG_LOUD,
		(
			"(delta, delta_LCK, delta_IQK) = (%d, %d, %d)\n",
			delta,
			delta_LCK,
			delta_IQK
		)
	);

	/* 4 6. If necessary, do LCK. */
	/*  Delta temperature is equal to or larger than 20 centigrade. */
	if (delta_LCK >= c.Threshold_IQK) {
		ODM_RT_TRACE(
			pDM_Odm,
			ODM_COMP_TX_PWR_TRACK,
			ODM_DBG_LOUD,
			(
				"delta_LCK(%d) >= Threshold_IQK(%d)\n",
				delta_LCK,
				c.Threshold_IQK
			)
		);
		pDM_Odm->RFCalibrateInfo.ThermalValue_LCK = ThermalValue;
		if (c.PHY_LCCalibrate)
			(*c.PHY_LCCalibrate)(pDM_Odm);
	}

	/* 3 7. If necessary, move the index of swing table to adjust Tx power. */
	if (delta > 0 && pDM_Odm->RFCalibrateInfo.TxPowerTrackControl) {
		/* delta" here is used to record the absolute value of differrence. */
		delta =
			ThermalValue > pHalData->EEPROMThermalMeter ?
			(ThermalValue - pHalData->EEPROMThermalMeter) :
			(pHalData->EEPROMThermalMeter - ThermalValue);

		if (delta >= TXPWR_TRACK_TABLE_SIZE)
			delta = TXPWR_TRACK_TABLE_SIZE - 1;

		/* 4 7.1 The Final Power Index = BaseIndex + PowerIndexOffset */
		if (ThermalValue > pHalData->EEPROMThermalMeter) {
			ODM_RT_TRACE(
				pDM_Odm,
				ODM_COMP_TX_PWR_TRACK,
				ODM_DBG_LOUD,
				(
					"deltaSwingTableIdx_TUP_A[%d] = %d\n",
					delta,
					deltaSwingTableIdx_TUP_A[delta]
				)
			);
			pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[ODM_RF_PATH_A] =
				pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_A];
			pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_A] =
				deltaSwingTableIdx_TUP_A[delta];

			/*  Record delta swing for mix mode power tracking */
			pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A] =
				deltaSwingTableIdx_TUP_A[delta];

			ODM_RT_TRACE(
				pDM_Odm,
				ODM_COMP_TX_PWR_TRACK,
				ODM_DBG_LOUD,
				(
					"******Temp is higher and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n",
					pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A]
				)
			);

			if (c.RfPathCount > 1) {
				ODM_RT_TRACE(
					pDM_Odm,
					ODM_COMP_TX_PWR_TRACK,
					ODM_DBG_LOUD,
					(
						"deltaSwingTableIdx_TUP_B[%d] = %d\n",
						delta,
						deltaSwingTableIdx_TUP_B[delta]
					)
				);
				pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[ODM_RF_PATH_B] =
					pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_B];
				pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_B] =
					deltaSwingTableIdx_TUP_B[delta];

				/*  Record delta swing for mix mode power tracking */
				pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B] =
					deltaSwingTableIdx_TUP_B[delta];
				ODM_RT_TRACE(
					pDM_Odm,
					ODM_COMP_TX_PWR_TRACK,
					ODM_DBG_LOUD,
					(
						"******Temp is higher and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B] = %d\n",
						pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B]
					)
				);
			}

		} else {
			ODM_RT_TRACE(
				pDM_Odm,
				ODM_COMP_TX_PWR_TRACK,
				ODM_DBG_LOUD,
				(
					"deltaSwingTableIdx_TDOWN_A[%d] = %d\n",
					delta,
					deltaSwingTableIdx_TDOWN_A[delta]
				)
			);

			pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[ODM_RF_PATH_A] =
				pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_A];
			pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_A] =
				-1 * deltaSwingTableIdx_TDOWN_A[delta];

			/*  Record delta swing for mix mode power tracking */
			pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A] =
				-1 * deltaSwingTableIdx_TDOWN_A[delta];

			ODM_RT_TRACE(
				pDM_Odm,
				ODM_COMP_TX_PWR_TRACK,
				ODM_DBG_LOUD,
				(
					"******Temp is lower and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n",
					pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A]
				)
			);

			if (c.RfPathCount > 1) {
				ODM_RT_TRACE(
					pDM_Odm,
					ODM_COMP_TX_PWR_TRACK,
					ODM_DBG_LOUD,
					(
						"deltaSwingTableIdx_TDOWN_B[%d] = %d\n",
						delta,
						deltaSwingTableIdx_TDOWN_B[delta]
					)
				);

				pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[ODM_RF_PATH_B] =
					pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_B];
				pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_B] =
					-1 * deltaSwingTableIdx_TDOWN_B[delta];

				 /*  Record delta swing for mix mode power tracking */
				pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B] =
					-1 * deltaSwingTableIdx_TDOWN_B[delta];

				ODM_RT_TRACE(
					pDM_Odm,
					ODM_COMP_TX_PWR_TRACK,
					ODM_DBG_LOUD,
					(
						"******Temp is lower and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B] = %d\n",
						pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B]
					)
				);
			}
		}

		for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++) {
			ODM_RT_TRACE(
				pDM_Odm,
				ODM_COMP_TX_PWR_TRACK,
				ODM_DBG_LOUD,
				(
					"\n\n ================================ [Path-%c] Calculating PowerIndexOffset ================================\n",
					(p == ODM_RF_PATH_A ? 'A' : 'B')
				)
			);

			if (
				pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[p] ==
				pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[p]
			) /*  If Thermal value changes but lookup table value still the same */
				pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = 0;
			else
				pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[p] - pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[p];      /*  Power Index Diff between 2 times Power Tracking */

			ODM_RT_TRACE(
				pDM_Odm,
				ODM_COMP_TX_PWR_TRACK,
				ODM_DBG_LOUD,
				(
					"[Path-%c] PowerIndexOffset(%d) = DeltaPowerIndex(%d) - DeltaPowerIndexLast(%d)\n",
					(
						p == ODM_RF_PATH_A ? 'A' : 'B'),
						pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p],
						pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[p],
						pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[p]
					)
				);

			pDM_Odm->RFCalibrateInfo.OFDM_index[p] =
				pDM_Odm->BbSwingIdxOfdmBase[p] +
				pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p];

			pDM_Odm->RFCalibrateInfo.CCK_index =
				pDM_Odm->BbSwingIdxCckBase +
				pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p];

			pDM_Odm->BbSwingIdxCck =
				pDM_Odm->RFCalibrateInfo.CCK_index;

			pDM_Odm->BbSwingIdxOfdm[p] =
				pDM_Odm->RFCalibrateInfo.OFDM_index[p];

			/*  *************Print BB Swing Base and Index Offset************* */
			ODM_RT_TRACE(
				pDM_Odm,
				ODM_COMP_TX_PWR_TRACK,
				ODM_DBG_LOUD,
				(
					"The 'CCK' final index(%d) = BaseIndex(%d) + PowerIndexOffset(%d)\n",
					pDM_Odm->BbSwingIdxCck,
					pDM_Odm->BbSwingIdxCckBase,
					pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p]
				)
			);
			ODM_RT_TRACE(
				pDM_Odm,
				ODM_COMP_TX_PWR_TRACK,
				ODM_DBG_LOUD,
				(
					"The 'OFDM' final index(%d) = BaseIndex[%c](%d) + PowerIndexOffset(%d)\n",
					pDM_Odm->BbSwingIdxOfdm[p],
					(p == ODM_RF_PATH_A ? 'A' : 'B'),
					pDM_Odm->BbSwingIdxOfdmBase[p],
					pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p]
				)
			);

			/* 4 7.1 Handle boundary conditions of index. */
			if (pDM_Odm->RFCalibrateInfo.OFDM_index[p] > c.SwingTableSize_OFDM-1)
				pDM_Odm->RFCalibrateInfo.OFDM_index[p] = c.SwingTableSize_OFDM-1;
			else if (pDM_Odm->RFCalibrateInfo.OFDM_index[p] < OFDM_min_index)
				pDM_Odm->RFCalibrateInfo.OFDM_index[p] = OFDM_min_index;
		}
		ODM_RT_TRACE(
			pDM_Odm,
			ODM_COMP_TX_PWR_TRACK,
			ODM_DBG_LOUD,
			("\n\n ========================================================================================================\n")
		);
		if (pDM_Odm->RFCalibrateInfo.CCK_index > c.SwingTableSize_CCK-1)
			pDM_Odm->RFCalibrateInfo.CCK_index = c.SwingTableSize_CCK-1;
		/* else if (pDM_Odm->RFCalibrateInfo.CCK_index < 0) */
			/* pDM_Odm->RFCalibrateInfo.CCK_index = 0; */
	} else {
		ODM_RT_TRACE(
			pDM_Odm,
			ODM_COMP_TX_PWR_TRACK,
			ODM_DBG_LOUD,
			(
				"The thermal meter is unchanged or TxPowerTracking OFF(%d): ThermalValue: %d , pDM_Odm->RFCalibrateInfo.ThermalValue: %d\n",
				pDM_Odm->RFCalibrateInfo.TxPowerTrackControl,
				ThermalValue,
				pDM_Odm->RFCalibrateInfo.ThermalValue
			)
		);

			for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++)
				pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = 0;
	}
	ODM_RT_TRACE(
		pDM_Odm,
		ODM_COMP_TX_PWR_TRACK,
		ODM_DBG_LOUD,
		(
			"TxPowerTracking: [CCK] Swing Current Index: %d, Swing Base Index: %d\n",
			pDM_Odm->RFCalibrateInfo.CCK_index,
			pDM_Odm->BbSwingIdxCckBase
		)
	);

	/* Print Swing base & current */
	for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++) {
		ODM_RT_TRACE(
			pDM_Odm,
			ODM_COMP_TX_PWR_TRACK,
			ODM_DBG_LOUD,
			(
				"TxPowerTracking: [OFDM] Swing Current Index: %d, Swing Base Index[%c]: %d\n",
				pDM_Odm->RFCalibrateInfo.OFDM_index[p],
				(p == ODM_RF_PATH_A ? 'A' : 'B'),
				pDM_Odm->BbSwingIdxOfdmBase[p]
			)
		);
	}

	if (
		(pDM_Odm->RFCalibrateInfo.PowerIndexOffset[ODM_RF_PATH_A] != 0 ||
		 pDM_Odm->RFCalibrateInfo.PowerIndexOffset[ODM_RF_PATH_B] != 0) &&
		 pDM_Odm->RFCalibrateInfo.TxPowerTrackControl
	 ) {
		/* 4 7.2 Configure the Swing Table to adjust Tx Power. */

		pDM_Odm->RFCalibrateInfo.bTxPowerChanged = true; /*  Always true after Tx Power is adjusted by power tracking. */
		/*  */
		/*  2012/04/23 MH According to Luke's suggestion, we can not write BB digital */
		/*  to increase TX power. Otherwise, EVM will be bad. */
		/*  */
		/*  2012/04/25 MH Add for tx power tracking to set tx power in tx agc for 88E. */
		if (ThermalValue > pDM_Odm->RFCalibrateInfo.ThermalValue) {
			ODM_RT_TRACE(
				pDM_Odm,
				ODM_COMP_TX_PWR_TRACK,
				ODM_DBG_LOUD,
				(
					"Temperature Increasing(A): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n",
					pDM_Odm->RFCalibrateInfo.PowerIndexOffset[ODM_RF_PATH_A],
					delta,
					ThermalValue,
					pHalData->EEPROMThermalMeter,
					pDM_Odm->RFCalibrateInfo.ThermalValue
				)
			);

			if (c.RfPathCount > 1)
				ODM_RT_TRACE(
					pDM_Odm,
					ODM_COMP_TX_PWR_TRACK,
					ODM_DBG_LOUD,
					(
						"Temperature Increasing(B): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n",
						pDM_Odm->RFCalibrateInfo.PowerIndexOffset[ODM_RF_PATH_B],
						delta,
						ThermalValue,
						pHalData->EEPROMThermalMeter,
						pDM_Odm->RFCalibrateInfo.ThermalValue
					)
				);

		} else if (ThermalValue < pDM_Odm->RFCalibrateInfo.ThermalValue) { /*  Low temperature */
			ODM_RT_TRACE(
				pDM_Odm,
				ODM_COMP_TX_PWR_TRACK,
				ODM_DBG_LOUD,
				(
					"Temperature Decreasing(A): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n",
					pDM_Odm->RFCalibrateInfo.PowerIndexOffset[ODM_RF_PATH_A],
					delta,
					ThermalValue,
					pHalData->EEPROMThermalMeter,
					pDM_Odm->RFCalibrateInfo.ThermalValue
				)
			);

			if (c.RfPathCount > 1)
				ODM_RT_TRACE(
					pDM_Odm,
					ODM_COMP_TX_PWR_TRACK,
					ODM_DBG_LOUD,
					(
						"Temperature Decreasing(B): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n",
						pDM_Odm->RFCalibrateInfo.PowerIndexOffset[ODM_RF_PATH_B],
						delta,
						ThermalValue,
						pHalData->EEPROMThermalMeter,
						pDM_Odm->RFCalibrateInfo.ThermalValue
					)
				);

		}

		if (ThermalValue > pHalData->EEPROMThermalMeter) {
			ODM_RT_TRACE(
				pDM_Odm,
				ODM_COMP_TX_PWR_TRACK,
				ODM_DBG_LOUD,
				(
					"Temperature(%d) higher than PG value(%d)\n",
					ThermalValue,
					pHalData->EEPROMThermalMeter
				)
			);

			ODM_RT_TRACE(
				pDM_Odm,
				ODM_COMP_TX_PWR_TRACK,
				ODM_DBG_LOUD,
				("**********Enter POWER Tracking MIX_MODE**********\n")
			);
			for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++)
					(*c.ODM_TxPwrTrackSetPwr)(pDM_Odm, MIX_MODE, p, 0);
		} else {
			ODM_RT_TRACE(
				pDM_Odm,
				ODM_COMP_TX_PWR_TRACK,
				ODM_DBG_LOUD,
				(
					"Temperature(%d) lower than PG value(%d)\n",
					ThermalValue,
					pHalData->EEPROMThermalMeter
				)
			);

			ODM_RT_TRACE(
				pDM_Odm,
				ODM_COMP_TX_PWR_TRACK,
				ODM_DBG_LOUD,
				("**********Enter POWER Tracking MIX_MODE**********\n")
			);
			for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++)
				(*c.ODM_TxPwrTrackSetPwr)(pDM_Odm, MIX_MODE, p, Indexforchannel);
		}

		/*  Record last time Power Tracking result as base. */
		pDM_Odm->BbSwingIdxCckBase = pDM_Odm->BbSwingIdxCck;
		for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++)
			pDM_Odm->BbSwingIdxOfdmBase[p] = pDM_Odm->BbSwingIdxOfdm[p];

		ODM_RT_TRACE(
			pDM_Odm,
			ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
			(
				"pDM_Odm->RFCalibrateInfo.ThermalValue = %d ThermalValue = %d\n",
				pDM_Odm->RFCalibrateInfo.ThermalValue,
				ThermalValue
			)
		);

		/* Record last Power Tracking Thermal Value */
		pDM_Odm->RFCalibrateInfo.ThermalValue = ThermalValue;
	}

	ODM_RT_TRACE(
		pDM_Odm,
		ODM_COMP_TX_PWR_TRACK,
		ODM_DBG_LOUD,
		("<===ODM_TXPowerTrackingCallback_ThermalMeter\n")
	);

	pDM_Odm->RFCalibrateInfo.TXPowercount = 0;
}




/* 3 ============================================================ */
/* 3 IQ Calibration */
/* 3 ============================================================ */

u8 ODM_GetRightChnlPlaceforIQK(u8 chnl)
{
	u8 channel_all[ODM_TARGET_CHNL_NUM_2G_5G] = {
		1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
		36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58,
		60, 62, 64, 100, 102, 104, 106, 108, 110, 112,
		114, 116, 118, 120, 122, 124, 126, 128, 130, 132,
		134, 136, 138, 140, 149, 151, 153, 155, 157, 159,
		161, 163, 165
	};
	u8 place = chnl;


	if (chnl > 14) {
		for (place = 14; place < sizeof(channel_all); place++) {
			if (channel_all[place] == chnl)
				return place-13;
		}
	}
	return 0;

}