GNU Linux-libre 4.14.290-gnu1
[releases.git] / drivers / staging / rtl8723bs / hal / odm_CfoTracking.c
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 }