xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/rtl8723bs/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  *****************************************************************************/
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