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