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 void 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 /*  */
24 void 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 
58 void 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