These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[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         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 */
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
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
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  *---------------------------------------------------------------------------*/
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
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
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 */