rtl8723a_rf6052.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  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. #define _RTL8723A_RF6052_C_
  37. #include <osdep_service.h>
  38. #include <drv_types.h>
  39. #include <rtl8723a_hal.h>
  40. #include <usb_ops_linux.h>
  41. /*-----------------------------------------------------------------------------
  42. * Function: PHY_RF6052SetBandwidth()
  43. *
  44. * Overview: This function is called by SetBWMode23aCallback8190Pci() only
  45. *
  46. * Input: struct rtw_adapter * Adapter
  47. * WIRELESS_BANDWIDTH_E Bandwidth 20M or 40M
  48. *
  49. * Output: NONE
  50. *
  51. * Return: NONE
  52. *
  53. * Note: For RF type 0222D
  54. *---------------------------------------------------------------------------*/
  55. void rtl8723a_phy_rf6052set_bw(struct rtw_adapter *Adapter,
  56. enum ht_channel_width Bandwidth) /* 20M or 40M */
  57. {
  58. struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
  59. switch (Bandwidth) {
  60. case HT_CHANNEL_WIDTH_20:
  61. pHalData->RfRegChnlVal[0] =
  62. (pHalData->RfRegChnlVal[0] & 0xfffff3ff) | 0x0400;
  63. PHY_SetRFReg(Adapter, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask,
  64. pHalData->RfRegChnlVal[0]);
  65. break;
  66. case HT_CHANNEL_WIDTH_40:
  67. pHalData->RfRegChnlVal[0] =
  68. (pHalData->RfRegChnlVal[0] & 0xfffff3ff);
  69. PHY_SetRFReg(Adapter, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask,
  70. pHalData->RfRegChnlVal[0]);
  71. break;
  72. default:
  73. break;
  74. }
  75. }
  76. /*-----------------------------------------------------------------------------
  77. * Function: PHY_RF6052SetCckTxPower
  78. *
  79. * Overview:
  80. *
  81. * Input: NONE
  82. *
  83. * Output: NONE
  84. *
  85. * Return: NONE
  86. *
  87. * Revised History:
  88. * When Who Remark
  89. * 11/05/2008 MHC Simulate 8192series..
  90. *
  91. *---------------------------------------------------------------------------*/
  92. void rtl823a_phy_rf6052setccktxpower(struct rtw_adapter *Adapter,
  93. u8 *pPowerlevel)
  94. {
  95. struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
  96. struct dm_priv *pdmpriv = &pHalData->dmpriv;
  97. struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv;
  98. u32 TxAGC[2] = {0, 0}, tmpval = 0;
  99. u8 idx1, idx2;
  100. u8 *ptr;
  101. if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
  102. TxAGC[RF_PATH_A] = 0x3f3f3f3f;
  103. TxAGC[RF_PATH_B] = 0x3f3f3f3f;
  104. for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
  105. TxAGC[idx1] = pPowerlevel[idx1] |
  106. (pPowerlevel[idx1] << 8) |
  107. (pPowerlevel[idx1] << 16) |
  108. (pPowerlevel[idx1] << 24);
  109. /*
  110. * 2010/10/18 MH For external PA module. We need
  111. * to limit power index to be less than 0x20.
  112. */
  113. if (TxAGC[idx1] > 0x20 && pHalData->ExternalPA)
  114. TxAGC[idx1] = 0x20;
  115. }
  116. } else {
  117. /* 20100427 Joseph: Driver dynamic Tx power shall not affect Tx
  118. * power. It shall be determined by power training mechanism. */
  119. /* Currently, we cannot fully disable driver dynamic tx power
  120. * mechanism because it is referenced by BT coexist mechanism. */
  121. /* In the future, two mechanism shall be separated from each other
  122. * and maintained independently. Thanks for Lanhsin's reminder. */
  123. if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) {
  124. TxAGC[RF_PATH_A] = 0x10101010;
  125. TxAGC[RF_PATH_B] = 0x10101010;
  126. } else if (pdmpriv->DynamicTxHighPowerLvl ==
  127. TxHighPwrLevel_Level2) {
  128. TxAGC[RF_PATH_A] = 0x00000000;
  129. TxAGC[RF_PATH_B] = 0x00000000;
  130. } else {
  131. for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
  132. TxAGC[idx1] = pPowerlevel[idx1] |
  133. (pPowerlevel[idx1] << 8) |
  134. (pPowerlevel[idx1] << 16) |
  135. (pPowerlevel[idx1] << 24);
  136. }
  137. if (pHalData->EEPROMRegulatory == 0) {
  138. tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][6]) +
  139. (pHalData->MCSTxPowerLevelOriginalOffset[0][7]<<8);
  140. TxAGC[RF_PATH_A] += tmpval;
  141. tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][14]) +
  142. (pHalData->MCSTxPowerLevelOriginalOffset[0][15]<<24);
  143. TxAGC[RF_PATH_B] += tmpval;
  144. }
  145. }
  146. }
  147. for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
  148. ptr = (u8 *)(&TxAGC[idx1]);
  149. for (idx2 = 0; idx2 < 4; idx2++) {
  150. if (*ptr > RF6052_MAX_TX_PWR)
  151. *ptr = RF6052_MAX_TX_PWR;
  152. ptr++;
  153. }
  154. }
  155. /* rf-A cck tx power */
  156. tmpval = TxAGC[RF_PATH_A] & 0xff;
  157. PHY_SetBBReg(Adapter, rTxAGC_A_CCK1_Mcs32, bMaskByte1, tmpval);
  158. tmpval = TxAGC[RF_PATH_A] >> 8;
  159. PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
  160. /* rf-B cck tx power */
  161. tmpval = TxAGC[RF_PATH_B] >> 24;
  162. PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, tmpval);
  163. tmpval = TxAGC[RF_PATH_B] & 0x00ffffff;
  164. PHY_SetBBReg(Adapter, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval);
  165. } /* PHY_RF6052SetCckTxPower */
  166. /* powerbase0 for OFDM rates */
  167. /* powerbase1 for HT MCS rates */
  168. static void getPowerBase(struct rtw_adapter *Adapter, u8 *pPowerLevel,
  169. u8 Channel, u32 *OfdmBase, u32 *MCSBase)
  170. {
  171. struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
  172. u32 ofdm, mcs;
  173. u8 Legacy_pwrdiff = 0;
  174. s8 HT20_pwrdiff = 0;
  175. u8 i, powerlevel[2];
  176. for (i = 0; i < 2; i++) {
  177. powerlevel[i] = pPowerLevel[i];
  178. Legacy_pwrdiff = pHalData->TxPwrLegacyHtDiff[i][Channel-1];
  179. ofdm = powerlevel[i] + Legacy_pwrdiff;
  180. ofdm = ofdm << 24 | ofdm << 16 | ofdm << 8 | ofdm;
  181. *(OfdmBase + i) = ofdm;
  182. }
  183. for (i = 0; i < 2; i++) {
  184. /* Check HT20 to HT40 diff */
  185. if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20) {
  186. HT20_pwrdiff = pHalData->TxPwrHt20Diff[i][Channel-1];
  187. powerlevel[i] += HT20_pwrdiff;
  188. }
  189. mcs = powerlevel[i];
  190. mcs = mcs << 24 | mcs << 16 | mcs << 8 | mcs;
  191. *(MCSBase + i) = mcs;
  192. }
  193. }
  194. static void
  195. getTxPowerWriteValByRegulatory(struct rtw_adapter *Adapter, u8 Channel,
  196. u8 index, u32 *powerBase0, u32 *powerBase1,
  197. u32 *pOutWriteVal)
  198. {
  199. struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
  200. struct dm_priv *pdmpriv = &pHalData->dmpriv;
  201. u8 i, chnlGroup = 0, pwr_diff_limit[4];
  202. u32 writeVal, customer_limit, rf;
  203. /* Index 0 & 1 = legacy OFDM, 2-5 = HT_MCS rate */
  204. for (rf = 0; rf < 2; rf++) {
  205. switch (pHalData->EEPROMRegulatory) {
  206. case 0: /* Realtek better performance */
  207. /* increase power diff defined by Realtek for
  208. * large power */
  209. chnlGroup = 0;
  210. writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] +
  211. ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
  212. break;
  213. case 1: /* Realtek regulatory */
  214. /* increase power diff defined by Realtek for
  215. * regulatory */
  216. if (pHalData->pwrGroupCnt == 1)
  217. chnlGroup = 0;
  218. if (pHalData->pwrGroupCnt >= 3) {
  219. if (Channel <= 3)
  220. chnlGroup = 0;
  221. else if (Channel >= 4 && Channel <= 9)
  222. chnlGroup = 1;
  223. else if (Channel > 9)
  224. chnlGroup = 2;
  225. if (pHalData->CurrentChannelBW ==
  226. HT_CHANNEL_WIDTH_20)
  227. chnlGroup++;
  228. else
  229. chnlGroup += 4;
  230. }
  231. writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] +
  232. ((index < 2) ? powerBase0[rf] :
  233. powerBase1[rf]);
  234. break;
  235. case 2: /* Better regulatory */
  236. /* don't increase any power diff */
  237. writeVal = (index < 2) ? powerBase0[rf] :
  238. powerBase1[rf];
  239. break;
  240. case 3: /* Customer defined power diff. */
  241. chnlGroup = 0;
  242. for (i = 0; i < 4; i++) {
  243. pwr_diff_limit[i] = (u8)((pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index +
  244. (rf ? 8 : 0)]&(0x7f << (i*8))) >> (i*8));
  245. if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_40) {
  246. if (pwr_diff_limit[i] > pHalData->PwrGroupHT40[rf][Channel-1])
  247. pwr_diff_limit[i] = pHalData->PwrGroupHT40[rf][Channel-1];
  248. } else {
  249. if (pwr_diff_limit[i] > pHalData->PwrGroupHT20[rf][Channel-1])
  250. pwr_diff_limit[i] = pHalData->PwrGroupHT20[rf][Channel-1];
  251. }
  252. }
  253. customer_limit = (pwr_diff_limit[3]<<24) | (pwr_diff_limit[2]<<16) |
  254. (pwr_diff_limit[1]<<8) | (pwr_diff_limit[0]);
  255. writeVal = customer_limit + ((index<2)?powerBase0[rf]:powerBase1[rf]);
  256. break;
  257. default:
  258. chnlGroup = 0;
  259. writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] +
  260. ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
  261. break;
  262. }
  263. /* 20100427 Joseph: Driver dynamic Tx power shall not affect Tx power.
  264. It shall be determined by power training mechanism. */
  265. /* Currently, we cannot fully disable driver dynamic tx power mechanism
  266. because it is referenced by BT coexist mechanism. */
  267. /* In the future, two mechanism shall be separated from each other and
  268. maintained independently. Thanks for Lanhsin's reminder. */
  269. if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1)
  270. writeVal = 0x14141414;
  271. else if (pdmpriv->DynamicTxHighPowerLvl ==
  272. TxHighPwrLevel_Level2)
  273. writeVal = 0x00000000;
  274. /* 20100628 Joseph: High power mode for BT-Coexist mechanism. */
  275. /* This mechanism is only applied when
  276. Driver-Highpower-Mechanism is OFF. */
  277. if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT1)
  278. writeVal = writeVal - 0x06060606;
  279. else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT2)
  280. writeVal = writeVal;
  281. *(pOutWriteVal + rf) = writeVal;
  282. }
  283. }
  284. static void writeOFDMPowerReg(struct rtw_adapter *Adapter, u8 index,
  285. u32 *pValue)
  286. {
  287. struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
  288. u16 RegOffset_A[6] = {
  289. rTxAGC_A_Rate18_06, rTxAGC_A_Rate54_24,
  290. rTxAGC_A_Mcs03_Mcs00, rTxAGC_A_Mcs07_Mcs04,
  291. rTxAGC_A_Mcs11_Mcs08, rTxAGC_A_Mcs15_Mcs12
  292. };
  293. u16 RegOffset_B[6] = {
  294. rTxAGC_B_Rate18_06, rTxAGC_B_Rate54_24,
  295. rTxAGC_B_Mcs03_Mcs00, rTxAGC_B_Mcs07_Mcs04,
  296. rTxAGC_B_Mcs11_Mcs08, rTxAGC_B_Mcs15_Mcs12
  297. };
  298. u8 i, rf, pwr_val[4];
  299. u32 writeVal;
  300. u16 RegOffset;
  301. for (rf = 0; rf < 2; rf++) {
  302. writeVal = pValue[rf];
  303. for (i = 0; i < 4; i++) {
  304. pwr_val[i] = (u8)((writeVal &
  305. (0x7f << (i * 8))) >> (i * 8));
  306. if (pwr_val[i] > RF6052_MAX_TX_PWR)
  307. pwr_val[i] = RF6052_MAX_TX_PWR;
  308. }
  309. writeVal = pwr_val[3] << 24 | pwr_val[2] << 16 |
  310. pwr_val[1] << 8 | pwr_val[0];
  311. if (rf == 0)
  312. RegOffset = RegOffset_A[index];
  313. else
  314. RegOffset = RegOffset_B[index];
  315. rtl8723au_write32(Adapter, RegOffset, writeVal);
  316. /* 201005115 Joseph: Set Tx Power diff for Tx power
  317. training mechanism. */
  318. if (((pHalData->rf_type == RF_2T2R) &&
  319. (RegOffset == rTxAGC_A_Mcs15_Mcs12 ||
  320. RegOffset == rTxAGC_B_Mcs15_Mcs12)) ||
  321. ((pHalData->rf_type != RF_2T2R) &&
  322. (RegOffset == rTxAGC_A_Mcs07_Mcs04 ||
  323. RegOffset == rTxAGC_B_Mcs07_Mcs04))) {
  324. writeVal = pwr_val[3];
  325. if (RegOffset == rTxAGC_A_Mcs15_Mcs12 ||
  326. RegOffset == rTxAGC_A_Mcs07_Mcs04)
  327. RegOffset = 0xc90;
  328. if (RegOffset == rTxAGC_B_Mcs15_Mcs12 ||
  329. RegOffset == rTxAGC_B_Mcs07_Mcs04)
  330. RegOffset = 0xc98;
  331. for (i = 0; i < 3; i++) {
  332. if (i != 2)
  333. writeVal = (writeVal > 8) ?
  334. (writeVal - 8) : 0;
  335. else
  336. writeVal = (writeVal > 6) ?
  337. (writeVal - 6) : 0;
  338. rtl8723au_write8(Adapter, RegOffset + i,
  339. (u8)writeVal);
  340. }
  341. }
  342. }
  343. }
  344. /*-----------------------------------------------------------------------------
  345. * Function: PHY_RF6052SetOFDMTxPower
  346. *
  347. * Overview: For legacy and HY OFDM, we must read EEPROM TX power index for
  348. * different channel and read original value in TX power
  349. * register area from 0xe00. We increase offset and
  350. * original value to be correct tx pwr.
  351. *
  352. * Input: NONE
  353. *
  354. * Output: NONE
  355. *
  356. * Return: NONE
  357. *
  358. * Revised History:
  359. * When Remark
  360. * 11/05/2008 MHC Simulate 8192 series method.
  361. * 01/06/2009 MHC 1. Prevent Path B tx power overflow or
  362. * underflow dure to A/B pwr difference or
  363. * legacy/HT pwr diff.
  364. * 2. We concern with path B legacy/HT OFDM difference.
  365. * 01/22/2009 MHC Support new EPRO format from SD3.
  366. *
  367. *---------------------------------------------------------------------------*/
  368. void rtl8723a_PHY_RF6052SetOFDMTxPower(struct rtw_adapter *Adapter,
  369. u8 *pPowerLevel, u8 Channel)
  370. {
  371. u32 writeVal[2], powerBase0[2], powerBase1[2];
  372. u8 index = 0;
  373. getPowerBase(Adapter, pPowerLevel, Channel,
  374. &powerBase0[0], &powerBase1[0]);
  375. for (index = 0; index < 6; index++) {
  376. getTxPowerWriteValByRegulatory(Adapter, Channel, index,
  377. &powerBase0[0], &powerBase1[0], &writeVal[0]);
  378. writeOFDMPowerReg(Adapter, index, &writeVal[0]);
  379. }
  380. }
  381. static int phy_RF6052_Config_ParaFile(struct rtw_adapter *Adapter)
  382. {
  383. u32 u4RegValue = 0;
  384. u8 eRFPath;
  385. struct bb_reg_define *pPhyReg;
  386. int rtStatus = _SUCCESS;
  387. struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
  388. /* 3----------------------------------------------------------------- */
  389. /* 3 <2> Initialize RF */
  390. /* 3----------------------------------------------------------------- */
  391. for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) {
  392. pPhyReg = &pHalData->PHYRegDef[eRFPath];
  393. /*----Store original RFENV control type----*/
  394. switch (eRFPath) {
  395. case RF_PATH_A:
  396. u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs,
  397. bRFSI_RFENV);
  398. break;
  399. case RF_PATH_B:
  400. u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs,
  401. bRFSI_RFENV << 16);
  402. break;
  403. }
  404. /*----Set RF_ENV enable----*/
  405. PHY_SetBBReg(Adapter, pPhyReg->rfintfe, bRFSI_RFENV << 16, 0x1);
  406. udelay(1);/* PlatformStallExecution(1); */
  407. /*----Set RF_ENV output high----*/
  408. PHY_SetBBReg(Adapter, pPhyReg->rfintfo, bRFSI_RFENV, 0x1);
  409. udelay(1);/* PlatformStallExecution(1); */
  410. /* Set bit number of Address and Data for RF register */
  411. PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireAddressLength,
  412. 0x0); /* Set 1 to 4 bits for 8255 */
  413. udelay(1);/* PlatformStallExecution(1); */
  414. PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireDataLength,
  415. 0x0); /* Set 0 to 12 bits for 8255 */
  416. udelay(1);/* PlatformStallExecution(1); */
  417. /*----Initialize RF fom connfiguration file----*/
  418. switch (eRFPath) {
  419. case RF_PATH_A:
  420. ODM_ReadAndConfig_RadioA_1T_8723A(&pHalData->odmpriv);
  421. break;
  422. case RF_PATH_B:
  423. break;
  424. }
  425. /*----Restore RFENV control type----*/;
  426. switch (eRFPath) {
  427. case RF_PATH_A:
  428. PHY_SetBBReg(Adapter, pPhyReg->rfintfs,
  429. bRFSI_RFENV, u4RegValue);
  430. break;
  431. case RF_PATH_B:
  432. PHY_SetBBReg(Adapter, pPhyReg->rfintfs,
  433. bRFSI_RFENV << 16, u4RegValue);
  434. break;
  435. }
  436. if (rtStatus != _SUCCESS) {
  437. goto phy_RF6052_Config_ParaFile_Fail;
  438. }
  439. }
  440. phy_RF6052_Config_ParaFile_Fail:
  441. return rtStatus;
  442. }
  443. int PHY_RF6052_Config8723A(struct rtw_adapter *Adapter)
  444. {
  445. struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
  446. /* Initialize general global value */
  447. /* TODO: Extend RF_PATH_C and RF_PATH_D in the future */
  448. if (pHalData->rf_type == RF_1T1R)
  449. pHalData->NumTotalRFPath = 1;
  450. else
  451. pHalData->NumTotalRFPath = 2;
  452. /* Config BB and RF */
  453. return phy_RF6052_Config_ParaFile(Adapter);
  454. }
  455. /* End of HalRf6052.c */