1 /******************************************************************************
3 * Copyright(c) 2007 - 2017 Realtek Corporation.
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.
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
14 * The full GNU General Public License is included in this distribution in the
15 * file called LICENSE.
17 * Contact Information:
18 * wlanfae <wlanfae@realtek.com>
19 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
20 * Hsinchu 300, Taiwan.
22 * Larry Finger <Larry.Finger@lwfinger.net>
24 *****************************************************************************/
25 #include "mp_precomp.h"
26 #include "phydm_precomp.h"
28 s32 phydm_get_cfo_hz(void *dm_void, u32 val, u8 bit_num, u8 frac_num)
32 val_s = phydm_cnvrt_2_sign(val, bit_num);
34 if (frac_num == 10) /*@ (X*312500)/1024 ~= X*305*/
36 else if (frac_num == 11) /*@ (X*312500)/2048 ~= X*152*/
38 else if (frac_num == 12) /*@ (X*312500)/4096 ~= X*76*/
44 #if (ODM_IC_11AC_SERIES_SUPPORT)
45 void phydm_get_cfo_info_ac(void *dm_void, struct phydm_cfo_rpt *cfo)
47 struct dm_struct *dm = (struct dm_struct *)dm_void;
54 val[0] = odm_read_4byte(dm, R_0xd0c);
55 val_1[0] = odm_read_4byte(dm, R_0xd10);
56 val_2[0] = odm_get_bb_reg(dm, R_0xd14, 0x1fff0000);
58 #if (defined(PHYDM_COMPILE_ABOVE_2SS))
59 val[1] = odm_read_4byte(dm, R_0xd4c);
60 val_1[1] = odm_read_4byte(dm, R_0xd50);
61 val_2[1] = odm_get_bb_reg(dm, R_0xd54, 0x1fff0000);
64 #if (defined(PHYDM_COMPILE_ABOVE_3SS))
65 val[2] = odm_read_4byte(dm, R_0xd8c);
66 val_1[2] = odm_read_4byte(dm, R_0xd90);
67 val_2[2] = odm_get_bb_reg(dm, R_0xd94, 0x1fff0000);
70 #if (defined(PHYDM_COMPILE_ABOVE_4SS))
71 val[3] = odm_read_4byte(dm, R_0xdcc);
72 val_1[3] = odm_read_4byte(dm, R_0xdd0);
73 val_2[3] = odm_get_bb_reg(dm, R_0xdd4, 0x1fff0000);
76 for (i = 0; i < dm->num_rf_path; i++) {
77 val_tmp = val[i] & 0xfff; /*@ Short CFO, S(12,11)*/
78 cfo->cfo_rpt_s[i] = phydm_get_cfo_hz(dm, val_tmp, 12, 11);
80 val_tmp = val[i] >> 16; /*@ Long CFO, S(13,12)*/
81 cfo->cfo_rpt_l[i] = phydm_get_cfo_hz(dm, val_tmp, 13, 12);
83 val_tmp = val_1[i] & 0x7ff; /*@ SCFO, S(11,10)*/
84 cfo->cfo_rpt_sec[i] = phydm_get_cfo_hz(dm, val_tmp, 11, 10);
86 val_tmp = val_1[i] >> 16; /*@ Acq CFO, S(13,12)*/
87 cfo->cfo_rpt_acq[i] = phydm_get_cfo_hz(dm, val_tmp, 13, 12);
89 val_tmp = val_2[i]; /*@ End CFO, S(13,12)*/
90 cfo->cfo_rpt_end[i] = phydm_get_cfo_hz(dm, val_tmp, 13, 12);
95 #if (ODM_IC_11N_SERIES_SUPPORT)
96 void phydm_get_cfo_info_n(void *dm_void, struct phydm_cfo_rpt *cfo)
98 struct dm_struct *dm = (struct dm_struct *)dm_void;
102 odm_set_bb_reg(dm, R_0xd00, BIT(26), 1);
104 val[0] = odm_read_4byte(dm, R_0xdac); /*@ Short CFO*/
105 val[1] = odm_read_4byte(dm, R_0xdb0); /*@ Long CFO*/
106 val[2] = odm_read_4byte(dm, R_0xdb8); /*@ Sec CFO*/
107 val[3] = odm_read_4byte(dm, R_0xde0); /*@ Acq CFO*/
108 val[4] = odm_read_4byte(dm, R_0xdbc); /*@ End CFO*/
111 val_tmp = (val[0] & 0x0fff0000) >> 16; /*@ Short CFO, S(12,11)*/
112 cfo->cfo_rpt_s[0] = phydm_get_cfo_hz(dm, val_tmp, 12, 11);
113 val_tmp = (val[1] & 0x1fff0000) >> 16; /*@ Long CFO, S(13,12)*/
114 cfo->cfo_rpt_l[0] = phydm_get_cfo_hz(dm, val_tmp, 13, 12);
115 val_tmp = (val[2] & 0x7ff0000) >> 16; /*@ Sec CFO, S(11,10)*/
116 cfo->cfo_rpt_sec[0] = phydm_get_cfo_hz(dm, val_tmp, 11, 10);
117 val_tmp = (val[3] & 0x1fff0000) >> 16; /*@ Acq CFO, S(13,12)*/
118 cfo->cfo_rpt_acq[0] = phydm_get_cfo_hz(dm, val_tmp, 13, 12);
119 val_tmp = (val[4] & 0x1fff0000) >> 16; /*@ Acq CFO, S(13,12)*/
120 cfo->cfo_rpt_end[0] = phydm_get_cfo_hz(dm, val_tmp, 13, 12);
122 #if (defined(PHYDM_COMPILE_ABOVE_2SS))
124 val_tmp = val[0] & 0xfff; /*@ Short CFO, S(12,11)*/
125 cfo->cfo_rpt_s[1] = phydm_get_cfo_hz(dm, val_tmp, 12, 11);
126 val_tmp = val[1] & 0x1fff; /*@ Long CFO, S(13,12)*/
127 cfo->cfo_rpt_l[1] = phydm_get_cfo_hz(dm, val_tmp, 13, 12);
128 val_tmp = val[2] & 0x7ff; /*@ Sec CFO, S(11,10)*/
129 cfo->cfo_rpt_sec[1] = phydm_get_cfo_hz(dm, val_tmp, 11, 10);
130 val_tmp = val[3] & 0x1fff; /*@ Acq CFO, S(13,12)*/
131 cfo->cfo_rpt_acq[1] = phydm_get_cfo_hz(dm, val_tmp, 13, 12);
132 val_tmp = val[4] & 0x1fff; /*@ Acq CFO, S(13,12)*/
133 cfo->cfo_rpt_end[1] = phydm_get_cfo_hz(dm, val_tmp, 13, 12);
137 void phydm_set_atc_status(void *dm_void, boolean atc_status)
139 struct dm_struct *dm = (struct dm_struct *)dm_void;
140 struct phydm_cfo_track_struct *cfo_track = &dm->dm_cfo_track;
144 PHYDM_DBG(dm, DBG_CFO_TRK, "[%s]ATC_en=%d\n", __func__, atc_status);
146 if (cfo_track->is_atc_status == atc_status)
149 reg_tmp = ODM_REG(BB_ATC, dm);
150 mask_tmp = ODM_BIT(BB_ATC, dm);
151 odm_set_bb_reg(dm, reg_tmp, mask_tmp, atc_status);
152 cfo_track->is_atc_status = atc_status;
156 phydm_get_atc_status(void *dm_void)
158 boolean atc_status = false;
159 struct dm_struct *dm = (struct dm_struct *)dm_void;
163 reg_tmp = ODM_REG(BB_ATC, dm);
164 mask_tmp = ODM_BIT(BB_ATC, dm);
166 atc_status = (boolean)odm_get_bb_reg(dm, reg_tmp, mask_tmp);
168 PHYDM_DBG(dm, DBG_CFO_TRK, "[%s]atc_status=%d\n", __func__, atc_status);
173 void phydm_get_cfo_info(void *dm_void, struct phydm_cfo_rpt *cfo)
175 struct dm_struct *dm = (struct dm_struct *)dm_void;
177 switch (dm->ic_ip_series) {
178 #if (ODM_IC_11N_SERIES_SUPPORT)
180 phydm_get_cfo_info_n(dm, cfo);
183 #if (ODM_IC_11AC_SERIES_SUPPORT)
185 phydm_get_cfo_info_ac(dm, cfo);
193 void phydm_set_crystal_cap(void *dm_void, u8 crystal_cap)
195 struct dm_struct *dm = (struct dm_struct *)dm_void;
196 struct phydm_cfo_track_struct *cfo_track = &dm->dm_cfo_track;
199 if (cfo_track->crystal_cap == crystal_cap)
202 if (dm->support_ic_type & (ODM_RTL8822C | ODM_RTL8814B)) {
204 reg_val = crystal_cap | (crystal_cap << 7);
207 reg_val = crystal_cap | (crystal_cap << 6);
210 cfo_track->crystal_cap = crystal_cap;
212 if (dm->support_ic_type & (ODM_RTL8188E | ODM_RTL8188F)) {
213 #if (RTL8188E_SUPPORT || RTL8188F_SUPPORT)
214 /* write 0x24[22:17] = 0x24[16:11] = crystal_cap */
215 odm_set_mac_reg(dm, R_0x24, 0x7ff800, reg_val);
218 #if (RTL8812A_SUPPORT)
219 else if (dm->support_ic_type & ODM_RTL8812) {
220 /* write 0x2C[30:25] = 0x2C[24:19] = crystal_cap */
221 odm_set_mac_reg(dm, R_0x2c, 0x7FF80000, reg_val);
224 #if (RTL8703B_SUPPORT || RTL8723B_SUPPORT || RTL8192E_SUPPORT ||\
225 RTL8821A_SUPPORT || RTL8723D_SUPPORT)
226 else if ((dm->support_ic_type &
227 (ODM_RTL8703B | ODM_RTL8723B | ODM_RTL8192E | ODM_RTL8821 |
229 /* @0x2C[23:18] = 0x2C[17:12] = crystal_cap */
230 odm_set_mac_reg(dm, R_0x2c, 0x00FFF000, reg_val);
233 #if (RTL8814A_SUPPORT)
234 else if (dm->support_ic_type & ODM_RTL8814A) {
235 /* write 0x2C[26:21] = 0x2C[20:15] = crystal_cap */
236 odm_set_mac_reg(dm, R_0x2c, 0x07FF8000, reg_val);
239 #if (RTL8822B_SUPPORT || RTL8821C_SUPPORT || RTL8197F_SUPPORT ||\
241 else if (dm->support_ic_type & (ODM_RTL8822B | ODM_RTL8821C |
242 ODM_RTL8197F | ODM_RTL8192F)) {
243 /* write 0x24[30:25] = 0x28[6:1] = crystal_cap */
244 odm_set_mac_reg(dm, R_0x24, 0x7e000000, crystal_cap);
245 odm_set_mac_reg(dm, R_0x28, 0x7e, crystal_cap);
248 #if (RTL8710B_SUPPORT)
249 else if (dm->support_ic_type & (ODM_RTL8710B)) {
250 #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE))
251 /* write 0x60[29:24] = 0x60[23:18] = crystal_cap */
252 HAL_SetSYSOnReg(dm->adapter, R_0x60, 0x3FFC0000, reg_val);
256 #if (RTL8822C_SUPPORT || RTL8814B_SUPPORT)
257 else if (dm->support_ic_type & (ODM_RTL8822C | ODM_RTL8814B)) {
258 /* write 0x1040[23:17] = 0x1040[16:10] = crystal_cap */
259 odm_set_mac_reg(dm, R_0x1040, 0x00FFFC00, reg_val);
262 PHYDM_DBG(dm, DBG_CFO_TRK, "Set rystal_cap = 0x%x\n",
263 cfo_track->crystal_cap);
266 void phydm_cfo_tracking_reset(void *dm_void)
268 struct dm_struct *dm = (struct dm_struct *)dm_void;
269 struct phydm_cfo_track_struct *cfo_track = &dm->dm_cfo_track;
271 PHYDM_DBG(dm, DBG_CFO_TRK, "%s ======>\n", __func__);
273 if (dm->support_ic_type & (ODM_RTL8822C | ODM_RTL8814B))
274 cfo_track->def_x_cap = cfo_track->crystal_cap_default & 0x7F;
276 cfo_track->def_x_cap = cfo_track->crystal_cap_default & 0x3f;
278 cfo_track->is_adjust = true;
280 if (cfo_track->crystal_cap > cfo_track->def_x_cap) {
281 phydm_set_crystal_cap(dm, cfo_track->crystal_cap - 1);
282 PHYDM_DBG(dm, DBG_CFO_TRK, "approch to Init-val (0x%x)\n",
283 cfo_track->crystal_cap);
285 } else if (cfo_track->crystal_cap < cfo_track->def_x_cap) {
286 phydm_set_crystal_cap(dm, cfo_track->crystal_cap + 1);
287 PHYDM_DBG(dm, DBG_CFO_TRK, "approch to init-val 0x%x\n",
288 cfo_track->crystal_cap);
291 #if ODM_IC_11N_SERIES_SUPPORT
292 #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE))
293 if (dm->support_ic_type & ODM_IC_11N_SERIES)
294 phydm_set_atc_status(dm, true);
299 void phydm_cfo_tracking_init(void *dm_void)
301 struct dm_struct *dm = (struct dm_struct *)dm_void;
302 struct phydm_cfo_track_struct *cfo_track = &dm->dm_cfo_track;
304 PHYDM_DBG(dm, DBG_CFO_TRK, "[%s]=========>\n", __func__);
305 if (dm->support_ic_type & (ODM_RTL8822C | ODM_RTL8814B))
306 cfo_track->crystal_cap = cfo_track->crystal_cap_default & 0x7F;
308 cfo_track->crystal_cap = cfo_track->crystal_cap_default & 0x3f;
310 cfo_track->def_x_cap = cfo_track->crystal_cap;
311 cfo_track->is_adjust = true;
312 PHYDM_DBG(dm, DBG_CFO_TRK, "crystal_cap=0x%x\n", cfo_track->def_x_cap);
314 #if (RTL8822B_SUPPORT || RTL8821C_SUPPORT)
315 /* @Crystal cap. control by WiFi */
316 if (dm->support_ic_type & (ODM_RTL8822B | ODM_RTL8821C))
317 odm_set_mac_reg(dm, R_0x10, 0x40, 0x1);
321 void phydm_cfo_tracking(void *dm_void)
323 struct dm_struct *dm = (struct dm_struct *)dm_void;
324 struct phydm_cfo_track_struct *cfo_track = &dm->dm_cfo_track;
325 s32 cfo_avg = 0, cfo_path_sum = 0, cfo_abs = 0;
326 u32 cfo_rpt_sum = 0, cfo_khz_avg[4] = {0};
327 s8 crystal_cap = cfo_track->crystal_cap;
328 u8 i = 0, valid_path_cnt = 0;
330 if (!(dm->support_ability & ODM_BB_CFO_TRACKING))
333 PHYDM_DBG(dm, DBG_CFO_TRK, "%s ======>\n", __func__);
335 if (!dm->is_linked || !dm->is_one_entry_only) {
336 phydm_cfo_tracking_reset(dm);
337 PHYDM_DBG(dm, DBG_CFO_TRK, "is_linked=%d, one_entry_only=%d\n",
338 dm->is_linked, dm->is_one_entry_only);
342 if (cfo_track->packet_count == cfo_track->packet_count_pre) {
343 PHYDM_DBG(dm, DBG_CFO_TRK, "Pkt cnt doesn't change\n");
346 cfo_track->packet_count_pre = cfo_track->packet_count;
349 for (i = 0; i < dm->num_rf_path; i++) {
350 if (cfo_track->CFO_cnt[i] == 0)
355 if (cfo_track->CFO_tail[i] < 0)
356 cfo_abs = 0 - cfo_track->CFO_tail[i];
358 cfo_abs = cfo_track->CFO_tail[i];
360 cfo_rpt_sum = (u32)CFO_HW_RPT_2_KHZ(cfo_abs);
361 cfo_khz_avg[i] = cfo_rpt_sum / cfo_track->CFO_cnt[i];
363 PHYDM_DBG(dm, DBG_CFO_TRK,
364 "[Path-%d] CFO_sum=((%d)), cnt=((%d)), CFO_avg=((%s%d))kHz\n",
365 i, cfo_rpt_sum, cfo_track->CFO_cnt[i],
366 ((cfo_track->CFO_tail[i] < 0) ? "-" : " "),
370 for (i = 0; i < valid_path_cnt; i++) {
371 if (cfo_track->CFO_tail[i] < 0)
372 cfo_path_sum += (0 - (s32)cfo_khz_avg[i]);
374 cfo_path_sum += (s32)cfo_khz_avg[i];
377 if (valid_path_cnt >= 2)
378 cfo_avg = cfo_path_sum / valid_path_cnt;
380 cfo_avg = cfo_path_sum;
382 cfo_track->CFO_ave_pre = cfo_avg;
384 PHYDM_DBG(dm, DBG_CFO_TRK, "path_cnt=%d, CFO_avg_path=%d kHz\n",
385 valid_path_cnt, cfo_avg);
388 for (i = 0; i < dm->num_rf_path; i++) {
389 cfo_track->CFO_tail[i] = 0;
390 cfo_track->CFO_cnt[i] = 0;
393 /* To adjust crystal cap or not */
394 if (!cfo_track->is_adjust) {
395 if (cfo_avg > CFO_TRK_ENABLE_TH ||
396 cfo_avg < (-CFO_TRK_ENABLE_TH))
397 cfo_track->is_adjust = true;
399 if (cfo_avg < CFO_TRK_STOP_TH &&
400 cfo_avg > (-CFO_TRK_STOP_TH))
401 cfo_track->is_adjust = false;
404 #ifdef ODM_CONFIG_BT_COEXIST
405 /*@BT case: Disable CFO tracking */
406 if (dm->bt_info_table.is_bt_enabled) {
407 cfo_track->is_adjust = false;
408 phydm_set_crystal_cap(dm, cfo_track->def_x_cap);
409 PHYDM_DBG(dm, DBG_CFO_TRK, "[BT]Disable CFO_track\n");
413 /*@Adjust Crystal Cap. */
414 if (cfo_track->is_adjust) {
415 if (cfo_avg > CFO_TRK_STOP_TH)
417 else if (cfo_avg < (-CFO_TRK_STOP_TH))
420 if (dm->support_ic_type & (ODM_RTL8822C |
422 if (crystal_cap > 0x7F)
425 if (crystal_cap > 0x3F)
431 phydm_set_crystal_cap(dm, (u8)crystal_cap);
434 PHYDM_DBG(dm, DBG_CFO_TRK, "X_cap{Curr,Default}={0x%x,0x%x}\n",
435 cfo_track->crystal_cap, cfo_track->def_x_cap);
437 /* @Dynamic ATC switch */
438 #if ODM_IC_11N_SERIES_SUPPORT
439 #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE))
440 if (dm->support_ic_type & ODM_IC_11N_SERIES) {
441 if (cfo_avg < CFO_TH_ATC && cfo_avg > -CFO_TH_ATC)
442 phydm_set_atc_status(dm, false);
444 phydm_set_atc_status(dm, true);
452 void phydm_parsing_cfo(void *dm_void, void *pktinfo_void, s8 *pcfotail,
455 struct dm_struct *dm = (struct dm_struct *)dm_void;
456 struct phydm_perpkt_info_struct *pktinfo = NULL;
457 struct phydm_cfo_track_struct *cfo_track = &dm->dm_cfo_track;
458 boolean valid_info = false;
461 if (!(dm->support_ability & ODM_BB_CFO_TRACKING))
464 pktinfo = (struct phydm_perpkt_info_struct *)pktinfo_void;
466 #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE))
467 if (pktinfo->is_packet_match_bssid)
470 if (dm->number_active_client == 1)
474 if (num_ss > dm->num_rf_path) /*@For fool proof*/
475 num_ss = dm->num_rf_path;
477 PHYDM_DBG(dm, DBG_CFO_TRK, "num_ss=%d, num_rf_path=%d\n",
478 num_ss, dm->num_rf_path);
481 /* @ Update CFO report for path-A & path-B */
482 /* Only paht-A and path-B have CFO tail and short CFO */
483 for (i = 0; i < num_ss; i++) {
484 cfo_track->CFO_tail[i] += pcfotail[i];
485 cfo_track->CFO_cnt[i]++;
487 PHYDM_DBG(dm, DBG_CFO_TRK,
488 "[ID %d][path %d][rate 0x%x] CFO_tail = ((%d)), CFO_tail_sum = ((%d)), CFO_cnt = ((%d))\n",
489 pktinfo->station_id, i, pktinfo->data_rate,
490 pcfotail[i], cfo_track->CFO_tail[i],
491 cfo_track->CFO_cnt[i]);
495 /* @ Update packet counter */
496 if (cfo_track->packet_count == 0xffffffff)
497 cfo_track->packet_count = 0;
499 cfo_track->packet_count++;