/******************************************************************************
 *
 * Copyright(c) 2007 - 2017  Realtek Corporation.
 *
 * 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.
 *
 * The full GNU General Public License is included in this distribution in the
 * file called LICENSE.
 *
 * Contact Information:
 * wlanfae <wlanfae@realtek.com>
 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
 * Hsinchu 300, Taiwan.
 *
 * Larry Finger <Larry.Finger@lwfinger.net>
 *
 *****************************************************************************/

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

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

void configure_txpower_track(void *p_dm_void, struct _TXPWRTRACK_CFG *p_config)
{
	struct PHY_DM_STRUCT *p_dm = (struct PHY_DM_STRUCT *)p_dm_void;

#if RTL8192E_SUPPORT
	if (p_dm->support_ic_type == ODM_RTL8192E)
		configure_txpower_track_8192e(p_config);
#endif
#if RTL8821A_SUPPORT
	if (p_dm->support_ic_type == ODM_RTL8821)
		configure_txpower_track_8821a(p_config);
#endif
#if RTL8812A_SUPPORT
	if (p_dm->support_ic_type == ODM_RTL8812)
		configure_txpower_track_8812a(p_config);
#endif
#if RTL8188E_SUPPORT
	if (p_dm->support_ic_type == ODM_RTL8188E)
		configure_txpower_track_8188e(p_config);
#endif

#if RTL8723B_SUPPORT
	if (p_dm->support_ic_type == ODM_RTL8723B)
		configure_txpower_track_8723b(p_config);
#endif

#if RTL8814A_SUPPORT
	if (p_dm->support_ic_type == ODM_RTL8814A)
		configure_txpower_track_8814a(p_config);
#endif

#if RTL8703B_SUPPORT
	if (p_dm->support_ic_type == ODM_RTL8703B)
		configure_txpower_track_8703b(p_config);
#endif

#if RTL8188F_SUPPORT
	if (p_dm->support_ic_type == ODM_RTL8188F)
		configure_txpower_track_8188f(p_config);
#endif
#if RTL8723D_SUPPORT
	if (p_dm->support_ic_type == ODM_RTL8723D)
		configure_txpower_track_8723d(p_config);
#endif
/* JJ ADD 20161014 */
#if RTL8710B_SUPPORT
	if (p_dm->support_ic_type == ODM_RTL8710B)
		configure_txpower_track_8710b(p_config);
#endif

#if RTL8822B_SUPPORT
	if (p_dm->support_ic_type == ODM_RTL8822B)
		configure_txpower_track_8822b(p_config);
#endif
#if RTL8821C_SUPPORT
	if (p_dm->support_ic_type == ODM_RTL8821C)
		configure_txpower_track_8821c(p_config);
#endif
}

/* **********************************************************************
 * <20121113, Kordan> This function should be called when tx_agc 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_clear_txpowertracking_state(void *p_dm_void)
{
	struct PHY_DM_STRUCT *p_dm = (struct PHY_DM_STRUCT *)p_dm_void;
#if (DM_ODM_SUPPORT_TYPE == ODM_CE) && defined(DM_ODM_CE_MAC80211)
	struct rtl_priv *rtlpriv = (struct rtl_priv *)p_dm->adapter;
	struct rtl_efuse *rtlefu = rtl_efuse(rtlpriv);
#else
	PHAL_DATA_TYPE	p_hal_data = GET_HAL_DATA(p_dm->adapter);
#endif
	u8 p = 0;
	struct odm_rf_calibration_structure *p_rf_calibrate_info =
		&p_dm->rf_calibrate_info;

	p_rf_calibrate_info->bb_swing_idx_cck_base =
		p_rf_calibrate_info->default_cck_index;
	p_rf_calibrate_info->bb_swing_idx_cck =
		p_rf_calibrate_info->default_cck_index;
	p_dm->rf_calibrate_info.CCK_index = 0;

	for (p = RF_PATH_A; p < MAX_RF_PATH; ++p) {
		p_rf_calibrate_info->bb_swing_idx_ofdm_base[p] =
			p_rf_calibrate_info->default_ofdm_index;
		p_rf_calibrate_info->bb_swing_idx_ofdm[p] =
			p_rf_calibrate_info->default_ofdm_index;
		p_rf_calibrate_info->OFDM_index[p] =
			p_rf_calibrate_info->default_ofdm_index;

		p_rf_calibrate_info->power_index_offset[p] = 0;
		p_rf_calibrate_info->delta_power_index[p] = 0;
		p_rf_calibrate_info->delta_power_index_last[p] = 0;

		p_rf_calibrate_info->absolute_ofdm_swing_idx[p] =
			0; /* Initial Mix mode power tracking*/
		p_rf_calibrate_info->remnant_ofdm_swing_idx[p] = 0;
		p_rf_calibrate_info->kfree_offset[p] = 0;
	}

	p_rf_calibrate_info->modify_tx_agc_flag_path_a =
		false; /*Initial at Modify Tx Scaling mode*/
	p_rf_calibrate_info->modify_tx_agc_flag_path_b =
		false; /*Initial at Modify Tx Scaling mode*/
	p_rf_calibrate_info->modify_tx_agc_flag_path_c =
		false; /*Initial at Modify Tx Scaling mode*/
	p_rf_calibrate_info->modify_tx_agc_flag_path_d =
		false; /*Initial at Modify Tx Scaling mode*/
	p_rf_calibrate_info->remnant_cck_swing_idx = 0;
#if (DM_ODM_SUPPORT_TYPE == ODM_CE) && defined(DM_ODM_CE_MAC80211)
	p_rf_calibrate_info->thermal_value = rtlefu->eeprom_thermalmeter;
#else
	p_rf_calibrate_info->thermal_value = p_hal_data->eeprom_thermal_meter;
#endif

	p_rf_calibrate_info->modify_tx_agc_value_cck =
		0; /* modify by Mingzhi.Guo */
	p_rf_calibrate_info->modify_tx_agc_value_ofdm =
		0; /* modify by Mingzhi.Guo */
}

