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