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