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 
10 #define READ_AND_CONFIG_MP(ic, txt) (ODM_ReadAndConfig_MP_##ic##txt(pDM_Odm))
11 #define READ_AND_CONFIG     READ_AND_CONFIG_MP
12 
13 static u8 odm_query_rx_pwr_percentage(s8 ant_power)
14 {
15 	if ((ant_power <= -100) || (ant_power >= 20))
16 		return	0;
17 	else if (ant_power >= 0)
18 		return	100;
19 	else
20 		return 100 + ant_power;
21 
22 }
23 
24 s32 odm_signal_scale_mapping(struct dm_odm_t *dm_odm, s32 curr_sig)
25 {
26 	s32 ret_sig = 0;
27 
28 	if (dm_odm->SupportInterface  == ODM_ITRF_SDIO) {
29 		if (curr_sig >= 51 && curr_sig <= 100)
30 			ret_sig = 100;
31 		else if (curr_sig >= 41 && curr_sig <= 50)
32 			ret_sig = 80 + ((curr_sig - 40)*2);
33 		else if (curr_sig >= 31 && curr_sig <= 40)
34 			ret_sig = 66 + (curr_sig - 30);
35 		else if (curr_sig >= 21 && curr_sig <= 30)
36 			ret_sig = 54 + (curr_sig - 20);
37 		else if (curr_sig >= 10 && curr_sig <= 20)
38 			ret_sig = 42 + (((curr_sig - 10) * 2) / 3);
39 		else if (curr_sig >= 5 && curr_sig <= 9)
40 			ret_sig = 22 + (((curr_sig - 5) * 3) / 2);
41 		else if (curr_sig >= 1 && curr_sig <= 4)
42 			ret_sig = 6 + (((curr_sig - 1) * 3) / 2);
43 		else
44 			ret_sig = curr_sig;
45 	}
46 
47 	return ret_sig;
48 }
49 
50 static u8 odm_evm_db_to_percentage(s8 value)
51 {
52 	/*  */
53 	/*  -33dB~0dB to 0%~99% */
54 	/*  */
55 	s8 ret_val;
56 
57 	ret_val = value;
58 	ret_val /= 2;
59 
60 	if (ret_val >= 0)
61 		ret_val = 0;
62 	if (ret_val <= -33)
63 		ret_val = -33;
64 
65 	ret_val = 0 - ret_val;
66 	ret_val *= 3;
67 
68 	if (ret_val == 99)
69 		ret_val = 100;
70 
71 	return ret_val;
72 }
73 
74 static s8 odm_cck_rssi(u8 lna_idx, u8 vga_idx)
75 {
76 	s8 rx_pwr_all = 0x00;
77 
78 	switch (lna_idx) {
79 	/* 46  53 73 95 201301231630 */
80 	/*  46 53 77 99 201301241630 */
81 
82 	case 6:
83 		rx_pwr_all = -34 - (2 * vga_idx);
84 		break;
85 	case 4:
86 		rx_pwr_all = -14 - (2 * vga_idx);
87 		break;
88 	case 1:
89 		rx_pwr_all = 6 - (2 * vga_idx);
90 		break;
91 	case 0:
92 		rx_pwr_all = 16 - (2 * vga_idx);
93 		break;
94 	default:
95 		/* rx_pwr_all = -53+(2*(31-VGA_idx)); */
96 		break;
97 	}
98 	return rx_pwr_all;
99 }
100 
101 static void odm_rx_phy_status_parsing(struct dm_odm_t *dm_odm,
102 				      struct odm_phy_info *phy_info,
103 				      u8 *phy_status,
104 				      struct odm_packet_info *pkt_info)
105 {
106 	u8 i;
107 	s8 rx_pwr[4], rx_pwr_all = 0;
108 	u8 evm, pwdb_all = 0, pwdb_all_bt;
109 	u8 rssi, total_rssi = 0;
110 	bool is_cck_rate = false;
111 	u8 rf_rx_num = 0;
112 	u8 lna_idx, vga_idx;
113 	struct phy_status_rpt_8192cd_t *phy_sta_rpt = (struct phy_status_rpt_8192cd_t *)phy_status;
114 
115 	is_cck_rate = pkt_info->data_rate <= DESC_RATE11M;
116 	phy_info->rx_mimo_signal_quality[RF_PATH_A] = -1;
117 	phy_info->rx_mimo_signal_quality[RF_PATH_B] = -1;
118 
119 
120 	if (is_cck_rate) {
121 		u8 cck_agc_rpt;
122 
123 		dm_odm->PhyDbgInfo.NumQryPhyStatusCCK++;
124 
125 		/*
126 		 * (1)Hardware does not provide RSSI for CCK/
127 		 * (2)PWDB, Average PWDB calculated by
128 		 *    hardware (for rate adaptive)
129 		 */
130 
131 		cck_agc_rpt = phy_sta_rpt->cck_agc_rpt_ofdm_cfosho_a;
132 
133 		/*
134 		 * 2011.11.28 LukeLee: 88E use different LNA & VGA gain table
135 		 * The RSSI formula should be modified according to the gain table
136 		 */
137 		lna_idx = ((cck_agc_rpt & 0xE0)>>5);
138 		vga_idx = (cck_agc_rpt & 0x1F);
139 		rx_pwr_all = odm_cck_rssi(lna_idx, vga_idx);
140 		pwdb_all = odm_query_rx_pwr_percentage(rx_pwr_all);
141 		if (pwdb_all > 100)
142 			pwdb_all = 100;
143 
144 		phy_info->rx_pwd_ba11 = pwdb_all;
145 		phy_info->bt_rx_rssi_percentage = pwdb_all;
146 		phy_info->recv_signal_power = rx_pwr_all;
147 
148 		/*  (3) Get Signal Quality (EVM) */
149 
150 		/* if (pPktinfo->bPacketMatchBSSID) */
151 		{
152 			u8 sq, sq_rpt;
153 
154 			if (phy_info->rx_pwd_ba11 > 40 && !dm_odm->bInHctTest)
155 				sq = 100;
156 			else {
157 				sq_rpt = phy_sta_rpt->cck_sig_qual_ofdm_pwdb_all;
158 
159 				if (sq_rpt > 64)
160 					sq = 0;
161 				else if (sq_rpt < 20)
162 					sq = 100;
163 				else
164 					sq = ((64-sq_rpt) * 100) / 44;
165 
166 			}
167 
168 			phy_info->signal_quality = sq;
169 			phy_info->rx_mimo_signal_quality[RF_PATH_A] = sq;
170 			phy_info->rx_mimo_signal_quality[RF_PATH_B] = -1;
171 		}
172 	} else { /* is OFDM rate */
173 		dm_odm->PhyDbgInfo.NumQryPhyStatusOFDM++;
174 
175 		/*
176 		 * (1)Get RSSI for HT rate
177 		 */
178 
179 		for (i = RF_PATH_A; i < RF_PATH_MAX; i++) {
180 			/*  2008/01/30 MH we will judge RF RX path now. */
181 			if (dm_odm->RFPathRxEnable & BIT(i))
182 				rf_rx_num++;
183 			/* else */
184 				/* continue; */
185 
186 			rx_pwr[i] = ((phy_sta_rpt->path_agc[i].gain & 0x3F) * 2) - 110;
187 
188 			phy_info->rx_pwr[i] = rx_pwr[i];
189 
190 			/* Translate DBM to percentage. */
191 			rssi = odm_query_rx_pwr_percentage(rx_pwr[i]);
192 			total_rssi += rssi;
193 
194 			phy_info->rx_mimo_signal_strength[i] = (u8)rssi;
195 
196 			/* Get Rx snr value in DB */
197 			phy_info->rx_snr[i] = dm_odm->PhyDbgInfo.RxSNRdB[i] = (s32)(phy_sta_rpt->path_rxsnr[i]/2);
198 		}
199 
200 		/*
201 		 * (2)PWDB, Average PWDB calculated by hardware (for rate adaptive)
202 		 */
203 		rx_pwr_all = ((phy_sta_rpt->cck_sig_qual_ofdm_pwdb_all >> 1) & 0x7f) - 110;
204 
205 		pwdb_all_bt = pwdb_all = odm_query_rx_pwr_percentage(rx_pwr_all);
206 
207 		phy_info->rx_pwd_ba11 = pwdb_all;
208 		phy_info->bt_rx_rssi_percentage = pwdb_all_bt;
209 		phy_info->rx_power = rx_pwr_all;
210 		phy_info->recv_signal_power = rx_pwr_all;
211 
212 		/*
213 		 * (3)EVM of HT rate
214 		 *
215 		 * Only spatial stream 1 makes sense
216 		 *
217 		 * Do not use shift operation like "rx_evmX >>= 1"
218 		 * because the compiler of free build environment
219 		 * fill most significant bit to "zero" when doing
220 		 * shifting operation which may change a negative
221 		 * value to positive one, then the dbm value (which
222 		 * is supposed to be negative) is not correct
223 		 * anymore.
224 		 */
225 		evm = odm_evm_db_to_percentage(phy_sta_rpt->stream_rxevm[0]); /* dbm */
226 
227 		/*  Fill value in RFD, Get the first spatial stream only */
228 		phy_info->signal_quality = (u8)(evm & 0xff);
229 
230 		phy_info->rx_mimo_signal_quality[RF_PATH_A] = (u8)(evm & 0xff);
231 
232 		odm_parsing_cfo(dm_odm, pkt_info, phy_sta_rpt->path_cfotail);
233 	}
234 
235 	/*
236 	 * UI BSS List signal strength(in percentage), make it good
237 	 * looking, from 0~100.
238 	 * It is assigned to the BSS List in GetValueFromBeaconOrProbeRsp().
239 	 */
240 	if (is_cck_rate) {
241 		phy_info->signal_strength = (u8)(odm_signal_scale_mapping(dm_odm, pwdb_all));
242 	} else {
243 		if (rf_rx_num != 0) {
244 			phy_info->signal_strength = (u8)(odm_signal_scale_mapping(dm_odm, total_rssi /= rf_rx_num));
245 		}
246 	}
247 }
248 
249 static void odm_Process_RSSIForDM(
250 	struct dm_odm_t *pDM_Odm, struct odm_phy_info *pPhyInfo, struct odm_packet_info *pPktinfo
251 )
252 {
253 
254 	s32 UndecoratedSmoothedPWDB, UndecoratedSmoothedCCK, UndecoratedSmoothedOFDM, RSSI_Ave;
255 	u8 isCCKrate = 0;
256 	u8 RSSI_max, RSSI_min, i;
257 	u32 OFDM_pkt = 0;
258 	u32 Weighting = 0;
259 	PSTA_INFO_T pEntry;
260 
261 
262 	if (pPktinfo->station_id == 0xFF)
263 		return;
264 
265 	pEntry = pDM_Odm->pODM_StaInfo[pPktinfo->station_id];
266 
267 	if (!IS_STA_VALID(pEntry))
268 		return;
269 
270 	if ((!pPktinfo->bssid_match))
271 		return;
272 
273 	if (pPktinfo->is_beacon)
274 		pDM_Odm->PhyDbgInfo.NumQryBeaconPkt++;
275 
276 	isCCKrate = ((pPktinfo->data_rate <= DESC_RATE11M)) ? true : false;
277 	pDM_Odm->RxRate = pPktinfo->data_rate;
278 
279 	/* Statistic for antenna/path diversity------------------ */
280 	if (pDM_Odm->SupportAbility & ODM_BB_ANT_DIV) {
281 
282 	}
283 
284 	/* Smart Antenna Debug Message------------------ */
285 
286 	UndecoratedSmoothedCCK = pEntry->rssi_stat.UndecoratedSmoothedCCK;
287 	UndecoratedSmoothedOFDM = pEntry->rssi_stat.UndecoratedSmoothedOFDM;
288 	UndecoratedSmoothedPWDB = pEntry->rssi_stat.UndecoratedSmoothedPWDB;
289 
290 	if (pPktinfo->to_self || pPktinfo->is_beacon) {
291 
292 		if (!isCCKrate) { /* ofdm rate */
293 			if (pPhyInfo->rx_mimo_signal_strength[RF_PATH_B] == 0) {
294 				RSSI_Ave = pPhyInfo->rx_mimo_signal_strength[RF_PATH_A];
295 				pDM_Odm->RSSI_A = pPhyInfo->rx_mimo_signal_strength[RF_PATH_A];
296 				pDM_Odm->RSSI_B = 0;
297 			} else {
298 				pDM_Odm->RSSI_A =  pPhyInfo->rx_mimo_signal_strength[RF_PATH_A];
299 				pDM_Odm->RSSI_B = pPhyInfo->rx_mimo_signal_strength[RF_PATH_B];
300 
301 				if (
302 					pPhyInfo->rx_mimo_signal_strength[RF_PATH_A] >
303 					pPhyInfo->rx_mimo_signal_strength[RF_PATH_B]
304 				) {
305 					RSSI_max = pPhyInfo->rx_mimo_signal_strength[RF_PATH_A];
306 					RSSI_min = pPhyInfo->rx_mimo_signal_strength[RF_PATH_B];
307 				} else {
308 					RSSI_max = pPhyInfo->rx_mimo_signal_strength[RF_PATH_B];
309 					RSSI_min = pPhyInfo->rx_mimo_signal_strength[RF_PATH_A];
310 				}
311 
312 				if ((RSSI_max-RSSI_min) < 3)
313 					RSSI_Ave = RSSI_max;
314 				else if ((RSSI_max-RSSI_min) < 6)
315 					RSSI_Ave = RSSI_max - 1;
316 				else if ((RSSI_max-RSSI_min) < 10)
317 					RSSI_Ave = RSSI_max - 2;
318 				else
319 					RSSI_Ave = RSSI_max - 3;
320 			}
321 
322 			/* 1 Process OFDM RSSI */
323 			if (UndecoratedSmoothedOFDM <= 0)	/*  initialize */
324 				UndecoratedSmoothedOFDM = pPhyInfo->rx_pwd_ba11;
325 			else {
326 				if (pPhyInfo->rx_pwd_ba11 > (u32)UndecoratedSmoothedOFDM) {
327 					UndecoratedSmoothedOFDM =
328 							((UndecoratedSmoothedOFDM*(Rx_Smooth_Factor-1)) +
329 							RSSI_Ave)/Rx_Smooth_Factor;
330 					UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM + 1;
331 				} else {
332 					UndecoratedSmoothedOFDM =
333 							((UndecoratedSmoothedOFDM*(Rx_Smooth_Factor-1)) +
334 							RSSI_Ave)/Rx_Smooth_Factor;
335 				}
336 			}
337 
338 			pEntry->rssi_stat.PacketMap = (pEntry->rssi_stat.PacketMap<<1) | BIT0;
339 
340 		} else {
341 			RSSI_Ave = pPhyInfo->rx_pwd_ba11;
342 			pDM_Odm->RSSI_A = (u8) pPhyInfo->rx_pwd_ba11;
343 			pDM_Odm->RSSI_B = 0;
344 
345 			/* 1 Process CCK RSSI */
346 			if (UndecoratedSmoothedCCK <= 0)	/*  initialize */
347 				UndecoratedSmoothedCCK = pPhyInfo->rx_pwd_ba11;
348 			else {
349 				if (pPhyInfo->rx_pwd_ba11 > (u32)UndecoratedSmoothedCCK) {
350 					UndecoratedSmoothedCCK =
351 							((UndecoratedSmoothedCCK*(Rx_Smooth_Factor-1)) +
352 							pPhyInfo->rx_pwd_ba11)/Rx_Smooth_Factor;
353 					UndecoratedSmoothedCCK = UndecoratedSmoothedCCK + 1;
354 				} else {
355 					UndecoratedSmoothedCCK =
356 							((UndecoratedSmoothedCCK*(Rx_Smooth_Factor-1)) +
357 							pPhyInfo->rx_pwd_ba11)/Rx_Smooth_Factor;
358 				}
359 			}
360 			pEntry->rssi_stat.PacketMap = pEntry->rssi_stat.PacketMap<<1;
361 		}
362 
363 		/* if (pEntry) */
364 		{
365 			/* 2011.07.28 LukeLee: modified to prevent unstable CCK RSSI */
366 			if (pEntry->rssi_stat.ValidBit >= 64)
367 				pEntry->rssi_stat.ValidBit = 64;
368 			else
369 				pEntry->rssi_stat.ValidBit++;
370 
371 			for (i = 0; i < pEntry->rssi_stat.ValidBit; i++)
372 				OFDM_pkt += (u8)(pEntry->rssi_stat.PacketMap>>i)&BIT0;
373 
374 			if (pEntry->rssi_stat.ValidBit == 64) {
375 				Weighting = ((OFDM_pkt<<4) > 64)?64:(OFDM_pkt<<4);
376 				UndecoratedSmoothedPWDB = (Weighting*UndecoratedSmoothedOFDM+(64-Weighting)*UndecoratedSmoothedCCK)>>6;
377 			} else {
378 				if (pEntry->rssi_stat.ValidBit != 0)
379 					UndecoratedSmoothedPWDB = (OFDM_pkt*UndecoratedSmoothedOFDM+(pEntry->rssi_stat.ValidBit-OFDM_pkt)*UndecoratedSmoothedCCK)/pEntry->rssi_stat.ValidBit;
380 				else
381 					UndecoratedSmoothedPWDB = 0;
382 			}
383 
384 			pEntry->rssi_stat.UndecoratedSmoothedCCK = UndecoratedSmoothedCCK;
385 			pEntry->rssi_stat.UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM;
386 			pEntry->rssi_stat.UndecoratedSmoothedPWDB = UndecoratedSmoothedPWDB;
387 		}
388 
389 	}
390 }
391 
392 
393 /*  */
394 /*  Endianness before calling this API */
395 /*  */
396 void odm_phy_status_query(struct dm_odm_t *dm_odm, struct odm_phy_info *phy_info,
397 			  u8 *phy_status, struct odm_packet_info *pkt_info)
398 {
399 
400 	odm_rx_phy_status_parsing(dm_odm, phy_info, phy_status, pkt_info);
401 
402 	if (!dm_odm->RSSI_test)
403 		odm_Process_RSSIForDM(dm_odm, phy_info, pkt_info);
404 }
405 
406 /*  */
407 /*  If you want to add a new IC, Please follow below template and generate a new one. */
408 /*  */
409 /*  */
410 
411 enum hal_status ODM_ConfigRFWithHeaderFile(
412 	struct dm_odm_t *pDM_Odm,
413 	enum ODM_RF_Config_Type ConfigType,
414 	enum rf_path eRFPath
415 )
416 {
417 	if (ConfigType == CONFIG_RF_RADIO)
418 		READ_AND_CONFIG(8723B, _RadioA);
419 	else if (ConfigType == CONFIG_RF_TXPWR_LMT)
420 		READ_AND_CONFIG(8723B, _TXPWR_LMT);
421 
422 	return HAL_STATUS_SUCCESS;
423 }
424 
425 enum hal_status ODM_ConfigRFWithTxPwrTrackHeaderFile(struct dm_odm_t *pDM_Odm)
426 {
427 	if (pDM_Odm->SupportInterface == ODM_ITRF_SDIO)
428 		READ_AND_CONFIG(8723B, _TxPowerTrack_SDIO);
429 
430 	return HAL_STATUS_SUCCESS;
431 }
432 
433 enum hal_status ODM_ConfigBBWithHeaderFile(
434 	struct dm_odm_t *pDM_Odm, enum ODM_BB_Config_Type ConfigType
435 )
436 {
437 	if (ConfigType == CONFIG_BB_PHY_REG)
438 		READ_AND_CONFIG(8723B, _PHY_REG);
439 	else if (ConfigType == CONFIG_BB_AGC_TAB)
440 		READ_AND_CONFIG(8723B, _AGC_TAB);
441 	else if (ConfigType == CONFIG_BB_PHY_REG_PG)
442 		READ_AND_CONFIG(8723B, _PHY_REG_PG);
443 
444 	return HAL_STATUS_SUCCESS;
445 }
446 
447