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