net: wireless: rockchip_wlan: add rtl8723cs support
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / rtl8723cs / hal / phydm / phydm_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  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17  *
18  *
19  ******************************************************************************/
20 #include "mp_precomp.h"
21 #include "phydm_precomp.h"
22
23 void
24 odm_set_crystal_cap(
25         void                                    *p_dm_void,
26         u8                                      crystal_cap
27 )
28 {
29         struct PHY_DM_STRUCT                                    *p_dm_odm = (struct PHY_DM_STRUCT *)p_dm_void;
30         struct _CFO_TRACKING_                           *p_cfo_track = (struct _CFO_TRACKING_ *)phydm_get_structure(p_dm_odm, PHYDM_CFOTRACK);
31         struct _ADAPTER                                         *adapter = p_dm_odm->adapter;/* JJ modified 20161115 */
32
33         if (p_cfo_track->crystal_cap == crystal_cap)
34                 return;
35
36         p_cfo_track->crystal_cap = crystal_cap;
37
38 #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE))
39         if (p_dm_odm->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(p_dm_odm, REG_AFE_XTAL_CTRL, 0x007ff800, (crystal_cap | (crystal_cap << 6)));
43         } else if (p_dm_odm->support_ic_type & ODM_RTL8812) {
44                 /* write 0x2C[30:25] = 0x2C[24:19] = crystal_cap */
45                 crystal_cap = crystal_cap & 0x3F;
46                 odm_set_bb_reg(p_dm_odm, REG_MAC_PHY_CTRL, 0x7FF80000, (crystal_cap | (crystal_cap << 6)));
47         } else if ((p_dm_odm->support_ic_type & (ODM_RTL8703B | ODM_RTL8723B | ODM_RTL8192E | ODM_RTL8821))) {
48                 /* 0x2C[23:18] = 0x2C[17:12] = crystal_cap */
49                 crystal_cap = crystal_cap & 0x3F;
50                 odm_set_bb_reg(p_dm_odm, REG_MAC_PHY_CTRL, 0x00FFF000, (crystal_cap | (crystal_cap << 6)));
51         }  else if (p_dm_odm->support_ic_type & ODM_RTL8814A) {
52                 /* write 0x2C[26:21] = 0x2C[20:15] = crystal_cap */
53                 crystal_cap = crystal_cap & 0x3F;
54                 odm_set_bb_reg(p_dm_odm, REG_MAC_PHY_CTRL, 0x07FF8000, (crystal_cap | (crystal_cap << 6)));
55         } else if (p_dm_odm->support_ic_type & (ODM_RTL8822B | ODM_RTL8821C)) {
56                 /* write 0x24[30:25] = 0x28[6:1] = crystal_cap */
57                 crystal_cap = crystal_cap & 0x3F;
58                 odm_set_bb_reg(p_dm_odm, REG_AFE_XTAL_CTRL, 0x7e000000, crystal_cap);
59                 odm_set_bb_reg(p_dm_odm, REG_AFE_PLL_CTRL, 0x7e, crystal_cap);
60         } else {
61                 ODM_RT_TRACE(p_dm_odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("odm_set_crystal_cap(): Use default setting.\n"));
62                 odm_set_bb_reg(p_dm_odm, REG_MAC_PHY_CTRL, 0xFFF000, (crystal_cap | (crystal_cap << 6)));
63         }
64
65         ODM_RT_TRACE(p_dm_odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("odm_set_crystal_cap(): crystal_cap = 0x%x\n", crystal_cap));
66 #endif
67
68 /* JJ modified 20161115 */
69 #if (DM_ODM_SUPPORT_TYPE & ODM_WIN)
70         if (p_dm_odm->support_ic_type & (ODM_RTL8710B)) {
71         /* write 0x60[29:24] = 0x60[23:18] = crystal_cap */
72         crystal_cap = crystal_cap & 0x3F;
73         HAL_SetSYSOnReg(adapter, REG_SYS_XTAL_CTRL0, 0x3FFC0000, (crystal_cap | (crystal_cap << 6)));
74         }
75 #endif
76
77 }
78
79 u8
80 odm_get_default_crytaltal_cap(
81         void                                    *p_dm_void
82 )
83 {
84         struct PHY_DM_STRUCT                                    *p_dm_odm = (struct PHY_DM_STRUCT *)p_dm_void;
85         u8                                              crystal_cap = 0x20;
86
87 #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE))
88         struct _ADAPTER                                 *adapter = p_dm_odm->adapter;
89         HAL_DATA_TYPE                           *p_hal_data = GET_HAL_DATA(adapter);
90
91         crystal_cap = p_hal_data->crystal_cap;
92 #else
93         struct rtl8192cd_priv   *priv           = p_dm_odm->priv;
94
95         if (priv->pmib->dot11RFEntry.xcap > 0)
96                 crystal_cap = priv->pmib->dot11RFEntry.xcap;
97 #endif
98
99         crystal_cap = crystal_cap & 0x3f;
100
101         return crystal_cap;
102 }
103
104 void
105 odm_set_atc_status(
106         void                                    *p_dm_void,
107         boolean                                 atc_status
108 )
109 {
110         struct PHY_DM_STRUCT                                    *p_dm_odm = (struct PHY_DM_STRUCT *)p_dm_void;
111         struct _CFO_TRACKING_                           *p_cfo_track = (struct _CFO_TRACKING_ *)phydm_get_structure(p_dm_odm, PHYDM_CFOTRACK);
112
113         if (p_cfo_track->is_atc_status == atc_status)
114                 return;
115
116         odm_set_bb_reg(p_dm_odm, ODM_REG(BB_ATC, p_dm_odm), ODM_BIT(BB_ATC, p_dm_odm), atc_status);
117         p_cfo_track->is_atc_status = atc_status;
118 }
119
120 boolean
121 odm_get_atc_status(
122         void                                    *p_dm_void
123 )
124 {
125         boolean                                         atc_status;
126         struct PHY_DM_STRUCT                                    *p_dm_odm = (struct PHY_DM_STRUCT *)p_dm_void;
127
128         atc_status = (boolean)odm_get_bb_reg(p_dm_odm, ODM_REG(BB_ATC, p_dm_odm), ODM_BIT(BB_ATC, p_dm_odm));
129         return atc_status;
130 }
131
132 void
133 odm_cfo_tracking_reset(
134         void                                    *p_dm_void
135 )
136 {
137         struct PHY_DM_STRUCT                                    *p_dm_odm = (struct PHY_DM_STRUCT *)p_dm_void;
138         struct _CFO_TRACKING_                           *p_cfo_track = (struct _CFO_TRACKING_ *)phydm_get_structure(p_dm_odm, PHYDM_CFOTRACK);
139
140         p_cfo_track->def_x_cap = odm_get_default_crytaltal_cap(p_dm_odm);
141         p_cfo_track->is_adjust = true;
142
143         if (p_cfo_track->crystal_cap > p_cfo_track->def_x_cap) {
144                 odm_set_crystal_cap(p_dm_odm, p_cfo_track->crystal_cap - 1);
145                 ODM_RT_TRACE(p_dm_odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD,
146                         ("odm_cfo_tracking_reset(): approch default value (0x%x)\n", p_cfo_track->crystal_cap));
147         } else if (p_cfo_track->crystal_cap < p_cfo_track->def_x_cap) {
148                 odm_set_crystal_cap(p_dm_odm, p_cfo_track->crystal_cap + 1);
149                 ODM_RT_TRACE(p_dm_odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD,
150                         ("odm_cfo_tracking_reset(): approch default value (0x%x)\n", p_cfo_track->crystal_cap));
151         }
152
153 #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE))
154         odm_set_atc_status(p_dm_odm, true);
155 #endif
156 }
157
158 void
159 odm_cfo_tracking_init(
160         void                                    *p_dm_void
161 )
162 {
163         struct PHY_DM_STRUCT                                    *p_dm_odm = (struct PHY_DM_STRUCT *)p_dm_void;
164         struct _CFO_TRACKING_                           *p_cfo_track = (struct _CFO_TRACKING_ *)phydm_get_structure(p_dm_odm, PHYDM_CFOTRACK);
165
166         p_cfo_track->def_x_cap = p_cfo_track->crystal_cap = odm_get_default_crytaltal_cap(p_dm_odm);
167         p_cfo_track->is_atc_status = odm_get_atc_status(p_dm_odm);
168         p_cfo_track->is_adjust = true;
169         ODM_RT_TRACE(p_dm_odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("ODM_CfoTracking_init()=========>\n"));
170         ODM_RT_TRACE(p_dm_odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("ODM_CfoTracking_init(): is_atc_status = %d, crystal_cap = 0x%x\n", p_cfo_track->is_atc_status, p_cfo_track->def_x_cap));
171
172 #if RTL8822B_SUPPORT
173         /* Crystal cap. control by WiFi */
174         if (p_dm_odm->support_ic_type & ODM_RTL8822B)
175                 odm_set_bb_reg(p_dm_odm, 0x10, 0x40, 0x1);
176 #endif
177
178 #if RTL8821C_SUPPORT
179         /* Crystal cap. control by WiFi */
180         if (p_dm_odm->support_ic_type & ODM_RTL8821C)
181                 odm_set_bb_reg(p_dm_odm, 0x10, 0x40, 0x1);
182 #endif
183 }
184
185 void
186 odm_cfo_tracking(
187         void                                    *p_dm_void
188 )
189 {
190         struct PHY_DM_STRUCT                                    *p_dm_odm = (struct PHY_DM_STRUCT *)p_dm_void;
191         struct _CFO_TRACKING_                           *p_cfo_track = (struct _CFO_TRACKING_ *)phydm_get_structure(p_dm_odm, PHYDM_CFOTRACK);
192         s32                                             CFO_ave = 0;
193         u32                                             CFO_rpt_sum, cfo_khz_avg[4] = {0};
194         s32                                             CFO_ave_diff;
195         s8                                              crystal_cap = p_cfo_track->crystal_cap;
196         u8                                              adjust_xtal = 1, i, valid_path_cnt = 0;
197
198         /* 4 Support ability */
199         if (!(p_dm_odm->support_ability & ODM_BB_CFO_TRACKING)) {
200                 ODM_RT_TRACE(p_dm_odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("odm_cfo_tracking(): Return: support_ability ODM_BB_CFO_TRACKING is disabled\n"));
201                 return;
202         }
203
204         ODM_RT_TRACE(p_dm_odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("odm_cfo_tracking()=========>\n"));
205
206         if (!p_dm_odm->is_linked || !p_dm_odm->is_one_entry_only) {
207                 /* 4 No link or more than one entry */
208                 odm_cfo_tracking_reset(p_dm_odm);
209                 ODM_RT_TRACE(p_dm_odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("odm_cfo_tracking(): Reset: is_linked = %d, is_one_entry_only = %d\n",
210                         p_dm_odm->is_linked, p_dm_odm->is_one_entry_only));
211         } else {
212                 /* 3 1. CFO Tracking */
213                 /* 4 1.1 No new packet */
214                 if (p_cfo_track->packet_count == p_cfo_track->packet_count_pre) {
215                         ODM_RT_TRACE(p_dm_odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("odm_cfo_tracking(): packet counter doesn't change\n"));
216                         return;
217                 }
218                 p_cfo_track->packet_count_pre = p_cfo_track->packet_count;
219
220                 /* 4 1.2 Calculate CFO */
221                 for (i = 0; i < p_dm_odm->num_rf_path; i++) {
222
223                         if (p_cfo_track->CFO_cnt[i] == 0)
224                                 continue;
225
226                         valid_path_cnt++;
227                         CFO_rpt_sum = (u32)((p_cfo_track->CFO_tail[i] < 0) ? (0 - p_cfo_track->CFO_tail[i]) :  p_cfo_track->CFO_tail[i]);
228                         cfo_khz_avg[i] = CFO_HW_RPT_2_MHZ(CFO_rpt_sum) / p_cfo_track->CFO_cnt[i];
229
230                         ODM_RT_TRACE(p_dm_odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("[path %d] CFO_rpt_sum = (( %d )), CFO_cnt = (( %d )) , CFO_avg= (( %s%d )) kHz\n",
231                                 i, CFO_rpt_sum, p_cfo_track->CFO_cnt[i], ((p_cfo_track->CFO_tail[i] < 0) ? "-" : " "), cfo_khz_avg[i]));
232                 }
233
234                 for (i = 0; i < valid_path_cnt; i++) {
235
236                         /* ODM_RT_TRACE(p_dm_odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("path [%d], p_cfo_track->CFO_tail = %d\n", i, p_cfo_track->CFO_tail[i])); */
237                         if (p_cfo_track->CFO_tail[i] < 0) {
238                                 CFO_ave += (0 - (s32)cfo_khz_avg[i]);
239                                 /* ODM_RT_TRACE(p_dm_odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("CFO_ave = %d\n", CFO_ave)); */
240                         } else
241                                 CFO_ave += (s32)cfo_khz_avg[i];
242                 }
243
244                 if (valid_path_cnt >= 2)
245                         CFO_ave = CFO_ave / valid_path_cnt;
246
247                 ODM_RT_TRACE(p_dm_odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("valid_path_cnt = ((%d)), CFO_ave = ((%d kHz))\n", valid_path_cnt, CFO_ave));
248
249                 /*reset counter*/
250                 for (i = 0; i < p_dm_odm->num_rf_path; i++) {
251                         p_cfo_track->CFO_tail[i] = 0;
252                         p_cfo_track->CFO_cnt[i] = 0;
253                 }
254
255                 /* 4 1.3 Avoid abnormal large CFO */
256                 CFO_ave_diff = (p_cfo_track->CFO_ave_pre >= CFO_ave) ? (p_cfo_track->CFO_ave_pre - CFO_ave) : (CFO_ave - p_cfo_track->CFO_ave_pre);
257                 if (CFO_ave_diff > 20 && p_cfo_track->large_cfo_hit == 0 && !p_cfo_track->is_adjust) {
258                         ODM_RT_TRACE(p_dm_odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("odm_cfo_tracking(): first large CFO hit\n"));
259                         p_cfo_track->large_cfo_hit = 1;
260                         return;
261                 } else
262                         p_cfo_track->large_cfo_hit = 0;
263                 p_cfo_track->CFO_ave_pre = CFO_ave;
264
265                 /* 4 1.4 Dynamic Xtal threshold */
266                 if (p_cfo_track->is_adjust == false) {
267                         if (CFO_ave > CFO_TH_XTAL_HIGH || CFO_ave < (-CFO_TH_XTAL_HIGH))
268                                 p_cfo_track->is_adjust = true;
269                 } else {
270                         if (CFO_ave < CFO_TH_XTAL_LOW && CFO_ave > (-CFO_TH_XTAL_LOW))
271                                 p_cfo_track->is_adjust = false;
272                 }
273
274 #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE))
275                 /* 4 1.5 BT case: Disable CFO tracking */
276                 if (p_dm_odm->is_bt_enabled) {
277                         p_cfo_track->is_adjust = false;
278                         odm_set_crystal_cap(p_dm_odm, p_cfo_track->def_x_cap);
279                         ODM_RT_TRACE(p_dm_odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("odm_cfo_tracking(): Disable CFO tracking for BT!!\n"));
280                 }
281 #if 0
282                 /* 4 1.6 Big jump */
283                 if (p_cfo_track->is_adjust) {
284                         if (CFO_ave > CFO_TH_XTAL_LOW)
285                                 adjust_xtal =  adjust_xtal + ((CFO_ave - CFO_TH_XTAL_LOW) >> 2);
286                         else if (CFO_ave < (-CFO_TH_XTAL_LOW))
287                                 adjust_xtal =  adjust_xtal + ((CFO_TH_XTAL_LOW - CFO_ave) >> 2);
288
289                         ODM_RT_TRACE(p_dm_odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("odm_cfo_tracking(): Crystal cap offset = %d\n", adjust_xtal));
290                 }
291 #endif
292 #endif
293
294                 /* 4 1.7 Adjust Crystal Cap. */
295                 if (p_cfo_track->is_adjust) {
296                         if (CFO_ave > CFO_TH_XTAL_LOW)
297                                 crystal_cap = crystal_cap + adjust_xtal;
298                         else if (CFO_ave < (-CFO_TH_XTAL_LOW))
299                                 crystal_cap = crystal_cap - adjust_xtal;
300
301                         if (crystal_cap > 0x3f)
302                                 crystal_cap = 0x3f;
303                         else if (crystal_cap < 0)
304                                 crystal_cap = 0;
305
306                         odm_set_crystal_cap(p_dm_odm, (u8)crystal_cap);
307                 }
308                 ODM_RT_TRACE(p_dm_odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("odm_cfo_tracking(): Crystal cap = 0x%x, Default Crystal cap = 0x%x\n",
309                         p_cfo_track->crystal_cap, p_cfo_track->def_x_cap));
310
311 #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE))
312                 if (p_dm_odm->support_ic_type & ODM_IC_11AC_SERIES)
313                         return;
314
315                 /* 3 2. Dynamic ATC switch */
316                 if (CFO_ave < CFO_TH_ATC && CFO_ave > -CFO_TH_ATC) {
317                         odm_set_atc_status(p_dm_odm, false);
318                         ODM_RT_TRACE(p_dm_odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("odm_cfo_tracking(): Disable ATC!!\n"));
319                 } else {
320                         odm_set_atc_status(p_dm_odm, true);
321                         ODM_RT_TRACE(p_dm_odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("odm_cfo_tracking(): Enable ATC!!\n"));
322                 }
323 #endif
324         }
325 }
326
327 void
328 odm_parsing_cfo(
329         void                    *p_dm_void,
330         void                    *p_pktinfo_void,
331         s8                      *pcfotail,
332         u8                      num_ss
333 )
334 {
335         struct PHY_DM_STRUCT                            *p_dm_odm = (struct PHY_DM_STRUCT *)p_dm_void;
336         struct _odm_per_pkt_info_               *p_pktinfo = (struct _odm_per_pkt_info_ *)p_pktinfo_void;
337         struct _CFO_TRACKING_                   *p_cfo_track = (struct _CFO_TRACKING_ *)phydm_get_structure(p_dm_odm, PHYDM_CFOTRACK);
338         u8                                      i;
339
340         if (!(p_dm_odm->support_ability & ODM_BB_CFO_TRACKING))
341                 return;
342
343 #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE))
344         if (p_pktinfo->is_packet_match_bssid)
345 #else
346         if (p_pktinfo->station_id != 0)
347 #endif
348         {
349                 if (num_ss > p_dm_odm->num_rf_path) /*For fool proof*/
350                         num_ss = p_dm_odm->num_rf_path;
351
352                 /*ODM_RT_TRACE(p_dm_odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("num_ss = ((%d)),  p_dm_odm->num_rf_path = ((%d))\n", num_ss,  p_dm_odm->num_rf_path));*/
353
354
355                 /* 3 Update CFO report for path-A & path-B */
356                 /* Only paht-A and path-B have CFO tail and short CFO */
357                 for (i = 0; i < num_ss; i++) {
358                         p_cfo_track->CFO_tail[i] += pcfotail[i];
359                         p_cfo_track->CFO_cnt[i]++;
360                         /*ODM_RT_TRACE(p_dm_odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("[ID %d][path %d][rate 0x%x] CFO_tail = ((%d)), CFO_tail_sum = ((%d)), CFO_cnt = ((%d))\n",
361                                 p_pktinfo->station_id, i, p_pktinfo->data_rate, pcfotail[i], p_cfo_track->CFO_tail[i], p_cfo_track->CFO_cnt[i]));
362                         */
363                 }
364
365                 /* 3 Update packet counter */
366                 if (p_cfo_track->packet_count == 0xffffffff)
367                         p_cfo_track->packet_count = 0;
368                 else
369                         p_cfo_track->packet_count++;
370         }
371 }