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