void odm_txpowertracking_callback_thermal_meter(
#if (DM_ODM_SUPPORT_TYPE & ODM_AP)
	struct PHY_DM_STRUCT		*p_dm
#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) && defined(DM_ODM_CE_MAC80211)
	void *p_dm_void
#else
	struct _ADAPTER	*adapter
#endif
	)
{
#if (DM_ODM_SUPPORT_TYPE == ODM_CE) && defined(DM_ODM_CE_MAC80211)
	struct PHY_DM_STRUCT *p_dm = (struct PHY_DM_STRUCT *)p_dm_void;
	struct rtl_priv *rtlpriv = (struct rtl_priv *)p_dm->adapter;
	struct rtl_efuse *rtlefu = rtl_efuse(rtlpriv);
	void *adapter = p_dm->adapter;
#elif !(DM_ODM_SUPPORT_TYPE & ODM_AP)
	HAL_DATA_TYPE	*p_hal_data = GET_HAL_DATA(adapter);
#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
	struct PHY_DM_STRUCT		*p_dm = &p_hal_data->DM_OutSrc;
#elif (DM_ODM_SUPPORT_TYPE == ODM_CE)
	struct PHY_DM_STRUCT		*p_dm = &p_hal_data->odmpriv;
#endif
#endif

	struct odm_rf_calibration_structure *p_rf_calibrate_info =
		&(p_dm->rf_calibrate_info);
	struct _IQK_INFORMATION *p_iqk_info = &p_dm->IQK_info;

	u8 thermal_value = 0, delta, delta_LCK, delta_IQK, p = 0, i = 0;
	s8 diff_DPK[4] = {0};
	u8 thermal_value_avg_count = 0;
	u32 thermal_value_avg = 0, regc80, regcd0, regcd4, regab4;

	u8 OFDM_min_index =
		0; /* OFDM BB Swing should be less than +3.0dB, which is required by Arthur */
	u8 indexforchannel =
		0; /* get_right_chnl_place_for_iqk(p_hal_data->current_channel) */
#if (DM_ODM_SUPPORT_TYPE == ODM_CE) && defined(DM_ODM_CE_MAC80211)
	u8 power_tracking_type = 0; /* no specify type */
#else
	u8			power_tracking_type = p_hal_data->rf_power_tracking_type;
#endif
	u8 xtal_offset_eanble = 0;
	s8 thermal_value_temp = 0;

	struct _TXPWRTRACK_CFG c = {0};

	/* 4 1. The following TWO tables decide the final index of OFDM/CCK swing table. */
	u8 *delta_swing_table_idx_tup_a = NULL;
	u8 *delta_swing_table_idx_tdown_a = NULL;
	u8 *delta_swing_table_idx_tup_b = NULL;
	u8 *delta_swing_table_idx_tdown_b = NULL;
	/*for 8814 add by Yu Chen*/
	u8 *delta_swing_table_idx_tup_c = NULL;
	u8 *delta_swing_table_idx_tdown_c = NULL;
	u8 *delta_swing_table_idx_tup_d = NULL;
	u8 *delta_swing_table_idx_tdown_d = NULL;
	/*for Xtal Offset by James.Tung*/
	s8 *delta_swing_table_xtal_up = NULL;
	s8 *delta_swing_table_xtal_down = NULL;

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

	configure_txpower_track(p_dm, &c);

	(*c.get_delta_swing_table)(p_dm, (u8 **)&delta_swing_table_idx_tup_a,
				   (u8 **)&delta_swing_table_idx_tdown_a,
				   (u8 **)&delta_swing_table_idx_tup_b,
				   (u8 **)&delta_swing_table_idx_tdown_b);

	if (p_dm->support_ic_type & ODM_RTL8814A) /*for 8814 path C & D*/
		(*c.get_delta_swing_table8814only)(
			p_dm, (u8 **)&delta_swing_table_idx_tup_c,
			(u8 **)&delta_swing_table_idx_tdown_c,
			(u8 **)&delta_swing_table_idx_tup_d,
			(u8 **)&delta_swing_table_idx_tdown_d);
	/* JJ ADD 20161014 */
	if (p_dm->support_ic_type &
	    (ODM_RTL8703B | ODM_RTL8723D | ODM_RTL8710B)) /*for Xtal Offset*/
		(*c.get_delta_swing_xtal_table)(
			p_dm, (s8 **)&delta_swing_table_xtal_up,
			(s8 **)&delta_swing_table_xtal_down);

	p_rf_calibrate_info
		->txpowertracking_callback_cnt++; /*cosa add for debug*/
	p_rf_calibrate_info->is_txpowertracking_init = true;

/*p_rf_calibrate_info->txpowertrack_control = p_hal_data->txpowertrack_control;
	<Kordan> We should keep updating the control variable according to HalData.
	<Kordan> rf_calibrate_info.rega24 will be initialized when ODM HW configuring, but MP configures with para files. */
#if (DM_ODM_SUPPORT_TYPE & ODM_WIN)
#if (MP_DRIVER == 1)
	p_rf_calibrate_info->rega24 = 0x090e1317;
#endif
#elif (DM_ODM_SUPPORT_TYPE & ODM_CE)
	if (*(p_dm->p_mp_mode) == true)
		p_rf_calibrate_info->rega24 = 0x090e1317;
#endif

	ODM_RT_TRACE(
		p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
		("===>odm_txpowertracking_callback_thermal_meter\n p_rf_calibrate_info->bb_swing_idx_cck_base: %d, p_rf_calibrate_info->bb_swing_idx_ofdm_base[A]: %d, p_rf_calibrate_info->default_ofdm_index: %d\n",
		 p_rf_calibrate_info->bb_swing_idx_cck_base,
		 p_rf_calibrate_info->bb_swing_idx_ofdm_base[RF_PATH_A],
		 p_rf_calibrate_info->default_ofdm_index));

#if (DM_ODM_SUPPORT_TYPE == ODM_CE) && defined(DM_ODM_CE_MAC80211)
	ODM_RT_TRACE(
		p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
		("p_rf_calibrate_info->txpowertrack_control=%d,  rtlefu->eeprom_thermalmeter %d\n",
		 p_rf_calibrate_info->txpowertrack_control,
		 rtlefu->eeprom_thermalmeter));
#else
	ODM_RT_TRACE(p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
		("p_rf_calibrate_info->txpowertrack_control=%d,  p_hal_data->eeprom_thermal_meter %d\n", p_rf_calibrate_info->txpowertrack_control,  p_hal_data->eeprom_thermal_meter));
#endif

	thermal_value =
		(u8)odm_get_rf_reg(p_dm, RF_PATH_A, c.thermal_reg_addr,
				   0xfc00); /* 0x42: RF Reg[15:10] 88E */

	thermal_value_temp = thermal_value + phydm_get_thermal_offset(p_dm);

	ODM_RT_TRACE(
		p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
		("thermal_value_temp(%d) = thermal_value(%d) + power_trim_thermal(%d)\n",
		 thermal_value_temp, thermal_value,
		 phydm_get_thermal_offset(p_dm)));

	if (thermal_value_temp > 63)
		thermal_value = 63;
	else if (thermal_value_temp < 0)
		thermal_value = 0;
	else
		thermal_value = thermal_value_temp;

	/*add log by zhao he, check c80/c94/c14/ca0 value*/
	if (p_dm->support_ic_type == ODM_RTL8723D) {
		regc80 = odm_get_bb_reg(p_dm, BBREG_0xc80, MASKDWORD);
		regcd0 = odm_get_bb_reg(p_dm, BBREG_0xcd0, MASKDWORD);
		regcd4 = odm_get_bb_reg(p_dm, BBREG_0xcd4, MASKDWORD);
		regab4 = odm_get_bb_reg(p_dm, BBREG_0xab4, 0x000007FF);
		ODM_RT_TRACE(
			p_dm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
			("BBREG_0xc80 = 0x%x BBREG_0xcd0 = 0x%x BBREG_0xcd4 = 0x%x BBREG_0xab4 = 0x%x\n",
			 regc80, regcd0, regcd4, regab4));
	}
	/* JJ ADD 20161014 */
	if (p_dm->support_ic_type == ODM_RTL8710B) {
		regc80 = odm_get_bb_reg(p_dm, BBREG_0xc80, MASKDWORD);
		regcd0 = odm_get_bb_reg(p_dm, BBREG_0xcd0, MASKDWORD);
		regcd4 = odm_get_bb_reg(p_dm, BBREG_0xcd4, MASKDWORD);
		regab4 = odm_get_bb_reg(p_dm, BBREG_0xab4, 0x000007FF);
		ODM_RT_TRACE(
			p_dm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
			("BBREG_0xc80 = 0x%x BBREG_0xcd0 = 0x%x BBREG_0xcd4 = 0x%x BBREG_0xab4 = 0x%x\n",
			 regc80, regcd0, regcd4, regab4));
	}

	if (!p_rf_calibrate_info->txpowertrack_control)
		return;

#if (DM_ODM_SUPPORT_TYPE == ODM_CE) && defined(DM_ODM_CE_MAC80211)
	if (rtlefu->eeprom_thermalmeter == 0xff) {
		ODM_RT_TRACE(
			p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
			("no pg, p_hal_data->eeprom_thermal_meter = 0x%x\n",
			 rtlefu->eeprom_thermalmeter));
		return;
	}
#else
	if (p_hal_data->eeprom_thermal_meter == 0xff) {
		ODM_RT_TRACE(p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("no pg, p_hal_data->eeprom_thermal_meter = 0x%x\n", p_hal_data->eeprom_thermal_meter));
		return;
	}
#endif

	/*4 3. Initialize ThermalValues of rf_calibrate_info*/

	if (p_rf_calibrate_info->is_reloadtxpowerindex)
		ODM_RT_TRACE(p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
			     ("reload ofdm index for band switch\n"));

	/*4 4. Calculate average thermal meter*/

	p_rf_calibrate_info->thermal_value_avg
		[p_rf_calibrate_info->thermal_value_avg_index] = thermal_value;
	p_rf_calibrate_info->thermal_value_avg_index++;
	if (p_rf_calibrate_info->thermal_value_avg_index ==
	    c.average_thermal_num) /*Average times =  c.average_thermal_num*/
		p_rf_calibrate_info->thermal_value_avg_index = 0;

	for (i = 0; i < c.average_thermal_num; i++) {
		if (p_rf_calibrate_info->thermal_value_avg[i]) {
			thermal_value_avg +=
				p_rf_calibrate_info->thermal_value_avg[i];
			thermal_value_avg_count++;
		}
	}

	if (thermal_value_avg_count) { /* Calculate Average thermal_value after average enough times */
		thermal_value =
			(u8)(thermal_value_avg / thermal_value_avg_count);
#if (DM_ODM_SUPPORT_TYPE == ODM_CE) && defined(DM_ODM_CE_MAC80211)
		p_rf_calibrate_info->thermal_value_delta =
			thermal_value - rtlefu->eeprom_thermalmeter;
		ODM_RT_TRACE(
			p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
			("AVG Thermal Meter = 0x%X, EFUSE Thermal base = 0x%X\n",
			 thermal_value, rtlefu->eeprom_thermalmeter));
#else
		p_rf_calibrate_info->thermal_value_delta = thermal_value - p_hal_data->eeprom_thermal_meter;
		ODM_RT_TRACE(p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
			("AVG Thermal Meter = 0x%X, EFUSE Thermal base = 0x%X\n", thermal_value, p_hal_data->eeprom_thermal_meter));
#endif
	}

	/* 4 5. Calculate delta, delta_LCK, delta_IQK. */

	/* "delta" here is used to determine whether thermal value changes or not. */
	delta = (thermal_value > p_rf_calibrate_info->thermal_value) ?
			(thermal_value - p_rf_calibrate_info->thermal_value) :
			(p_rf_calibrate_info->thermal_value - thermal_value);
	delta_LCK = (thermal_value > p_rf_calibrate_info->thermal_value_lck) ?
			    (thermal_value -
			     p_rf_calibrate_info->thermal_value_lck) :
			    (p_rf_calibrate_info->thermal_value_lck -
			     thermal_value);
	delta_IQK = (thermal_value > p_rf_calibrate_info->thermal_value_iqk) ?
			    (thermal_value -
			     p_rf_calibrate_info->thermal_value_iqk) :
			    (p_rf_calibrate_info->thermal_value_iqk -
			     thermal_value);

	if (p_rf_calibrate_info->thermal_value_iqk ==
	    0xff) { /*no PG, use thermal value for IQK*/
		p_rf_calibrate_info->thermal_value_iqk = thermal_value;
		delta_IQK = (thermal_value >
			     p_rf_calibrate_info->thermal_value_iqk) ?
				    (thermal_value -
				     p_rf_calibrate_info->thermal_value_iqk) :
				    (p_rf_calibrate_info->thermal_value_iqk -
				     thermal_value);
		ODM_RT_TRACE(p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
			     ("no PG, use thermal_value for IQK\n"));
	}

	for (p = RF_PATH_A; p < c.rf_path_count; p++)
		diff_DPK[p] = (s8)thermal_value -
			      (s8)p_rf_calibrate_info->dpk_thermal[p];

	/*4 6. If necessary, do LCK.*/

	if (!(p_dm->support_ic_type &
	      ODM_RTL8821)) { /*no PG, do LCK at initial status*/
		if (p_rf_calibrate_info->thermal_value_lck == 0xff) {
			ODM_RT_TRACE(p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
				     ("no PG, do LCK\n"));
			p_rf_calibrate_info->thermal_value_lck = thermal_value;

			/*Use RTLCK, so close power tracking driver LCK*/
			if (!(p_dm->support_ic_type & ODM_RTL8814A) &&
			    !(p_dm->support_ic_type & ODM_RTL8822B) &&
			    c.phy_lc_calibrate)
				(*c.phy_lc_calibrate)(p_dm);

			delta_LCK = (thermal_value >
				     p_rf_calibrate_info->thermal_value_lck) ?
					    (thermal_value -
					     p_rf_calibrate_info
						     ->thermal_value_lck) :
					    (p_rf_calibrate_info
						     ->thermal_value_lck -
					     thermal_value);
		}

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

		/* Wait sacn to do LCK by RF Jenyu*/
		if ((*p_dm->p_is_scan_in_process == false) &&
		    (!p_iqk_info->rfk_forbidden)) {
			/* Delta temperature is equal to or larger than 20 centigrade.*/
			if (delta_LCK >= c.threshold_iqk) {
				ODM_RT_TRACE(
					p_dm, ODM_COMP_TX_PWR_TRACK,
					ODM_DBG_LOUD,
					("delta_LCK(%d) >= threshold_iqk(%d)\n",
					 delta_LCK, c.threshold_iqk));
				p_rf_calibrate_info->thermal_value_lck =
					thermal_value;

				/*Use RTLCK, so close power tracking driver LCK*/
				if (!(p_dm->support_ic_type & ODM_RTL8814A) &&
				    !(p_dm->support_ic_type & ODM_RTL8822B) &&
				    c.phy_lc_calibrate)
					(*c.phy_lc_calibrate)(p_dm);
			}
		}
	}

	/*3 7. If necessary, move the index of swing table to adjust Tx power.*/

	if (delta > 0 && p_rf_calibrate_info->txpowertrack_control) {
/* "delta" here is used to record the absolute value of differrence. */
#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE))
#if (DM_ODM_SUPPORT_TYPE == ODM_CE) && defined(DM_ODM_CE_MAC80211)
		delta = thermal_value > rtlefu->eeprom_thermalmeter ?
				(thermal_value - rtlefu->eeprom_thermalmeter) :
				(rtlefu->eeprom_thermalmeter - thermal_value);
#else
		delta = thermal_value > p_hal_data->eeprom_thermal_meter ? (thermal_value - p_hal_data->eeprom_thermal_meter) : (p_hal_data->eeprom_thermal_meter - thermal_value);
#endif
#else
		delta = (thermal_value > p_dm->priv->pmib->dot11RFEntry.ther) ? (thermal_value - p_dm->priv->pmib->dot11RFEntry.ther) : (p_dm->priv->pmib->dot11RFEntry.ther - thermal_value);
#endif
		if (delta >= TXPWR_TRACK_TABLE_SIZE)
			delta = TXPWR_TRACK_TABLE_SIZE - 1;

/*4 7.1 The Final Power index = BaseIndex + power_index_offset*/

#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE))
#if (DM_ODM_SUPPORT_TYPE == ODM_CE) && defined(DM_ODM_CE_MAC80211)
		if (thermal_value > rtlefu->eeprom_thermalmeter) {
#else
		if (thermal_value > p_hal_data->eeprom_thermal_meter) {
#endif
#else
		if (thermal_value > p_dm->priv->pmib->dot11RFEntry.ther) {
#endif

			for (p = RF_PATH_A; p < c.rf_path_count; p++) {
				p_rf_calibrate_info->delta_power_index_last[p] =
					p_rf_calibrate_info->delta_power_index
						[p]; /*recording poer index offset*/
				switch (p) {
				case RF_PATH_B:
					ODM_RT_TRACE(
						p_dm, ODM_COMP_TX_PWR_TRACK,
						ODM_DBG_LOUD,
						("delta_swing_table_idx_tup_b[%d] = %d\n",
						 delta,
						 delta_swing_table_idx_tup_b
							 [delta]));

					p_rf_calibrate_info
						->delta_power_index[p] =
						delta_swing_table_idx_tup_b
							[delta];
					p_rf_calibrate_info->absolute_ofdm_swing_idx
						[p] = delta_swing_table_idx_tup_b
						[delta]; /*Record delta swing for mix mode power tracking*/
					ODM_RT_TRACE(
						p_dm, ODM_COMP_TX_PWR_TRACK,
						ODM_DBG_LOUD,
						("******Temp is higher and p_rf_calibrate_info->absolute_ofdm_swing_idx[RF_PATH_B] = %d\n",
						 p_rf_calibrate_info
							 ->absolute_ofdm_swing_idx
								 [p]));
					break;

				case RF_PATH_C:
					ODM_RT_TRACE(
						p_dm, ODM_COMP_TX_PWR_TRACK,
						ODM_DBG_LOUD,
						("delta_swing_table_idx_tup_c[%d] = %d\n",
						 delta,
						 delta_swing_table_idx_tup_c
							 [delta]));

					p_rf_calibrate_info
						->delta_power_index[p] =
						delta_swing_table_idx_tup_c
							[delta];
					p_rf_calibrate_info->absolute_ofdm_swing_idx
						[p] = delta_swing_table_idx_tup_c
						[delta]; /*Record delta swing for mix mode power tracking*/
					ODM_RT_TRACE(
						p_dm, ODM_COMP_TX_PWR_TRACK,
						ODM_DBG_LOUD,
						("******Temp is higher and p_rf_calibrate_info->absolute_ofdm_swing_idx[RF_PATH_C] = %d\n",
						 p_rf_calibrate_info
							 ->absolute_ofdm_swing_idx
								 [p]));
					break;

				case RF_PATH_D:
					ODM_RT_TRACE(
						p_dm, ODM_COMP_TX_PWR_TRACK,
						ODM_DBG_LOUD,
						("delta_swing_table_idx_tup_d[%d] = %d\n",
						 delta,
						 delta_swing_table_idx_tup_d
							 [delta]));

					p_rf_calibrate_info
						->delta_power_index[p] =
						delta_swing_table_idx_tup_d
							[delta];
					p_rf_calibrate_info->absolute_ofdm_swing_idx
						[p] = delta_swing_table_idx_tup_d
						[delta]; /*Record delta swing for mix mode power tracking*/
					ODM_RT_TRACE(
						p_dm, ODM_COMP_TX_PWR_TRACK,
						ODM_DBG_LOUD,
						("******Temp is higher and p_rf_calibrate_info->absolute_ofdm_swing_idx[RF_PATH_D] = %d\n",
						 p_rf_calibrate_info
							 ->absolute_ofdm_swing_idx
								 [p]));
					break;

				default:
					ODM_RT_TRACE(
						p_dm, ODM_COMP_TX_PWR_TRACK,
						ODM_DBG_LOUD,
						("delta_swing_table_idx_tup_a[%d] = %d\n",
						 delta,
						 delta_swing_table_idx_tup_a
							 [delta]));

					p_rf_calibrate_info
						->delta_power_index[p] =
						delta_swing_table_idx_tup_a
							[delta];
					p_rf_calibrate_info->absolute_ofdm_swing_idx
						[p] = delta_swing_table_idx_tup_a
						[delta]; /*Record delta swing for mix mode power tracking*/
					ODM_RT_TRACE(
						p_dm, ODM_COMP_TX_PWR_TRACK,
						ODM_DBG_LOUD,
						("******Temp is higher and p_rf_calibrate_info->absolute_ofdm_swing_idx[RF_PATH_A] = %d\n",
						 p_rf_calibrate_info
							 ->absolute_ofdm_swing_idx
								 [p]));
					break;
				}
			}
			/* JJ ADD 20161014 */
			if (p_dm->support_ic_type &
			    (ODM_RTL8703B | ODM_RTL8723D | ODM_RTL8710B)) {
				/*Save xtal_offset from Xtal table*/
				p_rf_calibrate_info->xtal_offset_last =
					p_rf_calibrate_info
						->xtal_offset; /*recording last Xtal offset*/
				ODM_RT_TRACE(
					p_dm, ODM_COMP_TX_PWR_TRACK,
					ODM_DBG_LOUD,
					("[Xtal] delta_swing_table_xtal_up[%d] = %d\n",
					 delta,
					 delta_swing_table_xtal_up[delta]));
				p_rf_calibrate_info->xtal_offset =
					delta_swing_table_xtal_up[delta];
				xtal_offset_eanble =
					(p_rf_calibrate_info
						 ->xtal_offset_last !=
					 p_rf_calibrate_info->xtal_offset);
			}

		} else {
			for (p = RF_PATH_A; p < c.rf_path_count; p++) {
				p_rf_calibrate_info->delta_power_index_last[p] =
					p_rf_calibrate_info->delta_power_index
						[p]; /*recording poer index offset*/

				switch (p) {
				case RF_PATH_B:
					ODM_RT_TRACE(
						p_dm, ODM_COMP_TX_PWR_TRACK,
						ODM_DBG_LOUD,
						("delta_swing_table_idx_tdown_b[%d] = %d\n",
						 delta,
						 delta_swing_table_idx_tdown_b
							 [delta]));
					p_rf_calibrate_info
						->delta_power_index[p] =
						-1 *
						delta_swing_table_idx_tdown_b
							[delta];
					p_rf_calibrate_info
						->absolute_ofdm_swing_idx[p] =
						-1 *
						delta_swing_table_idx_tdown_b
							[delta]; /*Record delta swing for mix mode power tracking*/
					ODM_RT_TRACE(
						p_dm, ODM_COMP_TX_PWR_TRACK,
						ODM_DBG_LOUD,
						("******Temp is lower and p_rf_calibrate_info->absolute_ofdm_swing_idx[RF_PATH_B] = %d\n",
						 p_rf_calibrate_info
							 ->absolute_ofdm_swing_idx
								 [p]));
					break;

				case RF_PATH_C:
					ODM_RT_TRACE(
						p_dm, ODM_COMP_TX_PWR_TRACK,
						ODM_DBG_LOUD,
						("delta_swing_table_idx_tdown_c[%d] = %d\n",
						 delta,
						 delta_swing_table_idx_tdown_c
							 [delta]));
					p_rf_calibrate_info
						->delta_power_index[p] =
						-1 *
						delta_swing_table_idx_tdown_c
							[delta];
					p_rf_calibrate_info
						->absolute_ofdm_swing_idx[p] =
						-1 *
						delta_swing_table_idx_tdown_c
							[delta]; /*Record delta swing for mix mode power tracking*/
					ODM_RT_TRACE(
						p_dm, ODM_COMP_TX_PWR_TRACK,
						ODM_DBG_LOUD,
						("******Temp is lower and p_rf_calibrate_info->absolute_ofdm_swing_idx[RF_PATH_C] = %d\n",
						 p_rf_calibrate_info
							 ->absolute_ofdm_swing_idx
								 [p]));
					break;

				case RF_PATH_D:
					ODM_RT_TRACE(
						p_dm, ODM_COMP_TX_PWR_TRACK,
						ODM_DBG_LOUD,
						("delta_swing_table_idx_tdown_d[%d] = %d\n",
						 delta,
						 delta_swing_table_idx_tdown_d
							 [delta]));
					p_rf_calibrate_info
						->delta_power_index[p] =
						-1 *
						delta_swing_table_idx_tdown_d
							[delta];
					p_rf_calibrate_info
						->absolute_ofdm_swing_idx[p] =
						-1 *
						delta_swing_table_idx_tdown_d
							[delta]; /*Record delta swing for mix mode power tracking*/
					ODM_RT_TRACE(
						p_dm, ODM_COMP_TX_PWR_TRACK,
						ODM_DBG_LOUD,
						("******Temp is lower and p_rf_calibrate_info->absolute_ofdm_swing_idx[RF_PATH_D] = %d\n",
						 p_rf_calibrate_info
							 ->absolute_ofdm_swing_idx
								 [p]));
					break;

				default:
					ODM_RT_TRACE(
						p_dm, ODM_COMP_TX_PWR_TRACK,
						ODM_DBG_LOUD,
						("delta_swing_table_idx_tdown_a[%d] = %d\n",
						 delta,
						 delta_swing_table_idx_tdown_a
							 [delta]));
					p_rf_calibrate_info
						->delta_power_index[p] =
						-1 *
						delta_swing_table_idx_tdown_a
							[delta];
					p_rf_calibrate_info
						->absolute_ofdm_swing_idx[p] =
						-1 *
						delta_swing_table_idx_tdown_a
							[delta]; /*Record delta swing for mix mode power tracking*/
					ODM_RT_TRACE(
						p_dm, ODM_COMP_TX_PWR_TRACK,
						ODM_DBG_LOUD,
						("******Temp is lower and p_rf_calibrate_info->absolute_ofdm_swing_idx[RF_PATH_A] = %d\n",
						 p_rf_calibrate_info
							 ->absolute_ofdm_swing_idx
								 [p]));
					break;
				}
			}
			/* JJ ADD 20161014 */
			if (p_dm->support_ic_type &
			    (ODM_RTL8703B | ODM_RTL8723D | ODM_RTL8710B)) {
				/*Save xtal_offset from Xtal table*/
				p_rf_calibrate_info->xtal_offset_last =
					p_rf_calibrate_info
						->xtal_offset; /*recording last Xtal offset*/
				ODM_RT_TRACE(
					p_dm, ODM_COMP_TX_PWR_TRACK,
					ODM_DBG_LOUD,
					("[Xtal] delta_swing_table_xtal_down[%d] = %d\n",
					 delta,
					 delta_swing_table_xtal_down[delta]));
				p_rf_calibrate_info->xtal_offset =
					delta_swing_table_xtal_down[delta];
				xtal_offset_eanble =
					(p_rf_calibrate_info
						 ->xtal_offset_last !=
					 p_rf_calibrate_info->xtal_offset);
			}
		}

		for (p = RF_PATH_A; p < c.rf_path_count; p++) {
			ODM_RT_TRACE(
				p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
				("\n\n=========================== [path-%d] Calculating power_index_offset===========================\n",
				 p));

			if (p_rf_calibrate_info->delta_power_index[p] ==
			    p_rf_calibrate_info->delta_power_index_last
				    [p]) /*If Thermal value changes but lookup table value still the same*/
				p_rf_calibrate_info->power_index_offset[p] = 0;
			else
				p_rf_calibrate_info->power_index_offset[p] =
					p_rf_calibrate_info
						->delta_power_index[p] -
					p_rf_calibrate_info->delta_power_index_last
						[p]; /*Power index diff between 2 times Power Tracking*/

			ODM_RT_TRACE(
				p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
				("[path-%d] power_index_offset(%d) = delta_power_index(%d) - delta_power_index_last(%d)\n",
				 p, p_rf_calibrate_info->power_index_offset[p],
				 p_rf_calibrate_info->delta_power_index[p],
				 p_rf_calibrate_info
					 ->delta_power_index_last[p]));

			p_rf_calibrate_info->OFDM_index[p] =
				p_rf_calibrate_info->bb_swing_idx_ofdm_base[p] +
				p_rf_calibrate_info->power_index_offset[p];
			p_rf_calibrate_info->CCK_index =
				p_rf_calibrate_info->bb_swing_idx_cck_base +
				p_rf_calibrate_info->power_index_offset[p];

			p_rf_calibrate_info->bb_swing_idx_cck =
				p_rf_calibrate_info->CCK_index;
			p_rf_calibrate_info->bb_swing_idx_ofdm[p] =
				p_rf_calibrate_info->OFDM_index[p];

			/*************Print BB Swing base and index Offset*************/

			ODM_RT_TRACE(
				p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
				("The 'CCK' final index(%d) = BaseIndex(%d) + power_index_offset(%d)\n",
				 p_rf_calibrate_info->bb_swing_idx_cck,
				 p_rf_calibrate_info->bb_swing_idx_cck_base,
				 p_rf_calibrate_info->power_index_offset[p]));
			ODM_RT_TRACE(
				p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
				("The 'OFDM' final index(%d) = BaseIndex[%d](%d) + power_index_offset(%d)\n",
				 p_rf_calibrate_info->bb_swing_idx_ofdm[p], p,
				 p_rf_calibrate_info->bb_swing_idx_ofdm_base[p],
				 p_rf_calibrate_info->power_index_offset[p]));

			/*4 7.1 Handle boundary conditions of index.*/

			if (p_rf_calibrate_info->OFDM_index[p] >
			    c.swing_table_size_ofdm - 1)
				p_rf_calibrate_info->OFDM_index[p] =
					c.swing_table_size_ofdm - 1;
			else if (p_rf_calibrate_info->OFDM_index[p] <=
				 OFDM_min_index)
				p_rf_calibrate_info->OFDM_index[p] =
					OFDM_min_index;
		}

		ODM_RT_TRACE(
			p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
			("\n\n========================================================================================================\n"));

		if (p_rf_calibrate_info->CCK_index > c.swing_table_size_cck - 1)
			p_rf_calibrate_info->CCK_index =
				c.swing_table_size_cck - 1;
		else if (p_rf_calibrate_info->CCK_index <= 0)
			p_rf_calibrate_info->CCK_index = 0;
	} else {
		ODM_RT_TRACE(
			p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
			("The thermal meter is unchanged or TxPowerTracking OFF(%d): thermal_value: %d, p_rf_calibrate_info->thermal_value: %d\n",
			 p_rf_calibrate_info->txpowertrack_control,
			 thermal_value, p_rf_calibrate_info->thermal_value));

		for (p = RF_PATH_A; p < c.rf_path_count; p++)
			p_rf_calibrate_info->power_index_offset[p] = 0;
	}

	ODM_RT_TRACE(
		p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
		("TxPowerTracking: [CCK] Swing Current index: %d, Swing base index: %d\n",
		 p_rf_calibrate_info->CCK_index,
		 p_rf_calibrate_info
			 ->bb_swing_idx_cck_base)); /*Print Swing base & current*/

	for (p = RF_PATH_A; p < c.rf_path_count; p++) {
		ODM_RT_TRACE(
			p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
			("TxPowerTracking: [OFDM] Swing Current index: %d, Swing base index[%d]: %d\n",
			 p_rf_calibrate_info->OFDM_index[p], p,
			 p_rf_calibrate_info->bb_swing_idx_ofdm_base[p]));
	}

	if ((p_dm->support_ic_type & ODM_RTL8814A)) {
		ODM_RT_TRACE(p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
			     ("power_tracking_type=%d\n", power_tracking_type));

		if (power_tracking_type == 0) {
			ODM_RT_TRACE(
				p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
				("**********Enter POWER Tracking MIX_MODE**********\n"));
			for (p = RF_PATH_A; p < c.rf_path_count; p++)
				(*c.odm_tx_pwr_track_set_pwr)(p_dm, MIX_MODE, p,
							      0);
		} else if (power_tracking_type == 1) {
			ODM_RT_TRACE(
				p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
				("**********Enter POWER Tracking MIX(2G) TSSI(5G) MODE**********\n"));
			for (p = RF_PATH_A; p < c.rf_path_count; p++)
				(*c.odm_tx_pwr_track_set_pwr)(
					p_dm, MIX_2G_TSSI_5G_MODE, p, 0);
		} else if (power_tracking_type == 2) {
			ODM_RT_TRACE(
				p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
				("**********Enter POWER Tracking MIX(5G) TSSI(2G)MODE**********\n"));
			for (p = RF_PATH_A; p < c.rf_path_count; p++)
				(*c.odm_tx_pwr_track_set_pwr)(
					p_dm, MIX_5G_TSSI_2G_MODE, p, 0);
		} else if (power_tracking_type == 3) {
			ODM_RT_TRACE(
				p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
				("**********Enter POWER Tracking TSSI MODE**********\n"));
			for (p = RF_PATH_A; p < c.rf_path_count; p++)
				(*c.odm_tx_pwr_track_set_pwr)(p_dm, TSSI_MODE,
							      p, 0);
		}
		p_rf_calibrate_info->thermal_value =
			thermal_value; /*Record last Power Tracking Thermal value*/

	} else if ((p_rf_calibrate_info->power_index_offset[RF_PATH_A] != 0 ||
		    p_rf_calibrate_info->power_index_offset[RF_PATH_B] != 0 ||
		    p_rf_calibrate_info->power_index_offset[RF_PATH_C] != 0 ||
		    p_rf_calibrate_info->power_index_offset[RF_PATH_D] != 0) &&
#if (DM_ODM_SUPPORT_TYPE == ODM_CE) && defined(DM_ODM_CE_MAC80211)
		   p_rf_calibrate_info->txpowertrack_control &&
		   (rtlefu->eeprom_thermalmeter != 0xff)) {
#else
		p_rf_calibrate_info->txpowertrack_control && (p_hal_data->eeprom_thermal_meter != 0xff)) {
#endif
		/* 4 7.2 Configure the Swing Table to adjust Tx Power. */

		p_rf_calibrate_info->is_tx_power_changed =
			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 (thermal_value > p_rf_calibrate_info->thermal_value) {
			for (p = RF_PATH_A; p < c.rf_path_count; p++) {
#if (DM_ODM_SUPPORT_TYPE == ODM_CE) && defined(DM_ODM_CE_MAC80211)
				ODM_RT_TRACE(
					p_dm, ODM_COMP_TX_PWR_TRACK,
					ODM_DBG_LOUD,
					("Temperature Increasing(%d): delta_pi: %d, delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n",
					 p, p_rf_calibrate_info
						    ->power_index_offset[p],
					 delta, thermal_value,
					 rtlefu->eeprom_thermalmeter,
					 p_rf_calibrate_info->thermal_value));
#else
				ODM_RT_TRACE(p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
					("Temperature Increasing(%d): delta_pi: %d, delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n",
					p, p_rf_calibrate_info->power_index_offset[p], delta, thermal_value, p_hal_data->eeprom_thermal_meter, p_rf_calibrate_info->thermal_value));
#endif
			}
		} else if (thermal_value <
			   p_rf_calibrate_info
				   ->thermal_value) { /*Low temperature*/
			for (p = RF_PATH_A; p < c.rf_path_count; p++) {
#if (DM_ODM_SUPPORT_TYPE == ODM_CE) && defined(DM_ODM_CE_MAC80211)
				ODM_RT_TRACE(
					p_dm, ODM_COMP_TX_PWR_TRACK,
					ODM_DBG_LOUD,
					("Temperature Decreasing(%d): delta_pi: %d, delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n",
					 p, p_rf_calibrate_info
						    ->power_index_offset[p],
					 delta, thermal_value,
					 rtlefu->eeprom_thermalmeter,
					 p_rf_calibrate_info->thermal_value));
#else
				ODM_RT_TRACE(p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
					("Temperature Decreasing(%d): delta_pi: %d, delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n",
					p, p_rf_calibrate_info->power_index_offset[p], delta, thermal_value, p_hal_data->eeprom_thermal_meter, p_rf_calibrate_info->thermal_value));
#endif
			}
		}

#if !(DM_ODM_SUPPORT_TYPE & ODM_AP)
#if (DM_ODM_SUPPORT_TYPE == ODM_CE) && defined(DM_ODM_CE_MAC80211)
		if (thermal_value > rtlefu->eeprom_thermalmeter)
#else
		if (thermal_value > p_hal_data->eeprom_thermal_meter)
#endif
#else
		if (thermal_value > p_dm->priv->pmib->dot11RFEntry.ther)
#endif
		{
#if (DM_ODM_SUPPORT_TYPE == ODM_CE) && defined(DM_ODM_CE_MAC80211)
			ODM_RT_TRACE(
				p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
				("Temperature(%d) higher than PG value(%d)\n",
				 thermal_value, rtlefu->eeprom_thermalmeter));
#else
			ODM_RT_TRACE(p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
				("Temperature(%d) higher than PG value(%d)\n", thermal_value, p_hal_data->eeprom_thermal_meter));
#endif

			if (p_dm->support_ic_type == ODM_RTL8188E ||
			    p_dm->support_ic_type == ODM_RTL8192E ||
			    p_dm->support_ic_type == ODM_RTL8821 ||
			    p_dm->support_ic_type == ODM_RTL8812 ||
			    p_dm->support_ic_type == ODM_RTL8723B ||
			    p_dm->support_ic_type == ODM_RTL8814A ||
			    p_dm->support_ic_type == ODM_RTL8703B ||
			    p_dm->support_ic_type == ODM_RTL8188F ||
			    p_dm->support_ic_type == ODM_RTL8822B ||
			    p_dm->support_ic_type == ODM_RTL8723D ||
			    p_dm->support_ic_type == ODM_RTL8821C ||
			    p_dm->support_ic_type ==
				    ODM_RTL8710B) { /* JJ ADD 20161014 */

				ODM_RT_TRACE(
					p_dm, ODM_COMP_TX_PWR_TRACK,
					ODM_DBG_LOUD,
					("**********Enter POWER Tracking MIX_MODE**********\n"));
				for (p = RF_PATH_A; p < c.rf_path_count; p++)
					(*c.odm_tx_pwr_track_set_pwr)(
						p_dm, MIX_MODE, p, 0);
			} else {
				ODM_RT_TRACE(
					p_dm, ODM_COMP_TX_PWR_TRACK,
					ODM_DBG_LOUD,
					("**********Enter POWER Tracking BBSWING_MODE**********\n"));
				for (p = RF_PATH_A; p < c.rf_path_count; p++)
					(*c.odm_tx_pwr_track_set_pwr)(
						p_dm, BBSWING, p,
						indexforchannel);
			}
		} else {
#if (DM_ODM_SUPPORT_TYPE == ODM_CE) && defined(DM_ODM_CE_MAC80211)
			ODM_RT_TRACE(
				p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
				("Temperature(%d) lower than PG value(%d)\n",
				 thermal_value, rtlefu->eeprom_thermalmeter));
#else
			ODM_RT_TRACE(p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
				("Temperature(%d) lower than PG value(%d)\n", thermal_value, p_hal_data->eeprom_thermal_meter));
#endif

			if (p_dm->support_ic_type == ODM_RTL8188E ||
			    p_dm->support_ic_type == ODM_RTL8192E ||
			    p_dm->support_ic_type == ODM_RTL8821 ||
			    p_dm->support_ic_type == ODM_RTL8812 ||
			    p_dm->support_ic_type == ODM_RTL8723B ||
			    p_dm->support_ic_type == ODM_RTL8814A ||
			    p_dm->support_ic_type == ODM_RTL8703B ||
			    p_dm->support_ic_type == ODM_RTL8188F ||
			    p_dm->support_ic_type == ODM_RTL8822B ||
			    p_dm->support_ic_type == ODM_RTL8723D ||
			    p_dm->support_ic_type == ODM_RTL8821C ||
			    p_dm->support_ic_type ==
				    ODM_RTL8710B) { /* JJ ADD 20161014 */

				ODM_RT_TRACE(
					p_dm, ODM_COMP_TX_PWR_TRACK,
					ODM_DBG_LOUD,
					("**********Enter POWER Tracking MIX_MODE**********\n"));
				for (p = RF_PATH_A; p < c.rf_path_count; p++)
					(*c.odm_tx_pwr_track_set_pwr)(
						p_dm, MIX_MODE, p,
						indexforchannel);
			} else {
				ODM_RT_TRACE(
					p_dm, ODM_COMP_TX_PWR_TRACK,
					ODM_DBG_LOUD,
					("**********Enter POWER Tracking BBSWING_MODE**********\n"));
				for (p = RF_PATH_A; p < c.rf_path_count; p++)
					(*c.odm_tx_pwr_track_set_pwr)(
						p_dm, BBSWING, p,
						indexforchannel);
			}
		}

		p_rf_calibrate_info->bb_swing_idx_cck_base =
			p_rf_calibrate_info
				->bb_swing_idx_cck; /*Record last time Power Tracking result as base.*/
		for (p = RF_PATH_A; p < c.rf_path_count; p++)
			p_rf_calibrate_info->bb_swing_idx_ofdm_base[p] =
				p_rf_calibrate_info->bb_swing_idx_ofdm[p];

		ODM_RT_TRACE(
			p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
			("p_rf_calibrate_info->thermal_value = %d thermal_value= %d\n",
			 p_rf_calibrate_info->thermal_value, thermal_value));

		p_rf_calibrate_info->thermal_value =
			thermal_value; /*Record last Power Tracking Thermal value*/
	}

	if (p_dm->support_ic_type == ODM_RTL8703B ||
	    p_dm->support_ic_type == ODM_RTL8723D ||
	    p_dm->support_ic_type == ODM_RTL8710B) { /* JJ ADD 20161014 */

#if (DM_ODM_SUPPORT_TYPE == ODM_CE) && defined(DM_ODM_CE_MAC80211)
		if (xtal_offset_eanble != 0 &&
		    p_rf_calibrate_info->txpowertrack_control &&
		    (rtlefu->eeprom_thermalmeter != 0xff)) {
#else
		if (xtal_offset_eanble != 0 && p_rf_calibrate_info->txpowertrack_control && (p_hal_data->eeprom_thermal_meter != 0xff)) {
#endif

			ODM_RT_TRACE(
				p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
				("**********Enter Xtal Tracking**********\n"));

#if !(DM_ODM_SUPPORT_TYPE & ODM_AP)
#if (DM_ODM_SUPPORT_TYPE == ODM_CE) && defined(DM_ODM_CE_MAC80211)
			if (thermal_value > rtlefu->eeprom_thermalmeter) {
#else
			if (thermal_value > p_hal_data->eeprom_thermal_meter) {
#endif
#else
			if (thermal_value > p_dm->priv->pmib->dot11RFEntry.ther) {
#endif

#if (DM_ODM_SUPPORT_TYPE == ODM_CE) && defined(DM_ODM_CE_MAC80211)
				ODM_RT_TRACE(
					p_dm, ODM_COMP_TX_PWR_TRACK,
					ODM_DBG_LOUD,
					("Temperature(%d) higher than PG value(%d)\n",
					 thermal_value,
					 rtlefu->eeprom_thermalmeter));
#else
				ODM_RT_TRACE(p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
					("Temperature(%d) higher than PG value(%d)\n", thermal_value, p_hal_data->eeprom_thermal_meter));
#endif
				(*c.odm_txxtaltrack_set_xtal)(p_dm);
			} else {
#if (DM_ODM_SUPPORT_TYPE == ODM_CE) && defined(DM_ODM_CE_MAC80211)
				ODM_RT_TRACE(
					p_dm, ODM_COMP_TX_PWR_TRACK,
					ODM_DBG_LOUD,
					("Temperature(%d) lower than PG value(%d)\n",
					 thermal_value,
					 rtlefu->eeprom_thermalmeter));
#else
				ODM_RT_TRACE(p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
					("Temperature(%d) lower than PG value(%d)\n", thermal_value, p_hal_data->eeprom_thermal_meter));
#endif
				(*c.odm_txxtaltrack_set_xtal)(p_dm);
			}
		}
		ODM_RT_TRACE(p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
			     ("**********End Xtal Tracking**********\n"));
	}

#if !(DM_ODM_SUPPORT_TYPE & ODM_AP)

	/* Wait sacn to do IQK by RF Jenyu*/
	if ((*p_dm->p_is_scan_in_process == false) &&
	    (!p_iqk_info->rfk_forbidden)) {
		if (!IS_HARDWARE_TYPE_8723B(adapter)) {
			/*Delta temperature is equal to or larger than 20 centigrade (When threshold is 8).*/
			if (delta_IQK >= c.threshold_iqk) {
				p_rf_calibrate_info->thermal_value_iqk =
					thermal_value;
				ODM_RT_TRACE(
					p_dm, ODM_COMP_TX_PWR_TRACK,
					ODM_DBG_LOUD,
					("delta_IQK(%d) >= threshold_iqk(%d)\n",
					 delta_IQK, c.threshold_iqk));
				if (!p_rf_calibrate_info->is_iqk_in_progress)
					(*c.do_iqk)(p_dm, delta_IQK,
						    thermal_value, 8);
			}
		}
	}
	if (p_rf_calibrate_info->dpk_thermal[RF_PATH_A] != 0) {
		if (diff_DPK[RF_PATH_A] >= c.threshold_dpk) {
			odm_set_bb_reg(p_dm, BBREG_0x82c, BIT(31), 0x1);
			odm_set_bb_reg(p_dm, BBREG_0xcc4,
				       BIT(14) | BIT(13) | BIT(12) | BIT(11) |
					       BIT(10),
				       (diff_DPK[RF_PATH_A] / c.threshold_dpk));
			odm_set_bb_reg(p_dm, BBREG_0x82c, BIT(31), 0x0);
		} else if ((diff_DPK[RF_PATH_A] <= -1 * c.threshold_dpk)) {
			s32 value =
				0x20 + (diff_DPK[RF_PATH_A] / c.threshold_dpk);

			odm_set_bb_reg(p_dm, BBREG_0x82c, BIT(31), 0x1);
			odm_set_bb_reg(p_dm, BBREG_0xcc4,
				       BIT(14) | BIT(13) | BIT(12) | BIT(11) |
					       BIT(10),
				       value);
			odm_set_bb_reg(p_dm, BBREG_0x82c, BIT(31), 0x0);
		} else {
			odm_set_bb_reg(p_dm, BBREG_0x82c, BIT(31), 0x1);
			odm_set_bb_reg(p_dm, BBREG_0xcc4,
				       BIT(14) | BIT(13) | BIT(12) | BIT(11) |
					       BIT(10),
				       0);
			odm_set_bb_reg(p_dm, BBREG_0x82c, BIT(31), 0x0);
		}
	}
	if (p_rf_calibrate_info->dpk_thermal[RF_PATH_B] != 0) {
		if (diff_DPK[RF_PATH_B] >= c.threshold_dpk) {
			odm_set_bb_reg(p_dm, BBREG_0x82c, BIT(31), 0x1);
			odm_set_bb_reg(p_dm, BBREG_0xec4,
				       BIT(14) | BIT(13) | BIT(12) | BIT(11) |
					       BIT(10),
				       (diff_DPK[RF_PATH_B] / c.threshold_dpk));
			odm_set_bb_reg(p_dm, BBREG_0x82c, BIT(31), 0x0);
		} else if ((diff_DPK[RF_PATH_B] <= -1 * c.threshold_dpk)) {
			s32 value =
				0x20 + (diff_DPK[RF_PATH_B] / c.threshold_dpk);

			odm_set_bb_reg(p_dm, BBREG_0x82c, BIT(31), 0x1);
			odm_set_bb_reg(p_dm, BBREG_0xec4,
				       BIT(14) | BIT(13) | BIT(12) | BIT(11) |
					       BIT(10),
				       value);
			odm_set_bb_reg(p_dm, BBREG_0x82c, BIT(31), 0x0);
		} else {
			odm_set_bb_reg(p_dm, BBREG_0x82c, BIT(31), 0x1);
			odm_set_bb_reg(p_dm, BBREG_0xec4,
				       BIT(14) | BIT(13) | BIT(12) | BIT(11) |
					       BIT(10),
				       0);
			odm_set_bb_reg(p_dm, BBREG_0x82c, BIT(31), 0x0);
		}
	}

#endif

	ODM_RT_TRACE(p_dm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
		     ("<===odm_txpowertracking_callback_thermal_meter\n"));

	p_rf_calibrate_info->tx_powercount = 0;
}

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

void odm_reset_iqk_result(void *p_dm_void) { return; }
#if !(DM_ODM_SUPPORT_TYPE & ODM_AP)
u8 odm_get_right_chnl_place_for_iqk(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;
}
#endif

void odm_iq_calibrate(struct PHY_DM_STRUCT *p_dm)
{
#if (DM_ODM_SUPPORT_TYPE & (ODM_CE))
#if RTL8812A_SUPPORT
	struct _ADAPTER *adapter = p_dm->adapter;
#endif
#endif
	struct _IQK_INFORMATION *p_iqk_info = &p_dm->IQK_info;

#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
	if (*p_dm->p_is_fcs_mode_enable)
		return;
#endif

#if (DM_ODM_SUPPORT_TYPE & (ODM_CE))
#if RTL8812A_SUPPORT
	if (IS_HARDWARE_TYPE_8812AU(adapter))
		return;
#endif
#endif

	if ((p_dm->is_linked) && (!p_iqk_info->rfk_forbidden)) {
		if ((*p_dm->p_channel != p_dm->pre_channel) &&
		    (!*p_dm->p_is_scan_in_process)) {
			p_dm->pre_channel = *p_dm->p_channel;
			p_dm->linked_interval = 0;
		}

		if (p_dm->linked_interval < 3)
			p_dm->linked_interval++;

		if (p_dm->linked_interval == 2)
			halrf_iqk_trigger(p_dm, false);
	} else
		p_dm->linked_interval = 0;
}

void phydm_rf_init(void *p_dm_void)
{
	struct PHY_DM_STRUCT *p_dm = (struct PHY_DM_STRUCT *)p_dm_void;
	odm_txpowertracking_init(p_dm);

#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE))
	odm_clear_txpowertracking_state(p_dm);
#endif

#if (DM_ODM_SUPPORT_TYPE & (ODM_AP))
#if (RTL8814A_SUPPORT == 1)
	if (p_dm->support_ic_type & ODM_RTL8814A)
		phy_iq_calibrate_8814a_init(p_dm);
#endif
#endif
}

void phydm_rf_watchdog(void *p_dm_void)
{
	struct PHY_DM_STRUCT *p_dm = (struct PHY_DM_STRUCT *)p_dm_void;
#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE))
	odm_txpowertracking_check(p_dm);
/*if (p_dm->support_ic_type & ODM_IC_11AC_SERIES)*/
/*odm_iq_calibrate(p_dm);*/
#endif
}
