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