1 // SPDX-License-Identifier: GPL-2.0
2 /******************************************************************************
3  *
4  * Copyright(c) 2007 - 2016  Realtek Corporation.
5  *
6  * Contact Information:
7  * wlanfae <wlanfae@realtek.com>
8  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
9  * Hsinchu 300, Taiwan.
10  *
11  * Larry Finger <Larry.Finger@lwfinger.net>
12  *
13  *****************************************************************************/
14 #include "mp_precomp.h"
15 #include "phydm_precomp.h"
16 
odm_set_crystal_cap(void * dm_void,u8 crystal_cap)17 static void odm_set_crystal_cap(void *dm_void, u8 crystal_cap)
18 {
19 	struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
20 	struct cfo_tracking *cfo_track =
21 		(struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK);
22 
23 	if (cfo_track->crystal_cap == crystal_cap)
24 		return;
25 
26 	cfo_track->crystal_cap = crystal_cap;
27 
28 	if (dm->support_ic_type & (ODM_RTL8188E | ODM_RTL8188F)) {
29 		/* write 0x24[22:17] = 0x24[16:11] = crystal_cap */
30 		crystal_cap = crystal_cap & 0x3F;
31 		odm_set_bb_reg(dm, REG_AFE_XTAL_CTRL, 0x007ff800,
32 			       (crystal_cap | (crystal_cap << 6)));
33 	} else if (dm->support_ic_type & ODM_RTL8812) {
34 		/* write 0x2C[30:25] = 0x2C[24:19] = crystal_cap */
35 		crystal_cap = crystal_cap & 0x3F;
36 		odm_set_bb_reg(dm, REG_MAC_PHY_CTRL, 0x7FF80000,
37 			       (crystal_cap | (crystal_cap << 6)));
38 	} else if ((dm->support_ic_type & (ODM_RTL8703B | ODM_RTL8723B |
39 					   ODM_RTL8192E | ODM_RTL8821))) {
40 		/* 0x2C[23:18] = 0x2C[17:12] = crystal_cap */
41 		crystal_cap = crystal_cap & 0x3F;
42 		odm_set_bb_reg(dm, REG_MAC_PHY_CTRL, 0x00FFF000,
43 			       (crystal_cap | (crystal_cap << 6)));
44 	} else if (dm->support_ic_type & ODM_RTL8814A) {
45 		/* write 0x2C[26:21] = 0x2C[20:15] = crystal_cap */
46 		crystal_cap = crystal_cap & 0x3F;
47 		odm_set_bb_reg(dm, REG_MAC_PHY_CTRL, 0x07FF8000,
48 			       (crystal_cap | (crystal_cap << 6)));
49 	} else if (dm->support_ic_type & (ODM_RTL8822B | ODM_RTL8821C)) {
50 		/* write 0x24[30:25] = 0x28[6:1] = crystal_cap */
51 		crystal_cap = crystal_cap & 0x3F;
52 		odm_set_bb_reg(dm, REG_AFE_XTAL_CTRL, 0x7e000000, crystal_cap);
53 		odm_set_bb_reg(dm, REG_AFE_PLL_CTRL, 0x7e, crystal_cap);
54 	} else {
55 		ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
56 			     "%s(): Use default setting.\n", __func__);
57 		odm_set_bb_reg(dm, REG_MAC_PHY_CTRL, 0xFFF000,
58 			       (crystal_cap | (crystal_cap << 6)));
59 	}
60 
61 	ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, "%s(): crystal_cap = 0x%x\n",
62 		     __func__, crystal_cap);
63 
64 	/* JJ modified 20161115 */
65 }
66 
odm_get_default_crytaltal_cap(void * dm_void)67 static u8 odm_get_default_crytaltal_cap(void *dm_void)
68 {
69 	struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
70 	u8 crystal_cap = 0x20;
71 
72 	struct rtl_priv *rtlpriv = (struct rtl_priv *)dm->adapter;
73 	struct rtl_efuse *rtlefuse = rtl_efuse(rtlpriv);
74 
75 	crystal_cap = rtlefuse->crystalcap;
76 
77 	crystal_cap = crystal_cap & 0x3f;
78 
79 	return crystal_cap;
80 }
81 
odm_set_atc_status(void * dm_void,bool atc_status)82 static void odm_set_atc_status(void *dm_void, bool atc_status)
83 {
84 	struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
85 	struct cfo_tracking *cfo_track =
86 		(struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK);
87 
88 	if (cfo_track->is_atc_status == atc_status)
89 		return;
90 
91 	odm_set_bb_reg(dm, ODM_REG(BB_ATC, dm), ODM_BIT(BB_ATC, dm),
92 		       atc_status);
93 	cfo_track->is_atc_status = atc_status;
94 }
95 
odm_get_atc_status(void * dm_void)96 static bool odm_get_atc_status(void *dm_void)
97 {
98 	bool atc_status;
99 	struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
100 
101 	atc_status = (bool)odm_get_bb_reg(dm, ODM_REG(BB_ATC, dm),
102 					  ODM_BIT(BB_ATC, dm));
103 	return atc_status;
104 }
105 
odm_cfo_tracking_reset(void * dm_void)106 void odm_cfo_tracking_reset(void *dm_void)
107 {
108 	struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
109 	struct cfo_tracking *cfo_track =
110 		(struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK);
111 
112 	cfo_track->def_x_cap = odm_get_default_crytaltal_cap(dm);
113 	cfo_track->is_adjust = true;
114 
115 	if (cfo_track->crystal_cap > cfo_track->def_x_cap) {
116 		odm_set_crystal_cap(dm, cfo_track->crystal_cap - 1);
117 		ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
118 			     "%s(): approch default value (0x%x)\n", __func__,
119 			     cfo_track->crystal_cap);
120 	} else if (cfo_track->crystal_cap < cfo_track->def_x_cap) {
121 		odm_set_crystal_cap(dm, cfo_track->crystal_cap + 1);
122 		ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
123 			     "%s(): approch default value (0x%x)\n", __func__,
124 			     cfo_track->crystal_cap);
125 	}
126 
127 	odm_set_atc_status(dm, true);
128 }
129 
odm_cfo_tracking_init(void * dm_void)130 void odm_cfo_tracking_init(void *dm_void)
131 {
132 	struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
133 	struct cfo_tracking *cfo_track =
134 		(struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK);
135 
136 	cfo_track->crystal_cap = odm_get_default_crytaltal_cap(dm);
137 	cfo_track->def_x_cap = cfo_track->crystal_cap;
138 	cfo_track->is_atc_status = odm_get_atc_status(dm);
139 	cfo_track->is_adjust = true;
140 	ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, "%s()=========>\n", __func__);
141 	ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
142 		     "%s(): is_atc_status = %d, crystal_cap = 0x%x\n", __func__,
143 		     cfo_track->is_atc_status, cfo_track->def_x_cap);
144 
145 	/* Crystal cap. control by WiFi */
146 	if (dm->support_ic_type & ODM_RTL8822B)
147 		odm_set_bb_reg(dm, 0x10, 0x40, 0x1);
148 }
149 
odm_cfo_tracking(void * dm_void)150 void odm_cfo_tracking(void *dm_void)
151 {
152 	struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
153 	struct cfo_tracking *cfo_track =
154 		(struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK);
155 	s32 cfo_ave = 0;
156 	u32 cfo_rpt_sum, cfo_khz_avg[4] = {0};
157 	s32 cfo_ave_diff;
158 	s8 crystal_cap = cfo_track->crystal_cap;
159 	u8 adjust_xtal = 1, i, valid_path_cnt = 0;
160 
161 	/* 4 Support ability */
162 	if (!(dm->support_ability & ODM_BB_CFO_TRACKING)) {
163 		ODM_RT_TRACE(
164 			dm, ODM_COMP_CFO_TRACKING,
165 			"%s(): Return: support_ability ODM_BB_CFO_TRACKING is disabled\n",
166 			__func__);
167 		return;
168 	}
169 
170 	ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING, "%s()=========>\n", __func__);
171 
172 	if (!dm->is_linked || !dm->is_one_entry_only) {
173 		/* 4 No link or more than one entry */
174 		odm_cfo_tracking_reset(dm);
175 		ODM_RT_TRACE(
176 			dm, ODM_COMP_CFO_TRACKING,
177 			"%s(): Reset: is_linked = %d, is_one_entry_only = %d\n",
178 			__func__, dm->is_linked, dm->is_one_entry_only);
179 	} else {
180 		/* 3 1. CFO Tracking */
181 		/* 4 1.1 No new packet */
182 		if (cfo_track->packet_count == cfo_track->packet_count_pre) {
183 			ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
184 				     "%s(): packet counter doesn't change\n",
185 				     __func__);
186 			return;
187 		}
188 		cfo_track->packet_count_pre = cfo_track->packet_count;
189 
190 		/* 4 1.2 Calculate CFO */
191 		for (i = 0; i < dm->num_rf_path; i++) {
192 			if (cfo_track->CFO_cnt[i] == 0)
193 				continue;
194 
195 			valid_path_cnt++;
196 			cfo_rpt_sum =
197 				(u32)((cfo_track->CFO_tail[i] < 0) ?
198 					      (0 - cfo_track->CFO_tail[i]) :
199 					      cfo_track->CFO_tail[i]);
200 			cfo_khz_avg[i] = CFO_HW_RPT_2_MHZ(cfo_rpt_sum) /
201 					 cfo_track->CFO_cnt[i];
202 
203 			ODM_RT_TRACE(
204 				dm, ODM_COMP_CFO_TRACKING,
205 				"[path %d] cfo_rpt_sum = (( %d )), CFO_cnt = (( %d )) , CFO_avg= (( %s%d )) kHz\n",
206 				i, cfo_rpt_sum, cfo_track->CFO_cnt[i],
207 				((cfo_track->CFO_tail[i] < 0) ? "-" : " "),
208 				cfo_khz_avg[i]);
209 		}
210 
211 		for (i = 0; i < valid_path_cnt; i++) {
212 			if (cfo_track->CFO_tail[i] < 0) {
213 				/* */
214 				cfo_ave += (0 - (s32)cfo_khz_avg[i]);
215 			} else {
216 				cfo_ave += (s32)cfo_khz_avg[i];
217 			}
218 		}
219 
220 		if (valid_path_cnt >= 2)
221 			cfo_ave = cfo_ave / valid_path_cnt;
222 
223 		ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
224 			     "valid_path_cnt = ((%d)), cfo_ave = ((%d kHz))\n",
225 			     valid_path_cnt, cfo_ave);
226 
227 		/*reset counter*/
228 		for (i = 0; i < dm->num_rf_path; i++) {
229 			cfo_track->CFO_tail[i] = 0;
230 			cfo_track->CFO_cnt[i] = 0;
231 		}
232 
233 		/* 4 1.3 Avoid abnormal large CFO */
234 		cfo_ave_diff = (cfo_track->CFO_ave_pre >= cfo_ave) ?
235 				       (cfo_track->CFO_ave_pre - cfo_ave) :
236 				       (cfo_ave - cfo_track->CFO_ave_pre);
237 		if (cfo_ave_diff > 20 && cfo_track->large_cfo_hit == 0 &&
238 		    !cfo_track->is_adjust) {
239 			ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
240 				     "%s(): first large CFO hit\n", __func__);
241 			cfo_track->large_cfo_hit = 1;
242 			return;
243 		}
244 
245 		cfo_track->large_cfo_hit = 0;
246 		cfo_track->CFO_ave_pre = cfo_ave;
247 
248 		/* 4 1.4 Dynamic Xtal threshold */
249 		if (!cfo_track->is_adjust) {
250 			if (cfo_ave > CFO_TH_XTAL_HIGH ||
251 			    cfo_ave < (-CFO_TH_XTAL_HIGH))
252 				cfo_track->is_adjust = true;
253 		} else {
254 			if (cfo_ave < CFO_TH_XTAL_LOW &&
255 			    cfo_ave > (-CFO_TH_XTAL_LOW))
256 				cfo_track->is_adjust = false;
257 		}
258 
259 		/* 4 1.5 BT case: Disable CFO tracking */
260 		if (dm->is_bt_enabled) {
261 			cfo_track->is_adjust = false;
262 			odm_set_crystal_cap(dm, cfo_track->def_x_cap);
263 			ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
264 				     "%s(): Disable CFO tracking for BT!!\n",
265 				     __func__);
266 		}
267 
268 		/* 4 1.7 Adjust Crystal Cap. */
269 		if (cfo_track->is_adjust) {
270 			if (cfo_ave > CFO_TH_XTAL_LOW)
271 				crystal_cap = crystal_cap + adjust_xtal;
272 			else if (cfo_ave < (-CFO_TH_XTAL_LOW))
273 				crystal_cap = crystal_cap - adjust_xtal;
274 
275 			if (crystal_cap > 0x3f)
276 				crystal_cap = 0x3f;
277 			else if (crystal_cap < 0)
278 				crystal_cap = 0;
279 
280 			odm_set_crystal_cap(dm, (u8)crystal_cap);
281 		}
282 		ODM_RT_TRACE(
283 			dm, ODM_COMP_CFO_TRACKING,
284 			"%s(): Crystal cap = 0x%x, Default Crystal cap = 0x%x\n",
285 			__func__, cfo_track->crystal_cap, cfo_track->def_x_cap);
286 
287 		if (dm->support_ic_type & ODM_IC_11AC_SERIES)
288 			return;
289 
290 		/* 3 2. Dynamic ATC switch */
291 		if (cfo_ave < CFO_TH_ATC && cfo_ave > -CFO_TH_ATC) {
292 			odm_set_atc_status(dm, false);
293 			ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
294 				     "%s(): Disable ATC!!\n", __func__);
295 		} else {
296 			odm_set_atc_status(dm, true);
297 			ODM_RT_TRACE(dm, ODM_COMP_CFO_TRACKING,
298 				     "%s(): Enable ATC!!\n", __func__);
299 		}
300 	}
301 }
302 
odm_parsing_cfo(void * dm_void,void * pktinfo_void,s8 * pcfotail,u8 num_ss)303 void odm_parsing_cfo(void *dm_void, void *pktinfo_void, s8 *pcfotail, u8 num_ss)
304 {
305 	struct phy_dm_struct *dm = (struct phy_dm_struct *)dm_void;
306 	struct dm_per_pkt_info *pktinfo =
307 		(struct dm_per_pkt_info *)pktinfo_void;
308 	struct cfo_tracking *cfo_track =
309 		(struct cfo_tracking *)phydm_get_structure(dm, PHYDM_CFOTRACK);
310 	u8 i;
311 
312 	if (!(dm->support_ability & ODM_BB_CFO_TRACKING))
313 		return;
314 
315 	if (pktinfo->is_packet_match_bssid) {
316 		if (num_ss > dm->num_rf_path) /*For fool proof*/
317 			num_ss = dm->num_rf_path;
318 
319 		/* 3 Update CFO report for path-A & path-B */
320 		/* Only paht-A and path-B have CFO tail and short CFO */
321 		for (i = 0; i < num_ss; i++) {
322 			cfo_track->CFO_tail[i] += pcfotail[i];
323 			cfo_track->CFO_cnt[i]++;
324 		}
325 
326 		/* 3 Update packet counter */
327 		if (cfo_track->packet_count == 0xffffffff)
328 			cfo_track->packet_count = 0;
329 		else
330 			cfo_track->packet_count++;
331 	}
332 }
333