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 * 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
phydm_get_cfo_hz(void * dm_void,u32 val,u8 bit_num,u8 frac_num)28 s32 phydm_get_cfo_hz(void *dm_void, u32 val, u8 bit_num, u8 frac_num)
29 {
30 s32 val_s = 0;
31
32 val_s = phydm_cnvrt_2_sign(val, bit_num);
33
34 if (frac_num == 10) /*@ (X*312500)/1024 ~= X*305*/
35 val_s *= 305;
36 else if (frac_num == 11) /*@ (X*312500)/2048 ~= X*152*/
37 val_s *= 152;
38 else if (frac_num == 12) /*@ (X*312500)/4096 ~= X*76*/
39 val_s *= 76;
40
41 return val_s;
42 }
43
44 #if (ODM_IC_11AC_SERIES_SUPPORT)
phydm_get_cfo_info_ac(void * dm_void,struct phydm_cfo_rpt * cfo)45 void phydm_get_cfo_info_ac(void *dm_void, struct phydm_cfo_rpt *cfo)
46 {
47 struct dm_struct *dm = (struct dm_struct *)dm_void;
48 u8 i = 0;
49 u32 val[4] = {0};
50 u32 val_1[4] = {0};
51 u32 val_2[4] = {0};
52 u32 val_tmp = 0;
53
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);
57
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);
62 #endif
63
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);
68 #endif
69
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);
74 #endif
75
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);
79
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);
82
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);
85
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);
88
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);
91 }
92 }
93 #endif
94
95 #if (ODM_IC_11N_SERIES_SUPPORT)
phydm_get_cfo_info_n(void * dm_void,struct phydm_cfo_rpt * cfo)96 void phydm_get_cfo_info_n(void *dm_void, struct phydm_cfo_rpt *cfo)
97 {
98 struct dm_struct *dm = (struct dm_struct *)dm_void;
99 u32 val[5] = {0};
100 u32 val_tmp = 0;
101
102 odm_set_bb_reg(dm, R_0xd00, BIT(26), 1);
103
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*/
109
110 /*@[path-A]*/
111 if (dm->support_ic_type & (ODM_RTL8721D | ODM_RTL8710C)) {
112 val_tmp = (val[0] & 0x0fff0000) >> 16; /*@ Short CFO, S(12,11)*/
113 cfo->cfo_rpt_s[0] = phydm_get_cfo_hz(dm, val_tmp, 12, 11);
114 val_tmp = (val[1] & 0x0fff0000) >> 16; /*@ Long CFO, S(12,11)*/
115 cfo->cfo_rpt_l[0] = phydm_get_cfo_hz(dm, val_tmp, 12, 11);
116 val_tmp = (val[2] & 0x0fff0000) >> 16; /*@ Sec CFO, S(12,11)*/
117 cfo->cfo_rpt_sec[0] = phydm_get_cfo_hz(dm, val_tmp, 12, 11);
118 val_tmp = (val[3] & 0x0fff0000) >> 16; /*@ Acq CFO, S(12,11)*/
119 cfo->cfo_rpt_acq[0] = phydm_get_cfo_hz(dm, val_tmp, 12, 11);
120 val_tmp = (val[4] & 0x0fff0000) >> 16; /*@ Acq CFO, S(12,11)*/
121 cfo->cfo_rpt_end[0] = phydm_get_cfo_hz(dm, val_tmp, 12, 11);
122 } else {
123 val_tmp = (val[0] & 0x0fff0000) >> 16; /*@ Short CFO, S(12,11)*/
124 cfo->cfo_rpt_s[0] = phydm_get_cfo_hz(dm, val_tmp, 12, 11);
125 val_tmp = (val[1] & 0x1fff0000) >> 16; /*@ Long CFO, S(13,12)*/
126 cfo->cfo_rpt_l[0] = phydm_get_cfo_hz(dm, val_tmp, 13, 12);
127 val_tmp = (val[2] & 0x7ff0000) >> 16; /*@ Sec CFO, S(11,10)*/
128 cfo->cfo_rpt_sec[0] = phydm_get_cfo_hz(dm, val_tmp, 11, 10);
129 val_tmp = (val[3] & 0x1fff0000) >> 16; /*@ Acq CFO, S(13,12)*/
130 cfo->cfo_rpt_acq[0] = phydm_get_cfo_hz(dm, val_tmp, 13, 12);
131 val_tmp = (val[4] & 0x1fff0000) >> 16; /*@ Acq CFO, S(13,12)*/
132 cfo->cfo_rpt_end[0] = phydm_get_cfo_hz(dm, val_tmp, 13, 12);
133 }
134
135 #if (defined(PHYDM_COMPILE_ABOVE_2SS))
136 /*@[path-B]*/
137 val_tmp = val[0] & 0xfff; /*@ Short CFO, S(12,11)*/
138 cfo->cfo_rpt_s[1] = phydm_get_cfo_hz(dm, val_tmp, 12, 11);
139 val_tmp = val[1] & 0x1fff; /*@ Long CFO, S(13,12)*/
140 cfo->cfo_rpt_l[1] = phydm_get_cfo_hz(dm, val_tmp, 13, 12);
141 val_tmp = val[2] & 0x7ff; /*@ Sec CFO, S(11,10)*/
142 cfo->cfo_rpt_sec[1] = phydm_get_cfo_hz(dm, val_tmp, 11, 10);
143 val_tmp = val[3] & 0x1fff; /*@ Acq CFO, S(13,12)*/
144 cfo->cfo_rpt_acq[1] = phydm_get_cfo_hz(dm, val_tmp, 13, 12);
145 val_tmp = val[4] & 0x1fff; /*@ Acq CFO, S(13,12)*/
146 cfo->cfo_rpt_end[1] = phydm_get_cfo_hz(dm, val_tmp, 13, 12);
147 #endif
148 }
149
phydm_set_atc_status(void * dm_void,boolean atc_status)150 void phydm_set_atc_status(void *dm_void, boolean atc_status)
151 {
152 struct dm_struct *dm = (struct dm_struct *)dm_void;
153 struct phydm_cfo_track_struct *cfo_track = &dm->dm_cfo_track;
154 u32 reg_tmp = 0;
155 u32 mask_tmp = 0;
156
157 PHYDM_DBG(dm, DBG_CFO_TRK, "[%s]ATC_en=%d\n", __func__, atc_status);
158
159 if (cfo_track->is_atc_status == atc_status)
160 return;
161
162 reg_tmp = ODM_REG(BB_ATC, dm);
163 mask_tmp = ODM_BIT(BB_ATC, dm);
164 odm_set_bb_reg(dm, reg_tmp, mask_tmp, atc_status);
165 cfo_track->is_atc_status = atc_status;
166 }
167
168 boolean
phydm_get_atc_status(void * dm_void)169 phydm_get_atc_status(void *dm_void)
170 {
171 boolean atc_status = false;
172 struct dm_struct *dm = (struct dm_struct *)dm_void;
173 u32 reg_tmp = 0;
174 u32 mask_tmp = 0;
175
176 reg_tmp = ODM_REG(BB_ATC, dm);
177 mask_tmp = ODM_BIT(BB_ATC, dm);
178
179 atc_status = (boolean)odm_get_bb_reg(dm, reg_tmp, mask_tmp);
180
181 PHYDM_DBG(dm, DBG_CFO_TRK, "[%s]atc_status=%d\n", __func__, atc_status);
182 return atc_status;
183 }
184 #endif
185
phydm_get_cfo_info(void * dm_void,struct phydm_cfo_rpt * cfo)186 void phydm_get_cfo_info(void *dm_void, struct phydm_cfo_rpt *cfo)
187 {
188 struct dm_struct *dm = (struct dm_struct *)dm_void;
189
190 switch (dm->ic_ip_series) {
191 #if (ODM_IC_11N_SERIES_SUPPORT)
192 case PHYDM_IC_N:
193 phydm_get_cfo_info_n(dm, cfo);
194 break;
195 #endif
196 #if (ODM_IC_11AC_SERIES_SUPPORT)
197 case PHYDM_IC_AC:
198 phydm_get_cfo_info_ac(dm, cfo);
199 break;
200 #endif
201 default:
202 break;
203 }
204 }
205
206 boolean
phydm_set_crystal_cap_reg(void * dm_void,u8 crystal_cap)207 phydm_set_crystal_cap_reg(void *dm_void, u8 crystal_cap)
208 {
209 struct dm_struct *dm = (struct dm_struct *)dm_void;
210 struct phydm_cfo_track_struct *cfo_track = &dm->dm_cfo_track;
211 u32 reg_val = 0;
212
213 if (dm->support_ic_type & (ODM_RTL8822C | ODM_RTL8814B |
214 ODM_RTL8195B | ODM_RTL8812F | ODM_RTL8721D |
215 ODM_RTL8710C | ODM_RTL8723F | ODM_RTL8814C)) {
216 crystal_cap &= 0x7F;
217 reg_val = crystal_cap | (crystal_cap << 7);
218 } else {
219 crystal_cap &= 0x3F;
220 reg_val = crystal_cap | (crystal_cap << 6);
221 }
222
223 cfo_track->crystal_cap = crystal_cap;
224
225 if (dm->support_ic_type & (ODM_RTL8188E | ODM_RTL8188F)) {
226 #if (RTL8188E_SUPPORT || RTL8188F_SUPPORT)
227 /* write 0x24[22:17] = 0x24[16:11] = crystal_cap */
228 odm_set_mac_reg(dm, R_0x24, 0x7ff800, reg_val);
229 #endif
230 }
231 #if (RTL8812A_SUPPORT)
232 else if (dm->support_ic_type & ODM_RTL8812) {
233 /* write 0x2C[30:25] = 0x2C[24:19] = crystal_cap */
234 odm_set_mac_reg(dm, R_0x2c, 0x7FF80000, reg_val);
235 }
236 #endif
237 #if (RTL8703B_SUPPORT || RTL8723B_SUPPORT || RTL8192E_SUPPORT ||\
238 RTL8821A_SUPPORT || RTL8723D_SUPPORT)
239 else if ((dm->support_ic_type &
240 (ODM_RTL8703B | ODM_RTL8723B | ODM_RTL8192E | ODM_RTL8821 |
241 ODM_RTL8723D))) {
242 /* @0x2C[23:18] = 0x2C[17:12] = crystal_cap */
243 odm_set_mac_reg(dm, R_0x2c, 0x00FFF000, reg_val);
244 }
245 #endif
246 #if (RTL8814A_SUPPORT)
247 else if (dm->support_ic_type & ODM_RTL8814A) {
248 /* write 0x2C[26:21] = 0x2C[20:15] = crystal_cap */
249 odm_set_mac_reg(dm, R_0x2c, 0x07FF8000, reg_val);
250 }
251 #endif
252 #if (RTL8822B_SUPPORT || RTL8821C_SUPPORT || RTL8197F_SUPPORT ||\
253 RTL8192F_SUPPORT || RTL8197G_SUPPORT || RTL8198F_SUPPORT)
254 else if (dm->support_ic_type & (ODM_RTL8822B | ODM_RTL8821C |
255 ODM_RTL8197F | ODM_RTL8192F | ODM_RTL8197G | ODM_RTL8198F)) {
256 /* write 0x24[30:25] = 0x28[6:1] = crystal_cap */
257 odm_set_mac_reg(dm, R_0x24, 0x7e000000, crystal_cap);
258 odm_set_mac_reg(dm, R_0x28, 0x7e, crystal_cap);
259 }
260 #endif
261 #if (RTL8710B_SUPPORT)
262 else if (dm->support_ic_type & (ODM_RTL8710B)) {
263 #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE))
264 /* write 0x60[29:24] = 0x60[23:18] = crystal_cap */
265 HAL_SetSYSOnReg(dm->adapter, R_0x60, 0x3FFC0000, reg_val);
266 #endif
267 }
268 #endif
269 #if (RTL8195B_SUPPORT)
270 else if (dm->support_ic_type & ODM_RTL8195B) {
271 phydm_set_crystalcap(dm, (u8)(reg_val & 0x7f));
272 }
273 #endif
274 #if (RTL8721D_SUPPORT)
275 else if (dm->support_ic_type & (ODM_RTL8721D)) {
276 /* write 0x4800_0228[30:24] crystal_cap */
277 /*HAL_SetSYSOnReg(dm->adapter, */
278 /*REG_SYS_XTAL_8721d, 0x7F000000, crystal_cap);*/
279 u32 temp_val = HAL_READ32(SYSTEM_CTRL_BASE_LP,
280 REG_SYS_EFUSE_SYSCFG2);
281 temp_val = ((crystal_cap << 24) & 0x7F000000)
282 | (temp_val & (~0x7F000000));
283 HAL_WRITE32(SYSTEM_CTRL_BASE_LP, REG_SYS_EFUSE_SYSCFG2,
284 temp_val);
285 }
286 #endif
287 #if (RTL8710C_SUPPORT)
288 else if (dm->support_ic_type & (ODM_RTL8710C)) {
289 /* write MAC reg 0x28[13:7][6:0] crystal_cap */
290 phydm_set_crystalcap(dm, (u8)(reg_val & 0x7f));
291 }
292 #endif
293 #if (RTL8723F_SUPPORT)
294 else if (dm->support_ic_type & ODM_RTL8723F) {
295 /* write 0x103c[23:17] = 0x103c[16:10] = crystal_cap */
296 odm_set_mac_reg(dm, R_0x103c, 0x00FFFC00, reg_val);
297 }
298 #endif
299 #if (RTL8822C_SUPPORT || RTL8814B_SUPPORT || RTL8812F_SUPPORT)
300 else if (dm->support_ic_type & (ODM_RTL8822C | ODM_RTL8814B |
301 ODM_RTL8812F | ODM_RTL8814C)) {
302 /* write 0x1040[23:17] = 0x1040[16:10] = crystal_cap */
303 odm_set_mac_reg(dm, R_0x1040, 0x00FFFC00, reg_val);
304 } else {
305 return false;
306 }
307 #endif
308 return true;
309 }
310
phydm_set_crystal_cap(void * dm_void,u8 crystal_cap)311 void phydm_set_crystal_cap(void *dm_void, u8 crystal_cap)
312 {
313 struct dm_struct *dm = (struct dm_struct *)dm_void;
314 struct phydm_cfo_track_struct *cfo_track = &dm->dm_cfo_track;
315
316 if (cfo_track->crystal_cap == crystal_cap)
317 return;
318
319 if (phydm_set_crystal_cap_reg(dm, crystal_cap))
320 PHYDM_DBG(dm, DBG_CFO_TRK, "Set crystal_cap = 0x%x\n",
321 cfo_track->crystal_cap);
322 else
323 PHYDM_DBG(dm, DBG_CFO_TRK, "Set fail\n");
324 }
325
phydm_cfo_tracking_reset(void * dm_void)326 void phydm_cfo_tracking_reset(void *dm_void)
327 {
328 struct dm_struct *dm = (struct dm_struct *)dm_void;
329 struct phydm_cfo_track_struct *cfo_track = &dm->dm_cfo_track;
330
331 PHYDM_DBG(dm, DBG_CFO_TRK, "%s ======>\n", __func__);
332
333 if (dm->support_ic_type & (ODM_RTL8822C | ODM_RTL8814B | ODM_RTL8195B |
334 ODM_RTL8812F | ODM_RTL8710C | ODM_RTL8721D | ODM_RTL8723F |
335 ODM_RTL8814C))
336 cfo_track->def_x_cap = cfo_track->crystal_cap_default & 0x7f;
337 else
338 cfo_track->def_x_cap = cfo_track->crystal_cap_default & 0x3f;
339
340 cfo_track->is_adjust = true;
341
342 if (cfo_track->crystal_cap > cfo_track->def_x_cap) {
343 phydm_set_crystal_cap(dm, cfo_track->crystal_cap - 1);
344 PHYDM_DBG(dm, DBG_CFO_TRK, "approch to Init-val (0x%x)\n",
345 cfo_track->crystal_cap);
346
347 } else if (cfo_track->crystal_cap < cfo_track->def_x_cap) {
348 phydm_set_crystal_cap(dm, cfo_track->crystal_cap + 1);
349 PHYDM_DBG(dm, DBG_CFO_TRK, "approch to init-val 0x%x\n",
350 cfo_track->crystal_cap);
351 }
352
353 #if ODM_IC_11N_SERIES_SUPPORT
354 #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE))
355 if (dm->support_ic_type & ODM_IC_11N_SERIES)
356 phydm_set_atc_status(dm, true);
357 #endif
358 #endif
359 #ifdef PHYDM_IC_JGR3_SERIES_SUPPORT
360 #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE | ODM_AP))
361 if (dm->support_ic_type & (ODM_RTL8814B | ODM_RTL8814C)) {
362 /*Disable advance time for CFO residual*/
363 odm_set_bb_reg(dm, R_0xc2c, BIT29, 0x0);
364 }
365 #endif
366 #endif
367 }
368
phydm_cfo_tracking_init(void * dm_void)369 void phydm_cfo_tracking_init(void *dm_void)
370 {
371 struct dm_struct *dm = (struct dm_struct *)dm_void;
372 struct phydm_cfo_track_struct *cfo_track = &dm->dm_cfo_track;
373
374 PHYDM_DBG(dm, DBG_CFO_TRK, "[%s]=========>\n", __func__);
375 if (dm->support_ic_type & (ODM_RTL8822C | ODM_RTL8814B | ODM_RTL8195B |
376 ODM_RTL8812F | ODM_RTL8710C | ODM_RTL8721D | ODM_RTL8723F |
377 ODM_RTL8814C))
378 cfo_track->crystal_cap = cfo_track->crystal_cap_default & 0x7f;
379 else
380 cfo_track->crystal_cap = cfo_track->crystal_cap_default & 0x3f;
381
382 cfo_track->def_x_cap = cfo_track->crystal_cap;
383 cfo_track->is_adjust = true;
384 PHYDM_DBG(dm, DBG_CFO_TRK, "crystal_cap=0x%x\n", cfo_track->def_x_cap);
385
386 #if (RTL8822B_SUPPORT || RTL8821C_SUPPORT)
387 /* @Crystal cap. control by WiFi */
388 if (dm->support_ic_type & (ODM_RTL8822B | ODM_RTL8821C))
389 odm_set_mac_reg(dm, R_0x10, 0x40, 0x1);
390 #endif
391 }
392
phydm_cfo_tracking(void * dm_void)393 void phydm_cfo_tracking(void *dm_void)
394 {
395 struct dm_struct *dm = (struct dm_struct *)dm_void;
396 struct phydm_cfo_track_struct *cfo_track = &dm->dm_cfo_track;
397 s32 cfo_avg = 0, cfo_path_sum = 0, cfo_abs = 0;
398 u32 cfo_rpt_sum = 0, cfo_khz_avg[4] = {0};
399 s8 crystal_cap = cfo_track->crystal_cap;
400 u8 i = 0, valid_path_cnt = 0;
401
402 if (!(dm->support_ability & ODM_BB_CFO_TRACKING))
403 return;
404
405 PHYDM_DBG(dm, DBG_CFO_TRK, "%s ======>\n", __func__);
406
407 if (!dm->is_linked || !dm->is_one_entry_only) {
408 phydm_cfo_tracking_reset(dm);
409 PHYDM_DBG(dm, DBG_CFO_TRK, "is_linked=%d, one_entry_only=%d\n",
410 dm->is_linked, dm->is_one_entry_only);
411
412 } else {
413 /* No new packet */
414 if (cfo_track->packet_count == cfo_track->packet_count_pre) {
415 PHYDM_DBG(dm, DBG_CFO_TRK, "Pkt cnt doesn't change\n");
416 return;
417 }
418 cfo_track->packet_count_pre = cfo_track->packet_count;
419
420 /*@Calculate CFO */
421 for (i = 0; i < dm->num_rf_path; i++) {
422 if (!(dm->rx_ant_status & BIT(i)))
423 continue;
424
425 valid_path_cnt++;
426
427 if (cfo_track->CFO_tail[i] < 0)
428 cfo_abs = 0 - cfo_track->CFO_tail[i];
429 else
430 cfo_abs = cfo_track->CFO_tail[i];
431
432 cfo_rpt_sum = (u32)CFO_HW_RPT_2_KHZ(cfo_abs);
433 cfo_khz_avg[i] = PHYDM_DIV(cfo_rpt_sum,
434 cfo_track->CFO_cnt[i]);
435
436 PHYDM_DBG(dm, DBG_CFO_TRK,
437 "[Path-%d] CFO_sum=((%d)), cnt=((%d)), CFO_avg=((%s%d))kHz\n",
438 i, cfo_rpt_sum, cfo_track->CFO_cnt[i],
439 ((cfo_track->CFO_tail[i] < 0) ? "-" : " "),
440 cfo_khz_avg[i]);
441
442 if (cfo_track->CFO_tail[i] < 0)
443 cfo_path_sum += (0 - (s32)cfo_khz_avg[i]);
444 else
445 cfo_path_sum += (s32)cfo_khz_avg[i];
446 }
447
448 if (valid_path_cnt >= 2)
449 cfo_avg = cfo_path_sum / valid_path_cnt;
450 else
451 cfo_avg = cfo_path_sum;
452
453 cfo_track->CFO_ave_pre = cfo_avg;
454
455 PHYDM_DBG(dm, DBG_CFO_TRK, "path_cnt=%d, CFO_avg_path=%d kHz\n",
456 valid_path_cnt, cfo_avg);
457
458 /*reset counter*/
459 for (i = 0; i < dm->num_rf_path; i++) {
460 cfo_track->CFO_tail[i] = 0;
461 cfo_track->CFO_cnt[i] = 0;
462 }
463
464 /* To adjust crystal cap or not */
465 if (!cfo_track->is_adjust) {
466 if (cfo_avg > CFO_TRK_ENABLE_TH ||
467 cfo_avg < (-CFO_TRK_ENABLE_TH))
468 cfo_track->is_adjust = true;
469 } else {
470 if (cfo_avg <= CFO_TRK_STOP_TH &&
471 cfo_avg >= (-CFO_TRK_STOP_TH))
472 cfo_track->is_adjust = false;
473 }
474
475 #ifdef ODM_CONFIG_BT_COEXIST
476 /*@BT case: Disable CFO tracking */
477 if (dm->bt_info_table.is_bt_enabled) {
478 cfo_track->is_adjust = false;
479 phydm_set_crystal_cap(dm, cfo_track->def_x_cap);
480 PHYDM_DBG(dm, DBG_CFO_TRK, "[BT]Disable CFO_track\n");
481 }
482 #endif
483
484 /*@Adjust Crystal Cap. */
485 if (cfo_track->is_adjust) {
486 if (cfo_avg > CFO_TRK_STOP_TH)
487 crystal_cap += 1;
488 else if (cfo_avg < (-CFO_TRK_STOP_TH))
489 crystal_cap -= 1;
490
491 if (dm->support_ic_type & (ODM_RTL8822C | ODM_RTL8814B |
492 ODM_RTL8195B | ODM_RTL8812F | ODM_RTL8710C |
493 ODM_RTL8721D | ODM_RTL8723F | ODM_RTL8814C)) {
494 if (crystal_cap > 0x7F)
495 crystal_cap = 0x7F;
496 } else {
497 if (crystal_cap > 0x3F)
498 crystal_cap = 0x3F;
499 }
500 if (crystal_cap < 0)
501 crystal_cap = 0;
502
503 phydm_set_crystal_cap(dm, (u8)crystal_cap);
504 }
505
506 PHYDM_DBG(dm, DBG_CFO_TRK, "X_cap{Curr,Default}={0x%x,0x%x}\n",
507 cfo_track->crystal_cap, cfo_track->def_x_cap);
508
509 /* @Dynamic ATC switch */
510 #if ODM_IC_11N_SERIES_SUPPORT
511 #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE))
512 if (dm->support_ic_type & ODM_IC_11N_SERIES) {
513 if (cfo_avg < CFO_TH_ATC && cfo_avg > -CFO_TH_ATC)
514 phydm_set_atc_status(dm, false);
515 else
516 phydm_set_atc_status(dm, true);
517
518 }
519 #endif
520 #endif
521 #ifdef PHYDM_IC_JGR3_SERIES_SUPPORT
522 #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE | ODM_AP))
523 if (dm->support_ic_type & (ODM_RTL8814B | ODM_RTL8814C)) {
524 //Disable advance time for CFO residual
525 odm_set_bb_reg(dm, R_0xc2c, BIT29, 0x0);
526 }
527 #endif
528 #endif
529 }
530 }
531
phydm_parsing_cfo(void * dm_void,void * pktinfo_void,s8 * pcfotail,u8 num_ss)532 void phydm_parsing_cfo(void *dm_void, void *pktinfo_void, s8 *pcfotail,
533 u8 num_ss)
534 {
535 struct dm_struct *dm = (struct dm_struct *)dm_void;
536 struct phydm_perpkt_info_struct *pktinfo = NULL;
537 struct phydm_cfo_track_struct *cfo_track = &dm->dm_cfo_track;
538 boolean valid_info = false;
539 u8 i = 0;
540
541 if (!(dm->support_ability & ODM_BB_CFO_TRACKING))
542 return;
543
544 pktinfo = (struct phydm_perpkt_info_struct *)pktinfo_void;
545
546 #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE | ODM_IOT))
547 if (pktinfo->is_packet_match_bssid)
548 valid_info = true;
549 #else
550 if (dm->number_active_client == 1)
551 valid_info = true;
552 #endif
553 if (valid_info) {
554 if (num_ss > dm->num_rf_path) /*@For fool proof*/
555 num_ss = dm->num_rf_path;
556 #if 0
557 PHYDM_DBG(dm, DBG_CFO_TRK, "num_ss=%d, num_rf_path=%d\n",
558 num_ss, dm->num_rf_path);
559 #endif
560
561 /* @ Update CFO report for path-A & path-B */
562 /* Only paht-A and path-B have CFO tail and short CFO */
563 for (i = 0; i < dm->num_rf_path; i++) {
564 if (!(dm->rx_ant_status & BIT(i)))
565 continue;
566 cfo_track->CFO_tail[i] += pcfotail[i];
567 cfo_track->CFO_cnt[i]++;
568 #if 0
569 PHYDM_DBG(dm, DBG_CFO_TRK,
570 "[ID %d][path %d][rate 0x%x] CFO_tail = ((%d)), CFO_tail_sum = ((%d)), CFO_cnt = ((%d))\n",
571 pktinfo->station_id, i, pktinfo->data_rate,
572 pcfotail[i], cfo_track->CFO_tail[i],
573 cfo_track->CFO_cnt[i]);
574 #endif
575 }
576
577 /* @ Update packet counter */
578 if (cfo_track->packet_count == 0xffffffff)
579 cfo_track->packet_count = 0;
580 else
581 cfo_track->packet_count++;
582 }
583 }
584
585 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
phy_Init_crystal_capacity(void * dm_void,u8 crystal_cap)586 void phy_Init_crystal_capacity(void *dm_void, u8 crystal_cap)
587 {
588 struct dm_struct *dm = (struct dm_struct *)dm_void;
589
590 if (!phydm_set_crystal_cap_reg(dm, crystal_cap))
591 RT_TRACE_F(COMP_INIT, DBG_SERIOUS,
592 ("Crystal is not initialized!\n"));
593 }
594 #endif
595
phydm_cfo_tracking_debug(void * dm_void,char input[][16],u32 * _used,char * output,u32 * _out_len)596 void phydm_cfo_tracking_debug(void *dm_void, char input[][16], u32 *_used,
597 char *output, u32 *_out_len)
598 {
599 struct dm_struct *dm = (struct dm_struct *)dm_void;
600 struct phydm_cfo_track_struct *cfo_track = &dm->dm_cfo_track;
601 char help[] = "-h";
602 u32 var1[10] = {0};
603 u32 used = *_used;
604 u32 out_len = *_out_len;
605
606 if ((strcmp(input[1], help) == 0)) {
607 PDM_SNPF(out_len, used, output + used, out_len - used,
608 "set Xcap: {1}\n");
609 PDM_SNPF(out_len, used, output + used, out_len - used,
610 "show Xcap: {100}\n");
611 } else {
612 PHYDM_SSCANF(input[1], DCMD_DECIMAL, &var1[0]);
613
614 if (var1[0] == 1) {
615 PHYDM_SSCANF(input[2], DCMD_HEX, &var1[1]);
616 phydm_set_crystal_cap(dm, (u8)var1[1]);
617 PDM_SNPF(out_len, used, output + used, out_len - used,
618 "Set X_cap=0x%x\n", cfo_track->crystal_cap);
619 } else if (var1[0] == 100) {
620 PDM_SNPF(out_len, used, output + used, out_len - used,
621 "X_cap=0x%x\n", cfo_track->crystal_cap);
622 }
623 }
624 *_used = used;
625 *_out_len = out_len;
626 }
627
628