linux/drivers/staging/rtl8723au/hal/HalDMOutSrc8723A_CE.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/*  Description: */
  16/*  This file is for 92CE/92CU dynamic mechanism only */
  17
  18/*  include files */
  19
  20#include "odm_precomp.h"
  21#include <usb_ops_linux.h>
  22
  23#define         DPK_DELTA_MAPPING_NUM   13
  24#define         index_mapping_HP_NUM    15
  25/* 091212 chiyokolin */
  26static void
  27odm_TXPowerTrackingCallback_ThermalMeter_92C(struct rtw_adapter *Adapter)
  28{
  29        struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
  30        struct dm_priv *pdmpriv = &pHalData->dmpriv;
  31        u8 ThermalValue = 0, delta, delta_LCK, delta_IQK, delta_HP;
  32        int ele_A, ele_D, TempCCk, X, value32;
  33        int Y, ele_C;
  34        s8 OFDM_index[2], CCK_index = 0, OFDM_index_old[2] = {0};
  35        s8 CCK_index_old = 0;
  36        int i = 0;
  37        u8 OFDM_min_index = 6, rf; /* OFDM BB Swing should be less than +3.0dB*/
  38        u8 ThermalValue_HP_count = 0;
  39        u32 ThermalValue_HP = 0;
  40        s32 index_mapping_HP[index_mapping_HP_NUM] = {
  41                0, 1, 3, 4, 6,
  42                7, 9, 10, 12, 13,
  43                15, 16, 18, 19, 21
  44        };
  45        s8 index_HP;
  46
  47        pdmpriv->TXPowerTrackingCallbackCnt++;  /* cosa add for debug */
  48        pdmpriv->bTXPowerTrackingInit = true;
  49
  50        if (pHalData->CurrentChannel == 14 && !pdmpriv->bCCKinCH14)
  51                pdmpriv->bCCKinCH14 = true;
  52        else if (pHalData->CurrentChannel != 14 && pdmpriv->bCCKinCH14)
  53                pdmpriv->bCCKinCH14 = false;
  54
  55        ThermalValue = (u8)PHY_QueryRFReg(Adapter, RF_PATH_A, RF_T_METER,
  56                                          0x1f);/*  0x24: RF Reg[4:0]    */
  57
  58        rtl8723a_phy_ap_calibrate(Adapter, (ThermalValue -
  59                                  pHalData->EEPROMThermalMeter));
  60
  61        if (pHalData->rf_type == RF_2T2R)
  62                rf = 2;
  63        else
  64                rf = 1;
  65
  66        if (ThermalValue) {
  67                /* Query OFDM path A default setting     */
  68                ele_D = rtl8723au_read32(Adapter, rOFDM0_XATxIQImbalance) &
  69                        bMaskOFDM_D;
  70                for (i = 0; i < OFDM_TABLE_SIZE_92C; i++) {
  71                        /* find the index */
  72                        if (ele_D == (OFDMSwingTable23A[i]&bMaskOFDM_D)) {
  73                                OFDM_index_old[0] = (u8)i;
  74                                break;
  75                        }
  76                }
  77
  78                /* Query OFDM path B default setting  */
  79                if (pHalData->rf_type == RF_2T2R) {
  80                        ele_D = rtl8723au_read32(Adapter,
  81                                                 rOFDM0_XBTxIQImbalance);
  82                        ele_D &= bMaskOFDM_D;
  83                        for (i = 0; i < OFDM_TABLE_SIZE_92C; i++) {     /* find the index  */
  84                                if (ele_D == (OFDMSwingTable23A[i]&bMaskOFDM_D)) {
  85                                        OFDM_index_old[1] = (u8)i;
  86                                        break;
  87                                }
  88                        }
  89                }
  90
  91                /* Query CCK default setting From 0xa24 */
  92                TempCCk = rtl8723au_read32(Adapter, rCCK0_TxFilter2) & bMaskCCK;
  93                for (i = 0 ; i < CCK_TABLE_SIZE ; i++) {
  94                        if (pdmpriv->bCCKinCH14) {
  95                                if (!memcmp(&TempCCk,
  96                                            &CCKSwingTable_Ch1423A[i][2], 4)) {
  97                                        CCK_index_old = (u8)i;
  98                                        break;
  99                                }
 100                        } else {
 101                                if (!memcmp(&TempCCk,
 102                                            &CCKSwingTable_Ch1_Ch1323A[i][2], 4)) {
 103                                        CCK_index_old = (u8)i;
 104                                        break;
 105                                }
 106                        }
 107                }
 108
 109                if (!pdmpriv->ThermalValue) {
 110                        pdmpriv->ThermalValue = pHalData->EEPROMThermalMeter;
 111                        pdmpriv->ThermalValue_LCK = ThermalValue;
 112                        pdmpriv->ThermalValue_IQK = ThermalValue;
 113                        pdmpriv->ThermalValue_DPK = pHalData->EEPROMThermalMeter;
 114
 115                        for (i = 0; i < rf; i++) {
 116                                pdmpriv->OFDM_index_HP[i] = OFDM_index_old[i];
 117                                pdmpriv->OFDM_index[i] = OFDM_index_old[i];
 118                        }
 119                        pdmpriv->CCK_index_HP = CCK_index_old;
 120                        pdmpriv->CCK_index = CCK_index_old;
 121                }
 122
 123                if (pHalData->BoardType == BOARD_USB_High_PA) {
 124                        pdmpriv->ThermalValue_HP[pdmpriv->ThermalValue_HP_index] = ThermalValue;
 125                        pdmpriv->ThermalValue_HP_index++;
 126                        if (pdmpriv->ThermalValue_HP_index == HP_THERMAL_NUM)
 127                                pdmpriv->ThermalValue_HP_index = 0;
 128
 129                        for (i = 0; i < HP_THERMAL_NUM; i++) {
 130                                if (pdmpriv->ThermalValue_HP[i]) {
 131                                        ThermalValue_HP += pdmpriv->ThermalValue_HP[i];
 132                                        ThermalValue_HP_count++;
 133                                }
 134                        }
 135
 136                        if (ThermalValue_HP_count)
 137                                ThermalValue = (u8)(ThermalValue_HP / ThermalValue_HP_count);
 138                }
 139
 140                delta = (ThermalValue > pdmpriv->ThermalValue) ?
 141                        (ThermalValue - pdmpriv->ThermalValue) :
 142                        (pdmpriv->ThermalValue - ThermalValue);
 143                if (pHalData->BoardType == BOARD_USB_High_PA) {
 144                        if (pdmpriv->bDoneTxpower)
 145                                delta_HP = (ThermalValue > pdmpriv->ThermalValue) ?
 146                                           (ThermalValue - pdmpriv->ThermalValue) :
 147                                           (pdmpriv->ThermalValue - ThermalValue);
 148                        else
 149                                delta_HP = ThermalValue > pHalData->EEPROMThermalMeter ?
 150                                           (ThermalValue - pHalData->EEPROMThermalMeter) :
 151                                           (pHalData->EEPROMThermalMeter - ThermalValue);
 152                } else {
 153                        delta_HP = 0;
 154                }
 155                delta_LCK = (ThermalValue > pdmpriv->ThermalValue_LCK) ?
 156                            (ThermalValue - pdmpriv->ThermalValue_LCK) :
 157                            (pdmpriv->ThermalValue_LCK - ThermalValue);
 158                delta_IQK = (ThermalValue > pdmpriv->ThermalValue_IQK) ?
 159                            (ThermalValue - pdmpriv->ThermalValue_IQK) :
 160                            (pdmpriv->ThermalValue_IQK - ThermalValue);
 161
 162                if (delta_LCK > 1) {
 163                        pdmpriv->ThermalValue_LCK = ThermalValue;
 164                        rtl8723a_phy_lc_calibrate(Adapter);
 165                }
 166
 167                if ((delta > 0 || delta_HP > 0) && pdmpriv->TxPowerTrackControl) {
 168                        if (pHalData->BoardType == BOARD_USB_High_PA) {
 169                                pdmpriv->bDoneTxpower = true;
 170                                delta_HP = ThermalValue > pHalData->EEPROMThermalMeter ?
 171                                           (ThermalValue - pHalData->EEPROMThermalMeter) :
 172                                           (pHalData->EEPROMThermalMeter - ThermalValue);
 173
 174                                if (delta_HP > index_mapping_HP_NUM-1)
 175                                        index_HP = index_mapping_HP[index_mapping_HP_NUM-1];
 176                                else
 177                                        index_HP = index_mapping_HP[delta_HP];
 178
 179                                if (ThermalValue > pHalData->EEPROMThermalMeter) {
 180                                        /* set larger Tx power */
 181                                        for (i = 0; i < rf; i++)
 182                                                OFDM_index[i] = pdmpriv->OFDM_index_HP[i] - index_HP;
 183                                        CCK_index = pdmpriv->CCK_index_HP - index_HP;
 184                                } else {
 185                                        for (i = 0; i < rf; i++)
 186                                                OFDM_index[i] = pdmpriv->OFDM_index_HP[i] + index_HP;
 187                                        CCK_index = pdmpriv->CCK_index_HP + index_HP;
 188                                }
 189
 190                                delta_HP = (ThermalValue > pdmpriv->ThermalValue) ?
 191                                           (ThermalValue - pdmpriv->ThermalValue) :
 192                                           (pdmpriv->ThermalValue - ThermalValue);
 193                        } else {
 194                                if (ThermalValue > pdmpriv->ThermalValue) {
 195                                        for (i = 0; i < rf; i++)
 196                                                pdmpriv->OFDM_index[i] -= delta;
 197                                        pdmpriv->CCK_index -= delta;
 198                                } else {
 199                                        for (i = 0; i < rf; i++)
 200                                                pdmpriv->OFDM_index[i] += delta;
 201                                        pdmpriv->CCK_index += delta;
 202                                }
 203                        }
 204
 205                        /* no adjust */
 206                        if (pHalData->BoardType != BOARD_USB_High_PA) {
 207                                if (ThermalValue > pHalData->EEPROMThermalMeter) {
 208                                        for (i = 0; i < rf; i++)
 209                                                OFDM_index[i] = pdmpriv->OFDM_index[i]+1;
 210                                        CCK_index = pdmpriv->CCK_index+1;
 211                                } else {
 212                                        for (i = 0; i < rf; i++)
 213                                                OFDM_index[i] = pdmpriv->OFDM_index[i];
 214                                        CCK_index = pdmpriv->CCK_index;
 215                                }
 216                        }
 217                        for (i = 0; i < rf; i++) {
 218                                if (OFDM_index[i] > (OFDM_TABLE_SIZE_92C-1))
 219                                        OFDM_index[i] = (OFDM_TABLE_SIZE_92C-1);
 220                                else if (OFDM_index[i] < OFDM_min_index)
 221                                        OFDM_index[i] = OFDM_min_index;
 222                        }
 223
 224                        if (CCK_index > (CCK_TABLE_SIZE-1))
 225                                CCK_index = CCK_TABLE_SIZE-1;
 226                        else if (CCK_index < 0)
 227                                CCK_index = 0;
 228                }
 229
 230                if (pdmpriv->TxPowerTrackControl &&
 231                    (delta != 0 || delta_HP != 0)) {
 232                        /* Adujst OFDM Ant_A according to IQK result */
 233                        ele_D = (OFDMSwingTable23A[OFDM_index[0]] & 0xFFC00000)>>22;
 234                        X = pdmpriv->RegE94;
 235                        Y = pdmpriv->RegE9C;
 236
 237                        if (X != 0) {
 238                                if ((X & 0x00000200) != 0)
 239                                        X = X | 0xFFFFFC00;
 240                                ele_A = ((X * ele_D)>>8)&0x000003FF;
 241
 242                                /* new element C = element D x Y */
 243                                if ((Y & 0x00000200) != 0)
 244                                        Y = Y | 0xFFFFFC00;
 245                                ele_C = ((Y * ele_D)>>8)&0x000003FF;
 246
 247                                /* write new elements A, C, D to regC80 and regC94, element B is always 0 */
 248                                value32 = (ele_D<<22)|((ele_C&0x3F)<<16)|ele_A;
 249                                rtl8723au_write32(Adapter,
 250                                                  rOFDM0_XATxIQImbalance,
 251                                                  value32);
 252
 253                                value32 = (ele_C&0x000003C0)>>6;
 254                                PHY_SetBBReg(Adapter, rOFDM0_XCTxAFE, bMaskH4Bits, value32);
 255
 256                                value32 = ((X * ele_D)>>7)&0x01;
 257                                PHY_SetBBReg(Adapter, rOFDM0_ECCAThreshold,
 258                                             BIT(31), value32);
 259
 260                                value32 = ((Y * ele_D)>>7)&0x01;
 261                                PHY_SetBBReg(Adapter, rOFDM0_ECCAThreshold,
 262                                             BIT(29), value32);
 263                        } else {
 264                                rtl8723au_write32(Adapter,
 265                                                  rOFDM0_XATxIQImbalance,
 266                                                  OFDMSwingTable23A[OFDM_index[0]]);
 267                                PHY_SetBBReg(Adapter, rOFDM0_XCTxAFE,
 268                                             bMaskH4Bits, 0x00);
 269                                PHY_SetBBReg(Adapter, rOFDM0_ECCAThreshold,
 270                                             BIT(31) | BIT(29), 0x00);
 271                        }
 272
 273                        /* Adjust CCK according to IQK result */
 274                        if (!pdmpriv->bCCKinCH14) {
 275                                rtl8723au_write8(Adapter, 0xa22, CCKSwingTable_Ch1_Ch1323A[CCK_index][0]);
 276                                rtl8723au_write8(Adapter, 0xa23, CCKSwingTable_Ch1_Ch1323A[CCK_index][1]);
 277                                rtl8723au_write8(Adapter, 0xa24, CCKSwingTable_Ch1_Ch1323A[CCK_index][2]);
 278                                rtl8723au_write8(Adapter, 0xa25, CCKSwingTable_Ch1_Ch1323A[CCK_index][3]);
 279                                rtl8723au_write8(Adapter, 0xa26, CCKSwingTable_Ch1_Ch1323A[CCK_index][4]);
 280                                rtl8723au_write8(Adapter, 0xa27, CCKSwingTable_Ch1_Ch1323A[CCK_index][5]);
 281                                rtl8723au_write8(Adapter, 0xa28, CCKSwingTable_Ch1_Ch1323A[CCK_index][6]);
 282                                rtl8723au_write8(Adapter, 0xa29, CCKSwingTable_Ch1_Ch1323A[CCK_index][7]);
 283                        } else {
 284                                rtl8723au_write8(Adapter, 0xa22, CCKSwingTable_Ch1423A[CCK_index][0]);
 285                                rtl8723au_write8(Adapter, 0xa23, CCKSwingTable_Ch1423A[CCK_index][1]);
 286                                rtl8723au_write8(Adapter, 0xa24, CCKSwingTable_Ch1423A[CCK_index][2]);
 287                                rtl8723au_write8(Adapter, 0xa25, CCKSwingTable_Ch1423A[CCK_index][3]);
 288                                rtl8723au_write8(Adapter, 0xa26, CCKSwingTable_Ch1423A[CCK_index][4]);
 289                                rtl8723au_write8(Adapter, 0xa27, CCKSwingTable_Ch1423A[CCK_index][5]);
 290                                rtl8723au_write8(Adapter, 0xa28, CCKSwingTable_Ch1423A[CCK_index][6]);
 291                                rtl8723au_write8(Adapter, 0xa29, CCKSwingTable_Ch1423A[CCK_index][7]);
 292                        }
 293
 294                        if (pHalData->rf_type == RF_2T2R) {
 295                                ele_D = (OFDMSwingTable23A[(u8)OFDM_index[1]] & 0xFFC00000)>>22;
 296
 297                                /* new element A = element D x X */
 298                                X = pdmpriv->RegEB4;
 299                                Y = pdmpriv->RegEBC;
 300
 301                                if (X != 0) {
 302                                        if ((X & 0x00000200) != 0)      /* consider minus */
 303                                                X = X | 0xFFFFFC00;
 304                                        ele_A = ((X * ele_D)>>8)&0x000003FF;
 305
 306                                        /* new element C = element D x Y */
 307                                        if ((Y & 0x00000200) != 0)
 308                                                Y = Y | 0xFFFFFC00;
 309                                        ele_C = ((Y * ele_D)>>8)&0x00003FF;
 310
 311                                        /* write new elements A, C, D to regC88 and regC9C, element B is always 0 */
 312                                        value32 = (ele_D<<22)|((ele_C&0x3F)<<16) | ele_A;
 313                                        rtl8723au_write32(Adapter, rOFDM0_XBTxIQImbalance, value32);
 314
 315                                        value32 = (ele_C&0x000003C0)>>6;
 316                                        PHY_SetBBReg(Adapter, rOFDM0_XDTxAFE, bMaskH4Bits, value32);
 317
 318                                        value32 = ((X * ele_D)>>7)&0x01;
 319                                        PHY_SetBBReg(Adapter,
 320                                                     rOFDM0_ECCAThreshold,
 321                                                     BIT(27), value32);
 322
 323                                        value32 = ((Y * ele_D)>>7)&0x01;
 324                                        PHY_SetBBReg(Adapter,
 325                                                     rOFDM0_ECCAThreshold,
 326                                                     BIT(25), value32);
 327                                } else {
 328                                        rtl8723au_write32(Adapter,
 329                                                          rOFDM0_XBTxIQImbalance,
 330                                                          OFDMSwingTable23A[OFDM_index[1]]);
 331                                        PHY_SetBBReg(Adapter,
 332                                                     rOFDM0_XDTxAFE,
 333                                                     bMaskH4Bits, 0x00);
 334                                        PHY_SetBBReg(Adapter,
 335                                                     rOFDM0_ECCAThreshold,
 336                                                     BIT(27) | BIT(25), 0x00);
 337                                }
 338                        }
 339
 340                }
 341                if (delta_IQK > 3) {
 342                        pdmpriv->ThermalValue_IQK = ThermalValue;
 343                        rtl8723a_phy_iq_calibrate(Adapter, false);
 344                }
 345
 346                /* update thermal meter value */
 347                if (pdmpriv->TxPowerTrackControl)
 348                        pdmpriv->ThermalValue = ThermalValue;
 349        }
 350        pdmpriv->TXPowercount = 0;
 351}
 352
 353/*      Description: */
 354/*              - Dispatch TxPower Tracking direct call ONLY for 92s. */
 355/*              - We shall NOT schedule Workitem within PASSIVE LEVEL, which will cause system resource */
 356/*                 leakage under some platform. */
 357/*      Assumption: */
 358/*              PASSIVE_LEVEL when this routine is called. */
 359static void ODM_TXPowerTracking92CDirectCall(struct rtw_adapter *Adapter)
 360{
 361        odm_TXPowerTrackingCallback_ThermalMeter_92C(Adapter);
 362}
 363
 364void rtl8723a_odm_check_tx_power_tracking(struct rtw_adapter *Adapter)
 365{
 366        struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
 367        struct dm_priv *pdmpriv = &pHalData->dmpriv;
 368
 369        if (!pdmpriv->TM_Trigger) {             /* at least delay 1 sec */
 370                PHY_SetRFReg(Adapter, RF_PATH_A, RF_T_METER, bRFRegOffsetMask, 0x60);
 371
 372                pdmpriv->TM_Trigger = 1;
 373                return;
 374        } else {
 375                ODM_TXPowerTracking92CDirectCall(Adapter);
 376                pdmpriv->TM_Trigger = 0;
 377        }
 378}
 379
 380/*      IQK */
 381#define MAX_TOLERANCE           5
 382#define IQK_DELAY_TIME          1       /* ms */
 383
 384static u8 _PHY_PathA_IQK(struct rtw_adapter *pAdapter, bool configPathB)
 385{
 386        u32 regEAC, regE94, regE9C, regEA4;
 387        u8 result = 0x00;
 388        struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter);
 389
 390        /* path-A IQK setting */
 391        rtl8723au_write32(pAdapter, rTx_IQK_Tone_A, 0x10008c1f);
 392        rtl8723au_write32(pAdapter, rRx_IQK_Tone_A, 0x10008c1f);
 393        rtl8723au_write32(pAdapter, rTx_IQK_PI_A, 0x82140102);
 394
 395        rtl8723au_write32(pAdapter, rRx_IQK_PI_A, configPathB ? 0x28160202 :
 396                IS_81xxC_VENDOR_UMC_B_CUT(pHalData->VersionID)?0x28160202:0x28160502);
 397
 398        /* path-B IQK setting */
 399        if (configPathB) {
 400                rtl8723au_write32(pAdapter, rTx_IQK_Tone_B, 0x10008c22);
 401                rtl8723au_write32(pAdapter, rRx_IQK_Tone_B, 0x10008c22);
 402                rtl8723au_write32(pAdapter, rTx_IQK_PI_B, 0x82140102);
 403                rtl8723au_write32(pAdapter, rRx_IQK_PI_B, 0x28160202);
 404        }
 405
 406        /* LO calibration setting */
 407        rtl8723au_write32(pAdapter, rIQK_AGC_Rsp, 0x001028d1);
 408
 409        /* One shot, path A LOK & IQK */
 410        rtl8723au_write32(pAdapter, rIQK_AGC_Pts, 0xf9000000);
 411        rtl8723au_write32(pAdapter, rIQK_AGC_Pts, 0xf8000000);
 412
 413        /*  delay x ms */
 414        /* PlatformStallExecution(IQK_DELAY_TIME*1000); */
 415        udelay(IQK_DELAY_TIME*1000);
 416
 417        /*  Check failed */
 418        regEAC = rtl8723au_read32(pAdapter, rRx_Power_After_IQK_A_2);
 419        regE94 = rtl8723au_read32(pAdapter, rTx_Power_Before_IQK_A);
 420        regE9C = rtl8723au_read32(pAdapter, rTx_Power_After_IQK_A);
 421        regEA4 = rtl8723au_read32(pAdapter, rRx_Power_Before_IQK_A_2);
 422
 423        if (!(regEAC & BIT(28)) &&
 424            (((regE94 & 0x03FF0000)>>16) != 0x142) &&
 425            (((regE9C & 0x03FF0000)>>16) != 0x42))
 426                result |= 0x01;
 427        else                    /* if Tx not OK, ignore Rx */
 428                return result;
 429
 430        if (!(regEAC & BIT(27)) && /* if Tx is OK, check whether Rx is OK */
 431            (((regEA4 & 0x03FF0000)>>16) != 0x132) &&
 432            (((regEAC & 0x03FF0000)>>16) != 0x36))
 433                result |= 0x02;
 434        else
 435                DBG_8723A("Path A Rx IQK fail!!\n");
 436        return result;
 437}
 438
 439static u8 _PHY_PathB_IQK(struct rtw_adapter *pAdapter)
 440{
 441        u32 regEAC, regEB4, regEBC, regEC4, regECC;
 442        u8 result = 0x00;
 443
 444        /* One shot, path B LOK & IQK */
 445        rtl8723au_write32(pAdapter, rIQK_AGC_Cont, 0x00000002);
 446        rtl8723au_write32(pAdapter, rIQK_AGC_Cont, 0x00000000);
 447
 448        /*  delay x ms */
 449        udelay(IQK_DELAY_TIME*1000);
 450
 451        /*  Check failed */
 452        regEAC = rtl8723au_read32(pAdapter, rRx_Power_After_IQK_A_2);
 453        regEB4 = rtl8723au_read32(pAdapter, rTx_Power_Before_IQK_B);
 454        regEBC = rtl8723au_read32(pAdapter, rTx_Power_After_IQK_B);
 455        regEC4 = rtl8723au_read32(pAdapter, rRx_Power_Before_IQK_B_2);
 456        regECC = rtl8723au_read32(pAdapter, rRx_Power_After_IQK_B_2);
 457
 458        if (!(regEAC & BIT(31)) &&
 459            (((regEB4 & 0x03FF0000)>>16) != 0x142) &&
 460            (((regEBC & 0x03FF0000)>>16) != 0x42))
 461                result |= 0x01;
 462        else
 463                return result;
 464
 465        if (!(regEAC & BIT(30)) &&
 466            (((regEC4 & 0x03FF0000)>>16) != 0x132) &&
 467            (((regECC & 0x03FF0000)>>16) != 0x36))
 468                result |= 0x02;
 469        else
 470                DBG_8723A("Path B Rx IQK fail!!\n");
 471        return result;
 472}
 473
 474static void _PHY_PathAFillIQKMatrix(struct rtw_adapter *pAdapter,
 475        bool bIQKOK,
 476        int result[][8],
 477        u8 final_candidate,
 478        bool bTxOnly
 479        )
 480{
 481        u32 Oldval_0, X, TX0_A, reg;
 482        s32 Y, TX0_C;
 483
 484        DBG_8723A("Path A IQ Calibration %s !\n", (bIQKOK)?"Success":"Failed");
 485
 486        if (final_candidate == 0xFF) {
 487                return;
 488        } else if (bIQKOK) {
 489                Oldval_0 = rtl8723au_read32(pAdapter, rOFDM0_XATxIQImbalance);
 490                Oldval_0 = (Oldval_0 >> 22) & 0x3FF;
 491
 492                X = result[final_candidate][0];
 493                if ((X & 0x00000200) != 0)
 494                        X = X | 0xFFFFFC00;
 495                TX0_A = (X * Oldval_0) >> 8;
 496                PHY_SetBBReg(pAdapter, rOFDM0_XATxIQImbalance, 0x3FF, TX0_A);
 497                PHY_SetBBReg(pAdapter, rOFDM0_ECCAThreshold, BIT(31),
 498                             ((X * Oldval_0>>7) & 0x1));
 499
 500                Y = result[final_candidate][1];
 501                if ((Y & 0x00000200) != 0)
 502                        Y = Y | 0xFFFFFC00;
 503                TX0_C = (Y * Oldval_0) >> 8;
 504                PHY_SetBBReg(pAdapter, rOFDM0_XCTxAFE, 0xF0000000,
 505                             ((TX0_C&0x3C0)>>6));
 506                PHY_SetBBReg(pAdapter, rOFDM0_XATxIQImbalance, 0x003F0000,
 507                             (TX0_C&0x3F));
 508                PHY_SetBBReg(pAdapter, rOFDM0_ECCAThreshold, BIT(29),
 509                             ((Y * Oldval_0>>7) & 0x1));
 510
 511                if (bTxOnly) {
 512                        DBG_8723A("_PHY_PathAFillIQKMatrix only Tx OK\n");
 513                        return;
 514                }
 515
 516                reg = result[final_candidate][2];
 517                PHY_SetBBReg(pAdapter, rOFDM0_XARxIQImbalance, 0x3FF, reg);
 518
 519                reg = result[final_candidate][3] & 0x3F;
 520                PHY_SetBBReg(pAdapter, rOFDM0_XARxIQImbalance, 0xFC00, reg);
 521
 522                reg = (result[final_candidate][3] >> 6) & 0xF;
 523                PHY_SetBBReg(pAdapter, rOFDM0_RxIQExtAnta, 0xF0000000, reg);
 524        }
 525}
 526
 527static void _PHY_PathBFillIQKMatrix(struct rtw_adapter *pAdapter, bool bIQKOK, int result[][8], u8 final_candidate, bool bTxOnly)
 528{
 529        u32 Oldval_1, X, TX1_A, reg;
 530        s32 Y, TX1_C;
 531
 532        DBG_8723A("Path B IQ Calibration %s !\n", (bIQKOK)?"Success":"Failed");
 533
 534        if (final_candidate == 0xFF) {
 535                return;
 536        } else if (bIQKOK) {
 537                Oldval_1 = rtl8723au_read32(pAdapter, rOFDM0_XBTxIQImbalance);
 538                Oldval_1 = (Oldval_1 >> 22) & 0x3FF;
 539
 540                X = result[final_candidate][4];
 541                if ((X & 0x00000200) != 0)
 542                        X = X | 0xFFFFFC00;
 543                TX1_A = (X * Oldval_1) >> 8;
 544                PHY_SetBBReg(pAdapter, rOFDM0_XBTxIQImbalance, 0x3FF, TX1_A);
 545                PHY_SetBBReg(pAdapter, rOFDM0_ECCAThreshold, BIT(27),
 546                             ((X * Oldval_1 >> 7) & 0x1));
 547
 548                Y = result[final_candidate][5];
 549                if ((Y & 0x00000200) != 0)
 550                        Y = Y | 0xFFFFFC00;
 551                TX1_C = (Y * Oldval_1) >> 8;
 552                PHY_SetBBReg(pAdapter, rOFDM0_XDTxAFE, 0xF0000000,
 553                             ((TX1_C & 0x3C0) >> 6));
 554                PHY_SetBBReg(pAdapter, rOFDM0_XBTxIQImbalance, 0x003F0000,
 555                             (TX1_C & 0x3F));
 556                PHY_SetBBReg(pAdapter, rOFDM0_ECCAThreshold, BIT(25),
 557                             ((Y * Oldval_1 >> 7) & 0x1));
 558
 559                if (bTxOnly)
 560                        return;
 561
 562                reg = result[final_candidate][6];
 563                PHY_SetBBReg(pAdapter, rOFDM0_XBRxIQImbalance, 0x3FF, reg);
 564
 565                reg = result[final_candidate][7] & 0x3F;
 566                PHY_SetBBReg(pAdapter, rOFDM0_XBRxIQImbalance, 0xFC00, reg);
 567
 568                reg = (result[final_candidate][7] >> 6) & 0xF;
 569                PHY_SetBBReg(pAdapter, rOFDM0_AGCRSSITable, 0x0000F000, reg);
 570        }
 571}
 572
 573static void _PHY_SaveADDARegisters(struct rtw_adapter *pAdapter, u32 *ADDAReg, u32 *ADDABackup, u32 RegisterNum)
 574{
 575        u32 i;
 576
 577        for (i = 0 ; i < RegisterNum ; i++) {
 578                ADDABackup[i] = rtl8723au_read32(pAdapter, ADDAReg[i]);
 579        }
 580}
 581
 582static void _PHY_SaveMACRegisters(struct rtw_adapter *pAdapter, u32 *MACReg,
 583                                  u32 *MACBackup)
 584{
 585        u32 i;
 586
 587        for (i = 0 ; i < (IQK_MAC_REG_NUM - 1); i++) {
 588                MACBackup[i] = rtl8723au_read8(pAdapter, MACReg[i]);
 589        }
 590        MACBackup[i] = rtl8723au_read32(pAdapter, MACReg[i]);
 591}
 592
 593static void _PHY_ReloadADDARegisters(struct rtw_adapter *pAdapter,
 594                                     u32 *ADDAReg, u32 *ADDABackup,
 595                                     u32 RegiesterNum)
 596{
 597        u32 i;
 598
 599        for (i = 0 ; i < RegiesterNum ; i++) {
 600                rtl8723au_write32(pAdapter, ADDAReg[i], ADDABackup[i]);
 601        }
 602}
 603
 604static void _PHY_ReloadMACRegisters(struct rtw_adapter *pAdapter,
 605                                    u32 *MACReg, u32 *MACBackup)
 606{
 607        u32 i;
 608
 609        for (i = 0 ; i < (IQK_MAC_REG_NUM - 1); i++)
 610                rtl8723au_write8(pAdapter, MACReg[i], (u8)MACBackup[i]);
 611
 612        rtl8723au_write32(pAdapter, MACReg[i], MACBackup[i]);
 613}
 614
 615static void _PHY_PathADDAOn(struct rtw_adapter *pAdapter, u32 *ADDAReg,
 616                            bool isPathAOn, bool is2T)
 617{
 618        u32 pathOn;
 619        u32 i;
 620
 621        pathOn = isPathAOn ? 0x04db25a4 : 0x0b1b25a4;
 622        if (!is2T) {
 623                pathOn = 0x0bdb25a0;
 624                rtl8723au_write32(pAdapter, ADDAReg[0], 0x0b1b25a0);
 625        } else {
 626                rtl8723au_write32(pAdapter, ADDAReg[0], pathOn);
 627        }
 628
 629        for (i = 1 ; i < IQK_ADDA_REG_NUM ; i++)
 630                rtl8723au_write32(pAdapter, ADDAReg[i], pathOn);
 631}
 632
 633static void _PHY_MACSettingCalibration(struct rtw_adapter *pAdapter,
 634                                       u32 *MACReg, u32 *MACBackup)
 635{
 636        u32 i = 0;
 637
 638        rtl8723au_write8(pAdapter, MACReg[i], 0x3F);
 639
 640        for (i = 1 ; i < (IQK_MAC_REG_NUM - 1); i++) {
 641                rtl8723au_write8(pAdapter, MACReg[i],
 642                                 (u8)(MACBackup[i] & ~BIT(3)));
 643        }
 644        rtl8723au_write8(pAdapter, MACReg[i], (u8)(MACBackup[i] & ~BIT(5)));
 645}
 646
 647static void _PHY_PathAStandBy(struct rtw_adapter *pAdapter)
 648{
 649        rtl8723au_write32(pAdapter, rFPGA0_IQK, 0x0);
 650        rtl8723au_write32(pAdapter, 0x840, 0x00010000);
 651        rtl8723au_write32(pAdapter, rFPGA0_IQK, 0x80800000);
 652}
 653
 654static void _PHY_PIModeSwitch(struct rtw_adapter *pAdapter, bool PIMode)
 655{
 656        u32 mode;
 657
 658        mode = PIMode ? 0x01000100 : 0x01000000;
 659        rtl8723au_write32(pAdapter, 0x820, mode);
 660        rtl8723au_write32(pAdapter, 0x828, mode);
 661}
 662
 663/*
 664return false => do IQK again
 665*/
 666static bool _PHY_SimularityCompare(struct rtw_adapter *pAdapter, int result[][8], u8 c1, u8 c2)
 667{
 668        u32 i, j, diff, SimularityBitMap, bound = 0;
 669        struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter);
 670        u8 final_candidate[2] = {0xFF, 0xFF};   /* for path A and path B */
 671        bool bResult = true;
 672
 673        if (pHalData->rf_type == RF_2T2R)
 674                bound = 8;
 675        else
 676                bound = 4;
 677
 678        SimularityBitMap = 0;
 679
 680        for (i = 0; i < bound; i++) {
 681                diff = (result[c1][i] > result[c2][i]) ? (result[c1][i] - result[c2][i]) : (result[c2][i] - result[c1][i]);
 682                if (diff > MAX_TOLERANCE) {
 683                        if ((i == 2 || i == 6) && !SimularityBitMap) {
 684                                if (result[c1][i]+result[c1][i+1] == 0)
 685                                        final_candidate[(i/4)] = c2;
 686                                else if (result[c2][i]+result[c2][i+1] == 0)
 687                                        final_candidate[(i/4)] = c1;
 688                                else
 689                                        SimularityBitMap = SimularityBitMap|(1<<i);
 690                        } else {
 691                                SimularityBitMap = SimularityBitMap|(1<<i);
 692                        }
 693                }
 694        }
 695
 696        if (SimularityBitMap == 0) {
 697                for (i = 0; i < (bound/4); i++) {
 698                        if (final_candidate[i] != 0xFF) {
 699                                for (j = i*4; j < (i+1)*4-2; j++)
 700                                        result[3][j] = result[final_candidate[i]][j];
 701                                bResult = false;
 702                        }
 703                }
 704                return bResult;
 705        } else if (!(SimularityBitMap & 0x0F)) {
 706                /* path A OK */
 707                for (i = 0; i < 4; i++)
 708                        result[3][i] = result[c1][i];
 709                return false;
 710        } else if (!(SimularityBitMap & 0xF0) && pHalData->rf_type == RF_2T2R) {
 711                /* path B OK */
 712                for (i = 4; i < 8; i++)
 713                        result[3][i] = result[c1][i];
 714                return false;
 715        } else {
 716                return false;
 717        }
 718}
 719
 720static void _PHY_IQCalibrate(struct rtw_adapter *pAdapter, int result[][8], u8 t, bool is2T)
 721{
 722        struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter);
 723        struct dm_priv *pdmpriv = &pHalData->dmpriv;
 724        u32 i;
 725        u8 PathAOK, PathBOK;
 726        u32 ADDA_REG[IQK_ADDA_REG_NUM] = {
 727                rFPGA0_XCD_SwitchControl, rBlue_Tooth,
 728                rRx_Wait_CCA, rTx_CCK_RFON,
 729                rTx_CCK_BBON, rTx_OFDM_RFON,
 730                rTx_OFDM_BBON, rTx_To_Rx,
 731                rTx_To_Tx, rRx_CCK,
 732                rRx_OFDM, rRx_Wait_RIFS,
 733                rRx_TO_Rx, rStandby,
 734                rSleep, rPMPD_ANAEN
 735        };
 736
 737        u32 IQK_MAC_REG[IQK_MAC_REG_NUM] = {
 738                REG_TXPAUSE, REG_BCN_CTRL,
 739                REG_BCN_CTRL_1, REG_GPIO_MUXCFG
 740        };
 741
 742        u32 IQK_BB_REG_92C[IQK_BB_REG_NUM] = {
 743                rOFDM0_TRxPathEnable, rOFDM0_TRMuxPar,
 744                rFPGA0_XCD_RFInterfaceSW, rConfig_AntA, rConfig_AntB,
 745                rFPGA0_XAB_RFInterfaceSW, rFPGA0_XA_RFInterfaceOE,
 746                rFPGA0_XB_RFInterfaceOE, rFPGA0_RFMOD
 747        };
 748
 749        const u32 retryCount = 2;
 750
 751        /*  Note: IQ calibration must be performed after loading  */
 752        /*              PHY_REG.txt , and radio_a, radio_b.txt   */
 753
 754        u32 bbvalue;
 755
 756        if (t == 0) {
 757                bbvalue = rtl8723au_read32(pAdapter, rFPGA0_RFMOD);
 758
 759                /*  Save ADDA parameters, turn Path A ADDA on */
 760                _PHY_SaveADDARegisters(pAdapter, ADDA_REG, pdmpriv->ADDA_backup, IQK_ADDA_REG_NUM);
 761                _PHY_SaveMACRegisters(pAdapter, IQK_MAC_REG, pdmpriv->IQK_MAC_backup);
 762                _PHY_SaveADDARegisters(pAdapter, IQK_BB_REG_92C, pdmpriv->IQK_BB_backup, IQK_BB_REG_NUM);
 763        }
 764        _PHY_PathADDAOn(pAdapter, ADDA_REG, true, is2T);
 765
 766        if (t == 0)
 767                pdmpriv->bRfPiEnable = (u8)
 768                        PHY_QueryBBReg(pAdapter, rFPGA0_XA_HSSIParameter1,
 769                                       BIT(8));
 770
 771        if (!pdmpriv->bRfPiEnable) {
 772                /*  Switch BB to PI mode to do IQ Calibration. */
 773                _PHY_PIModeSwitch(pAdapter, true);
 774        }
 775
 776        PHY_SetBBReg(pAdapter, rFPGA0_RFMOD, BIT(24), 0x00);
 777        rtl8723au_write32(pAdapter, rOFDM0_TRxPathEnable, 0x03a05600);
 778        rtl8723au_write32(pAdapter, rOFDM0_TRMuxPar, 0x000800e4);
 779        rtl8723au_write32(pAdapter, rFPGA0_XCD_RFInterfaceSW, 0x22204000);
 780        PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT(10), 0x01);
 781        PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT(26), 0x01);
 782        PHY_SetBBReg(pAdapter, rFPGA0_XA_RFInterfaceOE, BIT(10), 0x00);
 783        PHY_SetBBReg(pAdapter, rFPGA0_XB_RFInterfaceOE, BIT(10), 0x00);
 784
 785        if (is2T) {
 786                rtl8723au_write32(pAdapter,
 787                                  rFPGA0_XA_LSSIParameter, 0x00010000);
 788                rtl8723au_write32(pAdapter,
 789                                  rFPGA0_XB_LSSIParameter, 0x00010000);
 790        }
 791
 792        /* MAC settings */
 793        _PHY_MACSettingCalibration(pAdapter, IQK_MAC_REG, pdmpriv->IQK_MAC_backup);
 794
 795        /* Page B init */
 796        rtl8723au_write32(pAdapter, rConfig_AntA, 0x00080000);
 797
 798        if (is2T)
 799                rtl8723au_write32(pAdapter, rConfig_AntB, 0x00080000);
 800
 801        /*  IQ calibration setting */
 802        rtl8723au_write32(pAdapter, rFPGA0_IQK, 0x80800000);
 803        rtl8723au_write32(pAdapter, rTx_IQK, 0x01007c00);
 804        rtl8723au_write32(pAdapter, rRx_IQK, 0x01004800);
 805
 806        for (i = 0 ; i < retryCount ; i++) {
 807                PathAOK = _PHY_PathA_IQK(pAdapter, is2T);
 808                if (PathAOK == 0x03) {
 809                                DBG_8723A("Path A IQK Success!!\n");
 810                                result[t][0] = (rtl8723au_read32(pAdapter, rTx_Power_Before_IQK_A)&0x3FF0000)>>16;
 811                                result[t][1] = (rtl8723au_read32(pAdapter, rTx_Power_After_IQK_A)&0x3FF0000)>>16;
 812                                result[t][2] = (rtl8723au_read32(pAdapter, rRx_Power_Before_IQK_A_2)&0x3FF0000)>>16;
 813                                result[t][3] = (rtl8723au_read32(pAdapter, rRx_Power_After_IQK_A_2)&0x3FF0000)>>16;
 814                        break;
 815                } else if (i == (retryCount-1) && PathAOK == 0x01) {
 816                        /* Tx IQK OK */
 817                        DBG_8723A("Path A IQK Only  Tx Success!!\n");
 818
 819                        result[t][0] = (rtl8723au_read32(pAdapter, rTx_Power_Before_IQK_A)&0x3FF0000)>>16;
 820                        result[t][1] = (rtl8723au_read32(pAdapter, rTx_Power_After_IQK_A)&0x3FF0000)>>16;
 821                }
 822        }
 823
 824        if (0x00 == PathAOK) {
 825                DBG_8723A("Path A IQK failed!!\n");
 826        }
 827
 828        if (is2T) {
 829                _PHY_PathAStandBy(pAdapter);
 830
 831                /*  Turn Path B ADDA on */
 832                _PHY_PathADDAOn(pAdapter, ADDA_REG, false, is2T);
 833
 834                for (i = 0 ; i < retryCount ; i++) {
 835                        PathBOK = _PHY_PathB_IQK(pAdapter);
 836                        if (PathBOK == 0x03) {
 837                                DBG_8723A("Path B IQK Success!!\n");
 838                                result[t][4] = (rtl8723au_read32(pAdapter, rTx_Power_Before_IQK_B)&0x3FF0000)>>16;
 839                                result[t][5] = (rtl8723au_read32(pAdapter, rTx_Power_After_IQK_B)&0x3FF0000)>>16;
 840                                result[t][6] = (rtl8723au_read32(pAdapter, rRx_Power_Before_IQK_B_2)&0x3FF0000)>>16;
 841                                result[t][7] = (rtl8723au_read32(pAdapter, rRx_Power_After_IQK_B_2)&0x3FF0000)>>16;
 842                                break;
 843                        } else if (i == (retryCount - 1) && PathBOK == 0x01) {
 844                                /* Tx IQK OK */
 845                                DBG_8723A("Path B Only Tx IQK Success!!\n");
 846                                result[t][4] = (rtl8723au_read32(pAdapter, rTx_Power_Before_IQK_B)&0x3FF0000)>>16;
 847                                result[t][5] = (rtl8723au_read32(pAdapter, rTx_Power_After_IQK_B)&0x3FF0000)>>16;
 848                        }
 849                }
 850
 851                if (0x00 == PathBOK) {
 852                        DBG_8723A("Path B IQK failed!!\n");
 853                }
 854        }
 855
 856        /* Back to BB mode, load original value */
 857        rtl8723au_write32(pAdapter, rFPGA0_IQK, 0);
 858
 859        if (t != 0) {
 860                if (!pdmpriv->bRfPiEnable) {
 861                        /*  Switch back BB to SI mode after finish IQ Calibration. */
 862                        _PHY_PIModeSwitch(pAdapter, false);
 863                }
 864
 865                /*  Reload ADDA power saving parameters */
 866                _PHY_ReloadADDARegisters(pAdapter, ADDA_REG, pdmpriv->ADDA_backup, IQK_ADDA_REG_NUM);
 867
 868                /*  Reload MAC parameters */
 869                _PHY_ReloadMACRegisters(pAdapter, IQK_MAC_REG, pdmpriv->IQK_MAC_backup);
 870
 871                /*  Reload BB parameters */
 872                _PHY_ReloadADDARegisters(pAdapter, IQK_BB_REG_92C, pdmpriv->IQK_BB_backup, IQK_BB_REG_NUM);
 873
 874                /*  Restore RX initial gain */
 875                rtl8723au_write32(pAdapter,
 876                                  rFPGA0_XA_LSSIParameter, 0x00032ed3);
 877                if (is2T) {
 878                        rtl8723au_write32(pAdapter,
 879                                          rFPGA0_XB_LSSIParameter, 0x00032ed3);
 880                }
 881
 882                /* load 0xe30 IQC default value */
 883                rtl8723au_write32(pAdapter, rTx_IQK_Tone_A, 0x01008c00);
 884                rtl8723au_write32(pAdapter, rRx_IQK_Tone_A, 0x01008c00);
 885
 886        }
 887}
 888
 889static void _PHY_LCCalibrate(struct rtw_adapter *pAdapter, bool is2T)
 890{
 891        u8 tmpReg;
 892        u32 RF_Amode = 0, RF_Bmode = 0, LC_Cal;
 893
 894        /* Check continuous TX and Packet TX */
 895        tmpReg = rtl8723au_read8(pAdapter, 0xd03);
 896
 897        if ((tmpReg&0x70) != 0) {
 898                /* Deal with contisuous TX case */
 899                /* disable all continuous TX */
 900                rtl8723au_write8(pAdapter, 0xd03, tmpReg&0x8F);
 901        } else {
 902                /*  Deal with Packet TX case */
 903                /*  block all queues */
 904                rtl8723au_write8(pAdapter, REG_TXPAUSE, 0xFF);
 905        }
 906
 907        if ((tmpReg&0x70) != 0) {
 908                /* 1. Read original RF mode */
 909                /* Path-A */
 910                RF_Amode = PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_AC, bMask12Bits);
 911
 912                /* Path-B */
 913                if (is2T)
 914                        RF_Bmode = PHY_QueryRFReg(pAdapter, RF_PATH_B, RF_AC, bMask12Bits);
 915
 916                /* 2. Set RF mode = standby mode */
 917                /* Path-A */
 918                PHY_SetRFReg(pAdapter, RF_PATH_A, RF_AC, bMask12Bits, (RF_Amode&0x8FFFF)|0x10000);
 919
 920                /* Path-B */
 921                if (is2T)
 922                        PHY_SetRFReg(pAdapter, RF_PATH_B, RF_AC, bMask12Bits, (RF_Bmode&0x8FFFF)|0x10000);
 923        }
 924
 925        /* 3. Read RF reg18 */
 926        LC_Cal = PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_CHNLBW, bMask12Bits);
 927
 928        /* 4. Set LC calibration begin */
 929        PHY_SetRFReg(pAdapter, RF_PATH_A, RF_CHNLBW, bMask12Bits, LC_Cal|0x08000);
 930
 931        msleep(100);
 932
 933        /* Restore original situation */
 934        if ((tmpReg&0x70) != 0) {       /* Deal with contuous TX case  */
 935                /* Path-A */
 936                rtl8723au_write8(pAdapter, 0xd03, tmpReg);
 937                PHY_SetRFReg(pAdapter, RF_PATH_A, RF_AC, bMask12Bits, RF_Amode);
 938
 939                /* Path-B */
 940                if (is2T)
 941                        PHY_SetRFReg(pAdapter, RF_PATH_B, RF_AC, bMask12Bits, RF_Bmode);
 942        } else /*  Deal with Packet TX case */
 943                rtl8723au_write8(pAdapter, REG_TXPAUSE, 0x00);
 944}
 945
 946/* Analog Pre-distortion calibration */
 947#define         APK_BB_REG_NUM  8
 948#define         APK_CURVE_REG_NUM 4
 949#define         PATH_NUM                2
 950
 951void rtl8723a_phy_iq_calibrate(struct rtw_adapter *pAdapter, bool bReCovery)
 952{
 953        struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter);
 954        struct dm_priv *pdmpriv = &pHalData->dmpriv;
 955        s32 result[4][8];       /* last is final result */
 956        u8 i, final_candidate;
 957        bool bPathAOK, bPathBOK;
 958        s32 RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4;
 959        s32 RegECC, RegTmp = 0;
 960        bool is12simular, is13simular, is23simular;
 961        bool bStartContTx = false, bSingleTone = false;
 962        bool bCarrierSuppression = false;
 963        u32 IQK_BB_REG_92C[IQK_BB_REG_NUM] = {
 964                rOFDM0_XARxIQImbalance, rOFDM0_XBRxIQImbalance,
 965                rOFDM0_ECCAThreshold, rOFDM0_AGCRSSITable,
 966                rOFDM0_XATxIQImbalance, rOFDM0_XBTxIQImbalance,
 967                rOFDM0_XCTxAFE, rOFDM0_XDTxAFE,
 968                rOFDM0_RxIQExtAnta
 969        };
 970
 971        /* ignore IQK when continuous Tx */
 972        if (bStartContTx || bSingleTone || bCarrierSuppression)
 973                return;
 974
 975        if (bReCovery) {
 976                _PHY_ReloadADDARegisters(pAdapter, IQK_BB_REG_92C, pdmpriv->IQK_BB_backup_recover, 9);
 977                return;
 978        }
 979        DBG_8723A("IQK:Start!!!\n");
 980
 981        for (i = 0; i < 8; i++) {
 982                result[0][i] = 0;
 983                result[1][i] = 0;
 984                result[2][i] = 0;
 985                result[3][i] = 0;
 986        }
 987        final_candidate = 0xff;
 988        bPathAOK = false;
 989        bPathBOK = false;
 990        is12simular = false;
 991        is23simular = false;
 992        is13simular = false;
 993
 994        for (i = 0; i < 3; i++) {
 995                if (pHalData->rf_type == RF_2T2R)
 996                        _PHY_IQCalibrate(pAdapter, result, i, true);
 997                else /*  For 88C 1T1R */
 998                        _PHY_IQCalibrate(pAdapter, result, i, false);
 999
1000                if (i == 1) {
1001                        is12simular = _PHY_SimularityCompare(pAdapter, result, 0, 1);
1002                        if (is12simular) {
1003                                final_candidate = 0;
1004                                break;
1005                        }
1006                }
1007
1008                if (i == 2) {
1009                        is13simular = _PHY_SimularityCompare(pAdapter, result, 0, 2);
1010                        if (is13simular) {
1011                                final_candidate = 0;
1012                                break;
1013                        }
1014
1015                        is23simular = _PHY_SimularityCompare(pAdapter, result, 1, 2);
1016                        if (is23simular) {
1017                                final_candidate = 1;
1018                        } else {
1019                                for (i = 0; i < 8; i++)
1020                                        RegTmp += result[3][i];
1021
1022                                if (RegTmp != 0)
1023                                        final_candidate = 3;
1024                                else
1025                                        final_candidate = 0xFF;
1026                        }
1027                }
1028        }
1029
1030        for (i = 0; i < 4; i++) {
1031                RegE94 = result[i][0];
1032                RegE9C = result[i][1];
1033                RegEA4 = result[i][2];
1034                RegEAC = result[i][3];
1035                RegEB4 = result[i][4];
1036                RegEBC = result[i][5];
1037                RegEC4 = result[i][6];
1038                RegECC = result[i][7];
1039        }
1040
1041        if (final_candidate != 0xff) {
1042                RegE94 = result[final_candidate][0];
1043                pdmpriv->RegE94 =  RegE94;
1044                RegE9C = result[final_candidate][1];
1045                pdmpriv->RegE9C = RegE9C;
1046                RegEA4 = result[final_candidate][2];
1047                RegEAC = result[final_candidate][3];
1048                RegEB4 = result[final_candidate][4];
1049                pdmpriv->RegEB4 = RegEB4;
1050                RegEBC = result[final_candidate][5];
1051                pdmpriv->RegEBC = RegEBC;
1052                RegEC4 = result[final_candidate][6];
1053                RegECC = result[final_candidate][7];
1054                DBG_8723A("IQK: final_candidate is %x\n", final_candidate);
1055                DBG_8723A("IQK: RegE94 =%x RegE9C =%x RegEA4 =%x RegEAC =%x RegEB4 =%x RegEBC =%x RegEC4 =%x RegECC =%x\n ",
1056                          RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC);
1057                bPathAOK = bPathBOK = true;
1058        } else {
1059                RegE94 = RegEB4 = pdmpriv->RegE94 = pdmpriv->RegEB4 = 0x100;    /* X default value */
1060                RegE9C = RegEBC = pdmpriv->RegE9C = pdmpriv->RegEBC = 0x0;              /* Y default value */
1061        }
1062
1063        if ((RegE94 != 0)/*&&(RegEA4 != 0)*/)
1064                _PHY_PathAFillIQKMatrix(pAdapter, bPathAOK, result, final_candidate, (RegEA4 == 0));
1065
1066        if (pHalData->rf_type == RF_2T2R) {
1067                if ((RegEB4 != 0)/*&&(RegEC4 != 0)*/)
1068                        _PHY_PathBFillIQKMatrix(pAdapter, bPathBOK, result,
1069                                                final_candidate, (RegEC4 == 0));
1070        }
1071
1072        _PHY_SaveADDARegisters(pAdapter, IQK_BB_REG_92C, pdmpriv->IQK_BB_backup_recover, 9);
1073}
1074
1075void rtl8723a_phy_lc_calibrate(struct rtw_adapter *pAdapter)
1076{
1077        struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter);
1078        struct mlme_ext_priv *pmlmeext = &pAdapter->mlmeextpriv;
1079        bool bStartContTx = false, bSingleTone = false, bCarrierSuppression = false;
1080
1081        /* ignore IQK when continuous Tx */
1082        if (bStartContTx || bSingleTone || bCarrierSuppression)
1083                return;
1084
1085        if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS)
1086                return;
1087
1088        if (pHalData->rf_type == RF_2T2R)
1089                _PHY_LCCalibrate(pAdapter, true);
1090        else    /*  For 88C 1T1R */
1091                _PHY_LCCalibrate(pAdapter, false);
1092}
1093
1094void
1095rtl8723a_phy_ap_calibrate(struct rtw_adapter *pAdapter, char delta)
1096{
1097}
1098