1 // SPDX-License-Identifier: GPL-2.0
2 /******************************************************************************
3  *
4  * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
5  *
6  ******************************************************************************/
7 
8 #include "odm_precomp.h"
9 
odm_SetCrystalCap(void * pDM_VOID,u8 CrystalCap)10 static void odm_SetCrystalCap(void *pDM_VOID, u8 CrystalCap)
11 {
12 	PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
13 	PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack;
14 
15 	if (pCfoTrack->CrystalCap == CrystalCap)
16 		return;
17 
18 	pCfoTrack->CrystalCap = CrystalCap;
19 
20 	/*  0x2C[23:18] = 0x2C[17:12] = CrystalCap */
21 	CrystalCap = CrystalCap & 0x3F;
22 	PHY_SetBBReg(
23 		pDM_Odm->Adapter,
24 		REG_MAC_PHY_CTRL,
25 		0x00FFF000,
26 		(CrystalCap | (CrystalCap << 6))
27 	);
28 
29 	ODM_RT_TRACE(
30 		pDM_Odm,
31 		ODM_COMP_CFO_TRACKING,
32 		ODM_DBG_LOUD,
33 		(
34 			"odm_SetCrystalCap(): CrystalCap = 0x%x\n",
35 			CrystalCap
36 		)
37 	);
38 }
39 
odm_GetDefaultCrytaltalCap(void * pDM_VOID)40 static u8 odm_GetDefaultCrytaltalCap(void *pDM_VOID)
41 {
42 	PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
43 	u8 CrystalCap = 0x20;
44 
45 	struct adapter *Adapter = pDM_Odm->Adapter;
46 	struct hal_com_data *pHalData = GET_HAL_DATA(Adapter);
47 
48 	CrystalCap = pHalData->CrystalCap;
49 
50 	CrystalCap = CrystalCap & 0x3f;
51 
52 	return CrystalCap;
53 }
54 
odm_SetATCStatus(void * pDM_VOID,bool ATCStatus)55 static void odm_SetATCStatus(void *pDM_VOID, bool ATCStatus)
56 {
57 	PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
58 	PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack;
59 
60 	if (pCfoTrack->bATCStatus == ATCStatus)
61 		return;
62 
63 	PHY_SetBBReg(
64 		pDM_Odm->Adapter,
65 		ODM_REG(BB_ATC, pDM_Odm),
66 		ODM_BIT(BB_ATC, pDM_Odm),
67 		ATCStatus
68 	);
69 	pCfoTrack->bATCStatus = ATCStatus;
70 }
71 
odm_GetATCStatus(void * pDM_VOID)72 static bool odm_GetATCStatus(void *pDM_VOID)
73 {
74 	bool ATCStatus;
75 	PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
76 
77 	ATCStatus = (bool)PHY_QueryBBReg(
78 		pDM_Odm->Adapter,
79 		ODM_REG(BB_ATC, pDM_Odm),
80 		ODM_BIT(BB_ATC, pDM_Odm)
81 	);
82 	return ATCStatus;
83 }
84 
ODM_CfoTrackingReset(void * pDM_VOID)85 void ODM_CfoTrackingReset(void *pDM_VOID)
86 {
87 	PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
88 	PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack;
89 
90 	pCfoTrack->DefXCap = odm_GetDefaultCrytaltalCap(pDM_Odm);
91 	pCfoTrack->bAdjust = true;
92 
93 	odm_SetCrystalCap(pDM_Odm, pCfoTrack->DefXCap);
94 	odm_SetATCStatus(pDM_Odm, true);
95 }
96 
ODM_CfoTrackingInit(void * pDM_VOID)97 void ODM_CfoTrackingInit(void *pDM_VOID)
98 {
99 	PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
100 	PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack;
101 
102 	pCfoTrack->DefXCap =
103 		pCfoTrack->CrystalCap = odm_GetDefaultCrytaltalCap(pDM_Odm);
104 	pCfoTrack->bATCStatus = odm_GetATCStatus(pDM_Odm);
105 	pCfoTrack->bAdjust = true;
106 	ODM_RT_TRACE(
107 		pDM_Odm,
108 		ODM_COMP_CFO_TRACKING,
109 		ODM_DBG_LOUD,
110 		("ODM_CfoTracking_init() =========>\n")
111 	);
112 	ODM_RT_TRACE(
113 		pDM_Odm,
114 		ODM_COMP_CFO_TRACKING,
115 		ODM_DBG_LOUD,
116 		(
117 			"ODM_CfoTracking_init(): bATCStatus = %d, CrystalCap = 0x%x\n",
118 			pCfoTrack->bATCStatus,
119 			pCfoTrack->DefXCap
120 		)
121 	);
122 }
123 
ODM_CfoTracking(void * pDM_VOID)124 void ODM_CfoTracking(void *pDM_VOID)
125 {
126 	PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
127 	PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack;
128 	int CFO_kHz_A, CFO_kHz_B, CFO_ave = 0;
129 	int CFO_ave_diff;
130 	int CrystalCap = (int)pCfoTrack->CrystalCap;
131 	u8 Adjust_Xtal = 1;
132 
133 	/* 4 Support ability */
134 	if (!(pDM_Odm->SupportAbility & ODM_BB_CFO_TRACKING)) {
135 		ODM_RT_TRACE(
136 			pDM_Odm,
137 			ODM_COMP_CFO_TRACKING,
138 			ODM_DBG_LOUD,
139 			("ODM_CfoTracking(): Return: SupportAbility ODM_BB_CFO_TRACKING is disabled\n")
140 		);
141 		return;
142 	}
143 
144 	ODM_RT_TRACE(
145 		pDM_Odm,
146 		ODM_COMP_CFO_TRACKING,
147 		ODM_DBG_LOUD,
148 		("ODM_CfoTracking() =========>\n")
149 	);
150 
151 	if (!pDM_Odm->bLinked || !pDM_Odm->bOneEntryOnly) {
152 		/* 4 No link or more than one entry */
153 		ODM_CfoTrackingReset(pDM_Odm);
154 		ODM_RT_TRACE(
155 			pDM_Odm,
156 			ODM_COMP_CFO_TRACKING,
157 			ODM_DBG_LOUD,
158 			(
159 				"ODM_CfoTracking(): Reset: bLinked = %d, bOneEntryOnly = %d\n",
160 				pDM_Odm->bLinked,
161 				pDM_Odm->bOneEntryOnly
162 			)
163 		);
164 	} else {
165 		/* 3 1. CFO Tracking */
166 		/* 4 1.1 No new packet */
167 		if (pCfoTrack->packetCount == pCfoTrack->packetCount_pre) {
168 			ODM_RT_TRACE(
169 				pDM_Odm,
170 				ODM_COMP_CFO_TRACKING,
171 				ODM_DBG_LOUD,
172 				(
173 					"ODM_CfoTracking(): packet counter doesn't change\n"
174 				)
175 			);
176 			return;
177 		}
178 		pCfoTrack->packetCount_pre = pCfoTrack->packetCount;
179 
180 		/* 4 1.2 Calculate CFO */
181 		CFO_kHz_A =  (int)(pCfoTrack->CFO_tail[0] * 3125)  / 1280;
182 		CFO_kHz_B =  (int)(pCfoTrack->CFO_tail[1] * 3125)  / 1280;
183 
184 		if (pDM_Odm->RFType < ODM_2T2R)
185 			CFO_ave = CFO_kHz_A;
186 		else
187 			CFO_ave = (int)(CFO_kHz_A + CFO_kHz_B) >> 1;
188 		ODM_RT_TRACE(
189 			pDM_Odm,
190 			ODM_COMP_CFO_TRACKING,
191 			ODM_DBG_LOUD,
192 			(
193 				"ODM_CfoTracking(): CFO_kHz_A = %dkHz, CFO_kHz_B = %dkHz, CFO_ave = %dkHz\n",
194 				CFO_kHz_A,
195 				CFO_kHz_B,
196 				CFO_ave
197 			)
198 		);
199 
200 		/* 4 1.3 Avoid abnormal large CFO */
201 		CFO_ave_diff =
202 			(pCfoTrack->CFO_ave_pre >= CFO_ave) ?
203 			(pCfoTrack->CFO_ave_pre-CFO_ave) :
204 			(CFO_ave-pCfoTrack->CFO_ave_pre);
205 
206 		if (
207 			CFO_ave_diff > 20 &&
208 			pCfoTrack->largeCFOHit == 0 &&
209 			!pCfoTrack->bAdjust
210 		) {
211 			ODM_RT_TRACE(pDM_Odm, ODM_COMP_CFO_TRACKING, ODM_DBG_LOUD, ("ODM_CfoTracking(): first large CFO hit\n"));
212 			pCfoTrack->largeCFOHit = 1;
213 			return;
214 		} else
215 			pCfoTrack->largeCFOHit = 0;
216 		pCfoTrack->CFO_ave_pre = CFO_ave;
217 
218 		/* 4 1.4 Dynamic Xtal threshold */
219 		if (pCfoTrack->bAdjust == false) {
220 			if (CFO_ave > CFO_TH_XTAL_HIGH || CFO_ave < (-CFO_TH_XTAL_HIGH))
221 				pCfoTrack->bAdjust = true;
222 		} else {
223 			if (CFO_ave < CFO_TH_XTAL_LOW && CFO_ave > (-CFO_TH_XTAL_LOW))
224 				pCfoTrack->bAdjust = false;
225 		}
226 
227 		/* 4 1.5 BT case: Disable CFO tracking */
228 		if (pDM_Odm->bBtEnabled) {
229 			pCfoTrack->bAdjust = false;
230 			odm_SetCrystalCap(pDM_Odm, pCfoTrack->DefXCap);
231 			ODM_RT_TRACE(
232 				pDM_Odm,
233 				ODM_COMP_CFO_TRACKING,
234 				ODM_DBG_LOUD,
235 				("ODM_CfoTracking(): Disable CFO tracking for BT!!\n")
236 			);
237 		}
238 
239 		/* 4 1.6 Big jump */
240 		if (pCfoTrack->bAdjust) {
241 			if (CFO_ave > CFO_TH_XTAL_LOW)
242 				Adjust_Xtal = Adjust_Xtal+((CFO_ave-CFO_TH_XTAL_LOW)>>2);
243 			else if (CFO_ave < (-CFO_TH_XTAL_LOW))
244 				Adjust_Xtal = Adjust_Xtal+((CFO_TH_XTAL_LOW-CFO_ave)>>2);
245 
246 			ODM_RT_TRACE(
247 				pDM_Odm,
248 				ODM_COMP_CFO_TRACKING,
249 				ODM_DBG_LOUD,
250 				(
251 					"ODM_CfoTracking(): Crystal cap offset = %d\n",
252 					Adjust_Xtal
253 				)
254 			);
255 		}
256 
257 		/* 4 1.7 Adjust Crystal Cap. */
258 		if (pCfoTrack->bAdjust) {
259 			if (CFO_ave > CFO_TH_XTAL_LOW)
260 				CrystalCap = CrystalCap + Adjust_Xtal;
261 			else if (CFO_ave < (-CFO_TH_XTAL_LOW))
262 				CrystalCap = CrystalCap - Adjust_Xtal;
263 
264 			if (CrystalCap > 0x3f)
265 				CrystalCap = 0x3f;
266 			else if (CrystalCap < 0)
267 				CrystalCap = 0;
268 
269 			odm_SetCrystalCap(pDM_Odm, (u8)CrystalCap);
270 		}
271 		ODM_RT_TRACE(
272 			pDM_Odm,
273 			ODM_COMP_CFO_TRACKING,
274 			ODM_DBG_LOUD,
275 			(
276 				"ODM_CfoTracking(): Crystal cap = 0x%x, Default Crystal cap = 0x%x\n",
277 				pCfoTrack->CrystalCap,
278 				pCfoTrack->DefXCap
279 			)
280 		);
281 
282 		/* 3 2. Dynamic ATC switch */
283 		if (CFO_ave < CFO_TH_ATC && CFO_ave > -CFO_TH_ATC) {
284 			odm_SetATCStatus(pDM_Odm, false);
285 			ODM_RT_TRACE(
286 				pDM_Odm,
287 				ODM_COMP_CFO_TRACKING,
288 				ODM_DBG_LOUD,
289 				("ODM_CfoTracking(): Disable ATC!!\n")
290 			);
291 		} else {
292 			odm_SetATCStatus(pDM_Odm, true);
293 			ODM_RT_TRACE(
294 				pDM_Odm,
295 				ODM_COMP_CFO_TRACKING,
296 				ODM_DBG_LOUD,
297 				("ODM_CfoTracking(): Enable ATC!!\n")
298 			);
299 		}
300 	}
301 }
302 
ODM_ParsingCFO(void * pDM_VOID,void * pPktinfo_VOID,s8 * pcfotail)303 void ODM_ParsingCFO(void *pDM_VOID, void *pPktinfo_VOID, s8 *pcfotail)
304 {
305 	PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
306 	struct odm_packet_info *pPktinfo = (struct odm_packet_info *)pPktinfo_VOID;
307 	PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack;
308 	u8 i;
309 
310 	if (!(pDM_Odm->SupportAbility & ODM_BB_CFO_TRACKING))
311 		return;
312 
313 	if (pPktinfo->station_id != 0) {
314 		/* 3 Update CFO report for path-A & path-B */
315 		/*  Only paht-A and path-B have CFO tail and short CFO */
316 		for (i = ODM_RF_PATH_A; i <= ODM_RF_PATH_B; i++)
317 			pCfoTrack->CFO_tail[i] = (int)pcfotail[i];
318 
319 		/* 3 Update packet counter */
320 		if (pCfoTrack->packetCount == 0xffffffff)
321 			pCfoTrack->packetCount = 0;
322 		else
323 			pCfoTrack->packetCount++;
324 	}
325 }
326