xref: /linux/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c (revision a5f22b9b139762685810aa5a41fd0181488aea13) !
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_GetDefaultCrytaltalCap(void * pDM_VOID)30 static u8 odm_GetDefaultCrytaltalCap(void *pDM_VOID)
31 {
32 	struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID;
33 
34 	struct adapter *Adapter = pDM_Odm->Adapter;
35 	struct hal_com_data *pHalData = GET_HAL_DATA(Adapter);
36 
37 	return pHalData->CrystalCap & 0x3f;
38 }
39 
odm_SetATCStatus(void * pDM_VOID,bool ATCStatus)40 static void odm_SetATCStatus(void *pDM_VOID, bool ATCStatus)
41 {
42 	struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID;
43 	struct cfo_tracking *pCfoTrack = &pDM_Odm->DM_CfoTrack;
44 
45 	if (pCfoTrack->bATCStatus == ATCStatus)
46 		return;
47 
48 	PHY_SetBBReg(
49 		pDM_Odm->Adapter,
50 		ODM_REG(BB_ATC, pDM_Odm),
51 		ODM_BIT(BB_ATC, pDM_Odm),
52 		ATCStatus
53 	);
54 	pCfoTrack->bATCStatus = ATCStatus;
55 }
56 
odm_GetATCStatus(void * pDM_VOID)57 static bool odm_GetATCStatus(void *pDM_VOID)
58 {
59 	bool ATCStatus;
60 	struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID;
61 
62 	ATCStatus = (bool)PHY_QueryBBReg(
63 		pDM_Odm->Adapter,
64 		ODM_REG(BB_ATC, pDM_Odm),
65 		ODM_BIT(BB_ATC, pDM_Odm)
66 	);
67 	return ATCStatus;
68 }
69 
ODM_CfoTrackingReset(void * pDM_VOID)70 void ODM_CfoTrackingReset(void *pDM_VOID)
71 {
72 	struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID;
73 	struct cfo_tracking *pCfoTrack = &pDM_Odm->DM_CfoTrack;
74 
75 	pCfoTrack->DefXCap = odm_GetDefaultCrytaltalCap(pDM_Odm);
76 	pCfoTrack->bAdjust = true;
77 
78 	odm_SetCrystalCap(pDM_Odm, pCfoTrack->DefXCap);
79 	odm_SetATCStatus(pDM_Odm, true);
80 }
81 
ODM_CfoTrackingInit(void * pDM_VOID)82 void ODM_CfoTrackingInit(void *pDM_VOID)
83 {
84 	struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID;
85 	struct cfo_tracking *pCfoTrack = &pDM_Odm->DM_CfoTrack;
86 
87 	pCfoTrack->DefXCap =
88 		pCfoTrack->CrystalCap = odm_GetDefaultCrytaltalCap(pDM_Odm);
89 	pCfoTrack->bATCStatus = odm_GetATCStatus(pDM_Odm);
90 	pCfoTrack->bAdjust = true;
91 }
92 
ODM_CfoTracking(void * pDM_VOID)93 void ODM_CfoTracking(void *pDM_VOID)
94 {
95 	struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID;
96 	struct cfo_tracking *pCfoTrack = &pDM_Odm->DM_CfoTrack;
97 	int CFO_kHz_A, CFO_ave = 0;
98 	int CFO_ave_diff;
99 	int CrystalCap = (int)pCfoTrack->CrystalCap;
100 	u8 Adjust_Xtal = 1;
101 
102 	/* 4 Support ability */
103 	if (!(pDM_Odm->SupportAbility & ODM_BB_CFO_TRACKING))
104 		return;
105 
106 	if (!pDM_Odm->bLinked || !pDM_Odm->bOneEntryOnly) {
107 		/* 4 No link or more than one entry */
108 		ODM_CfoTrackingReset(pDM_Odm);
109 	} else {
110 		/* 3 1. CFO Tracking */
111 		/* 4 1.1 No new packet */
112 		if (pCfoTrack->packetCount == pCfoTrack->packetCount_pre)
113 			return;
114 
115 		pCfoTrack->packetCount_pre = pCfoTrack->packetCount;
116 
117 		/* 4 1.2 Calculate CFO */
118 		CFO_kHz_A =  (int)(pCfoTrack->CFO_tail[0] * 3125)  / 1280;
119 
120 		CFO_ave = CFO_kHz_A;
121 
122 		/* 4 1.3 Avoid abnormal large CFO */
123 		CFO_ave_diff =
124 			(pCfoTrack->CFO_ave_pre >= CFO_ave) ?
125 			(pCfoTrack->CFO_ave_pre-CFO_ave) :
126 			(CFO_ave-pCfoTrack->CFO_ave_pre);
127 
128 		if (
129 			CFO_ave_diff > 20 &&
130 			pCfoTrack->largeCFOHit == 0 &&
131 			!pCfoTrack->bAdjust
132 		) {
133 			pCfoTrack->largeCFOHit = 1;
134 			return;
135 		}
136 
137 		pCfoTrack->largeCFOHit = 0;
138 		pCfoTrack->CFO_ave_pre = CFO_ave;
139 
140 		/* 4 1.4 Dynamic Xtal threshold */
141 		if (pCfoTrack->bAdjust == false) {
142 			if (CFO_ave > CFO_TH_XTAL_HIGH || CFO_ave < (-CFO_TH_XTAL_HIGH))
143 				pCfoTrack->bAdjust = true;
144 		} else {
145 			if (CFO_ave < CFO_TH_XTAL_LOW && CFO_ave > (-CFO_TH_XTAL_LOW))
146 				pCfoTrack->bAdjust = false;
147 		}
148 
149 		/* 4 1.5 BT case: Disable CFO tracking */
150 		if (pDM_Odm->bBtEnabled) {
151 			pCfoTrack->bAdjust = false;
152 			odm_SetCrystalCap(pDM_Odm, pCfoTrack->DefXCap);
153 		}
154 
155 		/* 4 1.6 Big jump */
156 		if (pCfoTrack->bAdjust) {
157 			if (CFO_ave > CFO_TH_XTAL_LOW)
158 				Adjust_Xtal = Adjust_Xtal + ((CFO_ave - CFO_TH_XTAL_LOW) >> 2);
159 			else if (CFO_ave < (-CFO_TH_XTAL_LOW))
160 				Adjust_Xtal = Adjust_Xtal + ((CFO_TH_XTAL_LOW - CFO_ave) >> 2);
161 		}
162 
163 		/* 4 1.7 Adjust Crystal Cap. */
164 		if (pCfoTrack->bAdjust) {
165 			if (CFO_ave > CFO_TH_XTAL_LOW)
166 				CrystalCap = CrystalCap + Adjust_Xtal;
167 			else if (CFO_ave < (-CFO_TH_XTAL_LOW))
168 				CrystalCap = CrystalCap - Adjust_Xtal;
169 
170 			if (CrystalCap > 0x3f)
171 				CrystalCap = 0x3f;
172 			else if (CrystalCap < 0)
173 				CrystalCap = 0;
174 
175 			odm_SetCrystalCap(pDM_Odm, (u8)CrystalCap);
176 		}
177 
178 		/* 3 2. Dynamic ATC switch */
179 		if (CFO_ave < CFO_TH_ATC && CFO_ave > -CFO_TH_ATC)
180 			odm_SetATCStatus(pDM_Odm, false);
181 		else
182 			odm_SetATCStatus(pDM_Odm, true);
183 	}
184 }
185 
odm_parsing_cfo(void * dm_void,void * pkt_info_void,s8 * cfotail)186 void odm_parsing_cfo(void *dm_void, void *pkt_info_void, s8 *cfotail)
187 {
188 	struct dm_odm_t *dm_odm = (struct dm_odm_t *)dm_void;
189 	struct odm_packet_info *pkt_info = pkt_info_void;
190 	struct cfo_tracking *cfo_track = &dm_odm->DM_CfoTrack;
191 	u8 i;
192 
193 	if (!(dm_odm->SupportAbility & ODM_BB_CFO_TRACKING))
194 		return;
195 
196 	if (pkt_info->station_id != 0) {
197 		/*
198 		 * 3 Update CFO report for path-A & path-B
199 		 * Only paht-A and path-B have CFO tail and short CFO
200 		 */
201 		for (i = RF_PATH_A; i <= RF_PATH_B; i++)
202 			cfo_track->CFO_tail[i] = (int)cfotail[i];
203 
204 		/* 3 Update packet counter */
205 		if (cfo_track->packetCount == 0xffffffff)
206 			cfo_track->packetCount = 0;
207 		else
208 			cfo_track->packetCount++;
209 	}
210 }
211