xref: /OK3568_Linux_fs/external/rkwifibt/drivers/rtl8188fu/hal/phydm/phydm_cfotracking.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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 | ODM_RTL8710C)) {
215 		crystal_cap &= 0x7F;
216 		reg_val = crystal_cap | (crystal_cap << 7);
217 	} else {
218 		crystal_cap &= 0x3F;
219 		reg_val = crystal_cap | (crystal_cap << 6);
220 	}
221 
222 	cfo_track->crystal_cap = crystal_cap;
223 
224 	if (dm->support_ic_type & (ODM_RTL8188E | ODM_RTL8188F)) {
225 		#if (RTL8188E_SUPPORT || RTL8188F_SUPPORT)
226 		/* write 0x24[22:17] = 0x24[16:11] = crystal_cap */
227 		odm_set_mac_reg(dm, R_0x24, 0x7ff800, reg_val);
228 		#endif
229 	}
230 	#if (RTL8812A_SUPPORT)
231 	else if (dm->support_ic_type & ODM_RTL8812) {
232 		/* write 0x2C[30:25] = 0x2C[24:19] = crystal_cap */
233 		odm_set_mac_reg(dm, R_0x2c, 0x7FF80000, reg_val);
234 	}
235 	#endif
236 	#if (RTL8703B_SUPPORT || RTL8723B_SUPPORT || RTL8192E_SUPPORT ||\
237 	     RTL8821A_SUPPORT || RTL8723D_SUPPORT)
238 	else if ((dm->support_ic_type &
239 		 (ODM_RTL8703B | ODM_RTL8723B | ODM_RTL8192E | ODM_RTL8821 |
240 		 ODM_RTL8723D))) {
241 		/* @0x2C[23:18] = 0x2C[17:12] = crystal_cap */
242 		odm_set_mac_reg(dm, R_0x2c, 0x00FFF000, reg_val);
243 	}
244 	#endif
245 	#if (RTL8814A_SUPPORT)
246 	else if (dm->support_ic_type & ODM_RTL8814A) {
247 		/* write 0x2C[26:21] = 0x2C[20:15] = crystal_cap */
248 		odm_set_mac_reg(dm, R_0x2c, 0x07FF8000, reg_val);
249 	}
250 	#endif
251 	#if (RTL8822B_SUPPORT || RTL8821C_SUPPORT || RTL8197F_SUPPORT ||\
252 	     RTL8192F_SUPPORT || RTL8197G_SUPPORT || RTL8198F_SUPPORT)
253 	else if (dm->support_ic_type & (ODM_RTL8822B | ODM_RTL8821C |
254 		 ODM_RTL8197F | ODM_RTL8192F | ODM_RTL8197G | ODM_RTL8198F)) {
255 		/* write 0x24[30:25] = 0x28[6:1] = crystal_cap */
256 		odm_set_mac_reg(dm, R_0x24, 0x7e000000, crystal_cap);
257 		odm_set_mac_reg(dm, R_0x28, 0x7e, crystal_cap);
258 	}
259 	#endif
260 	#if (RTL8710B_SUPPORT)
261 	else if (dm->support_ic_type & (ODM_RTL8710B)) {
262 		#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE))
263 		/* write 0x60[29:24] = 0x60[23:18] = crystal_cap */
264 		HAL_SetSYSOnReg(dm->adapter, R_0x60, 0x3FFC0000, reg_val);
265 		#endif
266 	}
267 	#endif
268 	#if (RTL8195B_SUPPORT)
269 	else if (dm->support_ic_type & ODM_RTL8195B) {
270 		phydm_set_crystalcap(dm, (u8)(reg_val & 0x7f));
271 	}
272 	#endif
273 	#if (RTL8721D_SUPPORT)
274 	else if (dm->support_ic_type & (ODM_RTL8721D)) {
275 		/* write 0x4800_0228[30:24] crystal_cap */
276 		/*HAL_SetSYSOnReg(dm->adapter, */
277 		/*REG_SYS_XTAL_8721d, 0x7F000000, crystal_cap);*/
278 		u32 temp_val = HAL_READ32(SYSTEM_CTRL_BASE_LP,
279 					   REG_SYS_EFUSE_SYSCFG2);
280 		temp_val = ((crystal_cap << 24) & 0x7F000000)
281 						| (temp_val & (~0x7F000000));
282 		HAL_WRITE32(SYSTEM_CTRL_BASE_LP, REG_SYS_EFUSE_SYSCFG2,
283 			    temp_val);
284 	}
285 	#endif
286 	#if (RTL8710C_SUPPORT)
287 	else if (dm->support_ic_type & (ODM_RTL8710C)) {
288 		/* write MAC reg 0x28[13:7][6:0] crystal_cap */
289 		phydm_set_crystalcap(dm, (u8)(reg_val & 0x7f));
290 	}
291 	#endif
292 
293 #if (RTL8822C_SUPPORT || RTL8814B_SUPPORT || RTL8812F_SUPPORT)
294 	else if (dm->support_ic_type & (ODM_RTL8822C | ODM_RTL8814B |
295 		 ODM_RTL8812F)) {
296 		/* write 0x1040[23:17] = 0x1040[16:10] = crystal_cap */
297 		odm_set_mac_reg(dm, R_0x1040, 0x00FFFC00, reg_val);
298 	} else {
299 		return false;
300 	}
301 #endif
302 	return true;
303 }
304 
phydm_set_crystal_cap(void * dm_void,u8 crystal_cap)305 void phydm_set_crystal_cap(void *dm_void, u8 crystal_cap)
306 {
307 	struct dm_struct *dm = (struct dm_struct *)dm_void;
308 	struct phydm_cfo_track_struct *cfo_track = &dm->dm_cfo_track;
309 
310 	if (cfo_track->crystal_cap == crystal_cap)
311 		return;
312 
313 	if (phydm_set_crystal_cap_reg(dm, crystal_cap))
314 		PHYDM_DBG(dm, DBG_CFO_TRK, "Set crystal_cap = 0x%x\n",
315 			  cfo_track->crystal_cap);
316 	else
317 		PHYDM_DBG(dm, DBG_CFO_TRK, "Set fail\n");
318 }
319 
phydm_cfo_tracking_reset(void * dm_void)320 void phydm_cfo_tracking_reset(void *dm_void)
321 {
322 	struct dm_struct *dm = (struct dm_struct *)dm_void;
323 	struct phydm_cfo_track_struct *cfo_track = &dm->dm_cfo_track;
324 
325 	PHYDM_DBG(dm, DBG_CFO_TRK, "%s ======>\n", __func__);
326 
327 	if (dm->support_ic_type & (ODM_RTL8822C | ODM_RTL8814B | ODM_RTL8195B |
328 	    ODM_RTL8812F))
329 		cfo_track->def_x_cap = cfo_track->crystal_cap_default & 0x7f;
330 	else
331 		cfo_track->def_x_cap = cfo_track->crystal_cap_default & 0x3f;
332 
333 	cfo_track->is_adjust = true;
334 
335 	if (cfo_track->crystal_cap > cfo_track->def_x_cap) {
336 		phydm_set_crystal_cap(dm, cfo_track->crystal_cap - 1);
337 		PHYDM_DBG(dm, DBG_CFO_TRK, "approch to Init-val (0x%x)\n",
338 			  cfo_track->crystal_cap);
339 
340 	} else if (cfo_track->crystal_cap < cfo_track->def_x_cap) {
341 		phydm_set_crystal_cap(dm, cfo_track->crystal_cap + 1);
342 		PHYDM_DBG(dm, DBG_CFO_TRK, "approch to init-val 0x%x\n",
343 			  cfo_track->crystal_cap);
344 	}
345 
346 #if ODM_IC_11N_SERIES_SUPPORT
347 #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE))
348 	if (dm->support_ic_type & ODM_IC_11N_SERIES)
349 		phydm_set_atc_status(dm, true);
350 #endif
351 #endif
352 #ifdef PHYDM_IC_JGR3_SERIES_SUPPORT
353 #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE | ODM_AP))
354 	if (dm->support_ic_type & ODM_RTL8814B) {
355 		/*Disable advance time for CFO residual*/
356 		odm_set_bb_reg(dm, R_0xc2c, BIT29, 0x0);
357 	}
358 #endif
359 #endif
360 }
361 
phydm_cfo_tracking_init(void * dm_void)362 void phydm_cfo_tracking_init(void *dm_void)
363 {
364 	struct dm_struct *dm = (struct dm_struct *)dm_void;
365 	struct phydm_cfo_track_struct *cfo_track = &dm->dm_cfo_track;
366 
367 	PHYDM_DBG(dm, DBG_CFO_TRK, "[%s]=========>\n", __func__);
368 	if (dm->support_ic_type & (ODM_RTL8822C | ODM_RTL8814B | ODM_RTL8195B |
369 	    ODM_RTL8812F))
370 		cfo_track->crystal_cap = cfo_track->crystal_cap_default & 0x7f;
371 	else
372 		cfo_track->crystal_cap = cfo_track->crystal_cap_default & 0x3f;
373 
374 	cfo_track->def_x_cap = cfo_track->crystal_cap;
375 	cfo_track->is_adjust = true;
376 	PHYDM_DBG(dm, DBG_CFO_TRK, "crystal_cap=0x%x\n", cfo_track->def_x_cap);
377 
378 #if (RTL8822B_SUPPORT || RTL8821C_SUPPORT)
379 	/* @Crystal cap. control by WiFi */
380 	if (dm->support_ic_type & (ODM_RTL8822B | ODM_RTL8821C))
381 		odm_set_mac_reg(dm, R_0x10, 0x40, 0x1);
382 #endif
383 }
384 
phydm_cfo_tracking(void * dm_void)385 void phydm_cfo_tracking(void *dm_void)
386 {
387 	struct dm_struct *dm = (struct dm_struct *)dm_void;
388 	struct phydm_cfo_track_struct *cfo_track = &dm->dm_cfo_track;
389 	s32 cfo_avg = 0, cfo_path_sum = 0, cfo_abs = 0;
390 	u32 cfo_rpt_sum = 0, cfo_khz_avg[4] = {0};
391 	s8 crystal_cap = cfo_track->crystal_cap;
392 	u8 i = 0, valid_path_cnt = 0;
393 
394 	if (!(dm->support_ability & ODM_BB_CFO_TRACKING))
395 		return;
396 
397 	PHYDM_DBG(dm, DBG_CFO_TRK, "%s ======>\n", __func__);
398 
399 	if (!dm->is_linked || !dm->is_one_entry_only) {
400 		phydm_cfo_tracking_reset(dm);
401 		PHYDM_DBG(dm, DBG_CFO_TRK, "is_linked=%d, one_entry_only=%d\n",
402 			  dm->is_linked, dm->is_one_entry_only);
403 
404 	} else {
405 		/* No new packet */
406 		if (cfo_track->packet_count == cfo_track->packet_count_pre) {
407 			PHYDM_DBG(dm, DBG_CFO_TRK, "Pkt cnt doesn't change\n");
408 			return;
409 		}
410 		cfo_track->packet_count_pre = cfo_track->packet_count;
411 
412 		/*@Calculate CFO */
413 		for (i = 0; i < dm->num_rf_path; i++) {
414 			if (!(dm->rx_ant_status & BIT(i)))
415 				continue;
416 
417 			valid_path_cnt++;
418 
419 			if (cfo_track->CFO_tail[i] < 0)
420 				cfo_abs = 0 - cfo_track->CFO_tail[i];
421 			else
422 				cfo_abs = cfo_track->CFO_tail[i];
423 
424 			cfo_rpt_sum = (u32)CFO_HW_RPT_2_KHZ(cfo_abs);
425 			cfo_khz_avg[i] = PHYDM_DIV(cfo_rpt_sum,
426 						   cfo_track->CFO_cnt[i]);
427 
428 			PHYDM_DBG(dm, DBG_CFO_TRK,
429 				  "[Path-%d] CFO_sum=((%d)), cnt=((%d)), CFO_avg=((%s%d))kHz\n",
430 				  i, cfo_rpt_sum, cfo_track->CFO_cnt[i],
431 				  ((cfo_track->CFO_tail[i] < 0) ? "-" : " "),
432 				  cfo_khz_avg[i]);
433 
434 			if (cfo_track->CFO_tail[i] < 0)
435 				cfo_path_sum += (0 - (s32)cfo_khz_avg[i]);
436 			else
437 				cfo_path_sum += (s32)cfo_khz_avg[i];
438 		}
439 
440 		if (valid_path_cnt >= 2)
441 			cfo_avg = cfo_path_sum / valid_path_cnt;
442 		else
443 			cfo_avg = cfo_path_sum;
444 
445 		cfo_track->CFO_ave_pre = cfo_avg;
446 
447 		PHYDM_DBG(dm, DBG_CFO_TRK, "path_cnt=%d, CFO_avg_path=%d kHz\n",
448 			  valid_path_cnt, cfo_avg);
449 
450 		/*reset counter*/
451 		for (i = 0; i < dm->num_rf_path; i++) {
452 			cfo_track->CFO_tail[i] = 0;
453 			cfo_track->CFO_cnt[i] = 0;
454 		}
455 
456 		/* To adjust crystal cap or not */
457 		if (!cfo_track->is_adjust) {
458 			if (cfo_avg > CFO_TRK_ENABLE_TH ||
459 			    cfo_avg < (-CFO_TRK_ENABLE_TH))
460 				cfo_track->is_adjust = true;
461 		} else {
462 			if (cfo_avg <= CFO_TRK_STOP_TH &&
463 			    cfo_avg >= (-CFO_TRK_STOP_TH))
464 				cfo_track->is_adjust = false;
465 		}
466 
467 		#ifdef ODM_CONFIG_BT_COEXIST
468 		/*@BT case: Disable CFO tracking */
469 		if (dm->bt_info_table.is_bt_enabled) {
470 			cfo_track->is_adjust = false;
471 			phydm_set_crystal_cap(dm, cfo_track->def_x_cap);
472 			PHYDM_DBG(dm, DBG_CFO_TRK, "[BT]Disable CFO_track\n");
473 		}
474 		#endif
475 
476 		/*@Adjust Crystal Cap. */
477 		if (cfo_track->is_adjust) {
478 			if (cfo_avg > CFO_TRK_STOP_TH)
479 				crystal_cap += 1;
480 			else if (cfo_avg < (-CFO_TRK_STOP_TH))
481 				crystal_cap -= 1;
482 
483 			if (dm->support_ic_type & (ODM_RTL8822C | ODM_RTL8814B |
484 			    ODM_RTL8195B | ODM_RTL8812F)) {
485 				if (crystal_cap > 0x7F)
486 					crystal_cap = 0x7F;
487 			} else {
488 				if (crystal_cap > 0x3F)
489 					crystal_cap = 0x3F;
490 			}
491 			if (crystal_cap < 0)
492 				crystal_cap = 0;
493 
494 			phydm_set_crystal_cap(dm, (u8)crystal_cap);
495 		}
496 
497 		PHYDM_DBG(dm, DBG_CFO_TRK, "X_cap{Curr,Default}={0x%x,0x%x}\n",
498 			  cfo_track->crystal_cap, cfo_track->def_x_cap);
499 
500 		/* @Dynamic ATC switch */
501 		#if ODM_IC_11N_SERIES_SUPPORT
502 		#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE))
503 		if (dm->support_ic_type & ODM_IC_11N_SERIES) {
504 			if (cfo_avg < CFO_TH_ATC && cfo_avg > -CFO_TH_ATC)
505 				phydm_set_atc_status(dm, false);
506 			else
507 				phydm_set_atc_status(dm, true);
508 
509 		}
510 		#endif
511 		#endif
512 		#ifdef PHYDM_IC_JGR3_SERIES_SUPPORT
513 		#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE | ODM_AP))
514 		if (dm->support_ic_type & ODM_RTL8814B) {
515 			//Disable advance time for CFO residual
516 			odm_set_bb_reg(dm, R_0xc2c, BIT29, 0x0);
517 		}
518 		#endif
519 		#endif
520 	}
521 }
522 
phydm_parsing_cfo(void * dm_void,void * pktinfo_void,s8 * pcfotail,u8 num_ss)523 void phydm_parsing_cfo(void *dm_void, void *pktinfo_void, s8 *pcfotail,
524 		       u8 num_ss)
525 {
526 	struct dm_struct *dm = (struct dm_struct *)dm_void;
527 	struct phydm_perpkt_info_struct *pktinfo = NULL;
528 	struct phydm_cfo_track_struct *cfo_track = &dm->dm_cfo_track;
529 	boolean valid_info = false;
530 	u8 i = 0;
531 
532 	if (!(dm->support_ability & ODM_BB_CFO_TRACKING))
533 		return;
534 
535 	pktinfo = (struct phydm_perpkt_info_struct *)pktinfo_void;
536 
537 #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE | ODM_IOT))
538 	if (pktinfo->is_packet_match_bssid)
539 		valid_info = true;
540 #else
541 	if (dm->number_active_client == 1)
542 		valid_info = true;
543 #endif
544 	if (valid_info) {
545 		if (num_ss > dm->num_rf_path) /*@For fool proof*/
546 			num_ss = dm->num_rf_path;
547 		#if 0
548 		PHYDM_DBG(dm, DBG_CFO_TRK, "num_ss=%d, num_rf_path=%d\n",
549 			  num_ss, dm->num_rf_path);
550 		#endif
551 
552 		/* @ Update CFO report for path-A & path-B */
553 		/* Only paht-A and path-B have CFO tail and short CFO */
554 		for (i = 0; i < dm->num_rf_path; i++) {
555 			if (!(dm->rx_ant_status & BIT(i)))
556 				continue;
557 			cfo_track->CFO_tail[i] += pcfotail[i];
558 			cfo_track->CFO_cnt[i]++;
559 			#if 0
560 			PHYDM_DBG(dm, DBG_CFO_TRK,
561 				  "[ID %d][path %d][rate 0x%x] CFO_tail = ((%d)), CFO_tail_sum = ((%d)), CFO_cnt = ((%d))\n",
562 				  pktinfo->station_id, i, pktinfo->data_rate,
563 				  pcfotail[i], cfo_track->CFO_tail[i],
564 				  cfo_track->CFO_cnt[i]);
565 			#endif
566 		}
567 
568 		/* @ Update packet counter */
569 		if (cfo_track->packet_count == 0xffffffff)
570 			cfo_track->packet_count = 0;
571 		else
572 			cfo_track->packet_count++;
573 	}
574 }
575 
576 #if (DM_ODM_SUPPORT_TYPE == ODM_WIN)
phy_Init_crystal_capacity(void * dm_void,u8 crystal_cap)577 void phy_Init_crystal_capacity(void *dm_void, u8 crystal_cap)
578 {
579 	struct dm_struct *dm = (struct dm_struct *)dm_void;
580 
581 	if (!phydm_set_crystal_cap_reg(dm, crystal_cap))
582 		RT_TRACE_F(COMP_INIT, DBG_SERIOUS,
583 			   ("Crystal is not initialized!\n"));
584 }
585 #endif
586 
phydm_cfo_tracking_debug(void * dm_void,char input[][16],u32 * _used,char * output,u32 * _out_len)587 void phydm_cfo_tracking_debug(void *dm_void, char input[][16], u32 *_used,
588 			      char *output, u32 *_out_len)
589 {
590 	struct dm_struct *dm = (struct dm_struct *)dm_void;
591 	struct phydm_cfo_track_struct *cfo_track = &dm->dm_cfo_track;
592 	char help[] = "-h";
593 	u32 var1[10] = {0};
594 	u32 used = *_used;
595 	u32 out_len = *_out_len;
596 
597 	if ((strcmp(input[1], help) == 0)) {
598 		PDM_SNPF(out_len, used, output + used, out_len - used,
599 			 "set Xcap: {1}\n");
600 		PDM_SNPF(out_len, used, output + used, out_len - used,
601 			 "show Xcap: {100}\n");
602 	} else {
603 		PHYDM_SSCANF(input[1], DCMD_DECIMAL, &var1[0]);
604 
605 		if (var1[0] == 1) {
606 			PHYDM_SSCANF(input[2], DCMD_HEX, &var1[1]);
607 			phydm_set_crystal_cap(dm, (u8)var1[1]);
608 			PDM_SNPF(out_len, used, output + used, out_len - used,
609 				 "Set X_cap=0x%x\n", cfo_track->crystal_cap);
610 		} else if (var1[0] == 100) {
611 			PDM_SNPF(out_len, used, output + used, out_len - used,
612 				 "X_cap=0x%x\n", cfo_track->crystal_cap);
613 		}
614 	}
615 	*_used = used;
616 	*_out_len = out_len;
617 }
618 
619