linux/drivers/staging/rtl8723au/hal/rtl8723a_rf6052.c
<<
>>
Prefs
   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 *---------------------------------------------------------------------------*/
  59void 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
  99void 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 independently. 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 */
 193static 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
 225static void
 226getTxPowerWriteValByRegulatory(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 independently. 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
 322static 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 *---------------------------------------------------------------------------*/
 410void 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
 427static 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        }
 496phy_RF6052_Config_ParaFile_Fail:
 497        return rtStatus;
 498}
 499
 500int PHY_RF6052_Config8723A(struct rtw_adapter *Adapter)
 501{
 502        struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
 503
 504        /*  Initialize general global value */
 505        /*  TODO: Extend RF_PATH_C and RF_PATH_D in the future */
 506        if (pHalData->rf_type == RF_1T1R)
 507                pHalData->NumTotalRFPath = 1;
 508        else
 509                pHalData->NumTotalRFPath = 2;
 510
 511        /*  Config BB and RF */
 512        return phy_RF6052_Config_ParaFile(Adapter);
 513}
 514
 515/* End of HalRf6052.c */
 516