158391efdSNathan Chancellor // SPDX-License-Identifier: GPL-2.0
2554c0a3aSHans de Goede /******************************************************************************
3554c0a3aSHans de Goede  *
4554c0a3aSHans de Goede  * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
5554c0a3aSHans de Goede  *
6554c0a3aSHans de Goede  ******************************************************************************/
7554c0a3aSHans de Goede 
8554c0a3aSHans de Goede #include "odm_precomp.h"
9554c0a3aSHans de Goede 
odm_SetCrystalCap(void * pDM_VOID,u8 CrystalCap)10554c0a3aSHans de Goede static void odm_SetCrystalCap(void *pDM_VOID, u8 CrystalCap)
11554c0a3aSHans de Goede {
12f8010da6SMarco Cesati 	struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID;
130c10f844SMarco Cesati 	struct cfo_tracking *pCfoTrack = &pDM_Odm->DM_CfoTrack;
14554c0a3aSHans de Goede 
15554c0a3aSHans de Goede 	if (pCfoTrack->CrystalCap == CrystalCap)
16554c0a3aSHans de Goede 		return;
17554c0a3aSHans de Goede 
18554c0a3aSHans de Goede 	pCfoTrack->CrystalCap = CrystalCap;
19554c0a3aSHans de Goede 
20554c0a3aSHans de Goede 	/*  0x2C[23:18] = 0x2C[17:12] = CrystalCap */
21554c0a3aSHans de Goede 	CrystalCap = CrystalCap & 0x3F;
22554c0a3aSHans de Goede 	PHY_SetBBReg(
23554c0a3aSHans de Goede 		pDM_Odm->Adapter,
24554c0a3aSHans de Goede 		REG_MAC_PHY_CTRL,
25554c0a3aSHans de Goede 		0x00FFF000,
26554c0a3aSHans de Goede 		(CrystalCap | (CrystalCap << 6))
27554c0a3aSHans de Goede 	);
28554c0a3aSHans de Goede }
29554c0a3aSHans de Goede 
odm_GetDefaultCrytaltalCap(void * pDM_VOID)30554c0a3aSHans de Goede static u8 odm_GetDefaultCrytaltalCap(void *pDM_VOID)
31554c0a3aSHans de Goede {
32f8010da6SMarco Cesati 	struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID;
33554c0a3aSHans de Goede 
34554c0a3aSHans de Goede 	struct adapter *Adapter = pDM_Odm->Adapter;
35554c0a3aSHans de Goede 	struct hal_com_data *pHalData = GET_HAL_DATA(Adapter);
36554c0a3aSHans de Goede 
375a436cb1SColin Ian King 	return pHalData->CrystalCap & 0x3f;
38554c0a3aSHans de Goede }
39554c0a3aSHans de Goede 
odm_SetATCStatus(void * pDM_VOID,bool ATCStatus)40554c0a3aSHans de Goede static void odm_SetATCStatus(void *pDM_VOID, bool ATCStatus)
41554c0a3aSHans de Goede {
42f8010da6SMarco Cesati 	struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID;
430c10f844SMarco Cesati 	struct cfo_tracking *pCfoTrack = &pDM_Odm->DM_CfoTrack;
44554c0a3aSHans de Goede 
45554c0a3aSHans de Goede 	if (pCfoTrack->bATCStatus == ATCStatus)
46554c0a3aSHans de Goede 		return;
47554c0a3aSHans de Goede 
48554c0a3aSHans de Goede 	PHY_SetBBReg(
49554c0a3aSHans de Goede 		pDM_Odm->Adapter,
50554c0a3aSHans de Goede 		ODM_REG(BB_ATC, pDM_Odm),
51554c0a3aSHans de Goede 		ODM_BIT(BB_ATC, pDM_Odm),
52554c0a3aSHans de Goede 		ATCStatus
53554c0a3aSHans de Goede 	);
54554c0a3aSHans de Goede 	pCfoTrack->bATCStatus = ATCStatus;
55554c0a3aSHans de Goede }
56554c0a3aSHans de Goede 
odm_GetATCStatus(void * pDM_VOID)57554c0a3aSHans de Goede static bool odm_GetATCStatus(void *pDM_VOID)
58554c0a3aSHans de Goede {
59554c0a3aSHans de Goede 	bool ATCStatus;
60f8010da6SMarco Cesati 	struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID;
61554c0a3aSHans de Goede 
62554c0a3aSHans de Goede 	ATCStatus = (bool)PHY_QueryBBReg(
63554c0a3aSHans de Goede 		pDM_Odm->Adapter,
64554c0a3aSHans de Goede 		ODM_REG(BB_ATC, pDM_Odm),
65554c0a3aSHans de Goede 		ODM_BIT(BB_ATC, pDM_Odm)
66554c0a3aSHans de Goede 	);
67554c0a3aSHans de Goede 	return ATCStatus;
68554c0a3aSHans de Goede }
69554c0a3aSHans de Goede 
ODM_CfoTrackingReset(void * pDM_VOID)70554c0a3aSHans de Goede void ODM_CfoTrackingReset(void *pDM_VOID)
71554c0a3aSHans de Goede {
72f8010da6SMarco Cesati 	struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID;
730c10f844SMarco Cesati 	struct cfo_tracking *pCfoTrack = &pDM_Odm->DM_CfoTrack;
74554c0a3aSHans de Goede 
75554c0a3aSHans de Goede 	pCfoTrack->DefXCap = odm_GetDefaultCrytaltalCap(pDM_Odm);
76554c0a3aSHans de Goede 	pCfoTrack->bAdjust = true;
77554c0a3aSHans de Goede 
78554c0a3aSHans de Goede 	odm_SetCrystalCap(pDM_Odm, pCfoTrack->DefXCap);
79554c0a3aSHans de Goede 	odm_SetATCStatus(pDM_Odm, true);
80554c0a3aSHans de Goede }
81554c0a3aSHans de Goede 
ODM_CfoTrackingInit(void * pDM_VOID)82554c0a3aSHans de Goede void ODM_CfoTrackingInit(void *pDM_VOID)
83554c0a3aSHans de Goede {
84f8010da6SMarco Cesati 	struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID;
850c10f844SMarco Cesati 	struct cfo_tracking *pCfoTrack = &pDM_Odm->DM_CfoTrack;
86554c0a3aSHans de Goede 
87554c0a3aSHans de Goede 	pCfoTrack->DefXCap =
88554c0a3aSHans de Goede 		pCfoTrack->CrystalCap = odm_GetDefaultCrytaltalCap(pDM_Odm);
89554c0a3aSHans de Goede 	pCfoTrack->bATCStatus = odm_GetATCStatus(pDM_Odm);
90554c0a3aSHans de Goede 	pCfoTrack->bAdjust = true;
91554c0a3aSHans de Goede }
92554c0a3aSHans de Goede 
ODM_CfoTracking(void * pDM_VOID)93554c0a3aSHans de Goede void ODM_CfoTracking(void *pDM_VOID)
94554c0a3aSHans de Goede {
95f8010da6SMarco Cesati 	struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID;
960c10f844SMarco Cesati 	struct cfo_tracking *pCfoTrack = &pDM_Odm->DM_CfoTrack;
97*9d535e92SFabio Aiuto 	int CFO_kHz_A, CFO_ave = 0;
98554c0a3aSHans de Goede 	int CFO_ave_diff;
99554c0a3aSHans de Goede 	int CrystalCap = (int)pCfoTrack->CrystalCap;
100554c0a3aSHans de Goede 	u8 Adjust_Xtal = 1;
101554c0a3aSHans de Goede 
102554c0a3aSHans de Goede 	/* 4 Support ability */
103554c0a3aSHans de Goede 	if (!(pDM_Odm->SupportAbility & ODM_BB_CFO_TRACKING)) {
104554c0a3aSHans de Goede 		return;
105554c0a3aSHans de Goede 	}
106554c0a3aSHans de Goede 
107554c0a3aSHans de Goede 	if (!pDM_Odm->bLinked || !pDM_Odm->bOneEntryOnly) {
108554c0a3aSHans de Goede 		/* 4 No link or more than one entry */
109554c0a3aSHans de Goede 		ODM_CfoTrackingReset(pDM_Odm);
110554c0a3aSHans de Goede 	} else {
111554c0a3aSHans de Goede 		/* 3 1. CFO Tracking */
112554c0a3aSHans de Goede 		/* 4 1.1 No new packet */
113554c0a3aSHans de Goede 		if (pCfoTrack->packetCount == pCfoTrack->packetCount_pre) {
114554c0a3aSHans de Goede 			return;
115554c0a3aSHans de Goede 		}
116554c0a3aSHans de Goede 		pCfoTrack->packetCount_pre = pCfoTrack->packetCount;
117554c0a3aSHans de Goede 
118554c0a3aSHans de Goede 		/* 4 1.2 Calculate CFO */
119554c0a3aSHans de Goede 		CFO_kHz_A =  (int)(pCfoTrack->CFO_tail[0] * 3125)  / 1280;
120554c0a3aSHans de Goede 
121554c0a3aSHans de Goede 		CFO_ave = CFO_kHz_A;
122554c0a3aSHans de Goede 
123554c0a3aSHans de Goede 		/* 4 1.3 Avoid abnormal large CFO */
124554c0a3aSHans de Goede 		CFO_ave_diff =
125554c0a3aSHans de Goede 			(pCfoTrack->CFO_ave_pre >= CFO_ave) ?
126554c0a3aSHans de Goede 			(pCfoTrack->CFO_ave_pre-CFO_ave) :
127554c0a3aSHans de Goede 			(CFO_ave-pCfoTrack->CFO_ave_pre);
128554c0a3aSHans de Goede 
129554c0a3aSHans de Goede 		if (
130554c0a3aSHans de Goede 			CFO_ave_diff > 20 &&
131554c0a3aSHans de Goede 			pCfoTrack->largeCFOHit == 0 &&
132554c0a3aSHans de Goede 			!pCfoTrack->bAdjust
133554c0a3aSHans de Goede 		) {
134554c0a3aSHans de Goede 			pCfoTrack->largeCFOHit = 1;
135554c0a3aSHans de Goede 			return;
136554c0a3aSHans de Goede 		} else
137554c0a3aSHans de Goede 			pCfoTrack->largeCFOHit = 0;
138554c0a3aSHans de Goede 		pCfoTrack->CFO_ave_pre = CFO_ave;
139554c0a3aSHans de Goede 
140554c0a3aSHans de Goede 		/* 4 1.4 Dynamic Xtal threshold */
141554c0a3aSHans de Goede 		if (pCfoTrack->bAdjust == false) {
142554c0a3aSHans de Goede 			if (CFO_ave > CFO_TH_XTAL_HIGH || CFO_ave < (-CFO_TH_XTAL_HIGH))
143554c0a3aSHans de Goede 				pCfoTrack->bAdjust = true;
144554c0a3aSHans de Goede 		} else {
145554c0a3aSHans de Goede 			if (CFO_ave < CFO_TH_XTAL_LOW && CFO_ave > (-CFO_TH_XTAL_LOW))
146554c0a3aSHans de Goede 				pCfoTrack->bAdjust = false;
147554c0a3aSHans de Goede 		}
148554c0a3aSHans de Goede 
149554c0a3aSHans de Goede 		/* 4 1.5 BT case: Disable CFO tracking */
150554c0a3aSHans de Goede 		if (pDM_Odm->bBtEnabled) {
151554c0a3aSHans de Goede 			pCfoTrack->bAdjust = false;
152554c0a3aSHans de Goede 			odm_SetCrystalCap(pDM_Odm, pCfoTrack->DefXCap);
153554c0a3aSHans de Goede 		}
154554c0a3aSHans de Goede 
155554c0a3aSHans de Goede 		/* 4 1.6 Big jump */
156554c0a3aSHans de Goede 		if (pCfoTrack->bAdjust) {
157554c0a3aSHans de Goede 			if (CFO_ave > CFO_TH_XTAL_LOW)
158554c0a3aSHans de Goede 				Adjust_Xtal = Adjust_Xtal+((CFO_ave-CFO_TH_XTAL_LOW)>>2);
159554c0a3aSHans de Goede 			else if (CFO_ave < (-CFO_TH_XTAL_LOW))
160554c0a3aSHans de Goede 				Adjust_Xtal = Adjust_Xtal+((CFO_TH_XTAL_LOW-CFO_ave)>>2);
161554c0a3aSHans de Goede 		}
162554c0a3aSHans de Goede 
163554c0a3aSHans de Goede 		/* 4 1.7 Adjust Crystal Cap. */
164554c0a3aSHans de Goede 		if (pCfoTrack->bAdjust) {
165554c0a3aSHans de Goede 			if (CFO_ave > CFO_TH_XTAL_LOW)
166554c0a3aSHans de Goede 				CrystalCap = CrystalCap + Adjust_Xtal;
167554c0a3aSHans de Goede 			else if (CFO_ave < (-CFO_TH_XTAL_LOW))
168554c0a3aSHans de Goede 				CrystalCap = CrystalCap - Adjust_Xtal;
169554c0a3aSHans de Goede 
170554c0a3aSHans de Goede 			if (CrystalCap > 0x3f)
171554c0a3aSHans de Goede 				CrystalCap = 0x3f;
172554c0a3aSHans de Goede 			else if (CrystalCap < 0)
173554c0a3aSHans de Goede 				CrystalCap = 0;
174554c0a3aSHans de Goede 
175554c0a3aSHans de Goede 			odm_SetCrystalCap(pDM_Odm, (u8)CrystalCap);
176554c0a3aSHans de Goede 		}
177554c0a3aSHans de Goede 
178554c0a3aSHans de Goede 		/* 3 2. Dynamic ATC switch */
179554c0a3aSHans de Goede 		if (CFO_ave < CFO_TH_ATC && CFO_ave > -CFO_TH_ATC) {
180554c0a3aSHans de Goede 			odm_SetATCStatus(pDM_Odm, false);
181554c0a3aSHans de Goede 		} else {
182554c0a3aSHans de Goede 			odm_SetATCStatus(pDM_Odm, true);
183554c0a3aSHans de Goede 		}
184554c0a3aSHans de Goede 	}
185554c0a3aSHans de Goede }
186554c0a3aSHans de Goede 
odm_parsing_cfo(void * dm_void,void * pkt_info_void,s8 * cfotail)187caa976ebSFabio Aiuto void odm_parsing_cfo(void *dm_void, void *pkt_info_void, s8 *cfotail)
188554c0a3aSHans de Goede {
189caa976ebSFabio Aiuto 	struct dm_odm_t *dm_odm = (struct dm_odm_t *)dm_void;
190caa976ebSFabio Aiuto 	struct odm_packet_info *pkt_info = pkt_info_void;
191caa976ebSFabio Aiuto 	struct cfo_tracking *cfo_track = &dm_odm->DM_CfoTrack;
192554c0a3aSHans de Goede 	u8 i;
193554c0a3aSHans de Goede 
194caa976ebSFabio Aiuto 	if (!(dm_odm->SupportAbility & ODM_BB_CFO_TRACKING))
195554c0a3aSHans de Goede 		return;
196554c0a3aSHans de Goede 
197caa976ebSFabio Aiuto 	if (pkt_info->station_id != 0) {
198caa976ebSFabio Aiuto 		/*
199caa976ebSFabio Aiuto 		 * 3 Update CFO report for path-A & path-B
200caa976ebSFabio Aiuto 		 * Only paht-A and path-B have CFO tail and short CFO
201caa976ebSFabio Aiuto 		 */
20261b919feSFabio Aiuto 		for (i = RF_PATH_A; i <= RF_PATH_B; i++)
203caa976ebSFabio Aiuto 			cfo_track->CFO_tail[i] = (int)cfotail[i];
204554c0a3aSHans de Goede 
205554c0a3aSHans de Goede 		/* 3 Update packet counter */
206caa976ebSFabio Aiuto 		if (cfo_track->packetCount == 0xffffffff)
207caa976ebSFabio Aiuto 			cfo_track->packetCount = 0;
208554c0a3aSHans de Goede 		else
209caa976ebSFabio Aiuto 			cfo_track->packetCount++;
210554c0a3aSHans de Goede 	}
211554c0a3aSHans de Goede }
212