1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) 2007 - 2011 Realtek Corporation. */
3 
4 /******************************************************************************
5  *
6  *
7  * Module:	rtl8192c_rf6052.c	( Source C File)
8  *
9  * Note:	Provide RF 6052 series relative API.
10  *
11  * Function:
12  *
13  * Export:
14  *
15  * Abbrev:
16  *
17  * History:
18  * Data			Who		Remark
19  *
20  * 09/25/2008	MHC		Create initial version.
21  * 11/05/2008	MHC		Add API for tw power setting.
22  *
23  *
24 ******************************************************************************/
25 
26 #define _RTL8188E_RF6052_C_
27 
28 #include "../include/osdep_service.h"
29 #include "../include/drv_types.h"
30 #include "../include/rtl8188e_hal.h"
31 
32 /*-----------------------------------------------------------------------------
33  * Function:    PHY_RF6052SetBandwidth()
34  *
35  * Overview:    This function is called by SetBWModeCallback8190Pci() only
36  *
37  * Input:       struct adapter *Adapter
38  *			WIRELESS_BANDWIDTH_E	Bandwidth	20M or 40M
39  *
40  * Output:      NONE
41  *
42  * Return:      NONE
43  *
44  * Note:		For RF type 0222D
45  *---------------------------------------------------------------------------*/
rtl8188e_PHY_RF6052SetBandwidth(struct adapter * Adapter,enum ht_channel_width Bandwidth)46 void rtl8188e_PHY_RF6052SetBandwidth(struct adapter *Adapter,
47 				     enum ht_channel_width Bandwidth)
48 {
49 	struct hal_data_8188e *pHalData = &Adapter->haldata;
50 
51 	switch (Bandwidth) {
52 	case HT_CHANNEL_WIDTH_20:
53 		pHalData->RfRegChnlVal = ((pHalData->RfRegChnlVal & 0xfffff3ff) | BIT(10) | BIT(11));
54 		rtl8188e_PHY_SetRFReg(Adapter, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal);
55 		break;
56 	case HT_CHANNEL_WIDTH_40:
57 		pHalData->RfRegChnlVal = ((pHalData->RfRegChnlVal & 0xfffff3ff) | BIT(10));
58 		rtl8188e_PHY_SetRFReg(Adapter, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal);
59 		break;
60 	default:
61 		break;
62 	}
63 }
64 
65 /*-----------------------------------------------------------------------------
66  * Function:	PHY_RF6052SetCckTxPower
67  *
68  * Overview:
69  *
70  * Input:       NONE
71  *
72  * Output:      NONE
73  *
74  * Return:      NONE
75  *
76  * Revised History:
77  * When			Who		Remark
78  * 11/05/2008	MHC		Simulate 8192series..
79  *
80  *---------------------------------------------------------------------------*/
81 
82 void
rtl8188e_PHY_RF6052SetCckTxPower(struct adapter * Adapter,u8 * pPowerlevel)83 rtl8188e_PHY_RF6052SetCckTxPower(
84 		struct adapter *Adapter,
85 		u8 *pPowerlevel)
86 {
87 	struct hal_data_8188e *pHalData = &Adapter->haldata;
88 	struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv;
89 	u32 TxAGC[2] = {0, 0}, tmpval = 0, pwrtrac_value;
90 	u8 idx1, idx2;
91 	u8 *ptr;
92 	u8 direction;
93 
94 	if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
95 		TxAGC[RF_PATH_A] = 0x3f3f3f3f;
96 		TxAGC[RF_PATH_B] = 0x3f3f3f3f;
97 
98 		for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
99 			TxAGC[idx1] =
100 				pPowerlevel[idx1] | (pPowerlevel[idx1] << 8) |
101 				(pPowerlevel[idx1] << 16) | (pPowerlevel[idx1] << 24);
102 		}
103 	} else {
104 		for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
105 			TxAGC[idx1] =
106 				pPowerlevel[idx1] | (pPowerlevel[idx1] << 8) |
107 				(pPowerlevel[idx1] << 16) | (pPowerlevel[idx1] << 24);
108 		}
109 		if (pHalData->EEPROMRegulatory == 0) {
110 			tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][6]) +
111 					(pHalData->MCSTxPowerLevelOriginalOffset[0][7] << 8);
112 			TxAGC[RF_PATH_A] += tmpval;
113 
114 			tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][14]) +
115 					(pHalData->MCSTxPowerLevelOriginalOffset[0][15] << 24);
116 			TxAGC[RF_PATH_B] += tmpval;
117 		}
118 	}
119 	for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
120 		ptr = (u8 *)(&TxAGC[idx1]);
121 		for (idx2 = 0; idx2 < 4; idx2++) {
122 			if (*ptr > RF6052_MAX_TX_PWR)
123 				*ptr = RF6052_MAX_TX_PWR;
124 			ptr++;
125 		}
126 	}
127 	ODM_TxPwrTrackAdjust88E(&pHalData->odmpriv, 1, &direction, &pwrtrac_value);
128 
129 	if (direction == 1) {
130 		/*  Increase TX power */
131 		TxAGC[0] += pwrtrac_value;
132 		TxAGC[1] += pwrtrac_value;
133 	} else if (direction == 2) {
134 		/*  Decrease TX power */
135 		TxAGC[0] -=  pwrtrac_value;
136 		TxAGC[1] -=  pwrtrac_value;
137 	}
138 
139 	/*  rf-A cck tx power */
140 	tmpval = TxAGC[RF_PATH_A] & 0xff;
141 	rtl8188e_PHY_SetBBReg(Adapter, rTxAGC_A_CCK1_Mcs32, bMaskByte1, tmpval);
142 	tmpval = TxAGC[RF_PATH_A] >> 8;
143 	rtl8188e_PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
144 
145 	/*  rf-B cck tx power */
146 	tmpval = TxAGC[RF_PATH_B] >> 24;
147 	rtl8188e_PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, tmpval);
148 	tmpval = TxAGC[RF_PATH_B] & 0x00ffffff;
149 	rtl8188e_PHY_SetBBReg(Adapter, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval);
150 }	/* PHY_RF6052SetCckTxPower */
151 
152 /*  */
153 /*  powerbase0 for OFDM rates */
154 /*  powerbase1 for HT MCS rates */
155 /*  */
getpowerbase88e(struct adapter * Adapter,u8 * pPowerLevelOFDM,u8 * pPowerLevelBW20,u8 * pPowerLevelBW40,u8 Channel,u32 * OfdmBase,u32 * MCSBase)156 static void getpowerbase88e(struct adapter *Adapter, u8 *pPowerLevelOFDM,
157 			    u8 *pPowerLevelBW20, u8 *pPowerLevelBW40, u8 Channel, u32 *OfdmBase, u32 *MCSBase)
158 {
159 	struct hal_data_8188e *pHalData = &Adapter->haldata;
160 	u32 powerBase0, powerBase1;
161 	u8 i;
162 
163 	for (i = 0; i < 2; i++) {
164 		powerBase0 = pPowerLevelOFDM[i];
165 
166 		powerBase0 = (powerBase0 << 24) | (powerBase0 << 16) | (powerBase0 << 8) | powerBase0;
167 		*(OfdmBase + i) = powerBase0;
168 	}
169 
170 	/* Check HT20 to HT40 diff */
171 	if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
172 		powerBase1 = pPowerLevelBW20[0];
173 	else
174 		powerBase1 = pPowerLevelBW40[0];
175 	powerBase1 = (powerBase1 << 24) | (powerBase1 << 16) | (powerBase1 << 8) | powerBase1;
176 	*MCSBase = powerBase1;
177 }
178 
get_rx_power_val_by_reg(struct adapter * Adapter,u8 Channel,u8 index,u32 * powerBase0,u32 * powerBase1,u32 * pOutWriteVal)179 static void get_rx_power_val_by_reg(struct adapter *Adapter, u8 Channel,
180 				    u8 index, u32 *powerBase0, u32 *powerBase1,
181 				    u32 *pOutWriteVal)
182 {
183 	struct hal_data_8188e *pHalData = &Adapter->haldata;
184 	u8	i, chnlGroup = 0, pwr_diff_limit[4], customer_pwr_limit;
185 	s8	pwr_diff = 0;
186 	u32	writeVal, customer_limit, rf;
187 	u8	Regulatory = pHalData->EEPROMRegulatory;
188 
189 	/*  Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */
190 
191 	for (rf = 0; rf < 2; rf++) {
192 		switch (Regulatory) {
193 		case 0:	/*  Realtek better performance */
194 				/*  increase power diff defined by Realtek for large power */
195 			chnlGroup = 0;
196 			writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index + (rf ? 8 : 0)] +
197 				((index < 2) ? powerBase0[rf] : powerBase1[rf]);
198 			break;
199 		case 1:	/*  Realtek regulatory */
200 			/*  increase power diff defined by Realtek for regulatory */
201 			if (pHalData->pwrGroupCnt == 1)
202 				chnlGroup = 0;
203 			if (pHalData->pwrGroupCnt >= MAX_PG_GROUP) {
204 				if (Channel < 3)			/*  Channel 1-2 */
205 					chnlGroup = 0;
206 				else if (Channel < 6)		/*  Channel 3-5 */
207 					chnlGroup = 1;
208 				else	 if (Channel < 9)		/*  Channel 6-8 */
209 					chnlGroup = 2;
210 				else if (Channel < 12)		/*  Channel 9-11 */
211 					chnlGroup = 3;
212 				else if (Channel < 14)		/*  Channel 12-13 */
213 					chnlGroup = 4;
214 				else if (Channel == 14)		/*  Channel 14 */
215 					chnlGroup = 5;
216 			}
217 			writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index + (rf ? 8 : 0)] +
218 					((index < 2) ? powerBase0[rf] : powerBase1[rf]);
219 			break;
220 		case 2:	/*  Better regulatory */
221 				/*  don't increase any power diff */
222 			writeVal = ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
223 			break;
224 		case 3:	/*  Customer defined power diff. */
225 				/*  increase power diff defined by customer. */
226 			chnlGroup = 0;
227 
228 			if (index < 2)
229 				pwr_diff = pHalData->TxPwrLegacyHtDiff[rf][Channel - 1];
230 			else if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
231 				pwr_diff = pHalData->TxPwrHt20Diff[rf][Channel - 1];
232 
233 			if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_40)
234 				customer_pwr_limit = pHalData->PwrGroupHT40[rf][Channel - 1];
235 			else
236 				customer_pwr_limit = pHalData->PwrGroupHT20[rf][Channel - 1];
237 
238 			if (pwr_diff >= customer_pwr_limit)
239 				pwr_diff = 0;
240 			else
241 				pwr_diff = customer_pwr_limit - pwr_diff;
242 
243 			for (i = 0; i < 4; i++) {
244 				pwr_diff_limit[i] = (u8)((pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index + (rf ? 8 : 0)] & (0x7f << (i * 8))) >> (i * 8));
245 
246 				if (pwr_diff_limit[i] > pwr_diff)
247 					pwr_diff_limit[i] = pwr_diff;
248 			}
249 			customer_limit = (pwr_diff_limit[3] << 24) | (pwr_diff_limit[2] << 16) |
250 					 (pwr_diff_limit[1] << 8) | (pwr_diff_limit[0]);
251 			writeVal = customer_limit + ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
252 			break;
253 		default:
254 			chnlGroup = 0;
255 			writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index + (rf ? 8 : 0)] +
256 					((index < 2) ? powerBase0[rf] : powerBase1[rf]);
257 			break;
258 		}
259 
260 		*(pOutWriteVal + rf) = writeVal;
261 	}
262 }
writeOFDMPowerReg88E(struct adapter * Adapter,u8 index,u32 * pValue)263 static void writeOFDMPowerReg88E(struct adapter *Adapter, u8 index, u32 *pValue)
264 {
265 	u16 regoffset_a[6] = {
266 		rTxAGC_A_Rate18_06, rTxAGC_A_Rate54_24,
267 		rTxAGC_A_Mcs03_Mcs00, rTxAGC_A_Mcs07_Mcs04,
268 		rTxAGC_A_Mcs11_Mcs08, rTxAGC_A_Mcs15_Mcs12};
269 	u16 regoffset_b[6] = {
270 		rTxAGC_B_Rate18_06, rTxAGC_B_Rate54_24,
271 		rTxAGC_B_Mcs03_Mcs00, rTxAGC_B_Mcs07_Mcs04,
272 		rTxAGC_B_Mcs11_Mcs08, rTxAGC_B_Mcs15_Mcs12};
273 	u8 i, rf, pwr_val[4];
274 	u32 writeVal;
275 	u16 regoffset;
276 
277 	for (rf = 0; rf < 2; rf++) {
278 		writeVal = pValue[rf];
279 		for (i = 0; i < 4; i++) {
280 			pwr_val[i] = (u8)((writeVal & (0x7f << (i * 8))) >> (i * 8));
281 			if (pwr_val[i]  > RF6052_MAX_TX_PWR)
282 				pwr_val[i]  = RF6052_MAX_TX_PWR;
283 		}
284 		writeVal = (pwr_val[3] << 24) | (pwr_val[2] << 16) | (pwr_val[1] << 8) | pwr_val[0];
285 
286 		if (rf == 0)
287 			regoffset = regoffset_a[index];
288 		else
289 			regoffset = regoffset_b[index];
290 
291 		rtl8188e_PHY_SetBBReg(Adapter, regoffset, bMaskDWord, writeVal);
292 
293 		/*  201005115 Joseph: Set Tx Power diff for Tx power training mechanism. */
294 		if (regoffset == rTxAGC_A_Mcs07_Mcs04 || regoffset == rTxAGC_B_Mcs07_Mcs04) {
295 			writeVal = pwr_val[3];
296 			if (regoffset == rTxAGC_A_Mcs15_Mcs12 || regoffset == rTxAGC_A_Mcs07_Mcs04)
297 				regoffset = 0xc90;
298 			if (regoffset == rTxAGC_B_Mcs15_Mcs12 || regoffset == rTxAGC_B_Mcs07_Mcs04)
299 				regoffset = 0xc98;
300 			for (i = 0; i < 3; i++) {
301 				if (i != 2)
302 					writeVal = (writeVal > 8) ? (writeVal - 8) : 0;
303 				else
304 					writeVal = (writeVal > 6) ? (writeVal - 6) : 0;
305 				rtw_write8(Adapter, (u32)(regoffset + i), (u8)writeVal);
306 			}
307 		}
308 	}
309 }
310 
311 /*-----------------------------------------------------------------------------
312  * Function:	PHY_RF6052SetOFDMTxPower
313  *
314  * Overview:	For legacy and HY OFDM, we must read EEPROM TX power index for
315  *			different channel and read original value in TX power register area from
316  *			0xe00. We increase offset and original value to be correct tx pwr.
317  *
318  * Input:       NONE
319  *
320  * Output:      NONE
321  *
322  * Return:      NONE
323  *
324  * Revised History:
325  * When			Who		Remark
326  * 11/05/2008	MHC		Simulate 8192 series method.
327  * 01/06/2009	MHC		1. Prevent Path B tx power overflow or underflow dure to
328  *						A/B pwr difference or legacy/HT pwr diff.
329  *						2. We concern with path B legacy/HT OFDM difference.
330  * 01/22/2009	MHC		Support new EPRO format from SD3.
331  *
332  *---------------------------------------------------------------------------*/
333 
334 void
rtl8188e_PHY_RF6052SetOFDMTxPower(struct adapter * Adapter,u8 * pPowerLevelOFDM,u8 * pPowerLevelBW20,u8 * pPowerLevelBW40,u8 Channel)335 rtl8188e_PHY_RF6052SetOFDMTxPower(
336 		struct adapter *Adapter,
337 		u8 *pPowerLevelOFDM,
338 		u8 *pPowerLevelBW20,
339 		u8 *pPowerLevelBW40,
340 		u8 Channel)
341 {
342 	struct hal_data_8188e *pHalData = &Adapter->haldata;
343 	u32 writeVal[2], powerBase0[2], powerBase1[2], pwrtrac_value;
344 	u8 direction;
345 	u8 index = 0;
346 
347 	getpowerbase88e(Adapter, pPowerLevelOFDM, pPowerLevelBW20, pPowerLevelBW40, Channel, &powerBase0[0], &powerBase1[0]);
348 
349 	/*  2012/04/23 MH According to power tracking value, we need to revise OFDM tx power. */
350 	/*  This is ued to fix unstable power tracking mode. */
351 	ODM_TxPwrTrackAdjust88E(&pHalData->odmpriv, 0, &direction, &pwrtrac_value);
352 
353 	for (index = 0; index < 6; index++) {
354 		get_rx_power_val_by_reg(Adapter, Channel, index,
355 					&powerBase0[0], &powerBase1[0],
356 					&writeVal[0]);
357 
358 		if (direction == 1) {
359 			writeVal[0] += pwrtrac_value;
360 			writeVal[1] += pwrtrac_value;
361 		} else if (direction == 2) {
362 			writeVal[0] -= pwrtrac_value;
363 			writeVal[1] -= pwrtrac_value;
364 		}
365 		writeOFDMPowerReg88E(Adapter, index, &writeVal[0]);
366 	}
367 }
368 
phy_RF6052_Config_ParaFile(struct adapter * Adapter)369 int phy_RF6052_Config_ParaFile(struct adapter *Adapter)
370 {
371 	struct bb_reg_def *pPhyReg;
372 	struct hal_data_8188e *pHalData = &Adapter->haldata;
373 	u32 u4RegValue = 0;
374 	int rtStatus = _SUCCESS;
375 
376 	/* Initialize RF */
377 
378 	pPhyReg = &pHalData->PHYRegDef;
379 
380 	/*----Store original RFENV control type----*/
381 	u4RegValue = rtl8188e_PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV);
382 
383 	/*----Set RF_ENV enable----*/
384 	rtl8188e_PHY_SetBBReg(Adapter, pPhyReg->rfintfe, bRFSI_RFENV << 16, 0x1);
385 	udelay(1);/* PlatformStallExecution(1); */
386 
387 	/*----Set RF_ENV output high----*/
388 	rtl8188e_PHY_SetBBReg(Adapter, pPhyReg->rfintfo, bRFSI_RFENV, 0x1);
389 	udelay(1);/* PlatformStallExecution(1); */
390 
391 	/* Set bit number of Address and Data for RF register */
392 	rtl8188e_PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireAddressLength, 0x0);	/*  Set 1 to 4 bits for 8255 */
393 	udelay(1);/* PlatformStallExecution(1); */
394 
395 	rtl8188e_PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireDataLength, 0x0);	/*  Set 0 to 12  bits for 8255 */
396 	udelay(1);/* PlatformStallExecution(1); */
397 
398 	/*----Initialize RF fom connfiguration file----*/
399 	if (ODM_ReadAndConfig_RadioA_1T_8188E(&pHalData->odmpriv))
400 		rtStatus = _FAIL;
401 
402 	/*----Restore RFENV control type----*/;
403 	rtl8188e_PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV, u4RegValue);
404 
405 	return rtStatus;
406 }
407