1// SPDX-License-Identifier: GPL-2.0
2/******************************************************************************
3 *
4 * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
5 *
6 ******************************************************************************/
7
8/* include "Mp_Precomp.h" */
9#include "odm_precomp.h"
10
11void ConfigureTxpowerTrack(struct dm_odm_t *pDM_Odm, struct txpwrtrack_cfg *pConfig)
12{
13	ConfigureTxpowerTrack_8723B(pConfig);
14}
15
16/*  */
17/*  <20121113, Kordan> This function should be called when TxAGC changed. */
18/*  Otherwise the previous compensation is gone, because we record the */
19/*  delta of temperature between two TxPowerTracking watch dogs. */
20/*  */
21/*  NOTE: If Tx BB swing or Tx scaling is varified during run-time, still */
22/*        need to call this function. */
23/*  */
24void ODM_ClearTxPowerTrackingState(struct dm_odm_t *pDM_Odm)
25{
26	struct hal_com_data *pHalData = GET_HAL_DATA(pDM_Odm->Adapter);
27	u8 p = 0;
28
29	pDM_Odm->BbSwingIdxCckBase = pDM_Odm->DefaultCckIndex;
30	pDM_Odm->BbSwingIdxCck = pDM_Odm->DefaultCckIndex;
31	pDM_Odm->RFCalibrateInfo.CCK_index = 0;
32
33	for (p = RF_PATH_A; p < MAX_RF_PATH; ++p) {
34		pDM_Odm->BbSwingIdxOfdmBase[p] = pDM_Odm->DefaultOfdmIndex;
35		pDM_Odm->BbSwingIdxOfdm[p] = pDM_Odm->DefaultOfdmIndex;
36		pDM_Odm->RFCalibrateInfo.OFDM_index[p] = pDM_Odm->DefaultOfdmIndex;
37
38		pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = 0;
39		pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[p] = 0;
40		pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[p] = 0;
41		pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = 0;
42
43		/*  Initial Mix mode power tracking */
44		pDM_Odm->Absolute_OFDMSwingIdx[p] = 0;
45		pDM_Odm->Remnant_OFDMSwingIdx[p] = 0;
46	}
47
48	/* Initial at Modify Tx Scaling Mode */
49	pDM_Odm->Modify_TxAGC_Flag_PathA = false;
50	/* Initial at Modify Tx Scaling Mode */
51	pDM_Odm->Modify_TxAGC_Flag_PathB = false;
52	pDM_Odm->Remnant_CCKSwingIdx = 0;
53	pDM_Odm->RFCalibrateInfo.ThermalValue = pHalData->EEPROMThermalMeter;
54	pDM_Odm->RFCalibrateInfo.ThermalValue_IQK = pHalData->EEPROMThermalMeter;
55	pDM_Odm->RFCalibrateInfo.ThermalValue_LCK = pHalData->EEPROMThermalMeter;
56}
57
58void ODM_TXPowerTrackingCallback_ThermalMeter(struct adapter *Adapter)
59{
60
61	struct hal_com_data *pHalData = GET_HAL_DATA(Adapter);
62	struct dm_odm_t *pDM_Odm = &pHalData->odmpriv;
63
64	u8 ThermalValue = 0, delta, delta_LCK, p = 0, i = 0;
65	u8 ThermalValue_AVG_count = 0;
66	u32 ThermalValue_AVG = 0;
67
68	u8 OFDM_min_index = 0;  /*  OFDM BB Swing should be less than +3.0dB, which is required by Arthur */
69	u8 Indexforchannel = 0; /*  GetRightChnlPlaceforIQK(pHalData->CurrentChannel) */
70
71	struct txpwrtrack_cfg c;
72
73
74	/* 4 1. The following TWO tables decide the final index of OFDM/CCK swing table. */
75	u8 *deltaSwingTableIdx_TUP_A;
76	u8 *deltaSwingTableIdx_TDOWN_A;
77	u8 *deltaSwingTableIdx_TUP_B;
78	u8 *deltaSwingTableIdx_TDOWN_B;
79
80	/* 4 2. Initialization (7 steps in total) */
81
82	ConfigureTxpowerTrack(pDM_Odm, &c);
83
84	(*c.GetDeltaSwingTable)(
85		pDM_Odm,
86		(u8 **)&deltaSwingTableIdx_TUP_A,
87		(u8 **)&deltaSwingTableIdx_TDOWN_A,
88		(u8 **)&deltaSwingTableIdx_TUP_B,
89		(u8 **)&deltaSwingTableIdx_TDOWN_B
90	);
91
92	/* cosa add for debug */
93	pDM_Odm->RFCalibrateInfo.TXPowerTrackingCallbackCnt++;
94	pDM_Odm->RFCalibrateInfo.bTXPowerTrackingInit = true;
95
96	ThermalValue = (u8)PHY_QueryRFReg(pDM_Odm->Adapter, RF_PATH_A, c.ThermalRegAddr, 0xfc00);	/* 0x42: RF Reg[15:10] 88E */
97	if (
98		!pDM_Odm->RFCalibrateInfo.TxPowerTrackControl ||
99		pHalData->EEPROMThermalMeter == 0 ||
100		pHalData->EEPROMThermalMeter == 0xFF
101	)
102		return;
103
104	/* 4 3. Initialize ThermalValues of RFCalibrateInfo */
105
106	/* 4 4. Calculate average thermal meter */
107
108	pDM_Odm->RFCalibrateInfo.ThermalValue_AVG[pDM_Odm->RFCalibrateInfo.ThermalValue_AVG_index] = ThermalValue;
109	pDM_Odm->RFCalibrateInfo.ThermalValue_AVG_index++;
110	if (pDM_Odm->RFCalibrateInfo.ThermalValue_AVG_index == c.AverageThermalNum)   /* Average times =  c.AverageThermalNum */
111		pDM_Odm->RFCalibrateInfo.ThermalValue_AVG_index = 0;
112
113	for (i = 0; i < c.AverageThermalNum; i++) {
114		if (pDM_Odm->RFCalibrateInfo.ThermalValue_AVG[i]) {
115			ThermalValue_AVG += pDM_Odm->RFCalibrateInfo.ThermalValue_AVG[i];
116			ThermalValue_AVG_count++;
117		}
118	}
119
120	/* Calculate Average ThermalValue after average enough times */
121	if (ThermalValue_AVG_count) {
122		ThermalValue = (u8)(ThermalValue_AVG / ThermalValue_AVG_count);
123	}
124
125	/* 4 5. Calculate delta, delta_LCK */
126	/* delta" here is used to determine whether thermal value changes or not. */
127	delta =
128		(ThermalValue > pDM_Odm->RFCalibrateInfo.ThermalValue) ?
129		(ThermalValue - pDM_Odm->RFCalibrateInfo.ThermalValue) :
130		(pDM_Odm->RFCalibrateInfo.ThermalValue - ThermalValue);
131	delta_LCK =
132		(ThermalValue > pDM_Odm->RFCalibrateInfo.ThermalValue_LCK) ?
133		(ThermalValue - pDM_Odm->RFCalibrateInfo.ThermalValue_LCK) :
134		(pDM_Odm->RFCalibrateInfo.ThermalValue_LCK - ThermalValue);
135
136	/* 4 6. If necessary, do LCK. */
137	/*  Delta temperature is equal to or larger than 20 centigrade. */
138	if (delta_LCK >= c.Threshold_IQK) {
139		pDM_Odm->RFCalibrateInfo.ThermalValue_LCK = ThermalValue;
140		if (c.PHY_LCCalibrate)
141			(*c.PHY_LCCalibrate)(pDM_Odm);
142	}
143
144	/* 3 7. If necessary, move the index of swing table to adjust Tx power. */
145	if (delta > 0 && pDM_Odm->RFCalibrateInfo.TxPowerTrackControl) {
146		/* delta" here is used to record the absolute value of difference. */
147		delta =
148			ThermalValue > pHalData->EEPROMThermalMeter ?
149			(ThermalValue - pHalData->EEPROMThermalMeter) :
150			(pHalData->EEPROMThermalMeter - ThermalValue);
151
152		if (delta >= TXPWR_TRACK_TABLE_SIZE)
153			delta = TXPWR_TRACK_TABLE_SIZE - 1;
154
155		/* 4 7.1 The Final Power Index = BaseIndex + PowerIndexOffset */
156		if (ThermalValue > pHalData->EEPROMThermalMeter) {
157			pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[RF_PATH_A] =
158				pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[RF_PATH_A];
159			pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[RF_PATH_A] =
160				deltaSwingTableIdx_TUP_A[delta];
161
162			/*  Record delta swing for mix mode power tracking */
163			pDM_Odm->Absolute_OFDMSwingIdx[RF_PATH_A] =
164				deltaSwingTableIdx_TUP_A[delta];
165
166			if (c.RfPathCount > 1) {
167				pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[RF_PATH_B] =
168					pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[RF_PATH_B];
169				pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[RF_PATH_B] =
170					deltaSwingTableIdx_TUP_B[delta];
171
172				/*  Record delta swing for mix mode power tracking */
173				pDM_Odm->Absolute_OFDMSwingIdx[RF_PATH_B] =
174					deltaSwingTableIdx_TUP_B[delta];
175			}
176
177		} else {
178			pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[RF_PATH_A] =
179				pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[RF_PATH_A];
180			pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[RF_PATH_A] =
181				-1 * deltaSwingTableIdx_TDOWN_A[delta];
182
183			/*  Record delta swing for mix mode power tracking */
184			pDM_Odm->Absolute_OFDMSwingIdx[RF_PATH_A] =
185				-1 * deltaSwingTableIdx_TDOWN_A[delta];
186
187			if (c.RfPathCount > 1) {
188				pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[RF_PATH_B] =
189					pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[RF_PATH_B];
190				pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[RF_PATH_B] =
191					-1 * deltaSwingTableIdx_TDOWN_B[delta];
192
193				 /*  Record delta swing for mix mode power tracking */
194				pDM_Odm->Absolute_OFDMSwingIdx[RF_PATH_B] =
195					-1 * deltaSwingTableIdx_TDOWN_B[delta];
196			}
197		}
198
199		for (p = RF_PATH_A; p < c.RfPathCount; p++) {
200			if (
201				pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[p] ==
202				pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[p]
203			) /*  If Thermal value changes but lookup table value still the same */
204				pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = 0;
205			else
206				pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[p] - pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[p];      /*  Power Index Diff between 2 times Power Tracking */
207
208			pDM_Odm->RFCalibrateInfo.OFDM_index[p] =
209				pDM_Odm->BbSwingIdxOfdmBase[p] +
210				pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p];
211
212			pDM_Odm->RFCalibrateInfo.CCK_index =
213				pDM_Odm->BbSwingIdxCckBase +
214				pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p];
215
216			pDM_Odm->BbSwingIdxCck =
217				pDM_Odm->RFCalibrateInfo.CCK_index;
218
219			pDM_Odm->BbSwingIdxOfdm[p] =
220				pDM_Odm->RFCalibrateInfo.OFDM_index[p];
221
222			/* 4 7.1 Handle boundary conditions of index. */
223			if (pDM_Odm->RFCalibrateInfo.OFDM_index[p] > c.SwingTableSize_OFDM-1)
224				pDM_Odm->RFCalibrateInfo.OFDM_index[p] = c.SwingTableSize_OFDM-1;
225			else if (pDM_Odm->RFCalibrateInfo.OFDM_index[p] < OFDM_min_index)
226				pDM_Odm->RFCalibrateInfo.OFDM_index[p] = OFDM_min_index;
227		}
228		if (pDM_Odm->RFCalibrateInfo.CCK_index > c.SwingTableSize_CCK-1)
229			pDM_Odm->RFCalibrateInfo.CCK_index = c.SwingTableSize_CCK-1;
230		/* else if (pDM_Odm->RFCalibrateInfo.CCK_index < 0) */
231			/* pDM_Odm->RFCalibrateInfo.CCK_index = 0; */
232	} else {
233			for (p = RF_PATH_A; p < c.RfPathCount; p++)
234				pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = 0;
235	}
236
237	/* Print Swing base & current */
238	for (p = RF_PATH_A; p < c.RfPathCount; p++) {
239	}
240
241	if (
242		(pDM_Odm->RFCalibrateInfo.PowerIndexOffset[RF_PATH_A] != 0 ||
243		 pDM_Odm->RFCalibrateInfo.PowerIndexOffset[RF_PATH_B] != 0) &&
244		 pDM_Odm->RFCalibrateInfo.TxPowerTrackControl
245	 ) {
246		/* 4 7.2 Configure the Swing Table to adjust Tx Power. */
247
248		pDM_Odm->RFCalibrateInfo.bTxPowerChanged = true; /*  Always true after Tx Power is adjusted by power tracking. */
249		/*  */
250		/*  2012/04/23 MH According to Luke's suggestion, we can not write BB digital */
251		/*  to increase TX power. Otherwise, EVM will be bad. */
252		/*  */
253		/*  2012/04/25 MH Add for tx power tracking to set tx power in tx agc for 88E. */
254
255		if (ThermalValue > pHalData->EEPROMThermalMeter) {
256			for (p = RF_PATH_A; p < c.RfPathCount; p++)
257					(*c.ODM_TxPwrTrackSetPwr)(pDM_Odm, MIX_MODE, p, 0);
258		} else {
259			for (p = RF_PATH_A; p < c.RfPathCount; p++)
260				(*c.ODM_TxPwrTrackSetPwr)(pDM_Odm, MIX_MODE, p, Indexforchannel);
261		}
262
263		/*  Record last time Power Tracking result as base. */
264		pDM_Odm->BbSwingIdxCckBase = pDM_Odm->BbSwingIdxCck;
265		for (p = RF_PATH_A; p < c.RfPathCount; p++)
266			pDM_Odm->BbSwingIdxOfdmBase[p] = pDM_Odm->BbSwingIdxOfdm[p];
267
268		/* Record last Power Tracking Thermal Value */
269		pDM_Odm->RFCalibrateInfo.ThermalValue = ThermalValue;
270	}
271
272	pDM_Odm->RFCalibrateInfo.TXPowercount = 0;
273}
274