Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / staging / rtl8723au / hal / rtl8723a_rf6052.c
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  *---------------------------------------------------------------------------*/
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
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         bool TurboScanOff = false;
107         u8 idx1, idx2;
108         u8 *ptr;
109
110         /*  According to SD3 eechou's suggestion, we need to disable
111             turbo scan for RU. */
112         /*  Otherwise, external PA will be broken if power index > 0x20. */
113         if (pHalData->EEPROMRegulatory != 0 || pHalData->ExternalPA)
114                 TurboScanOff = true;
115
116         if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
117                 TxAGC[RF_PATH_A] = 0x3f3f3f3f;
118                 TxAGC[RF_PATH_B] = 0x3f3f3f3f;
119
120                 TurboScanOff = true;/* disable turbo scan */
121
122                 if (TurboScanOff) {
123                         for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
124                                 TxAGC[idx1] = pPowerlevel[idx1] |
125                                         (pPowerlevel[idx1] << 8) |
126                                         (pPowerlevel[idx1] << 16) |
127                                         (pPowerlevel[idx1] << 24);
128                                 /*  2010/10/18 MH For external PA module.
129                                     We need to limit power index to be less
130                                     than 0x20. */
131                                 if (TxAGC[idx1] > 0x20 && pHalData->ExternalPA)
132                                         TxAGC[idx1] = 0x20;
133                         }
134                 }
135         } else {
136 /*  20100427 Joseph: Driver dynamic Tx power shall not affect Tx
137  *  power. It shall be determined by power training mechanism. */
138 /*  Currently, we cannot fully disable driver dynamic tx power
139  *  mechanism because it is referenced by BT coexist mechanism. */
140 /*  In the future, two mechanism shall be separated from each other
141  *  and maintained independantly. Thanks for Lanhsin's reminder. */
142                 if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) {
143                         TxAGC[RF_PATH_A] = 0x10101010;
144                         TxAGC[RF_PATH_B] = 0x10101010;
145                 } else if (pdmpriv->DynamicTxHighPowerLvl ==
146                            TxHighPwrLevel_Level2) {
147                         TxAGC[RF_PATH_A] = 0x00000000;
148                         TxAGC[RF_PATH_B] = 0x00000000;
149                 } else {
150                         for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
151                                 TxAGC[idx1] = pPowerlevel[idx1] |
152                                         (pPowerlevel[idx1] << 8) |
153                                         (pPowerlevel[idx1] << 16) |
154                                         (pPowerlevel[idx1] << 24);
155                         }
156
157                         if (pHalData->EEPROMRegulatory == 0) {
158                                 tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][6]) +
159                                                 (pHalData->MCSTxPowerLevelOriginalOffset[0][7]<<8);
160                                 TxAGC[RF_PATH_A] += tmpval;
161
162                                 tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][14]) +
163                                                 (pHalData->MCSTxPowerLevelOriginalOffset[0][15]<<24);
164                                 TxAGC[RF_PATH_B] += tmpval;
165                         }
166                 }
167         }
168
169         for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
170                 ptr = (u8 *)(&TxAGC[idx1]);
171                 for (idx2 = 0; idx2 < 4; idx2++) {
172                         if (*ptr > RF6052_MAX_TX_PWR)
173                                 *ptr = RF6052_MAX_TX_PWR;
174                         ptr++;
175                 }
176         }
177
178         /*  rf-A cck tx power */
179         tmpval = TxAGC[RF_PATH_A] & 0xff;
180         PHY_SetBBReg(Adapter, rTxAGC_A_CCK1_Mcs32, bMaskByte1, tmpval);
181         tmpval = TxAGC[RF_PATH_A] >> 8;
182         PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
183
184         /*  rf-B cck tx power */
185         tmpval = TxAGC[RF_PATH_B] >> 24;
186         PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, tmpval);
187         tmpval = TxAGC[RF_PATH_B] & 0x00ffffff;
188         PHY_SetBBReg(Adapter, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval);
189 }       /* PHY_RF6052SetCckTxPower */
190
191 /*  powerbase0 for OFDM rates */
192 /*  powerbase1 for HT MCS rates */
193 static void getPowerBase(struct rtw_adapter *Adapter, u8 *pPowerLevel,
194                          u8 Channel, u32 *OfdmBase, u32 *MCSBase)
195 {
196         struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
197         u32 powerBase0, powerBase1;
198         u8 Legacy_pwrdiff = 0;
199         s8 HT20_pwrdiff = 0;
200         u8 i, powerlevel[2];
201
202         for (i = 0; i < 2; i++) {
203                 powerlevel[i] = pPowerLevel[i];
204                 Legacy_pwrdiff = pHalData->TxPwrLegacyHtDiff[i][Channel-1];
205                 powerBase0 = powerlevel[i] + Legacy_pwrdiff;
206
207                 powerBase0 = powerBase0 << 24 | powerBase0 << 16 |
208                         powerBase0 << 8 | powerBase0;
209                 *(OfdmBase + i) = powerBase0;
210         }
211
212         for (i = 0; i < 2; i++) {
213                 /* Check HT20 to HT40 diff */
214                 if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20) {
215                         HT20_pwrdiff = pHalData->TxPwrHt20Diff[i][Channel-1];
216                         powerlevel[i] += HT20_pwrdiff;
217                 }
218                 powerBase1 = powerlevel[i];
219                 powerBase1 = powerBase1 << 24 | powerBase1 << 16 |
220                         powerBase1 << 8 | powerBase1;
221                 *(MCSBase + i) = powerBase1;
222         }
223 }
224
225 static void
226 getTxPowerWriteValByRegulatory(struct rtw_adapter *Adapter, u8 Channel,
227                                u8 index, u32 *powerBase0, u32 *powerBase1,
228                                u32 *pOutWriteVal)
229 {
230         struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
231         struct dm_priv  *pdmpriv = &pHalData->dmpriv;
232         u8 i, chnlGroup = 0, pwr_diff_limit[4];
233         u32 writeVal, customer_limit, rf;
234
235         /*  Index 0 & 1 = legacy OFDM, 2-5 = HT_MCS rate */
236         for (rf = 0; rf < 2; rf++) {
237                 switch (pHalData->EEPROMRegulatory) {
238                 case 0: /*  Realtek better performance */
239                         /*  increase power diff defined by Realtek for
240                          *  large power */
241                         chnlGroup = 0;
242                         writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] +
243                                 ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
244                         break;
245                 case 1: /*  Realtek regulatory */
246                         /*  increase power diff defined by Realtek for
247                          *  regulatory */
248                         if (pHalData->pwrGroupCnt == 1)
249                                 chnlGroup = 0;
250                         if (pHalData->pwrGroupCnt >= 3) {
251                                 if (Channel <= 3)
252                                         chnlGroup = 0;
253                                 else if (Channel >= 4 && Channel <= 9)
254                                         chnlGroup = 1;
255                                 else if (Channel > 9)
256                                         chnlGroup = 2;
257
258                                 if (pHalData->CurrentChannelBW ==
259                                     HT_CHANNEL_WIDTH_20)
260                                         chnlGroup++;
261                                 else
262                                         chnlGroup += 4;
263                         }
264                         writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] +
265                                    ((index < 2) ? powerBase0[rf] :
266                                     powerBase1[rf]);
267                         break;
268                 case 2: /*  Better regulatory */
269                         /*  don't increase any power diff */
270                         writeVal = (index < 2) ? powerBase0[rf] :
271                                     powerBase1[rf];
272                         break;
273                 case 3: /*  Customer defined power diff. */
274                         chnlGroup = 0;
275
276                         for (i = 0; i < 4; i++) {
277                                 pwr_diff_limit[i] = (u8)((pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index +
278                                                     (rf ? 8 : 0)]&(0x7f << (i*8))) >> (i*8));
279                                 if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_40) {
280                                         if (pwr_diff_limit[i] > pHalData->PwrGroupHT40[rf][Channel-1])
281                                                 pwr_diff_limit[i] = pHalData->PwrGroupHT40[rf][Channel-1];
282                                 } else {
283                                         if (pwr_diff_limit[i] > pHalData->PwrGroupHT20[rf][Channel-1])
284                                                 pwr_diff_limit[i] = pHalData->PwrGroupHT20[rf][Channel-1];
285                                 }
286                         }
287                         customer_limit = (pwr_diff_limit[3]<<24) | (pwr_diff_limit[2]<<16) |
288                                                         (pwr_diff_limit[1]<<8) | (pwr_diff_limit[0]);
289                         writeVal = customer_limit + ((index<2)?powerBase0[rf]:powerBase1[rf]);
290                         break;
291                 default:
292                         chnlGroup = 0;
293                         writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] +
294                                         ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
295                         break;
296                 }
297
298 /*  20100427 Joseph: Driver dynamic Tx power shall not affect Tx power.
299     It shall be determined by power training mechanism. */
300 /*  Currently, we cannot fully disable driver dynamic tx power mechanism
301     because it is referenced by BT coexist mechanism. */
302 /*  In the future, two mechanism shall be separated from each other and
303     maintained independantly. Thanks for Lanhsin's reminder. */
304
305                 if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1)
306                         writeVal = 0x14141414;
307                 else if (pdmpriv->DynamicTxHighPowerLvl ==
308                          TxHighPwrLevel_Level2)
309                         writeVal = 0x00000000;
310
311                 /* 20100628 Joseph: High power mode for BT-Coexist mechanism. */
312                 /* This mechanism is only applied when
313                    Driver-Highpower-Mechanism is OFF. */
314                 if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT1)
315                         writeVal = writeVal - 0x06060606;
316                 else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT2)
317                         writeVal = writeVal;
318                 *(pOutWriteVal + rf) = writeVal;
319         }
320 }
321
322 static void writeOFDMPowerReg(struct rtw_adapter *Adapter, u8 index,
323                               u32 *pValue)
324 {
325         struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
326         u16 RegOffset_A[6] = {
327                 rTxAGC_A_Rate18_06, rTxAGC_A_Rate54_24,
328                 rTxAGC_A_Mcs03_Mcs00, rTxAGC_A_Mcs07_Mcs04,
329                 rTxAGC_A_Mcs11_Mcs08, rTxAGC_A_Mcs15_Mcs12
330         };
331         u16 RegOffset_B[6] = {
332                 rTxAGC_B_Rate18_06, rTxAGC_B_Rate54_24,
333                 rTxAGC_B_Mcs03_Mcs00, rTxAGC_B_Mcs07_Mcs04,
334                 rTxAGC_B_Mcs11_Mcs08, rTxAGC_B_Mcs15_Mcs12
335         };
336         u8 i, rf, pwr_val[4];
337         u32 writeVal;
338         u16 RegOffset;
339
340         for (rf = 0; rf < 2; rf++) {
341                 writeVal = pValue[rf];
342                 for (i = 0; i < 4; i++) {
343                         pwr_val[i] = (u8)((writeVal &
344                                            (0x7f << (i * 8))) >> (i * 8));
345                         if (pwr_val[i] > RF6052_MAX_TX_PWR)
346                                 pwr_val[i]  = RF6052_MAX_TX_PWR;
347                 }
348                 writeVal = pwr_val[3] << 24 | pwr_val[2] << 16 |
349                         pwr_val[1] << 8 | pwr_val[0];
350
351                 if (rf == 0)
352                         RegOffset = RegOffset_A[index];
353                 else
354                         RegOffset = RegOffset_B[index];
355
356                 rtl8723au_write32(Adapter, RegOffset, writeVal);
357
358                 /*  201005115 Joseph: Set Tx Power diff for Tx power
359                     training mechanism. */
360                 if (((pHalData->rf_type == RF_2T2R) &&
361                     (RegOffset == rTxAGC_A_Mcs15_Mcs12 ||
362                      RegOffset == rTxAGC_B_Mcs15_Mcs12)) ||
363                     ((pHalData->rf_type != RF_2T2R) &&
364                      (RegOffset == rTxAGC_A_Mcs07_Mcs04 ||
365                       RegOffset == rTxAGC_B_Mcs07_Mcs04))) {
366                         writeVal = pwr_val[3];
367                         if (RegOffset == rTxAGC_A_Mcs15_Mcs12 ||
368                             RegOffset == rTxAGC_A_Mcs07_Mcs04)
369                                 RegOffset = 0xc90;
370                         if (RegOffset == rTxAGC_B_Mcs15_Mcs12 ||
371                             RegOffset == rTxAGC_B_Mcs07_Mcs04)
372                                 RegOffset = 0xc98;
373                         for (i = 0; i < 3; i++) {
374                                 if (i != 2)
375                                         writeVal = (writeVal > 8) ?
376                                                 (writeVal - 8) : 0;
377                                 else
378                                         writeVal = (writeVal > 6) ?
379                                                 (writeVal - 6) : 0;
380                                 rtl8723au_write8(Adapter, RegOffset + i,
381                                                  (u8)writeVal);
382                         }
383                 }
384         }
385 }
386 /*-----------------------------------------------------------------------------
387  * Function:    PHY_RF6052SetOFDMTxPower
388  *
389  * Overview:    For legacy and HY OFDM, we must read EEPROM TX power index for
390  *              different channel and read original value in TX power
391  *              register area from 0xe00. We increase offset and
392  *              original value to be correct tx pwr.
393  *
394  * Input:       NONE
395  *
396  * Output:      NONE
397  *
398  * Return:      NONE
399  *
400  * Revised History:
401  * When                 Remark
402  * 11/05/2008   MHC     Simulate 8192 series method.
403  * 01/06/2009   MHC     1. Prevent Path B tx power overflow or
404  *                      underflow dure to A/B pwr difference or
405  *                      legacy/HT pwr diff.
406  *                      2. We concern with path B legacy/HT OFDM difference.
407  * 01/22/2009   MHC     Support new EPRO format from SD3.
408  *
409  *---------------------------------------------------------------------------*/
410 void rtl8723a_PHY_RF6052SetOFDMTxPower(struct rtw_adapter *Adapter,
411                                        u8 *pPowerLevel, u8 Channel)
412 {
413         u32 writeVal[2], powerBase0[2], powerBase1[2];
414         u8 index = 0;
415
416         getPowerBase(Adapter, pPowerLevel, Channel,
417                      &powerBase0[0], &powerBase1[0]);
418
419         for (index = 0; index < 6; index++) {
420                 getTxPowerWriteValByRegulatory(Adapter, Channel, index,
421                         &powerBase0[0], &powerBase1[0], &writeVal[0]);
422
423                 writeOFDMPowerReg(Adapter, index, &writeVal[0]);
424         }
425 }
426
427 static int phy_RF6052_Config_ParaFile(struct rtw_adapter *Adapter)
428 {
429         u32 u4RegValue = 0;
430         u8 eRFPath;
431         struct bb_reg_define *pPhyReg;
432         int rtStatus = _SUCCESS;
433         struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
434
435         /* 3----------------------------------------------------------------- */
436         /* 3 <2> Initialize RF */
437         /* 3----------------------------------------------------------------- */
438         for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) {
439
440                 pPhyReg = &pHalData->PHYRegDef[eRFPath];
441
442                 /*----Store original RFENV control type----*/
443                 switch (eRFPath) {
444                 case RF_PATH_A:
445                         u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs,
446                                                     bRFSI_RFENV);
447                         break;
448                 case RF_PATH_B:
449                         u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs,
450                                                     bRFSI_RFENV << 16);
451                         break;
452                 }
453
454                 /*----Set RF_ENV enable----*/
455                 PHY_SetBBReg(Adapter, pPhyReg->rfintfe, bRFSI_RFENV << 16, 0x1);
456                 udelay(1);/* PlatformStallExecution(1); */
457
458                 /*----Set RF_ENV output high----*/
459                 PHY_SetBBReg(Adapter, pPhyReg->rfintfo, bRFSI_RFENV, 0x1);
460                 udelay(1);/* PlatformStallExecution(1); */
461
462                 /* Set bit number of Address and Data for RF register */
463                 PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireAddressLength,
464                              0x0);      /*  Set 1 to 4 bits for 8255 */
465                 udelay(1);/* PlatformStallExecution(1); */
466
467                 PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireDataLength,
468                              0x0);      /*  Set 0 to 12  bits for 8255 */
469                 udelay(1);/* PlatformStallExecution(1); */
470
471                 /*----Initialize RF fom connfiguration file----*/
472                 switch (eRFPath) {
473                 case RF_PATH_A:
474                         ODM_ReadAndConfig_RadioA_1T_8723A(&pHalData->odmpriv);
475                         break;
476                 case RF_PATH_B:
477                         break;
478                 }
479
480                 /*----Restore RFENV control type----*/;
481                 switch (eRFPath) {
482                 case RF_PATH_A:
483                         PHY_SetBBReg(Adapter, pPhyReg->rfintfs,
484                                      bRFSI_RFENV, u4RegValue);
485                         break;
486                 case RF_PATH_B:
487                         PHY_SetBBReg(Adapter, pPhyReg->rfintfs,
488                                      bRFSI_RFENV << 16, u4RegValue);
489                         break;
490                 }
491
492                 if (rtStatus != _SUCCESS) {
493                         goto phy_RF6052_Config_ParaFile_Fail;
494                 }
495         }
496 phy_RF6052_Config_ParaFile_Fail:
497         return rtStatus;
498 }
499
500 int PHY_RF6052_Config8723A(struct rtw_adapter *Adapter)
501 {
502         struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
503         int rtStatus = _SUCCESS;
504
505         /*  Initialize general global value */
506         /*  TODO: Extend RF_PATH_C and RF_PATH_D in the future */
507         if (pHalData->rf_type == RF_1T1R)
508                 pHalData->NumTotalRFPath = 1;
509         else
510                 pHalData->NumTotalRFPath = 2;
511
512         /*  Config BB and RF */
513         rtStatus = phy_RF6052_Config_ParaFile(Adapter);
514         return rtStatus;
515 }
516
517 /* End of HalRf6052.c */