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, pConfig: &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 | |