GNU Linux-libre 4.14.290-gnu1
[releases.git] / drivers / staging / rtlwifi / phydm / phydm_cfotracking.c
1 /******************************************************************************
2  *
3  * Copyright(c) 2007 - 2016  Realtek Corporation.
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  * The full GNU General Public License is included in this distribution in the
15  * file called LICENSE.
16  *
17  * Contact Information:
18  * wlanfae <wlanfae@realtek.com>
19  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
20  * Hsinchu 300, Taiwan.
21  *
22  * Larry Finger <Larry.Finger@lwfinger.net>
23  *
24  *****************************************************************************/
25 #include "mp_precomp.h"
26 #include "phydm_precomp.h"
27
28 static void odm_set_crystal_cap(void *dm_void, u8 crystal_cap)
29 {
30         struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
31         struct cfo_tracking *cfo_track =
32                 (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK);
33
34         if (cfo_track->crystal_cap == crystal_cap)
35                 return;
36
37         cfo_track->crystal_cap = crystal_cap;
38
39         if (dm->support_ic_type & (ODM_RTL8188E | ODM_RTL8188F)) {
40                 /* write 0x24[22:17] = 0x24[16:11] = crystal_cap */
41                 crystal_cap = crystal_cap & 0x3F;
42                 odm_set_bb_reg(dm, REG_AFE_XTAL_CTRL, 0x007ff800,
43                                (crystal_cap | (crystal_cap << 6)));
44         } else if (dm->support_ic_type & ODM_RTL8812) {
45                 /* write 0x2C[30:25] = 0x2C[24:19] = crystal_cap */
46                 crystal_cap = crystal_cap & 0x3F;
47                 odm_set_bb_reg(dm, REG_MAC_PHY_CTRL, 0x7FF80000,
48                                (crystal_cap | (crystal_cap << 6)));
49         } else if ((dm->support_ic_type & (ODM_RTL8703B | ODM_RTL8723B |
50                                            ODM_RTL8192E | ODM_RTL8821))) {
51                 /* 0x2C[23:18] = 0x2C[17:12] = crystal_cap */
52                 crystal_cap = crystal_cap & 0x3F;
53                 odm_set_bb_reg(dm, REG_MAC_PHY_CTRL, 0x00FFF000,
54                                (crystal_cap | (crystal_cap << 6)));
55         } else if (dm->support_ic_type & ODM_RTL8814A) {
56                 /* write 0x2C[26:21] = 0x2C[20:15] = crystal_cap */
57                 crystal_cap = crystal_cap & 0x3F;
58                 odm_set_bb_reg(dm, REG_MAC_PHY_CTRL, 0x07FF8000,
59                                (crystal_cap | (crystal_cap << 6)));
60         } else if (dm->support_ic_type & (ODM_RTL8822B | ODM_RTL8821C)) {
61                 /* write 0x24[30:25] = 0x28[6:1] = crystal_cap */
62                 crystal_cap = crystal_cap & 0x3F;
63                 odm_set_bb_reg(dm, REG_AFE_XTAL_CTRL, 0x7e000000, crystal_cap);
64                 odm_set_bb_reg(dm, REG_AFE_PLL_CTRL, 0x7e, crystal_cap);
65         } else {
66                 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
67                              "%s(): Use default setting.\n", __func__);
68                 odm_set_bb_reg(dm, REG_MAC_PHY_CTRL, 0xFFF000,
69                                (crystal_cap | (crystal_cap << 6)));
70         }
71
72         ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, "%s(): crystal_cap = 0x%x\n",
73                      __func__, crystal_cap);
74
75         /* JJ modified 20161115 */
76 }
77
78 static u8 odm_get_default_crytaltal_cap(void *dm_void)
79 {
80         struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
81         u8 crystal_cap = 0x20;
82
83         struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter;
84         struct rtl_efuse *rtlefuse = rtl_efuse(rtlpriv);
85
86         crystal_cap = rtlefuse->crystalcap;
87
88         crystal_cap = crystal_cap & 0x3f;
89
90         return crystal_cap;
91 }
92
93 static void odm_set_atc_status(void *dm_void, bool atc_status)
94 {
95         struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
96         struct cfo_tracking *cfo_track =
97                 (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK);
98
99         if (cfo_track->is_atc_status == atc_status)
100                 return;
101
102         odm_set_bb_reg(dm, ODM_REG(BB_ATC, dm), ODM_BIT(BB_ATC, dm),
103                        atc_status);
104         cfo_track->is_atc_status = atc_status;
105 }
106
107 static bool odm_get_atc_status(void *dm_void)
108 {
109         bool atc_status;
110         struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
111
112         atc_status = (bool)odm_get_bb_reg(dm, ODM_REG(BB_ATC, dm),
113                                           ODM_BIT(BB_ATC, dm));
114         return atc_status;
115 }
116
117 void odm_cfo_tracking_reset(void *dm_void)
118 {
119         struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
120         struct cfo_tracking *cfo_track =
121                 (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK);
122
123         cfo_track->def_x_cap = odm_get_default_crytaltal_cap(dm);
124         cfo_track->is_adjust = true;
125
126         if (cfo_track->crystal_cap > cfo_track->def_x_cap) {
127                 odm_set_crystal_cap(dm, cfo_track->crystal_cap - 1);
128                 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
129                              "%s(): approch default value (0x%x)\n", __func__,
130                              cfo_track->crystal_cap);
131         } else if (cfo_track->crystal_cap < cfo_track->def_x_cap) {
132                 odm_set_crystal_cap(dm, cfo_track->crystal_cap + 1);
133                 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
134                              "%s(): approch default value (0x%x)\n", __func__,
135                              cfo_track->crystal_cap);
136         }
137
138         odm_set_atc_status(dm, true);
139 }
140
141 void odm_cfo_tracking_init(void *dm_void)
142 {
143         struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
144         struct cfo_tracking *cfo_track =
145                 (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK);
146
147         cfo_track->crystal_cap = odm_get_default_crytaltal_cap(dm);
148         cfo_track->def_x_cap = cfo_track->crystal_cap;
149         cfo_track->is_atc_status = odm_get_atc_status(dm);
150         cfo_track->is_adjust = true;
151         ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, "%s()=========>\n", __func__);
152         ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
153                      "%s(): is_atc_status = %d, crystal_cap = 0x%x\n", __func__,
154                      cfo_track->is_atc_status, cfo_track->def_x_cap);
155
156         /* Crystal cap. control by WiFi */
157         if (dm->support_ic_type & ODM_RTL8822B)
158                 odm_set_bb_reg(dm, 0x10, 0x40, 0x1);
159 }
160
161 void odm_cfo_tracking(void *dm_void)
162 {
163         struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
164         struct cfo_tracking *cfo_track =
165                 (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK);
166         s32 cfo_ave = 0;
167         u32 cfo_rpt_sum, cfo_khz_avg[4] = {0};
168         s32 cfo_ave_diff;
169         s8 crystal_cap = cfo_track->crystal_cap;
170         u8 adjust_xtal = 1, i, valid_path_cnt = 0;
171
172         /* 4 Support ability */
173         if (!(dm->support_ability & ODM_BB_CFO_TRACKING)) {
174                 ODM_RT_TRACE(
175                         dm, ODM_COMP_CFO_TRACKING,
176                         "%s(): Return: support_ability ODM_BB_CFO_TRACKING is disabled\n",
177                         __func__);
178                 return;
179         }
180
181         ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, "%s()=========>\n", __func__);
182
183         if (!dm->is_linked || !dm->is_one_entry_only) {
184                 /* 4 No link or more than one entry */
185                 odm_cfo_tracking_reset(dm);
186                 ODM_RT_TRACE(
187                         dm, ODM_COMP_CFO_TRACKING,
188                         "%s(): Reset: is_linked = %d, is_one_entry_only = %d\n",
189                         __func__, dm->is_linked, dm->is_one_entry_only);
190         } else {
191                 /* 3 1. CFO Tracking */
192                 /* 4 1.1 No new packet */
193                 if (cfo_track->packet_count == cfo_track->packet_count_pre) {
194                         ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
195                                      "%s(): packet counter doesn't change\n",
196                                      __func__);
197                         return;
198                 }
199                 cfo_track->packet_count_pre = cfo_track->packet_count;
200
201                 /* 4 1.2 Calculate CFO */
202                 for (i = 0; i < dm->num_rf_path; i++) {
203                         if (cfo_track->CFO_cnt[i] == 0)
204                                 continue;
205
206                         valid_path_cnt++;
207                         cfo_rpt_sum =
208                                 (u32)((cfo_track->CFO_tail[i] < 0) ?
209                                               (0 - cfo_track->CFO_tail[i]) :
210                                               cfo_track->CFO_tail[i]);
211                         cfo_khz_avg[i] = CFO_HW_RPT_2_MHZ(cfo_rpt_sum) /
212                                          cfo_track->CFO_cnt[i];
213
214                         ODM_RT_TRACE(
215                                 dm, ODM_COMP_CFO_TRACKING,
216                                 "[path %d] cfo_rpt_sum = (( %d )), CFO_cnt = (( %d )) , CFO_avg= (( %s%d )) kHz\n",
217                                 i, cfo_rpt_sum, cfo_track->CFO_cnt[i],
218                                 ((cfo_track->CFO_tail[i] < 0) ? "-" : " "),
219                                 cfo_khz_avg[i]);
220                 }
221
222                 for (i = 0; i < valid_path_cnt; i++) {
223                         if (cfo_track->CFO_tail[i] < 0) {
224                                 /* */
225                                 cfo_ave += (0 - (s32)cfo_khz_avg[i]);
226                         } else {
227                                 cfo_ave += (s32)cfo_khz_avg[i];
228                         }
229                 }
230
231                 if (valid_path_cnt >= 2)
232                         cfo_ave = cfo_ave / valid_path_cnt;
233
234                 ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
235                              "valid_path_cnt = ((%d)), cfo_ave = ((%d kHz))\n",
236                              valid_path_cnt, cfo_ave);
237
238                 /*reset counter*/
239                 for (i = 0; i < dm->num_rf_path; i++) {
240                         cfo_track->CFO_tail[i] = 0;
241                         cfo_track->CFO_cnt[i] = 0;
242                 }
243
244                 /* 4 1.3 Avoid abnormal large CFO */
245                 cfo_ave_diff = (cfo_track->CFO_ave_pre >= cfo_ave) ?
246                                        (cfo_track->CFO_ave_pre - cfo_ave) :
247                                        (cfo_ave - cfo_track->CFO_ave_pre);
248                 if (cfo_ave_diff > 20 && cfo_track->large_cfo_hit == 0 &&
249                     !cfo_track->is_adjust) {
250                         ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
251                                      "%s(): first large CFO hit\n", __func__);
252                         cfo_track->large_cfo_hit = 1;
253                         return;
254                 }
255
256                 cfo_track->large_cfo_hit = 0;
257                 cfo_track->CFO_ave_pre = cfo_ave;
258
259                 /* 4 1.4 Dynamic Xtal threshold */
260                 if (!cfo_track->is_adjust) {
261                         if (cfo_ave > CFO_TH_XTAL_HIGH ||
262                             cfo_ave < (-CFO_TH_XTAL_HIGH))
263                                 cfo_track->is_adjust = true;
264                 } else {
265                         if (cfo_ave < CFO_TH_XTAL_LOW &&
266                             cfo_ave > (-CFO_TH_XTAL_LOW))
267                                 cfo_track->is_adjust = false;
268                 }
269
270                 /* 4 1.5 BT case: Disable CFO tracking */
271                 if (dm->is_bt_enabled) {
272                         cfo_track->is_adjust = false;
273                         odm_set_crystal_cap(dm, cfo_track->def_x_cap);
274                         ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
275                                      "%s(): Disable CFO tracking for BT!!\n",
276                                      __func__);
277                 }
278
279                 /* 4 1.7 Adjust Crystal Cap. */
280                 if (cfo_track->is_adjust) {
281                         if (cfo_ave > CFO_TH_XTAL_LOW)
282                                 crystal_cap = crystal_cap + adjust_xtal;
283                         else if (cfo_ave < (-CFO_TH_XTAL_LOW))
284                                 crystal_cap = crystal_cap - adjust_xtal;
285
286                         if (crystal_cap > 0x3f)
287                                 crystal_cap = 0x3f;
288                         else if (crystal_cap < 0)
289                                 crystal_cap = 0;
290
291                         odm_set_crystal_cap(dm, (u8)crystal_cap);
292                 }
293                 ODM_RT_TRACE(
294                         dm, ODM_COMP_CFO_TRACKING,
295                         "%s(): Crystal cap = 0x%x, Default Crystal cap = 0x%x\n",
296                         __func__, cfo_track->crystal_cap, cfo_track->def_x_cap);
297
298                 if (dm->support_ic_type & ODM_IC_11AC_SERIES)
299                         return;
300
301                 /* 3 2. Dynamic ATC switch */
302                 if (cfo_ave < CFO_TH_ATC && cfo_ave > -CFO_TH_ATC) {
303                         odm_set_atc_status(dm, false);
304                         ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
305                                      "%s(): Disable ATC!!\n", __func__);
306                 } else {
307                         odm_set_atc_status(dm, true);
308                         ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
309                                      "%s(): Enable ATC!!\n", __func__);
310                 }
311         }
312 }
313
314 void odm_parsing_cfo(void *dm_void, void *pktinfo_void, s8 *pcfotail, u8 num_ss)
315 {
316         struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
317         struct dm_per_pkt_info *pktinfo =
318                 (struct dm_per_pkt_info *)pktinfo_void;
319         struct cfo_tracking *cfo_track =
320                 (struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK);
321         u8 i;
322
323         if (!(dm->support_ability & ODM_BB_CFO_TRACKING))
324                 return;
325
326         if (pktinfo->is_packet_match_bssid) {
327                 if (num_ss > dm->num_rf_path) /*For fool proof*/
328                         num_ss = dm->num_rf_path;
329
330                 /* 3 Update CFO report for path-A & path-B */
331                 /* Only paht-A and path-B have CFO tail and short CFO */
332                 for (i = 0; i < num_ss; i++) {
333                         cfo_track->CFO_tail[i] += pcfotail[i];
334                         cfo_track->CFO_cnt[i]++;
335                 }
336
337                 /* 3 Update packet counter */
338                 if (cfo_track->packet_count == 0xffffffff)
339                         cfo_track->packet_count = 0;
340                 else
341                         cfo_track->packet_count++;
342         }
343 }