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