1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) 2007 - 2011 Realtek Corporation. */
3
4 /******************************************************************************
5 *
6 *
7 * Module: rtl8192c_rf6052.c ( Source C File)
8 *
9 * Note: Provide RF 6052 series relative API.
10 *
11 * Function:
12 *
13 * Export:
14 *
15 * Abbrev:
16 *
17 * History:
18 * Data Who Remark
19 *
20 * 09/25/2008 MHC Create initial version.
21 * 11/05/2008 MHC Add API for tw power setting.
22 *
23 *
24 ******************************************************************************/
25
26 #define _RTL8188E_RF6052_C_
27
28 #include "../include/osdep_service.h"
29 #include "../include/drv_types.h"
30 #include "../include/rtl8188e_hal.h"
31
32 /*-----------------------------------------------------------------------------
33 * Function: PHY_RF6052SetBandwidth()
34 *
35 * Overview: This function is called by SetBWModeCallback8190Pci() only
36 *
37 * Input: struct adapter *Adapter
38 * WIRELESS_BANDWIDTH_E Bandwidth 20M or 40M
39 *
40 * Output: NONE
41 *
42 * Return: NONE
43 *
44 * Note: For RF type 0222D
45 *---------------------------------------------------------------------------*/
rtl8188e_PHY_RF6052SetBandwidth(struct adapter * Adapter,enum ht_channel_width Bandwidth)46 void rtl8188e_PHY_RF6052SetBandwidth(struct adapter *Adapter,
47 enum ht_channel_width Bandwidth)
48 {
49 struct hal_data_8188e *pHalData = &Adapter->haldata;
50
51 switch (Bandwidth) {
52 case HT_CHANNEL_WIDTH_20:
53 pHalData->RfRegChnlVal = ((pHalData->RfRegChnlVal & 0xfffff3ff) | BIT(10) | BIT(11));
54 rtl8188e_PHY_SetRFReg(Adapter, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal);
55 break;
56 case HT_CHANNEL_WIDTH_40:
57 pHalData->RfRegChnlVal = ((pHalData->RfRegChnlVal & 0xfffff3ff) | BIT(10));
58 rtl8188e_PHY_SetRFReg(Adapter, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal);
59 break;
60 default:
61 break;
62 }
63 }
64
65 /*-----------------------------------------------------------------------------
66 * Function: PHY_RF6052SetCckTxPower
67 *
68 * Overview:
69 *
70 * Input: NONE
71 *
72 * Output: NONE
73 *
74 * Return: NONE
75 *
76 * Revised History:
77 * When Who Remark
78 * 11/05/2008 MHC Simulate 8192series..
79 *
80 *---------------------------------------------------------------------------*/
81
82 void
rtl8188e_PHY_RF6052SetCckTxPower(struct adapter * Adapter,u8 * pPowerlevel)83 rtl8188e_PHY_RF6052SetCckTxPower(
84 struct adapter *Adapter,
85 u8 *pPowerlevel)
86 {
87 struct hal_data_8188e *pHalData = &Adapter->haldata;
88 struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv;
89 u32 TxAGC[2] = {0, 0}, tmpval = 0, pwrtrac_value;
90 u8 idx1, idx2;
91 u8 *ptr;
92 u8 direction;
93
94 if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
95 TxAGC[RF_PATH_A] = 0x3f3f3f3f;
96 TxAGC[RF_PATH_B] = 0x3f3f3f3f;
97
98 for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
99 TxAGC[idx1] =
100 pPowerlevel[idx1] | (pPowerlevel[idx1] << 8) |
101 (pPowerlevel[idx1] << 16) | (pPowerlevel[idx1] << 24);
102 }
103 } else {
104 for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
105 TxAGC[idx1] =
106 pPowerlevel[idx1] | (pPowerlevel[idx1] << 8) |
107 (pPowerlevel[idx1] << 16) | (pPowerlevel[idx1] << 24);
108 }
109 if (pHalData->EEPROMRegulatory == 0) {
110 tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][6]) +
111 (pHalData->MCSTxPowerLevelOriginalOffset[0][7] << 8);
112 TxAGC[RF_PATH_A] += tmpval;
113
114 tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][14]) +
115 (pHalData->MCSTxPowerLevelOriginalOffset[0][15] << 24);
116 TxAGC[RF_PATH_B] += tmpval;
117 }
118 }
119 for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
120 ptr = (u8 *)(&TxAGC[idx1]);
121 for (idx2 = 0; idx2 < 4; idx2++) {
122 if (*ptr > RF6052_MAX_TX_PWR)
123 *ptr = RF6052_MAX_TX_PWR;
124 ptr++;
125 }
126 }
127 ODM_TxPwrTrackAdjust88E(&pHalData->odmpriv, 1, &direction, &pwrtrac_value);
128
129 if (direction == 1) {
130 /* Increase TX power */
131 TxAGC[0] += pwrtrac_value;
132 TxAGC[1] += pwrtrac_value;
133 } else if (direction == 2) {
134 /* Decrease TX power */
135 TxAGC[0] -= pwrtrac_value;
136 TxAGC[1] -= pwrtrac_value;
137 }
138
139 /* rf-A cck tx power */
140 tmpval = TxAGC[RF_PATH_A] & 0xff;
141 rtl8188e_PHY_SetBBReg(Adapter, rTxAGC_A_CCK1_Mcs32, bMaskByte1, tmpval);
142 tmpval = TxAGC[RF_PATH_A] >> 8;
143 rtl8188e_PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
144
145 /* rf-B cck tx power */
146 tmpval = TxAGC[RF_PATH_B] >> 24;
147 rtl8188e_PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, tmpval);
148 tmpval = TxAGC[RF_PATH_B] & 0x00ffffff;
149 rtl8188e_PHY_SetBBReg(Adapter, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval);
150 } /* PHY_RF6052SetCckTxPower */
151
152 /* */
153 /* powerbase0 for OFDM rates */
154 /* powerbase1 for HT MCS rates */
155 /* */
getpowerbase88e(struct adapter * Adapter,u8 * pPowerLevelOFDM,u8 * pPowerLevelBW20,u8 * pPowerLevelBW40,u8 Channel,u32 * OfdmBase,u32 * MCSBase)156 static void getpowerbase88e(struct adapter *Adapter, u8 *pPowerLevelOFDM,
157 u8 *pPowerLevelBW20, u8 *pPowerLevelBW40, u8 Channel, u32 *OfdmBase, u32 *MCSBase)
158 {
159 struct hal_data_8188e *pHalData = &Adapter->haldata;
160 u32 powerBase0, powerBase1;
161 u8 i;
162
163 for (i = 0; i < 2; i++) {
164 powerBase0 = pPowerLevelOFDM[i];
165
166 powerBase0 = (powerBase0 << 24) | (powerBase0 << 16) | (powerBase0 << 8) | powerBase0;
167 *(OfdmBase + i) = powerBase0;
168 }
169
170 /* Check HT20 to HT40 diff */
171 if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
172 powerBase1 = pPowerLevelBW20[0];
173 else
174 powerBase1 = pPowerLevelBW40[0];
175 powerBase1 = (powerBase1 << 24) | (powerBase1 << 16) | (powerBase1 << 8) | powerBase1;
176 *MCSBase = powerBase1;
177 }
178
get_rx_power_val_by_reg(struct adapter * Adapter,u8 Channel,u8 index,u32 * powerBase0,u32 * powerBase1,u32 * pOutWriteVal)179 static void get_rx_power_val_by_reg(struct adapter *Adapter, u8 Channel,
180 u8 index, u32 *powerBase0, u32 *powerBase1,
181 u32 *pOutWriteVal)
182 {
183 struct hal_data_8188e *pHalData = &Adapter->haldata;
184 u8 i, chnlGroup = 0, pwr_diff_limit[4], customer_pwr_limit;
185 s8 pwr_diff = 0;
186 u32 writeVal, customer_limit, rf;
187 u8 Regulatory = pHalData->EEPROMRegulatory;
188
189 /* Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */
190
191 for (rf = 0; rf < 2; rf++) {
192 switch (Regulatory) {
193 case 0: /* Realtek better performance */
194 /* increase power diff defined by Realtek for large power */
195 chnlGroup = 0;
196 writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index + (rf ? 8 : 0)] +
197 ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
198 break;
199 case 1: /* Realtek regulatory */
200 /* increase power diff defined by Realtek for regulatory */
201 if (pHalData->pwrGroupCnt == 1)
202 chnlGroup = 0;
203 if (pHalData->pwrGroupCnt >= MAX_PG_GROUP) {
204 if (Channel < 3) /* Channel 1-2 */
205 chnlGroup = 0;
206 else if (Channel < 6) /* Channel 3-5 */
207 chnlGroup = 1;
208 else if (Channel < 9) /* Channel 6-8 */
209 chnlGroup = 2;
210 else if (Channel < 12) /* Channel 9-11 */
211 chnlGroup = 3;
212 else if (Channel < 14) /* Channel 12-13 */
213 chnlGroup = 4;
214 else if (Channel == 14) /* Channel 14 */
215 chnlGroup = 5;
216 }
217 writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index + (rf ? 8 : 0)] +
218 ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
219 break;
220 case 2: /* Better regulatory */
221 /* don't increase any power diff */
222 writeVal = ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
223 break;
224 case 3: /* Customer defined power diff. */
225 /* increase power diff defined by customer. */
226 chnlGroup = 0;
227
228 if (index < 2)
229 pwr_diff = pHalData->TxPwrLegacyHtDiff[rf][Channel - 1];
230 else if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
231 pwr_diff = pHalData->TxPwrHt20Diff[rf][Channel - 1];
232
233 if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_40)
234 customer_pwr_limit = pHalData->PwrGroupHT40[rf][Channel - 1];
235 else
236 customer_pwr_limit = pHalData->PwrGroupHT20[rf][Channel - 1];
237
238 if (pwr_diff >= customer_pwr_limit)
239 pwr_diff = 0;
240 else
241 pwr_diff = customer_pwr_limit - pwr_diff;
242
243 for (i = 0; i < 4; i++) {
244 pwr_diff_limit[i] = (u8)((pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index + (rf ? 8 : 0)] & (0x7f << (i * 8))) >> (i * 8));
245
246 if (pwr_diff_limit[i] > pwr_diff)
247 pwr_diff_limit[i] = pwr_diff;
248 }
249 customer_limit = (pwr_diff_limit[3] << 24) | (pwr_diff_limit[2] << 16) |
250 (pwr_diff_limit[1] << 8) | (pwr_diff_limit[0]);
251 writeVal = customer_limit + ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
252 break;
253 default:
254 chnlGroup = 0;
255 writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index + (rf ? 8 : 0)] +
256 ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
257 break;
258 }
259
260 *(pOutWriteVal + rf) = writeVal;
261 }
262 }
writeOFDMPowerReg88E(struct adapter * Adapter,u8 index,u32 * pValue)263 static void writeOFDMPowerReg88E(struct adapter *Adapter, u8 index, u32 *pValue)
264 {
265 u16 regoffset_a[6] = {
266 rTxAGC_A_Rate18_06, rTxAGC_A_Rate54_24,
267 rTxAGC_A_Mcs03_Mcs00, rTxAGC_A_Mcs07_Mcs04,
268 rTxAGC_A_Mcs11_Mcs08, rTxAGC_A_Mcs15_Mcs12};
269 u16 regoffset_b[6] = {
270 rTxAGC_B_Rate18_06, rTxAGC_B_Rate54_24,
271 rTxAGC_B_Mcs03_Mcs00, rTxAGC_B_Mcs07_Mcs04,
272 rTxAGC_B_Mcs11_Mcs08, rTxAGC_B_Mcs15_Mcs12};
273 u8 i, rf, pwr_val[4];
274 u32 writeVal;
275 u16 regoffset;
276
277 for (rf = 0; rf < 2; rf++) {
278 writeVal = pValue[rf];
279 for (i = 0; i < 4; i++) {
280 pwr_val[i] = (u8)((writeVal & (0x7f << (i * 8))) >> (i * 8));
281 if (pwr_val[i] > RF6052_MAX_TX_PWR)
282 pwr_val[i] = RF6052_MAX_TX_PWR;
283 }
284 writeVal = (pwr_val[3] << 24) | (pwr_val[2] << 16) | (pwr_val[1] << 8) | pwr_val[0];
285
286 if (rf == 0)
287 regoffset = regoffset_a[index];
288 else
289 regoffset = regoffset_b[index];
290
291 rtl8188e_PHY_SetBBReg(Adapter, regoffset, bMaskDWord, writeVal);
292
293 /* 201005115 Joseph: Set Tx Power diff for Tx power training mechanism. */
294 if (regoffset == rTxAGC_A_Mcs07_Mcs04 || regoffset == rTxAGC_B_Mcs07_Mcs04) {
295 writeVal = pwr_val[3];
296 if (regoffset == rTxAGC_A_Mcs15_Mcs12 || regoffset == rTxAGC_A_Mcs07_Mcs04)
297 regoffset = 0xc90;
298 if (regoffset == rTxAGC_B_Mcs15_Mcs12 || regoffset == rTxAGC_B_Mcs07_Mcs04)
299 regoffset = 0xc98;
300 for (i = 0; i < 3; i++) {
301 if (i != 2)
302 writeVal = (writeVal > 8) ? (writeVal - 8) : 0;
303 else
304 writeVal = (writeVal > 6) ? (writeVal - 6) : 0;
305 rtw_write8(Adapter, (u32)(regoffset + i), (u8)writeVal);
306 }
307 }
308 }
309 }
310
311 /*-----------------------------------------------------------------------------
312 * Function: PHY_RF6052SetOFDMTxPower
313 *
314 * Overview: For legacy and HY OFDM, we must read EEPROM TX power index for
315 * different channel and read original value in TX power register area from
316 * 0xe00. We increase offset and original value to be correct tx pwr.
317 *
318 * Input: NONE
319 *
320 * Output: NONE
321 *
322 * Return: NONE
323 *
324 * Revised History:
325 * When Who Remark
326 * 11/05/2008 MHC Simulate 8192 series method.
327 * 01/06/2009 MHC 1. Prevent Path B tx power overflow or underflow dure to
328 * A/B pwr difference or legacy/HT pwr diff.
329 * 2. We concern with path B legacy/HT OFDM difference.
330 * 01/22/2009 MHC Support new EPRO format from SD3.
331 *
332 *---------------------------------------------------------------------------*/
333
334 void
rtl8188e_PHY_RF6052SetOFDMTxPower(struct adapter * Adapter,u8 * pPowerLevelOFDM,u8 * pPowerLevelBW20,u8 * pPowerLevelBW40,u8 Channel)335 rtl8188e_PHY_RF6052SetOFDMTxPower(
336 struct adapter *Adapter,
337 u8 *pPowerLevelOFDM,
338 u8 *pPowerLevelBW20,
339 u8 *pPowerLevelBW40,
340 u8 Channel)
341 {
342 struct hal_data_8188e *pHalData = &Adapter->haldata;
343 u32 writeVal[2], powerBase0[2], powerBase1[2], pwrtrac_value;
344 u8 direction;
345 u8 index = 0;
346
347 getpowerbase88e(Adapter, pPowerLevelOFDM, pPowerLevelBW20, pPowerLevelBW40, Channel, &powerBase0[0], &powerBase1[0]);
348
349 /* 2012/04/23 MH According to power tracking value, we need to revise OFDM tx power. */
350 /* This is ued to fix unstable power tracking mode. */
351 ODM_TxPwrTrackAdjust88E(&pHalData->odmpriv, 0, &direction, &pwrtrac_value);
352
353 for (index = 0; index < 6; index++) {
354 get_rx_power_val_by_reg(Adapter, Channel, index,
355 &powerBase0[0], &powerBase1[0],
356 &writeVal[0]);
357
358 if (direction == 1) {
359 writeVal[0] += pwrtrac_value;
360 writeVal[1] += pwrtrac_value;
361 } else if (direction == 2) {
362 writeVal[0] -= pwrtrac_value;
363 writeVal[1] -= pwrtrac_value;
364 }
365 writeOFDMPowerReg88E(Adapter, index, &writeVal[0]);
366 }
367 }
368
phy_RF6052_Config_ParaFile(struct adapter * Adapter)369 int phy_RF6052_Config_ParaFile(struct adapter *Adapter)
370 {
371 struct bb_reg_def *pPhyReg;
372 struct hal_data_8188e *pHalData = &Adapter->haldata;
373 u32 u4RegValue = 0;
374 int rtStatus = _SUCCESS;
375
376 /* Initialize RF */
377
378 pPhyReg = &pHalData->PHYRegDef;
379
380 /*----Store original RFENV control type----*/
381 u4RegValue = rtl8188e_PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV);
382
383 /*----Set RF_ENV enable----*/
384 rtl8188e_PHY_SetBBReg(Adapter, pPhyReg->rfintfe, bRFSI_RFENV << 16, 0x1);
385 udelay(1);/* PlatformStallExecution(1); */
386
387 /*----Set RF_ENV output high----*/
388 rtl8188e_PHY_SetBBReg(Adapter, pPhyReg->rfintfo, bRFSI_RFENV, 0x1);
389 udelay(1);/* PlatformStallExecution(1); */
390
391 /* Set bit number of Address and Data for RF register */
392 rtl8188e_PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireAddressLength, 0x0); /* Set 1 to 4 bits for 8255 */
393 udelay(1);/* PlatformStallExecution(1); */
394
395 rtl8188e_PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireDataLength, 0x0); /* Set 0 to 12 bits for 8255 */
396 udelay(1);/* PlatformStallExecution(1); */
397
398 /*----Initialize RF fom connfiguration file----*/
399 if (ODM_ReadAndConfig_RadioA_1T_8188E(&pHalData->odmpriv))
400 rtStatus = _FAIL;
401
402 /*----Restore RFENV control type----*/;
403 rtl8188e_PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV, u4RegValue);
404
405 return rtStatus;
406 }
407