| // SPDX-License-Identifier: GPL-2.0 |
| /****************************************************************************** |
| * |
| * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. |
| * |
| ******************************************************************************/ |
| |
| #include "odm_precomp.h" |
| |
| static void odm_SetCrystalCap(void *pDM_VOID, u8 CrystalCap) |
| { |
| PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; |
| PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; |
| bool bEEPROMCheck; |
| struct adapter *Adapter = pDM_Odm->Adapter; |
| struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); |
| |
| bEEPROMCheck = pHalData->EEPROMVersion >= 0x01; |
| |
| if (pCfoTrack->CrystalCap == CrystalCap) |
| return; |
| |
| pCfoTrack->CrystalCap = CrystalCap; |
| |
| /* 0x2C[23:18] = 0x2C[17:12] = CrystalCap */ |
| CrystalCap = CrystalCap & 0x3F; |
| PHY_SetBBReg( |
| pDM_Odm->Adapter, |
| REG_MAC_PHY_CTRL, |
| 0x00FFF000, |
| (CrystalCap | (CrystalCap << 6)) |
| ); |
| |
| ODM_RT_TRACE( |
| pDM_Odm, |
| ODM_COMP_CFO_TRACKING, |
| ODM_DBG_LOUD, |
| ( |
| "odm_SetCrystalCap(): CrystalCap = 0x%x\n", |
| CrystalCap |
| ) |
| ); |
| } |
| |
| static u8 odm_GetDefaultCrytaltalCap(void *pDM_VOID) |
| { |
| PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; |
| u8 CrystalCap = 0x20; |
| |
| struct adapter *Adapter = pDM_Odm->Adapter; |
| struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); |
| |
| CrystalCap = pHalData->CrystalCap; |
| |
| CrystalCap = CrystalCap & 0x3f; |
| |
| return CrystalCap; |
| } |
| |
| static void odm_SetATCStatus(void *pDM_VOID, bool ATCStatus) |
| { |
| PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; |
| PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; |
| |
| if (pCfoTrack->bATCStatus == ATCStatus) |
| return; |
| |
| PHY_SetBBReg( |
| pDM_Odm->Adapter, |
| ODM_REG(BB_ATC, pDM_Odm), |
| ODM_BIT(BB_ATC, pDM_Odm), |
| ATCStatus |
| ); |
| pCfoTrack->bATCStatus = ATCStatus; |
| } |
| |
| static bool odm_GetATCStatus(void *pDM_VOID) |
| { |
| bool ATCStatus; |
| PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; |
| |
| ATCStatus = (bool)PHY_QueryBBReg( |
| pDM_Odm->Adapter, |
| ODM_REG(BB_ATC, pDM_Odm), |
| ODM_BIT(BB_ATC, pDM_Odm) |
| ); |
| return ATCStatus; |
| } |
| |
| void ODM_CfoTrackingReset(void *pDM_VOID) |
| { |
| PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; |
| PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; |
| |
| pCfoTrack->DefXCap = odm_GetDefaultCrytaltalCap(pDM_Odm); |
| pCfoTrack->bAdjust = true; |
| |
| odm_SetCrystalCap(pDM_Odm, pCfoTrack->DefXCap); |
| odm_SetATCStatus(pDM_Odm, true); |
| } |
| |
| void ODM_CfoTrackingInit(void *pDM_VOID) |
| { |
| PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; |
| PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; |
| |
| pCfoTrack->DefXCap = |
| pCfoTrack->CrystalCap = odm_GetDefaultCrytaltalCap(pDM_Odm); |
| pCfoTrack->bATCStatus = odm_GetATCStatus(pDM_Odm); |
| pCfoTrack->bAdjust = true; |
| ODM_RT_TRACE( |
| pDM_Odm, |
| ODM_COMP_CFO_TRACKING, |
| ODM_DBG_LOUD, |
| ("ODM_CfoTracking_init() =========>\n") |
| ); |
| ODM_RT_TRACE( |
| pDM_Odm, |
| ODM_COMP_CFO_TRACKING, |
| ODM_DBG_LOUD, |
| ( |
| "ODM_CfoTracking_init(): bATCStatus = %d, CrystalCap = 0x%x\n", |
| pCfoTrack->bATCStatus, |
| pCfoTrack->DefXCap |
| ) |
| ); |
| } |
| |
| void ODM_CfoTracking(void *pDM_VOID) |
| { |
| PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; |
| PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; |
| int CFO_kHz_A, CFO_kHz_B, CFO_ave = 0; |
| int CFO_ave_diff; |
| int CrystalCap = (int)pCfoTrack->CrystalCap; |
| u8 Adjust_Xtal = 1; |
| |
| /* 4 Support ability */ |
| if (!(pDM_Odm->SupportAbility & ODM_BB_CFO_TRACKING)) { |
| ODM_RT_TRACE( |
| pDM_Odm, |
| ODM_COMP_CFO_TRACKING, |
| ODM_DBG_LOUD, |
| ("ODM_CfoTracking(): Return: SupportAbility ODM_BB_CFO_TRACKING is disabled\n") |
| ); |
| return; |
| } |
| |
| ODM_RT_TRACE( |
| pDM_Odm, |
| ODM_COMP_CFO_TRACKING, |
| ODM_DBG_LOUD, |
| ("ODM_CfoTracking() =========>\n") |
| ); |
| |
| if (!pDM_Odm->bLinked || !pDM_Odm->bOneEntryOnly) { |
| /* 4 No link or more than one entry */ |
| ODM_CfoTrackingReset(pDM_Odm); |
| ODM_RT_TRACE( |
| pDM_Odm, |
| ODM_COMP_CFO_TRACKING, |
| ODM_DBG_LOUD, |
| ( |
| "ODM_CfoTracking(): Reset: bLinked = %d, bOneEntryOnly = %d\n", |
| pDM_Odm->bLinked, |
| pDM_Odm->bOneEntryOnly |
| ) |
| ); |
| } else { |
| /* 3 1. CFO Tracking */ |
| /* 4 1.1 No new packet */ |
| if (pCfoTrack->packetCount == pCfoTrack->packetCount_pre) { |
| ODM_RT_TRACE( |
| pDM_Odm, |
| ODM_COMP_CFO_TRACKING, |
| ODM_DBG_LOUD, |
| ( |
| "ODM_CfoTracking(): packet counter doesn't change\n" |
| ) |
| ); |
| return; |
| } |
| pCfoTrack->packetCount_pre = pCfoTrack->packetCount; |
| |
| /* 4 1.2 Calculate CFO */ |
| CFO_kHz_A = (int)(pCfoTrack->CFO_tail[0] * 3125) / 1280; |
| CFO_kHz_B = (int)(pCfoTrack->CFO_tail[1] * 3125) / 1280; |
| |
| if (pDM_Odm->RFType < ODM_2T2R) |
| CFO_ave = CFO_kHz_A; |
| else |
| CFO_ave = (int)(CFO_kHz_A + CFO_kHz_B) >> 1; |
| ODM_RT_TRACE( |
| pDM_Odm, |
| ODM_COMP_CFO_TRACKING, |
| ODM_DBG_LOUD, |
| ( |
| "ODM_CfoTracking(): CFO_kHz_A = %dkHz, CFO_kHz_B = %dkHz, CFO_ave = %dkHz\n", |
| CFO_kHz_A, |
| CFO_kHz_B, |
| CFO_ave |
| ) |
| ); |
| |
| /* 4 1.3 Avoid abnormal large CFO */ |
| CFO_ave_diff = |
| (pCfoTrack->CFO_ave_pre >= CFO_ave) ? |
| (pCfoTrack->CFO_ave_pre-CFO_ave) : |
| (CFO_ave-pCfoTrack->CFO_ave_pre); |
| |
| if ( |
| CFO_ave_diff > 20 && |
| pCfoTrack->largeCFOHit == 0 && |
| !pCfoTrack->bAdjust |
| ) { |
| ODM_RT_TRACE(pDM_Odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("ODM_CfoTracking(): first large CFO hit\n")); |
| pCfoTrack->largeCFOHit = 1; |
| return; |
| } else |
| pCfoTrack->largeCFOHit = 0; |
| pCfoTrack->CFO_ave_pre = CFO_ave; |
| |
| /* 4 1.4 Dynamic Xtal threshold */ |
| if (pCfoTrack->bAdjust == false) { |
| if (CFO_ave > CFO_TH_XTAL_HIGH || CFO_ave < (-CFO_TH_XTAL_HIGH)) |
| pCfoTrack->bAdjust = true; |
| } else { |
| if (CFO_ave < CFO_TH_XTAL_LOW && CFO_ave > (-CFO_TH_XTAL_LOW)) |
| pCfoTrack->bAdjust = false; |
| } |
| |
| /* 4 1.5 BT case: Disable CFO tracking */ |
| if (pDM_Odm->bBtEnabled) { |
| pCfoTrack->bAdjust = false; |
| odm_SetCrystalCap(pDM_Odm, pCfoTrack->DefXCap); |
| ODM_RT_TRACE( |
| pDM_Odm, |
| ODM_COMP_CFO_TRACKING, |
| ODM_DBG_LOUD, |
| ("ODM_CfoTracking(): Disable CFO tracking for BT!!\n") |
| ); |
| } |
| |
| /* 4 1.6 Big jump */ |
| if (pCfoTrack->bAdjust) { |
| if (CFO_ave > CFO_TH_XTAL_LOW) |
| Adjust_Xtal = Adjust_Xtal+((CFO_ave-CFO_TH_XTAL_LOW)>>2); |
| else if (CFO_ave < (-CFO_TH_XTAL_LOW)) |
| Adjust_Xtal = Adjust_Xtal+((CFO_TH_XTAL_LOW-CFO_ave)>>2); |
| |
| ODM_RT_TRACE( |
| pDM_Odm, |
| ODM_COMP_CFO_TRACKING, |
| ODM_DBG_LOUD, |
| ( |
| "ODM_CfoTracking(): Crystal cap offset = %d\n", |
| Adjust_Xtal |
| ) |
| ); |
| } |
| |
| /* 4 1.7 Adjust Crystal Cap. */ |
| if (pCfoTrack->bAdjust) { |
| if (CFO_ave > CFO_TH_XTAL_LOW) |
| CrystalCap = CrystalCap + Adjust_Xtal; |
| else if (CFO_ave < (-CFO_TH_XTAL_LOW)) |
| CrystalCap = CrystalCap - Adjust_Xtal; |
| |
| if (CrystalCap > 0x3f) |
| CrystalCap = 0x3f; |
| else if (CrystalCap < 0) |
| CrystalCap = 0; |
| |
| odm_SetCrystalCap(pDM_Odm, (u8)CrystalCap); |
| } |
| ODM_RT_TRACE( |
| pDM_Odm, |
| ODM_COMP_CFO_TRACKING, |
| ODM_DBG_LOUD, |
| ( |
| "ODM_CfoTracking(): Crystal cap = 0x%x, Default Crystal cap = 0x%x\n", |
| pCfoTrack->CrystalCap, |
| pCfoTrack->DefXCap |
| ) |
| ); |
| |
| /* 3 2. Dynamic ATC switch */ |
| if (CFO_ave < CFO_TH_ATC && CFO_ave > -CFO_TH_ATC) { |
| odm_SetATCStatus(pDM_Odm, false); |
| ODM_RT_TRACE( |
| pDM_Odm, |
| ODM_COMP_CFO_TRACKING, |
| ODM_DBG_LOUD, |
| ("ODM_CfoTracking(): Disable ATC!!\n") |
| ); |
| } else { |
| odm_SetATCStatus(pDM_Odm, true); |
| ODM_RT_TRACE( |
| pDM_Odm, |
| ODM_COMP_CFO_TRACKING, |
| ODM_DBG_LOUD, |
| ("ODM_CfoTracking(): Enable ATC!!\n") |
| ); |
| } |
| } |
| } |
| |
| void ODM_ParsingCFO(void *pDM_VOID, void *pPktinfo_VOID, s8 *pcfotail) |
| { |
| PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; |
| struct odm_packet_info *pPktinfo = (struct odm_packet_info *)pPktinfo_VOID; |
| PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; |
| u8 i; |
| |
| if (!(pDM_Odm->SupportAbility & ODM_BB_CFO_TRACKING)) |
| return; |
| |
| if (pPktinfo->station_id != 0) { |
| /* 3 Update CFO report for path-A & path-B */ |
| /* Only paht-A and path-B have CFO tail and short CFO */ |
| for (i = ODM_RF_PATH_A; i <= ODM_RF_PATH_B; i++) |
| pCfoTrack->CFO_tail[i] = (int)pcfotail[i]; |
| |
| /* 3 Update packet counter */ |
| if (pCfoTrack->packetCount == 0xffffffff) |
| pCfoTrack->packetCount = 0; |
| else |
| pCfoTrack->packetCount++; |
| } |
| } |