/****************************************************************************** * * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA * * ******************************************************************************/ /****************************************************************************** * * * Module: rtl8192c_rf6052.c ( Source C File) * * Note: Provide RF 6052 series relative API. * * Function: * * Export: * * Abbrev: * * History: * Data Who Remark * * 09/25/2008 MHC Create initial version. * 11/05/2008 MHC Add API for tw power setting. * * ******************************************************************************/ #define _RTL8188E_RF6052_C_ #include #include #include #include #include /*---------------------------Define Local Constant---------------------------*/ // Define local structure for debug!!!!! typedef struct RF_Shadow_Compare_Map { // Shadow register value u32 Value; // Compare or not flag u8 Compare; // Record If it had ever modified unpredicted u8 ErrorOrNot; // Recorver Flag u8 Recorver; // u8 Driver_Write; }RF_SHADOW_T; /*---------------------------Define Local Constant---------------------------*/ /*------------------------Define global variable-----------------------------*/ /*------------------------Define global variable-----------------------------*/ /*------------------------Define local variable------------------------------*/ // 2008/11/20 MH For Debug only, RF //static RF_SHADOW_T RF_Shadow[RF6052_MAX_PATH][RF6052_MAX_REG] = {0}; static RF_SHADOW_T RF_Shadow[RF6052_MAX_PATH][RF6052_MAX_REG]; /*------------------------Define local variable------------------------------*/ /*----------------------------------------------------------------------------- * Function: RF_ChangeTxPath * * Overview: For RL6052, we must change some RF settign for 1T or 2T. * * Input: u2Byte DataRate // 0x80-8f, 0x90-9f * * Output: NONE * * Return: NONE * * Revised History: * When Who Remark * 09/25/2008 MHC Create Version 0. * Firmwaer support the utility later. * *---------------------------------------------------------------------------*/ void rtl8188e_RF_ChangeTxPath( IN PADAPTER Adapter, IN u16 DataRate) { // We do not support gain table change inACUT now !!!! Delete later !!! #if 0//(RTL92SE_FPGA_VERIFY == 0) static u1Byte RF_Path_Type = 2; // 1 = 1T 2= 2T static u4Byte tx_gain_tbl1[6] = {0x17f50, 0x11f40, 0x0cf30, 0x08720, 0x04310, 0x00100}; static u4Byte tx_gain_tbl2[6] = {0x15ea0, 0x10e90, 0x0c680, 0x08250, 0x04040, 0x00030}; u1Byte i; if (RF_Path_Type == 2 && (DataRate&0xF) <= 0x7) { // Set TX SYNC power G2G3 loop filter PHY_SetRFReg(Adapter, (RF_RADIO_PATH_E)RF_PATH_A, RF_TXPA_G2, bRFRegOffsetMask, 0x0f000); PHY_SetRFReg(Adapter, (RF_RADIO_PATH_E)RF_PATH_A, RF_TXPA_G3, bRFRegOffsetMask, 0xeacf1); // Change TX AGC gain table for (i = 0; i < 6; i++) PHY_SetRFReg(Adapter, (RF_RADIO_PATH_E)RF_PATH_A, RF_TX_AGC, bRFRegOffsetMask, tx_gain_tbl1[i]); // Set PA to high value PHY_SetRFReg(Adapter, (RF_RADIO_PATH_E)RF_PATH_A, RF_TXPA_G2, bRFRegOffsetMask, 0x01e39); } else if (RF_Path_Type == 1 && (DataRate&0xF) >= 0x8) { // Set TX SYNC power G2G3 loop filter PHY_SetRFReg(Adapter, (RF_RADIO_PATH_E)RF_PATH_A, RF_TXPA_G2, bRFRegOffsetMask, 0x04440); PHY_SetRFReg(Adapter, (RF_RADIO_PATH_E)RF_PATH_A, RF_TXPA_G3, bRFRegOffsetMask, 0xea4f1); // Change TX AGC gain table for (i = 0; i < 6; i++) PHY_SetRFReg(Adapter, (RF_RADIO_PATH_E)RF_PATH_A, RF_TX_AGC, bRFRegOffsetMask, tx_gain_tbl2[i]); // Set PA low gain PHY_SetRFReg(Adapter, (RF_RADIO_PATH_E)RF_PATH_A, RF_TXPA_G2, bRFRegOffsetMask, 0x01e19); } #endif } /* RF_ChangeTxPath */ /*----------------------------------------------------------------------------- * Function: PHY_RF6052SetBandwidth() * * Overview: This function is called by SetBWModeCallback8190Pci() only * * Input: PADAPTER Adapter * WIRELESS_BANDWIDTH_E Bandwidth //20M or 40M * * Output: NONE * * Return: NONE * * Note: For RF type 0222D *---------------------------------------------------------------------------*/ VOID rtl8188e_PHY_RF6052SetBandwidth( IN PADAPTER Adapter, IN HT_CHANNEL_WIDTH Bandwidth) //20M or 40M { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); switch (Bandwidth) { case HT_CHANNEL_WIDTH_20: pHalData->RfRegChnlVal[0] = ((pHalData->RfRegChnlVal[0] & 0xfffff3ff) | BIT(10) | BIT(11)); PHY_SetRFReg(Adapter, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal[0]); break; case HT_CHANNEL_WIDTH_40: pHalData->RfRegChnlVal[0] = ((pHalData->RfRegChnlVal[0] & 0xfffff3ff)| BIT(10)); PHY_SetRFReg(Adapter, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal[0]); break; default: //RT_TRACE(COMP_DBG, DBG_LOUD, ("PHY_SetRF8225Bandwidth(): unknown Bandwidth: %#X\n",Bandwidth )); break; } } /*----------------------------------------------------------------------------- * Function: PHY_RF6052SetCckTxPower * * Overview: * * Input: NONE * * Output: NONE * * Return: NONE * * Revised History: * When Who Remark * 11/05/2008 MHC Simulate 8192series.. * *---------------------------------------------------------------------------*/ VOID rtl8188e_PHY_RF6052SetCckTxPower( IN PADAPTER Adapter, IN u8* pPowerlevel) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; struct dm_priv *pdmpriv = &pHalData->dmpriv; struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; //PMGNT_INFO pMgntInfo=&Adapter->MgntInfo; u32 TxAGC[2]={0, 0}, tmpval=0,pwrtrac_value; BOOLEAN TurboScanOff = _FALSE; u8 idx1, idx2; u8* ptr; u8 direction; //FOR CE ,must disable turbo scan TurboScanOff = _TRUE; if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { TxAGC[RF_PATH_A] = 0x3f3f3f3f; TxAGC[RF_PATH_B] = 0x3f3f3f3f; TurboScanOff = _TRUE;//disable turbo scan if (TurboScanOff) { for (idx1=RF_PATH_A; idx1<=RF_PATH_B; idx1++) { TxAGC[idx1] = pPowerlevel[idx1] | (pPowerlevel[idx1]<<8) | (pPowerlevel[idx1]<<16) | (pPowerlevel[idx1]<<24); #ifdef CONFIG_USB_HCI // 2010/10/18 MH For external PA module. We need to limit power index to be less than 0x20. if (TxAGC[idx1] > 0x20 && pHalData->ExternalPA) TxAGC[idx1] = 0x20; #endif } } } else { // 20100427 Joseph: Driver dynamic Tx power shall not affect Tx power. It shall be determined by power training mechanism. // Currently, we cannot fully disable driver dynamic tx power mechanism because it is referenced by BT coexist mechanism. // In the future, two mechanism shall be separated from each other and maintained independantly. Thanks for Lanhsin's reminder. if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) { TxAGC[RF_PATH_A] = 0x10101010; TxAGC[RF_PATH_B] = 0x10101010; } else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) { TxAGC[RF_PATH_A] = 0x00000000; TxAGC[RF_PATH_B] = 0x00000000; } else { for (idx1=RF_PATH_A; idx1<=RF_PATH_B; idx1++) { TxAGC[idx1] = pPowerlevel[idx1] | (pPowerlevel[idx1]<<8) | (pPowerlevel[idx1]<<16) | (pPowerlevel[idx1]<<24); } if (pHalData->EEPROMRegulatory==0) { tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][6]) + (pHalData->MCSTxPowerLevelOriginalOffset[0][7]<<8); TxAGC[RF_PATH_A] += tmpval; tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][14]) + (pHalData->MCSTxPowerLevelOriginalOffset[0][15]<<24); TxAGC[RF_PATH_B] += tmpval; } } } for (idx1=RF_PATH_A; idx1<=RF_PATH_B; idx1++) { ptr = (u8*)(&(TxAGC[idx1])); for (idx2=0; idx2<4; idx2++) { if (*ptr > RF6052_MAX_TX_PWR) *ptr = RF6052_MAX_TX_PWR; ptr++; } } ODM_TxPwrTrackAdjust88E(&pHalData->odmpriv, 1, &direction, &pwrtrac_value); if (direction == 1) // Increase TX pwoer { TxAGC[0] += pwrtrac_value; TxAGC[1] += pwrtrac_value; } else if (direction == 2) // Decrease TX pwoer { TxAGC[0] -= pwrtrac_value; TxAGC[1] -= pwrtrac_value; } // rf-A cck tx power tmpval = TxAGC[RF_PATH_A]&0xff; PHY_SetBBReg(Adapter, rTxAGC_A_CCK1_Mcs32, bMaskByte1, tmpval); //RTPRINT(FPHY, PHY_TXPWR, ("CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n", tmpval, rTxAGC_A_CCK1_Mcs32)); tmpval = TxAGC[RF_PATH_A]>>8; PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval); //RTPRINT(FPHY, PHY_TXPWR, ("CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n", tmpval, rTxAGC_B_CCK11_A_CCK2_11)); // rf-B cck tx power tmpval = TxAGC[RF_PATH_B]>>24; PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, tmpval); //RTPRINT(FPHY, PHY_TXPWR, ("CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", tmpval, rTxAGC_B_CCK11_A_CCK2_11)); tmpval = TxAGC[RF_PATH_B]&0x00ffffff; PHY_SetBBReg(Adapter, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval); //RTPRINT(FPHY, PHY_TXPWR, ("CCK PWR 1~5.5M (rf-B) = 0x%x (reg 0x%x)\n", // tmpval, rTxAGC_B_CCK1_55_Mcs32)); } /* PHY_RF6052SetCckTxPower */ #if 0 // // powerbase0 for OFDM rates // powerbase1 for HT MCS rates // static void getPowerBase( IN PADAPTER Adapter, IN u8* pPowerLevel, IN u8 Channel, IN OUT u32* OfdmBase, IN OUT u32* MCSBase ) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); u32 powerBase0, powerBase1; u8 Legacy_pwrdiff=0, HT20_pwrdiff=0; u8 i, powerlevel[2]; for (i=0; i<2; i++) { powerlevel[i] = pPowerLevel[i]; Legacy_pwrdiff = pHalData->TxPwrLegacyHtDiff[i][Channel-1]; powerBase0 = powerlevel[i] + Legacy_pwrdiff; powerBase0 = (powerBase0<<24) | (powerBase0<<16) |(powerBase0<<8) |powerBase0; *(OfdmBase+i) = powerBase0; //RTPRINT(FPHY, PHY_TXPWR, (" [OFDM power base index rf(%c) = 0x%x]\n", ((i==0)?'A':'B'), *(OfdmBase+i))); } for (i=0; i<2; i++) { //Check HT20 to HT40 diff if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20) { HT20_pwrdiff = pHalData->TxPwrHt20Diff[i][Channel-1]; powerlevel[i] += HT20_pwrdiff; } powerBase1 = powerlevel[i]; powerBase1 = (powerBase1<<24) | (powerBase1<<16) |(powerBase1<<8) |powerBase1; *(MCSBase+i) = powerBase1; //RTPRINT(FPHY, PHY_TXPWR, (" [MCS power base index rf(%c) = 0x%x]\n", ((i==0)?'A':'B'), *(MCSBase+i))); } } #endif // // powerbase0 for OFDM rates // powerbase1 for HT MCS rates // void getPowerBase88E( IN PADAPTER Adapter, IN u8* pPowerLevelOFDM, IN u8* pPowerLevelBW20, IN u8* pPowerLevelBW40, IN u8 Channel, IN OUT u32* OfdmBase, IN OUT u32* MCSBase ) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); u32 powerBase0, powerBase1; u8 Legacy_pwrdiff=0; s8 HT20_pwrdiff=0; u8 i, powerlevel[2]; for (i=0; i<2; i++) { powerBase0 = pPowerLevelOFDM[i]; powerBase0 = (powerBase0<<24) | (powerBase0<<16) |(powerBase0<<8) |powerBase0; *(OfdmBase+i) = powerBase0; //DBG_871X(" [OFDM power base index rf(%c) = 0x%x]\n", ((i==0)?'A':'B'), *(OfdmBase+i)); } for (i=0; iNumTotalRFPath; i++) { //Check HT20 to HT40 diff if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20) { powerlevel[i] = pPowerLevelBW20[i]; } else { powerlevel[i] = pPowerLevelBW40[i]; } powerBase1 = powerlevel[i]; powerBase1 = (powerBase1<<24) | (powerBase1<<16) |(powerBase1<<8) |powerBase1; *(MCSBase+i) = powerBase1; //DBG_871X(" [MCS power base index rf(%c) = 0x%x]\n", ((i==0)?'A':'B'), *(MCSBase+i)); } } #if 0 static void getTxPowerWriteValByRegulatory( IN PADAPTER Adapter, IN u8 Channel, IN u8 index, IN u32* powerBase0, IN u32* powerBase1, OUT u32* pOutWriteVal ) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); struct dm_priv *pdmpriv = &pHalData->dmpriv; u8 i, chnlGroup, pwr_diff_limit[4]; u32 writeVal, customer_limit, rf; // // Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate // for (rf=0; rf<2; rf++) { switch (pHalData->EEPROMRegulatory) { case 0: // Realtek better performance // increase power diff defined by Realtek for large power chnlGroup = 0; //RTPRINT(FPHY, PHY_TXPWR, ("MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%x\n", // chnlGroup, index, pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)])); writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] + ((index<2)?powerBase0[rf]:powerBase1[rf]); //RTPRINT(FPHY, PHY_TXPWR, ("RTK better performance, writeVal(%c) = 0x%x\n", ((rf==0)?'A':'B'), writeVal)); break; case 1: // Realtek regulatory // increase power diff defined by Realtek for regulatory { if (pHalData->pwrGroupCnt == 1) chnlGroup = 0; if (pHalData->pwrGroupCnt >= 3) { if (Channel <= 3) chnlGroup = 0; else if (Channel >= 4 && Channel <= 9) chnlGroup = 1; else if (Channel > 9) chnlGroup = 2; if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20) chnlGroup++; else chnlGroup+=4; } //RTPRINT(FPHY, PHY_TXPWR, ("MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%x\n", //chnlGroup, index, pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)])); writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] + ((index<2)?powerBase0[rf]:powerBase1[rf]); //RTPRINT(FPHY, PHY_TXPWR, ("Realtek regulatory, 20MHz, writeVal(%c) = 0x%x\n", ((rf==0)?'A':'B'), writeVal)); } break; case 2: // Better regulatory // don't increase any power diff writeVal = ((index<2)?powerBase0[rf]:powerBase1[rf]); //RTPRINT(FPHY, PHY_TXPWR, ("Better regulatory, writeVal(%c) = 0x%x\n", ((rf==0)?'A':'B'), writeVal)); break; case 3: // Customer defined power diff. // increase power diff defined by customer. chnlGroup = 0; //RTPRINT(FPHY, PHY_TXPWR, ("MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%x\n", // chnlGroup, index, pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)])); if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_40) { //RTPRINT(FPHY, PHY_TXPWR, ("customer's limit, 40MHz rf(%c) = 0x%x\n", // ((rf==0)?'A':'B'), pHalData->PwrGroupHT40[rf][Channel-1])); } else { //RTPRINT(FPHY, PHY_TXPWR, ("customer's limit, 20MHz rf(%c) = 0x%x\n", // ((rf==0)?'A':'B'), pHalData->PwrGroupHT20[rf][Channel-1])); } for (i=0; i<4; i++) { pwr_diff_limit[i] = (u8)((pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)]&(0x7f<<(i*8)))>>(i*8)); if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_40) { if (pwr_diff_limit[i] > pHalData->PwrGroupHT40[rf][Channel-1]) pwr_diff_limit[i] = pHalData->PwrGroupHT40[rf][Channel-1]; } else { if (pwr_diff_limit[i] > pHalData->PwrGroupHT20[rf][Channel-1]) pwr_diff_limit[i] = pHalData->PwrGroupHT20[rf][Channel-1]; } } customer_limit = (pwr_diff_limit[3]<<24) | (pwr_diff_limit[2]<<16) | (pwr_diff_limit[1]<<8) | (pwr_diff_limit[0]); //RTPRINT(FPHY, PHY_TXPWR, ("Customer's limit rf(%c) = 0x%x\n", ((rf==0)?'A':'B'), customer_limit)); writeVal = customer_limit + ((index<2)?powerBase0[rf]:powerBase1[rf]); //RTPRINT(FPHY, PHY_TXPWR, ("Customer, writeVal rf(%c)= 0x%x\n", ((rf==0)?'A':'B'), writeVal)); break; default: chnlGroup = 0; writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] + ((index<2)?powerBase0[rf]:powerBase1[rf]); //RTPRINT(FPHY, PHY_TXPWR, ("RTK better performance, writeVal rf(%c) = 0x%x\n", ((rf==0)?'A':'B'), writeVal)); break; } // 20100427 Joseph: Driver dynamic Tx power shall not affect Tx power. It shall be determined by power training mechanism. // Currently, we cannot fully disable driver dynamic tx power mechanism because it is referenced by BT coexist mechanism. // In the future, two mechanism shall be separated from each other and maintained independantly. Thanks for Lanhsin's reminder. if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) writeVal = 0x14141414; else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) writeVal = 0x00000000; // 20100628 Joseph: High power mode for BT-Coexist mechanism. // This mechanism is only applied when Driver-Highpower-Mechanism is OFF. if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT1) { //RTPRINT(FBT, BT_TRACE, ("Tx Power (-6)\n")); writeVal = writeVal - 0x06060606; } else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT2) { //RTPRINT(FBT, BT_TRACE, ("Tx Power (-0)\n")); writeVal = writeVal; } *(pOutWriteVal+rf) = writeVal; } } #endif void getTxPowerWriteValByRegulatory88E( IN PADAPTER Adapter, IN u8 Channel, IN u8 index, IN u32* powerBase0, IN u32* powerBase1, OUT u32* pOutWriteVal ) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); struct dm_priv *pdmpriv = &pHalData->dmpriv; u1Byte i, chnlGroup=0, pwr_diff_limit[4], customer_pwr_limit; s1Byte pwr_diff=0; u4Byte writeVal, customer_limit, rf; u1Byte Regulatory = pHalData->EEPROMRegulatory; // // Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate // #if 0 // (INTEL_PROXIMITY_SUPPORT == 1) if (pMgntInfo->IntelProximityModeInfo.PowerOutput > 0) Regulatory = 2; #endif for (rf=0; rf<2; rf++) { switch (Regulatory) { case 0: // Realtek better performance // increase power diff defined by Realtek for large power chnlGroup = 0; //RTPRINT(FPHY, PHY_TXPWR, ("MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%x\n", // chnlGroup, index, pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)])); writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] + ((index<2)?powerBase0[rf]:powerBase1[rf]); //RTPRINT(FPHY, PHY_TXPWR, ("RTK better performance, writeVal(%c) = 0x%x\n", ((rf==0)?'A':'B'), writeVal)); break; case 1: // Realtek regulatory // increase power diff defined by Realtek for regulatory { if (pHalData->pwrGroupCnt == 1) chnlGroup = 0; if (pHalData->pwrGroupCnt >= pHalData->PGMaxGroup) { if (Channel < 3) // Chanel 1-2 chnlGroup = 0; else if (Channel < 6) // Channel 3-5 chnlGroup = 1; else if (Channel <9) // Channel 6-8 chnlGroup = 2; else if (Channel <12) // Channel 9-11 chnlGroup = 3; else if (Channel <14) // Channel 12-13 chnlGroup = 4; else if (Channel ==14) // Channel 14 chnlGroup = 5; /* if (Channel <= 3) chnlGroup = 0; else if (Channel >= 4 && Channel <= 9) chnlGroup = 1; else if (Channel > 9) chnlGroup = 2; if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20) chnlGroup++; else chnlGroup+=4; */ } //RTPRINT(FPHY, PHY_TXPWR, ("MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%x\n", //chnlGroup, index, pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)])); writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] + ((index<2)?powerBase0[rf]:powerBase1[rf]); //RTPRINT(FPHY, PHY_TXPWR, ("Realtek regulatory, 20MHz, writeVal(%c) = 0x%x\n", ((rf==0)?'A':'B'), writeVal)); } break; case 2: // Better regulatory // don't increase any power diff writeVal = ((index<2)?powerBase0[rf]:powerBase1[rf]); //RTPRINT(FPHY, PHY_TXPWR, ("Better regulatory, writeVal(%c) = 0x%x\n", ((rf==0)?'A':'B'), writeVal)); break; case 3: // Customer defined power diff. // increase power diff defined by customer. chnlGroup = 0; //RTPRINT(FPHY, PHY_TXPWR, ("MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%x\n", // chnlGroup, index, pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)])); /* if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20_40) { RTPRINT(FPHY, PHY_TXPWR, ("customer's limit, 40MHz rf(%c) = 0x%x\n", ((rf==0)?'A':'B'), pHalData->PwrGroupHT40[rf][Channel-1])); } else { RTPRINT(FPHY, PHY_TXPWR, ("customer's limit, 20MHz rf(%c) = 0x%x\n", ((rf==0)?'A':'B'), pHalData->PwrGroupHT20[rf][Channel-1])); }*/ if (index < 2) pwr_diff = pHalData->TxPwrLegacyHtDiff[rf][Channel-1]; else if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20) pwr_diff = pHalData->TxPwrHt20Diff[rf][Channel-1]; //RTPRINT(FPHY, PHY_TXPWR, ("power diff rf(%c) = 0x%x\n", ((rf==0)?'A':'B'), pwr_diff)); if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_40) customer_pwr_limit = pHalData->PwrGroupHT40[rf][Channel-1]; else customer_pwr_limit = pHalData->PwrGroupHT20[rf][Channel-1]; //RTPRINT(FPHY, PHY_TXPWR, ("customer pwr limit rf(%c) = 0x%x\n", ((rf==0)?'A':'B'), customer_pwr_limit)); if (pwr_diff >= customer_pwr_limit) pwr_diff = 0; else pwr_diff = customer_pwr_limit - pwr_diff; for (i=0; i<4; i++) { pwr_diff_limit[i] = (u1Byte)((pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)]&(0x7f<<(i*8)))>>(i*8)); if (pwr_diff_limit[i] > pwr_diff) pwr_diff_limit[i] = pwr_diff; } customer_limit = (pwr_diff_limit[3]<<24) | (pwr_diff_limit[2]<<16) | (pwr_diff_limit[1]<<8) | (pwr_diff_limit[0]); //RTPRINT(FPHY, PHY_TXPWR, ("Customer's limit rf(%c) = 0x%x\n", ((rf==0)?'A':'B'), customer_limit)); writeVal = customer_limit + ((index<2)?powerBase0[rf]:powerBase1[rf]); //RTPRINT(FPHY, PHY_TXPWR, ("Customer, writeVal rf(%c)= 0x%x\n", ((rf==0)?'A':'B'), writeVal)); break; default: chnlGroup = 0; writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] + ((index<2)?powerBase0[rf]:powerBase1[rf]); //RTPRINT(FPHY, PHY_TXPWR, ("RTK better performance, writeVal rf(%c) = 0x%x\n", ((rf==0)?'A':'B'), writeVal)); break; } // 20100427 Joseph: Driver dynamic Tx power shall not affect Tx power. It shall be determined by power training mechanism. // Currently, we cannot fully disable driver dynamic tx power mechanism because it is referenced by BT coexist mechanism. // In the future, two mechanism shall be separated from each other and maintained independantly. Thanks for Lanhsin's reminder. //92d do not need this if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) writeVal = 0x14141414; else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) writeVal = 0x00000000; // 20100628 Joseph: High power mode for BT-Coexist mechanism. // This mechanism is only applied when Driver-Highpower-Mechanism is OFF. if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT1) { //RTPRINT(FBT, BT_TRACE, ("Tx Power (-6)\n")); writeVal = writeVal - 0x06060606; } else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT2) { //RTPRINT(FBT, BT_TRACE, ("Tx Power (-0)\n")); writeVal = writeVal ; } /* if (pMgntInfo->bDisableTXPowerByRate) { // add for OID_RT_11N_TX_POWER_BY_RATE ,disable tx powre change by rate writeVal = 0x2c2c2c2c; } */ *(pOutWriteVal+rf) = writeVal; } } static void writeOFDMPowerReg88E( IN PADAPTER Adapter, IN u8 index, IN u32* pValue ) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); u16 RegOffset_A[6] = { rTxAGC_A_Rate18_06, rTxAGC_A_Rate54_24, rTxAGC_A_Mcs03_Mcs00, rTxAGC_A_Mcs07_Mcs04, rTxAGC_A_Mcs11_Mcs08, rTxAGC_A_Mcs15_Mcs12}; u16 RegOffset_B[6] = { rTxAGC_B_Rate18_06, rTxAGC_B_Rate54_24, rTxAGC_B_Mcs03_Mcs00, rTxAGC_B_Mcs07_Mcs04, rTxAGC_B_Mcs11_Mcs08, rTxAGC_B_Mcs15_Mcs12}; u8 i, rf, pwr_val[4]; u32 writeVal; u16 RegOffset; for (rf=0; rf<2; rf++) { writeVal = pValue[rf]; for (i=0; i<4; i++) { pwr_val[i] = (u8)((writeVal & (0x7f<<(i*8)))>>(i*8)); if (pwr_val[i] > RF6052_MAX_TX_PWR) pwr_val[i] = RF6052_MAX_TX_PWR; } writeVal = (pwr_val[3]<<24) | (pwr_val[2]<<16) |(pwr_val[1]<<8) |pwr_val[0]; if (rf == 0) RegOffset = RegOffset_A[index]; else RegOffset = RegOffset_B[index]; PHY_SetBBReg(Adapter, RegOffset, bMaskDWord, writeVal); //RTPRINT(FPHY, PHY_TXPWR, ("Set 0x%x = %08x\n", RegOffset, writeVal)); // 201005115 Joseph: Set Tx Power diff for Tx power training mechanism. if (((pHalData->rf_type == RF_2T2R) && (RegOffset == rTxAGC_A_Mcs15_Mcs12 || RegOffset == rTxAGC_B_Mcs15_Mcs12))|| ((pHalData->rf_type != RF_2T2R) && (RegOffset == rTxAGC_A_Mcs07_Mcs04 || RegOffset == rTxAGC_B_Mcs07_Mcs04)) ) { writeVal = pwr_val[3]; if (RegOffset == rTxAGC_A_Mcs15_Mcs12 || RegOffset == rTxAGC_A_Mcs07_Mcs04) RegOffset = 0xc90; if (RegOffset == rTxAGC_B_Mcs15_Mcs12 || RegOffset == rTxAGC_B_Mcs07_Mcs04) RegOffset = 0xc98; for (i=0; i<3; i++) { if (i!=2) writeVal = (writeVal>8)?(writeVal-8):0; else writeVal = (writeVal>6)?(writeVal-6):0; rtw_write8(Adapter, (u32)(RegOffset+i), (u8)writeVal); } } } } /*----------------------------------------------------------------------------- * Function: PHY_RF6052SetOFDMTxPower * * Overview: For legacy and HY OFDM, we must read EEPROM TX power index for * different channel and read original value in TX power register area from * 0xe00. We increase offset and original value to be correct tx pwr. * * Input: NONE * * Output: NONE * * Return: NONE * * Revised History: * When Who Remark * 11/05/2008 MHC Simulate 8192 series method. * 01/06/2009 MHC 1. Prevent Path B tx power overflow or underflow dure to * A/B pwr difference or legacy/HT pwr diff. * 2. We concern with path B legacy/HT OFDM difference. * 01/22/2009 MHC Support new EPRO format from SD3. * *---------------------------------------------------------------------------*/ VOID rtl8188e_PHY_RF6052SetOFDMTxPower( IN PADAPTER Adapter, IN u8* pPowerLevelOFDM, IN u8* pPowerLevelBW20, IN u8* pPowerLevelBW40, IN u8 Channel) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); u32 writeVal[2], powerBase0[2], powerBase1[2], pwrtrac_value; u8 direction; u8 index = 0; //DBG_871X("PHY_RF6052SetOFDMTxPower, channel(%d)\n", Channel); getPowerBase88E(Adapter, pPowerLevelOFDM,pPowerLevelBW20,pPowerLevelBW40, Channel, &powerBase0[0], &powerBase1[0]); // // 2012/04/23 MH According to power tracking value, we need to revise OFDM tx power. // This is ued to fix unstable power tracking mode. // ODM_TxPwrTrackAdjust88E(&pHalData->odmpriv, 0, &direction, &pwrtrac_value); for (index=0; index<6; index++) { getTxPowerWriteValByRegulatory88E(Adapter, Channel, index, &powerBase0[0], &powerBase1[0], &writeVal[0]); if (direction == 1) { writeVal[0] += pwrtrac_value; writeVal[1] += pwrtrac_value; } else if (direction == 2) { writeVal[0] -= pwrtrac_value; writeVal[1] -= pwrtrac_value; } writeOFDMPowerReg88E(Adapter, index, &writeVal[0]); } } static VOID phy_RF6052_Config_HardCode( IN PADAPTER Adapter ) { // Set Default Bandwidth to 20M //Adapter->HalFunc .SetBWModeHandler(Adapter, HT_CHANNEL_WIDTH_20); // TODO: Set Default Channel to channel one for RTL8225 } static int phy_RF6052_Config_ParaFile( IN PADAPTER Adapter ) { u32 u4RegValue; u8 eRFPath; BB_REGISTER_DEFINITION_T *pPhyReg; int rtStatus = _SUCCESS; HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); static char sz88eRadioAFile[] = RTL8188E_PHY_RADIO_A; static char sz88eRadioBFile[] = RTL8188E_PHY_RADIO_B; char *pszRadioAFile, *pszRadioBFile; pszRadioAFile = sz88eRadioAFile; pszRadioBFile = sz88eRadioBFile; //3//----------------------------------------------------------------- //3// <2> Initialize RF //3//----------------------------------------------------------------- //for (eRFPath = RF_PATH_A; eRFPath NumTotalRFPath; eRFPath++) for (eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) { pPhyReg = &pHalData->PHYRegDef[eRFPath]; /*----Store original RFENV control type----*/ switch (eRFPath) { case RF_PATH_A: case RF_PATH_C: u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV); break; case RF_PATH_B : case RF_PATH_D: u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV<<16); break; } /*----Set RF_ENV enable----*/ PHY_SetBBReg(Adapter, pPhyReg->rfintfe, bRFSI_RFENV<<16, 0x1); rtw_udelay_os(1);//PlatformStallExecution(1); /*----Set RF_ENV output high----*/ PHY_SetBBReg(Adapter, pPhyReg->rfintfo, bRFSI_RFENV, 0x1); rtw_udelay_os(1);//PlatformStallExecution(1); /* Set bit number of Address and Data for RF register */ PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireAddressLength, 0x0); // Set 1 to 4 bits for 8255 rtw_udelay_os(1);//PlatformStallExecution(1); PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireDataLength, 0x0); // Set 0 to 12 bits for 8255 rtw_udelay_os(1);//PlatformStallExecution(1); /*----Initialize RF fom connfiguration file----*/ switch (eRFPath) { case RF_PATH_A: #ifdef CONFIG_EMBEDDED_FWIMG #ifdef CONFIG_PHY_SETTING_WITH_ODM if (HAL_STATUS_FAILURE ==ODM_ConfigRFWithHeaderFile(&pHalData->odmpriv,(ODM_RF_RADIO_PATH_E)eRFPath, (ODM_RF_RADIO_PATH_E)eRFPath)) rtStatus= _FAIL; #else rtStatus= rtl8188e_PHY_ConfigRFWithHeaderFile(Adapter,(RF_RADIO_PATH_E)eRFPath); #endif//#ifdef CONFIG_PHY_SETTING_WITH_ODM #else rtStatus = rtl8188e_PHY_ConfigRFWithParaFile(Adapter, pszRadioAFile, (RF_RADIO_PATH_E)eRFPath); #endif//#ifdef CONFIG_EMBEDDED_FWIMG break; case RF_PATH_B: #ifdef CONFIG_EMBEDDED_FWIMG #ifdef CONFIG_PHY_SETTING_WITH_ODM if (HAL_STATUS_FAILURE ==ODM_ConfigRFWithHeaderFile(&pHalData->odmpriv,(ODM_RF_RADIO_PATH_E)eRFPath, (ODM_RF_RADIO_PATH_E)eRFPath)) rtStatus= _FAIL; #else rtStatus = rtl8188e_PHY_ConfigRFWithHeaderFile(Adapter,(RF_RADIO_PATH_E)eRFPath); #endif //#ifdef CONFIG_PHY_SETTING_WITH_ODM #else rtStatus =rtl8188e_PHY_ConfigRFWithParaFile(Adapter, pszRadioBFile, (RF_RADIO_PATH_E)eRFPath); #endif break; case RF_PATH_C: break; case RF_PATH_D: break; } /*----Restore RFENV control type----*/; switch (eRFPath) { case RF_PATH_A: case RF_PATH_C: PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV, u4RegValue); break; case RF_PATH_B : case RF_PATH_D: PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV<<16, u4RegValue); break; } if (rtStatus != _SUCCESS){ //RT_TRACE(COMP_FPGA, DBG_LOUD, ("phy_RF6052_Config_ParaFile():Radio[%d] Fail!!", eRFPath)); goto phy_RF6052_Config_ParaFile_Fail; } } //RT_TRACE(COMP_INIT, DBG_LOUD, ("<---phy_RF6052_Config_ParaFile()\n")); return rtStatus; phy_RF6052_Config_ParaFile_Fail: return rtStatus; } int PHY_RF6052_Config8188E( IN PADAPTER Adapter) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); int rtStatus = _SUCCESS; // // Initialize general global value // // TODO: Extend RF_PATH_C and RF_PATH_D in the future if (pHalData->rf_type == RF_1T1R) pHalData->NumTotalRFPath = 1; else pHalData->NumTotalRFPath = 2; // // Config BB and RF // rtStatus = phy_RF6052_Config_ParaFile(Adapter); #if 0 switch ( Adapter->MgntInfo.bRegHwParaFile ) { case 0: phy_RF6052_Config_HardCode(Adapter); break; case 1: rtStatus = phy_RF6052_Config_ParaFile(Adapter); break; case 2: // Partial Modify. phy_RF6052_Config_HardCode(Adapter); phy_RF6052_Config_ParaFile(Adapter); break; default: phy_RF6052_Config_HardCode(Adapter); break; } #endif return rtStatus; } // // ==> RF shadow Operation API Code Section!!! // /*----------------------------------------------------------------------------- * Function: PHY_RFShadowRead * PHY_RFShadowWrite * PHY_RFShadowCompare * PHY_RFShadowRecorver * PHY_RFShadowCompareAll * PHY_RFShadowRecorverAll * PHY_RFShadowCompareFlagSet * PHY_RFShadowRecorverFlagSet * * Overview: When we set RF register, we must write shadow at first. * When we are running, we must compare shadow abd locate error addr. * Decide to recorver or not. * * Input: NONE * * Output: NONE * * Return: NONE * * Revised History: * When Who Remark * 11/20/2008 MHC Create Version 0. * *---------------------------------------------------------------------------*/ u32 PHY_RFShadowRead( IN PADAPTER Adapter, IN RF_RADIO_PATH_E eRFPath, IN u32 Offset) { return RF_Shadow[eRFPath][Offset].Value; } /* PHY_RFShadowRead */ VOID PHY_RFShadowWrite( IN PADAPTER Adapter, IN RF_RADIO_PATH_E eRFPath, IN u32 Offset, IN u32 Data) { RF_Shadow[eRFPath][Offset].Value = (Data & bRFRegOffsetMask); RF_Shadow[eRFPath][Offset].Driver_Write = _TRUE; } /* PHY_RFShadowWrite */ BOOLEAN PHY_RFShadowCompare( IN PADAPTER Adapter, IN RF_RADIO_PATH_E eRFPath, IN u32 Offset) { u32 reg; // Check if we need to check the register if (RF_Shadow[eRFPath][Offset].Compare == _TRUE) { reg = PHY_QueryRFReg(Adapter, eRFPath, Offset, bRFRegOffsetMask); // Compare shadow and real rf register for 20bits!! if (RF_Shadow[eRFPath][Offset].Value != reg) { // Locate error position. RF_Shadow[eRFPath][Offset].ErrorOrNot = _TRUE; //RT_TRACE(COMP_INIT, DBG_LOUD, //("PHY_RFShadowCompare RF-%d Addr%02lx Err = %05lx\n", //eRFPath, Offset, reg)); } return RF_Shadow[eRFPath][Offset].ErrorOrNot ; } return _FALSE; } /* PHY_RFShadowCompare */ VOID PHY_RFShadowRecorver( IN PADAPTER Adapter, IN RF_RADIO_PATH_E eRFPath, IN u32 Offset) { // Check if the address is error if (RF_Shadow[eRFPath][Offset].ErrorOrNot == _TRUE) { // Check if we need to recorver the register. if (RF_Shadow[eRFPath][Offset].Recorver == _TRUE) { PHY_SetRFReg(Adapter, eRFPath, Offset, bRFRegOffsetMask, RF_Shadow[eRFPath][Offset].Value); //RT_TRACE(COMP_INIT, DBG_LOUD, //("PHY_RFShadowRecorver RF-%d Addr%02lx=%05lx", //eRFPath, Offset, RF_Shadow[eRFPath][Offset].Value)); } } } /* PHY_RFShadowRecorver */ VOID PHY_RFShadowCompareAll( IN PADAPTER Adapter) { u32 eRFPath; u32 Offset; for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) { for (Offset = 0; Offset <= RF6052_MAX_REG; Offset++) { PHY_RFShadowCompare(Adapter, (RF_RADIO_PATH_E)eRFPath, Offset); } } } /* PHY_RFShadowCompareAll */ VOID PHY_RFShadowRecorverAll( IN PADAPTER Adapter) { u32 eRFPath; u32 Offset; for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) { for (Offset = 0; Offset <= RF6052_MAX_REG; Offset++) { PHY_RFShadowRecorver(Adapter, (RF_RADIO_PATH_E)eRFPath, Offset); } } } /* PHY_RFShadowRecorverAll */ VOID PHY_RFShadowCompareFlagSet( IN PADAPTER Adapter, IN RF_RADIO_PATH_E eRFPath, IN u32 Offset, IN u8 Type) { // Set True or False!!! RF_Shadow[eRFPath][Offset].Compare = Type; } /* PHY_RFShadowCompareFlagSet */ VOID PHY_RFShadowRecorverFlagSet( IN PADAPTER Adapter, IN RF_RADIO_PATH_E eRFPath, IN u32 Offset, IN u8 Type) { // Set True or False!!! RF_Shadow[eRFPath][Offset].Recorver= Type; } /* PHY_RFShadowRecorverFlagSet */ VOID PHY_RFShadowCompareFlagSetAll( IN PADAPTER Adapter) { u32 eRFPath; u32 Offset; for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) { for (Offset = 0; Offset <= RF6052_MAX_REG; Offset++) { // 2008/11/20 MH For S3S4 test, we only check reg 26/27 now!!!! if (Offset != 0x26 && Offset != 0x27) PHY_RFShadowCompareFlagSet(Adapter, (RF_RADIO_PATH_E)eRFPath, Offset, _FALSE); else PHY_RFShadowCompareFlagSet(Adapter, (RF_RADIO_PATH_E)eRFPath, Offset, _TRUE); } } } /* PHY_RFShadowCompareFlagSetAll */ VOID PHY_RFShadowRecorverFlagSetAll( IN PADAPTER Adapter) { u32 eRFPath; u32 Offset; for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) { for (Offset = 0; Offset <= RF6052_MAX_REG; Offset++) { // 2008/11/20 MH For S3S4 test, we only check reg 26/27 now!!!! if (Offset != 0x26 && Offset != 0x27) PHY_RFShadowRecorverFlagSet(Adapter, (RF_RADIO_PATH_E)eRFPath, Offset, _FALSE); else PHY_RFShadowRecorverFlagSet(Adapter, (RF_RADIO_PATH_E)eRFPath, Offset, _TRUE); } } } /* PHY_RFShadowCompareFlagSetAll */ VOID PHY_RFShadowRefresh( IN PADAPTER Adapter) { u32 eRFPath; u32 Offset; for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) { for (Offset = 0; Offset <= RF6052_MAX_REG; Offset++) { RF_Shadow[eRFPath][Offset].Value = 0; RF_Shadow[eRFPath][Offset].Compare = _FALSE; RF_Shadow[eRFPath][Offset].Recorver = _FALSE; RF_Shadow[eRFPath][Offset].ErrorOrNot = _FALSE; RF_Shadow[eRFPath][Offset].Driver_Write = _FALSE; } } } /* PHY_RFShadowRead */ /* End of HalRf6052.c */