1 /******************************************************************************
2  *
3  * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  ******************************************************************************/
15 /******************************************************************************
16  *
17  *
18  * Module:	rtl8192c_rf6052.c	(Source C File)
19  *
20  * Note:	Provide RF 6052 series relative API.
21  *
22  * Function:
23  *
24  * Export:
25  *
26  * Abbrev:
27  *
28  * History:
29  * Data			Who		Remark
30  *
31  * 09/25/2008	MHC		Create initial version.
32  * 11/05/2008	MHC		Add API for tw power setting.
33  *
34  *
35 ******************************************************************************/
36 
37 #define _RTL8723A_RF6052_C_
38 
39 #include <osdep_service.h>
40 #include <drv_types.h>
41 
42 #include <rtl8723a_hal.h>
43 #include <usb_ops_linux.h>
44 
45 /*-----------------------------------------------------------------------------
46  * Function:    PHY_RF6052SetBandwidth()
47  *
48  * Overview:    This function is called by SetBWMode23aCallback8190Pci() only
49  *
50  * Input:       struct rtw_adapter *				Adapter
51  *			WIRELESS_BANDWIDTH_E	Bandwidth	20M or 40M
52  *
53  * Output:      NONE
54  *
55  * Return:      NONE
56  *
57  * Note:		For RF type 0222D
58  *---------------------------------------------------------------------------*/
rtl8723a_phy_rf6052set_bw(struct rtw_adapter * Adapter,enum ht_channel_width Bandwidth)59 void rtl8723a_phy_rf6052set_bw(struct rtw_adapter *Adapter,
60 			       enum ht_channel_width Bandwidth)	/* 20M or 40M */
61 {
62 	struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
63 
64 	switch (Bandwidth) {
65 	case HT_CHANNEL_WIDTH_20:
66 		pHalData->RfRegChnlVal[0] =
67 			(pHalData->RfRegChnlVal[0] & 0xfffff3ff) | 0x0400;
68 		PHY_SetRFReg(Adapter, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask,
69 			     pHalData->RfRegChnlVal[0]);
70 		break;
71 	case HT_CHANNEL_WIDTH_40:
72 		pHalData->RfRegChnlVal[0] =
73 			(pHalData->RfRegChnlVal[0] & 0xfffff3ff);
74 		PHY_SetRFReg(Adapter, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask,
75 			     pHalData->RfRegChnlVal[0]);
76 		break;
77 	default:
78 		break;
79 	}
80 }
81 
82 /*-----------------------------------------------------------------------------
83  * Function:	PHY_RF6052SetCckTxPower
84  *
85  * Overview:
86  *
87  * Input:       NONE
88  *
89  * Output:      NONE
90  *
91  * Return:      NONE
92  *
93  * Revised History:
94  * When			Who		Remark
95  * 11/05/2008	MHC		Simulate 8192series..
96  *
97  *---------------------------------------------------------------------------*/
98 
rtl823a_phy_rf6052setccktxpower(struct rtw_adapter * Adapter,u8 * pPowerlevel)99 void rtl823a_phy_rf6052setccktxpower(struct rtw_adapter *Adapter,
100 				     u8 *pPowerlevel)
101 {
102 	struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
103 	struct dm_priv *pdmpriv = &pHalData->dmpriv;
104 	struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv;
105 	u32 TxAGC[2] = {0, 0}, tmpval = 0;
106 	u8 idx1, idx2;
107 	u8 *ptr;
108 
109 	if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
110 		TxAGC[RF_PATH_A] = 0x3f3f3f3f;
111 		TxAGC[RF_PATH_B] = 0x3f3f3f3f;
112 
113 		for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
114 			TxAGC[idx1] = pPowerlevel[idx1] |
115 				(pPowerlevel[idx1] << 8) |
116 				(pPowerlevel[idx1] << 16) |
117 				(pPowerlevel[idx1] << 24);
118 			/*
119 			 * 2010/10/18 MH For external PA module. We need
120 			 * to limit power index to be less than 0x20.
121 			 */
122 			if (TxAGC[idx1] > 0x20 && pHalData->ExternalPA)
123 				TxAGC[idx1] = 0x20;
124 		}
125 	} else {
126 /*  20100427 Joseph: Driver dynamic Tx power shall not affect Tx
127  *  power. It shall be determined by power training mechanism. */
128 /*  Currently, we cannot fully disable driver dynamic tx power
129  *  mechanism because it is referenced by BT coexist mechanism. */
130 /*  In the future, two mechanism shall be separated from each other
131  *  and maintained independently. Thanks for Lanhsin's reminder. */
132 		if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) {
133 			TxAGC[RF_PATH_A] = 0x10101010;
134 			TxAGC[RF_PATH_B] = 0x10101010;
135 		} else if (pdmpriv->DynamicTxHighPowerLvl ==
136 			   TxHighPwrLevel_Level2) {
137 			TxAGC[RF_PATH_A] = 0x00000000;
138 			TxAGC[RF_PATH_B] = 0x00000000;
139 		} else {
140 			for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
141 				TxAGC[idx1] = pPowerlevel[idx1] |
142 					(pPowerlevel[idx1] << 8) |
143 					(pPowerlevel[idx1] << 16) |
144 					(pPowerlevel[idx1] << 24);
145 			}
146 
147 			if (pHalData->EEPROMRegulatory == 0) {
148 				tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][6]) +
149 						(pHalData->MCSTxPowerLevelOriginalOffset[0][7]<<8);
150 				TxAGC[RF_PATH_A] += tmpval;
151 
152 				tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][14]) +
153 						(pHalData->MCSTxPowerLevelOriginalOffset[0][15]<<24);
154 				TxAGC[RF_PATH_B] += tmpval;
155 			}
156 		}
157 	}
158 
159 	for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
160 		ptr = (u8 *)(&TxAGC[idx1]);
161 		for (idx2 = 0; idx2 < 4; idx2++) {
162 			if (*ptr > RF6052_MAX_TX_PWR)
163 				*ptr = RF6052_MAX_TX_PWR;
164 			ptr++;
165 		}
166 	}
167 
168 	/*  rf-A cck tx power */
169 	tmpval = TxAGC[RF_PATH_A] & 0xff;
170 	PHY_SetBBReg(Adapter, rTxAGC_A_CCK1_Mcs32, bMaskByte1, tmpval);
171 	tmpval = TxAGC[RF_PATH_A] >> 8;
172 	PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
173 
174 	/*  rf-B cck tx power */
175 	tmpval = TxAGC[RF_PATH_B] >> 24;
176 	PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, tmpval);
177 	tmpval = TxAGC[RF_PATH_B] & 0x00ffffff;
178 	PHY_SetBBReg(Adapter, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval);
179 }	/* PHY_RF6052SetCckTxPower */
180 
181 /*  powerbase0 for OFDM rates */
182 /*  powerbase1 for HT MCS rates */
getPowerBase(struct rtw_adapter * Adapter,u8 * pPowerLevel,u8 Channel,u32 * OfdmBase,u32 * MCSBase)183 static void getPowerBase(struct rtw_adapter *Adapter, u8 *pPowerLevel,
184 			 u8 Channel, u32 *OfdmBase, u32 *MCSBase)
185 {
186 	struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
187 	u32 ofdm, mcs;
188 	u8 Legacy_pwrdiff = 0;
189 	s8 HT20_pwrdiff = 0;
190 	u8 i, powerlevel[2];
191 
192 	for (i = 0; i < 2; i++) {
193 		powerlevel[i] = pPowerLevel[i];
194 		Legacy_pwrdiff = pHalData->TxPwrLegacyHtDiff[i][Channel-1];
195 		ofdm = powerlevel[i] + Legacy_pwrdiff;
196 
197 		ofdm = ofdm << 24 | ofdm << 16 | ofdm << 8 | ofdm;
198 		*(OfdmBase + i) = ofdm;
199 	}
200 
201 	for (i = 0; i < 2; i++) {
202 		/* Check HT20 to HT40 diff */
203 		if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20) {
204 			HT20_pwrdiff = pHalData->TxPwrHt20Diff[i][Channel-1];
205 			powerlevel[i] += HT20_pwrdiff;
206 		}
207 		mcs = powerlevel[i];
208 		mcs = mcs << 24 | mcs << 16 | mcs << 8 | mcs;
209 		*(MCSBase + i) = mcs;
210 	}
211 }
212 
213 static void
getTxPowerWriteValByRegulatory(struct rtw_adapter * Adapter,u8 Channel,u8 index,u32 * powerBase0,u32 * powerBase1,u32 * pOutWriteVal)214 getTxPowerWriteValByRegulatory(struct rtw_adapter *Adapter, u8 Channel,
215 			       u8 index, u32 *powerBase0, u32 *powerBase1,
216 			       u32 *pOutWriteVal)
217 {
218 	struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
219 	struct dm_priv	*pdmpriv = &pHalData->dmpriv;
220 	u8 i, chnlGroup = 0, pwr_diff_limit[4];
221 	u32 writeVal, customer_limit, rf;
222 
223 	/*  Index 0 & 1 = legacy OFDM, 2-5 = HT_MCS rate */
224 	for (rf = 0; rf < 2; rf++) {
225 		switch (pHalData->EEPROMRegulatory) {
226 		case 0:	/*  Realtek better performance */
227 			/*  increase power diff defined by Realtek for
228 			 *  large power */
229 			chnlGroup = 0;
230 			writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] +
231 				((index < 2) ? powerBase0[rf] : powerBase1[rf]);
232 			break;
233 		case 1:	/*  Realtek regulatory */
234 			/*  increase power diff defined by Realtek for
235 			 *  regulatory */
236 			if (pHalData->pwrGroupCnt == 1)
237 				chnlGroup = 0;
238 			if (pHalData->pwrGroupCnt >= 3) {
239 				if (Channel <= 3)
240 					chnlGroup = 0;
241 				else if (Channel >= 4 && Channel <= 9)
242 					chnlGroup = 1;
243 				else if (Channel > 9)
244 					chnlGroup = 2;
245 
246 				if (pHalData->CurrentChannelBW ==
247 				    HT_CHANNEL_WIDTH_20)
248 					chnlGroup++;
249 				else
250 					chnlGroup += 4;
251 			}
252 			writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] +
253 				   ((index < 2) ? powerBase0[rf] :
254 				    powerBase1[rf]);
255 			break;
256 		case 2:	/*  Better regulatory */
257 			/*  don't increase any power diff */
258 			writeVal = (index < 2) ? powerBase0[rf] :
259 				    powerBase1[rf];
260 			break;
261 		case 3:	/*  Customer defined power diff. */
262 			chnlGroup = 0;
263 
264 			for (i = 0; i < 4; i++) {
265 				pwr_diff_limit[i] = (u8)((pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index +
266 						    (rf ? 8 : 0)]&(0x7f << (i*8))) >> (i*8));
267 				if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_40) {
268 					if (pwr_diff_limit[i] > pHalData->PwrGroupHT40[rf][Channel-1])
269 						pwr_diff_limit[i] = pHalData->PwrGroupHT40[rf][Channel-1];
270 				} else {
271 					if (pwr_diff_limit[i] > pHalData->PwrGroupHT20[rf][Channel-1])
272 						pwr_diff_limit[i] = pHalData->PwrGroupHT20[rf][Channel-1];
273 				}
274 			}
275 			customer_limit = (pwr_diff_limit[3]<<24) | (pwr_diff_limit[2]<<16) |
276 							(pwr_diff_limit[1]<<8) | (pwr_diff_limit[0]);
277 			writeVal = customer_limit + ((index<2)?powerBase0[rf]:powerBase1[rf]);
278 			break;
279 		default:
280 			chnlGroup = 0;
281 			writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] +
282 					((index < 2) ? powerBase0[rf] : powerBase1[rf]);
283 			break;
284 		}
285 
286 /*  20100427 Joseph: Driver dynamic Tx power shall not affect Tx power.
287     It shall be determined by power training mechanism. */
288 /*  Currently, we cannot fully disable driver dynamic tx power mechanism
289     because it is referenced by BT coexist mechanism. */
290 /*  In the future, two mechanism shall be separated from each other and
291     maintained independently. Thanks for Lanhsin's reminder. */
292 
293 		if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1)
294 			writeVal = 0x14141414;
295 		else if (pdmpriv->DynamicTxHighPowerLvl ==
296 			 TxHighPwrLevel_Level2)
297 			writeVal = 0x00000000;
298 
299 		/* 20100628 Joseph: High power mode for BT-Coexist mechanism. */
300 		/* This mechanism is only applied when
301 		   Driver-Highpower-Mechanism is OFF. */
302 		if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT1)
303 			writeVal = writeVal - 0x06060606;
304 		else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT2)
305 			writeVal = writeVal;
306 		*(pOutWriteVal + rf) = writeVal;
307 	}
308 }
309 
writeOFDMPowerReg(struct rtw_adapter * Adapter,u8 index,u32 * pValue)310 static void writeOFDMPowerReg(struct rtw_adapter *Adapter, u8 index,
311 			      u32 *pValue)
312 {
313 	struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
314 	u16 RegOffset_A[6] = {
315 		rTxAGC_A_Rate18_06, rTxAGC_A_Rate54_24,
316 		rTxAGC_A_Mcs03_Mcs00, rTxAGC_A_Mcs07_Mcs04,
317 		rTxAGC_A_Mcs11_Mcs08, rTxAGC_A_Mcs15_Mcs12
318 	};
319 	u16 RegOffset_B[6] = {
320 		rTxAGC_B_Rate18_06, rTxAGC_B_Rate54_24,
321 		rTxAGC_B_Mcs03_Mcs00, rTxAGC_B_Mcs07_Mcs04,
322 		rTxAGC_B_Mcs11_Mcs08, rTxAGC_B_Mcs15_Mcs12
323 	};
324 	u8 i, rf, pwr_val[4];
325 	u32 writeVal;
326 	u16 RegOffset;
327 
328 	for (rf = 0; rf < 2; rf++) {
329 		writeVal = pValue[rf];
330 		for (i = 0; i < 4; i++) {
331 			pwr_val[i] = (u8)((writeVal &
332 					   (0x7f << (i * 8))) >> (i * 8));
333 			if (pwr_val[i] > RF6052_MAX_TX_PWR)
334 				pwr_val[i]  = RF6052_MAX_TX_PWR;
335 		}
336 		writeVal = pwr_val[3] << 24 | pwr_val[2] << 16 |
337 			pwr_val[1] << 8 | pwr_val[0];
338 
339 		if (rf == 0)
340 			RegOffset = RegOffset_A[index];
341 		else
342 			RegOffset = RegOffset_B[index];
343 
344 		rtl8723au_write32(Adapter, RegOffset, writeVal);
345 
346 		/*  201005115 Joseph: Set Tx Power diff for Tx power
347 		    training mechanism. */
348 		if (((pHalData->rf_type == RF_2T2R) &&
349 		    (RegOffset == rTxAGC_A_Mcs15_Mcs12 ||
350 		     RegOffset == rTxAGC_B_Mcs15_Mcs12)) ||
351 		    ((pHalData->rf_type != RF_2T2R) &&
352 		     (RegOffset == rTxAGC_A_Mcs07_Mcs04 ||
353 		      RegOffset == rTxAGC_B_Mcs07_Mcs04))) {
354 			writeVal = pwr_val[3];
355 			if (RegOffset == rTxAGC_A_Mcs15_Mcs12 ||
356 			    RegOffset == rTxAGC_A_Mcs07_Mcs04)
357 				RegOffset = 0xc90;
358 			if (RegOffset == rTxAGC_B_Mcs15_Mcs12 ||
359 			    RegOffset == rTxAGC_B_Mcs07_Mcs04)
360 				RegOffset = 0xc98;
361 			for (i = 0; i < 3; i++) {
362 				if (i != 2)
363 					writeVal = (writeVal > 8) ?
364 						(writeVal - 8) : 0;
365 				else
366 					writeVal = (writeVal > 6) ?
367 						(writeVal - 6) : 0;
368 				rtl8723au_write8(Adapter, RegOffset + i,
369 						 (u8)writeVal);
370 			}
371 		}
372 	}
373 }
374 /*-----------------------------------------------------------------------------
375  * Function:	PHY_RF6052SetOFDMTxPower
376  *
377  * Overview:	For legacy and HY OFDM, we must read EEPROM TX power index for
378  *		different channel and read original value in TX power
379  *		register area from 0xe00. We increase offset and
380  *		original value to be correct tx pwr.
381  *
382  * Input:       NONE
383  *
384  * Output:      NONE
385  *
386  * Return:      NONE
387  *
388  * Revised History:
389  * When			Remark
390  * 11/05/2008	MHC	Simulate 8192 series method.
391  * 01/06/2009	MHC	1. Prevent Path B tx power overflow or
392  *			underflow dure to A/B pwr difference or
393  *			legacy/HT pwr diff.
394  *			2. We concern with path B legacy/HT OFDM difference.
395  * 01/22/2009	MHC	Support new EPRO format from SD3.
396  *
397  *---------------------------------------------------------------------------*/
rtl8723a_PHY_RF6052SetOFDMTxPower(struct rtw_adapter * Adapter,u8 * pPowerLevel,u8 Channel)398 void rtl8723a_PHY_RF6052SetOFDMTxPower(struct rtw_adapter *Adapter,
399 				       u8 *pPowerLevel, u8 Channel)
400 {
401 	u32 writeVal[2], powerBase0[2], powerBase1[2];
402 	u8 index = 0;
403 
404 	getPowerBase(Adapter, pPowerLevel, Channel,
405 		     &powerBase0[0], &powerBase1[0]);
406 
407 	for (index = 0; index < 6; index++) {
408 		getTxPowerWriteValByRegulatory(Adapter, Channel, index,
409 			&powerBase0[0], &powerBase1[0], &writeVal[0]);
410 
411 		writeOFDMPowerReg(Adapter, index, &writeVal[0]);
412 	}
413 }
414 
phy_RF6052_Config_ParaFile(struct rtw_adapter * Adapter)415 static int phy_RF6052_Config_ParaFile(struct rtw_adapter *Adapter)
416 {
417 	u32 u4RegValue = 0;
418 	u8 eRFPath;
419 	struct bb_reg_define *pPhyReg;
420 	int rtStatus = _SUCCESS;
421 	struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
422 
423 	/* 3----------------------------------------------------------------- */
424 	/* 3 <2> Initialize RF */
425 	/* 3----------------------------------------------------------------- */
426 	for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) {
427 
428 		pPhyReg = &pHalData->PHYRegDef[eRFPath];
429 
430 		/*----Store original RFENV control type----*/
431 		switch (eRFPath) {
432 		case RF_PATH_A:
433 			u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs,
434 						    bRFSI_RFENV);
435 			break;
436 		case RF_PATH_B:
437 			u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs,
438 						    bRFSI_RFENV << 16);
439 			break;
440 		}
441 
442 		/*----Set RF_ENV enable----*/
443 		PHY_SetBBReg(Adapter, pPhyReg->rfintfe, bRFSI_RFENV << 16, 0x1);
444 		udelay(1);/* PlatformStallExecution(1); */
445 
446 		/*----Set RF_ENV output high----*/
447 		PHY_SetBBReg(Adapter, pPhyReg->rfintfo, bRFSI_RFENV, 0x1);
448 		udelay(1);/* PlatformStallExecution(1); */
449 
450 		/* Set bit number of Address and Data for RF register */
451 		PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireAddressLength,
452 			     0x0);	/*  Set 1 to 4 bits for 8255 */
453 		udelay(1);/* PlatformStallExecution(1); */
454 
455 		PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireDataLength,
456 			     0x0);	/*  Set 0 to 12  bits for 8255 */
457 		udelay(1);/* PlatformStallExecution(1); */
458 
459 		/*----Initialize RF fom connfiguration file----*/
460 		switch (eRFPath) {
461 		case RF_PATH_A:
462 			ODM_ReadAndConfig_RadioA_1T_8723A(&pHalData->odmpriv);
463 			break;
464 		case RF_PATH_B:
465 			break;
466 		}
467 
468 		/*----Restore RFENV control type----*/;
469 		switch (eRFPath) {
470 		case RF_PATH_A:
471 			PHY_SetBBReg(Adapter, pPhyReg->rfintfs,
472 				     bRFSI_RFENV, u4RegValue);
473 			break;
474 		case RF_PATH_B:
475 			PHY_SetBBReg(Adapter, pPhyReg->rfintfs,
476 				     bRFSI_RFENV << 16, u4RegValue);
477 			break;
478 		}
479 
480 		if (rtStatus != _SUCCESS) {
481 			goto phy_RF6052_Config_ParaFile_Fail;
482 		}
483 	}
484 phy_RF6052_Config_ParaFile_Fail:
485 	return rtStatus;
486 }
487 
PHY_RF6052_Config8723A(struct rtw_adapter * Adapter)488 int PHY_RF6052_Config8723A(struct rtw_adapter *Adapter)
489 {
490 	struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
491 
492 	/*  Initialize general global value */
493 	/*  TODO: Extend RF_PATH_C and RF_PATH_D in the future */
494 	if (pHalData->rf_type == RF_1T1R)
495 		pHalData->NumTotalRFPath = 1;
496 	else
497 		pHalData->NumTotalRFPath = 2;
498 
499 	/*  Config BB and RF */
500 	return phy_RF6052_Config_ParaFile(Adapter);
501 }
502 
503 /* End of HalRf6052.c */
504