1 /****************************************************************************** 2 * 3 * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of version 2 of the GNU General Public License as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 ******************************************************************************/ 15 16 #include "odm_precomp.h" 17 18 static void odm_SetCrystalCap(void *pDM_VOID, u8 CrystalCap) 19 { 20 PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; 21 PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; 22 bool bEEPROMCheck; 23 struct adapter *Adapter = pDM_Odm->Adapter; 24 struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); 25 26 bEEPROMCheck = (pHalData->EEPROMVersion >= 0x01) ? true : false; 27 28 if (pCfoTrack->CrystalCap == CrystalCap) 29 return; 30 31 pCfoTrack->CrystalCap = CrystalCap; 32 33 /* 0x2C[23:18] = 0x2C[17:12] = CrystalCap */ 34 CrystalCap = CrystalCap & 0x3F; 35 PHY_SetBBReg( 36 pDM_Odm->Adapter, 37 REG_MAC_PHY_CTRL, 38 0x00FFF000, 39 (CrystalCap | (CrystalCap << 6)) 40 ); 41 42 ODM_RT_TRACE( 43 pDM_Odm, 44 ODM_COMP_CFO_TRACKING, 45 ODM_DBG_LOUD, 46 ( 47 "odm_SetCrystalCap(): CrystalCap = 0x%x\n", 48 CrystalCap 49 ) 50 ); 51 } 52 53 static u8 odm_GetDefaultCrytaltalCap(void *pDM_VOID) 54 { 55 PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; 56 u8 CrystalCap = 0x20; 57 58 struct adapter *Adapter = pDM_Odm->Adapter; 59 struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); 60 61 CrystalCap = pHalData->CrystalCap; 62 63 CrystalCap = CrystalCap & 0x3f; 64 65 return CrystalCap; 66 } 67 68 static void odm_SetATCStatus(void *pDM_VOID, bool ATCStatus) 69 { 70 PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; 71 PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; 72 73 if (pCfoTrack->bATCStatus == ATCStatus) 74 return; 75 76 PHY_SetBBReg( 77 pDM_Odm->Adapter, 78 ODM_REG(BB_ATC, pDM_Odm), 79 ODM_BIT(BB_ATC, pDM_Odm), 80 ATCStatus 81 ); 82 pCfoTrack->bATCStatus = ATCStatus; 83 } 84 85 static bool odm_GetATCStatus(void *pDM_VOID) 86 { 87 bool ATCStatus; 88 PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; 89 90 ATCStatus = (bool)PHY_QueryBBReg( 91 pDM_Odm->Adapter, 92 ODM_REG(BB_ATC, pDM_Odm), 93 ODM_BIT(BB_ATC, pDM_Odm) 94 ); 95 return ATCStatus; 96 } 97 98 void ODM_CfoTrackingReset(void *pDM_VOID) 99 { 100 PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; 101 PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; 102 103 pCfoTrack->DefXCap = odm_GetDefaultCrytaltalCap(pDM_Odm); 104 pCfoTrack->bAdjust = true; 105 106 odm_SetCrystalCap(pDM_Odm, pCfoTrack->DefXCap); 107 odm_SetATCStatus(pDM_Odm, true); 108 } 109 110 void ODM_CfoTrackingInit(void *pDM_VOID) 111 { 112 PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; 113 PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; 114 115 pCfoTrack->DefXCap = 116 pCfoTrack->CrystalCap = odm_GetDefaultCrytaltalCap(pDM_Odm); 117 pCfoTrack->bATCStatus = odm_GetATCStatus(pDM_Odm); 118 pCfoTrack->bAdjust = true; 119 ODM_RT_TRACE( 120 pDM_Odm, 121 ODM_COMP_CFO_TRACKING, 122 ODM_DBG_LOUD, 123 ("ODM_CfoTracking_init() =========>\n") 124 ); 125 ODM_RT_TRACE( 126 pDM_Odm, 127 ODM_COMP_CFO_TRACKING, 128 ODM_DBG_LOUD, 129 ( 130 "ODM_CfoTracking_init(): bATCStatus = %d, CrystalCap = 0x%x\n", 131 pCfoTrack->bATCStatus, 132 pCfoTrack->DefXCap 133 ) 134 ); 135 } 136 137 void ODM_CfoTracking(void *pDM_VOID) 138 { 139 PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; 140 PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; 141 int CFO_kHz_A, CFO_kHz_B, CFO_ave = 0; 142 int CFO_ave_diff; 143 int CrystalCap = (int)pCfoTrack->CrystalCap; 144 u8 Adjust_Xtal = 1; 145 146 /* 4 Support ability */ 147 if (!(pDM_Odm->SupportAbility & ODM_BB_CFO_TRACKING)) { 148 ODM_RT_TRACE( 149 pDM_Odm, 150 ODM_COMP_CFO_TRACKING, 151 ODM_DBG_LOUD, 152 ("ODM_CfoTracking(): Return: SupportAbility ODM_BB_CFO_TRACKING is disabled\n") 153 ); 154 return; 155 } 156 157 ODM_RT_TRACE( 158 pDM_Odm, 159 ODM_COMP_CFO_TRACKING, 160 ODM_DBG_LOUD, 161 ("ODM_CfoTracking() =========>\n") 162 ); 163 164 if (!pDM_Odm->bLinked || !pDM_Odm->bOneEntryOnly) { 165 /* 4 No link or more than one entry */ 166 ODM_CfoTrackingReset(pDM_Odm); 167 ODM_RT_TRACE( 168 pDM_Odm, 169 ODM_COMP_CFO_TRACKING, 170 ODM_DBG_LOUD, 171 ( 172 "ODM_CfoTracking(): Reset: bLinked = %d, bOneEntryOnly = %d\n", 173 pDM_Odm->bLinked, 174 pDM_Odm->bOneEntryOnly 175 ) 176 ); 177 } else { 178 /* 3 1. CFO Tracking */ 179 /* 4 1.1 No new packet */ 180 if (pCfoTrack->packetCount == pCfoTrack->packetCount_pre) { 181 ODM_RT_TRACE( 182 pDM_Odm, 183 ODM_COMP_CFO_TRACKING, 184 ODM_DBG_LOUD, 185 ( 186 "ODM_CfoTracking(): packet counter doesn't change\n" 187 ) 188 ); 189 return; 190 } 191 pCfoTrack->packetCount_pre = pCfoTrack->packetCount; 192 193 /* 4 1.2 Calculate CFO */ 194 CFO_kHz_A = (int)(pCfoTrack->CFO_tail[0] * 3125) / 1280; 195 CFO_kHz_B = (int)(pCfoTrack->CFO_tail[1] * 3125) / 1280; 196 197 if (pDM_Odm->RFType < ODM_2T2R) 198 CFO_ave = CFO_kHz_A; 199 else 200 CFO_ave = (int)(CFO_kHz_A + CFO_kHz_B) >> 1; 201 ODM_RT_TRACE( 202 pDM_Odm, 203 ODM_COMP_CFO_TRACKING, 204 ODM_DBG_LOUD, 205 ( 206 "ODM_CfoTracking(): CFO_kHz_A = %dkHz, CFO_kHz_B = %dkHz, CFO_ave = %dkHz\n", 207 CFO_kHz_A, 208 CFO_kHz_B, 209 CFO_ave 210 ) 211 ); 212 213 /* 4 1.3 Avoid abnormal large CFO */ 214 CFO_ave_diff = 215 (pCfoTrack->CFO_ave_pre >= CFO_ave) ? 216 (pCfoTrack->CFO_ave_pre-CFO_ave) : 217 (CFO_ave-pCfoTrack->CFO_ave_pre); 218 219 if ( 220 CFO_ave_diff > 20 && 221 pCfoTrack->largeCFOHit == 0 && 222 !pCfoTrack->bAdjust 223 ) { 224 ODM_RT_TRACE(pDM_Odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("ODM_CfoTracking(): first large CFO hit\n")); 225 pCfoTrack->largeCFOHit = 1; 226 return; 227 } else 228 pCfoTrack->largeCFOHit = 0; 229 pCfoTrack->CFO_ave_pre = CFO_ave; 230 231 /* 4 1.4 Dynamic Xtal threshold */ 232 if (pCfoTrack->bAdjust == false) { 233 if (CFO_ave > CFO_TH_XTAL_HIGH || CFO_ave < (-CFO_TH_XTAL_HIGH)) 234 pCfoTrack->bAdjust = true; 235 } else { 236 if (CFO_ave < CFO_TH_XTAL_LOW && CFO_ave > (-CFO_TH_XTAL_LOW)) 237 pCfoTrack->bAdjust = false; 238 } 239 240 /* 4 1.5 BT case: Disable CFO tracking */ 241 if (pDM_Odm->bBtEnabled) { 242 pCfoTrack->bAdjust = false; 243 odm_SetCrystalCap(pDM_Odm, pCfoTrack->DefXCap); 244 ODM_RT_TRACE( 245 pDM_Odm, 246 ODM_COMP_CFO_TRACKING, 247 ODM_DBG_LOUD, 248 ("ODM_CfoTracking(): Disable CFO tracking for BT!!\n") 249 ); 250 } 251 252 /* 4 1.6 Big jump */ 253 if (pCfoTrack->bAdjust) { 254 if (CFO_ave > CFO_TH_XTAL_LOW) 255 Adjust_Xtal = Adjust_Xtal+((CFO_ave-CFO_TH_XTAL_LOW)>>2); 256 else if (CFO_ave < (-CFO_TH_XTAL_LOW)) 257 Adjust_Xtal = Adjust_Xtal+((CFO_TH_XTAL_LOW-CFO_ave)>>2); 258 259 ODM_RT_TRACE( 260 pDM_Odm, 261 ODM_COMP_CFO_TRACKING, 262 ODM_DBG_LOUD, 263 ( 264 "ODM_CfoTracking(): Crystal cap offset = %d\n", 265 Adjust_Xtal 266 ) 267 ); 268 } 269 270 /* 4 1.7 Adjust Crystal Cap. */ 271 if (pCfoTrack->bAdjust) { 272 if (CFO_ave > CFO_TH_XTAL_LOW) 273 CrystalCap = CrystalCap + Adjust_Xtal; 274 else if (CFO_ave < (-CFO_TH_XTAL_LOW)) 275 CrystalCap = CrystalCap - Adjust_Xtal; 276 277 if (CrystalCap > 0x3f) 278 CrystalCap = 0x3f; 279 else if (CrystalCap < 0) 280 CrystalCap = 0; 281 282 odm_SetCrystalCap(pDM_Odm, (u8)CrystalCap); 283 } 284 ODM_RT_TRACE( 285 pDM_Odm, 286 ODM_COMP_CFO_TRACKING, 287 ODM_DBG_LOUD, 288 ( 289 "ODM_CfoTracking(): Crystal cap = 0x%x, Default Crystal cap = 0x%x\n", 290 pCfoTrack->CrystalCap, 291 pCfoTrack->DefXCap 292 ) 293 ); 294 295 /* 3 2. Dynamic ATC switch */ 296 if (CFO_ave < CFO_TH_ATC && CFO_ave > -CFO_TH_ATC) { 297 odm_SetATCStatus(pDM_Odm, false); 298 ODM_RT_TRACE( 299 pDM_Odm, 300 ODM_COMP_CFO_TRACKING, 301 ODM_DBG_LOUD, 302 ("ODM_CfoTracking(): Disable ATC!!\n") 303 ); 304 } else { 305 odm_SetATCStatus(pDM_Odm, true); 306 ODM_RT_TRACE( 307 pDM_Odm, 308 ODM_COMP_CFO_TRACKING, 309 ODM_DBG_LOUD, 310 ("ODM_CfoTracking(): Enable ATC!!\n") 311 ); 312 } 313 } 314 } 315 316 void ODM_ParsingCFO(void *pDM_VOID, void *pPktinfo_VOID, s8 *pcfotail) 317 { 318 PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; 319 PODM_PACKET_INFO_T pPktinfo = (PODM_PACKET_INFO_T)pPktinfo_VOID; 320 PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; 321 u8 i; 322 323 if (!(pDM_Odm->SupportAbility & ODM_BB_CFO_TRACKING)) 324 return; 325 326 if (pPktinfo->StationID != 0) { 327 /* 3 Update CFO report for path-A & path-B */ 328 /* Only paht-A and path-B have CFO tail and short CFO */ 329 for (i = ODM_RF_PATH_A; i <= ODM_RF_PATH_B; i++) 330 pCfoTrack->CFO_tail[i] = (int)pcfotail[i]; 331 332 /* 3 Update packet counter */ 333 if (pCfoTrack->packetCount == 0xffffffff) 334 pCfoTrack->packetCount = 0; 335 else 336 pCfoTrack->packetCount++; 337 } 338 } 339