GNU Linux-libre 4.19.207-gnu1
[releases.git] / drivers / staging / rtl8188eu / hal / rf.c
1 // SPDX-License-Identifier: GPL-2.0
2 /******************************************************************************
3  *
4  * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
5  *
6  ******************************************************************************/
7
8 #include <osdep_service.h>
9 #include <drv_types.h>
10 #include <phy.h>
11 #include <rf.h>
12 #include <rtl8188e_hal.h>
13
14 void rtl88eu_phy_rf6052_set_bandwidth(struct adapter *adapt,
15                                       enum ht_channel_width bandwidth)
16 {
17         struct hal_data_8188e *hal_data = adapt->HalData;
18
19         switch (bandwidth) {
20         case HT_CHANNEL_WIDTH_20:
21                 hal_data->RfRegChnlVal[0] = ((hal_data->RfRegChnlVal[0] &
22                                               0xfffff3ff) | BIT(10) | BIT(11));
23                 phy_set_rf_reg(adapt, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask,
24                                hal_data->RfRegChnlVal[0]);
25                 break;
26         case HT_CHANNEL_WIDTH_40:
27                 hal_data->RfRegChnlVal[0] = ((hal_data->RfRegChnlVal[0] &
28                                               0xfffff3ff) | BIT(10));
29                 phy_set_rf_reg(adapt, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask,
30                                hal_data->RfRegChnlVal[0]);
31                 break;
32         default:
33                 break;
34         }
35 }
36
37 void rtl88eu_phy_rf6052_set_cck_txpower(struct adapter *adapt, u8 *powerlevel)
38 {
39         struct hal_data_8188e *hal_data = adapt->HalData;
40         struct dm_priv *pdmpriv = &hal_data->dmpriv;
41         struct mlme_ext_priv *pmlmeext = &adapt->mlmeextpriv;
42         u32 tx_agc[2] = {0, 0}, tmpval = 0, pwrtrac_value;
43         u8 idx1, idx2;
44         u8 *ptr;
45         u8 direction;
46
47         if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
48                 tx_agc[RF_PATH_A] = 0x3f3f3f3f;
49                 tx_agc[RF_PATH_B] = 0x3f3f3f3f;
50                 for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
51                         tx_agc[idx1] = powerlevel[idx1] |
52                                       (powerlevel[idx1]<<8) |
53                                       (powerlevel[idx1]<<16) |
54                                       (powerlevel[idx1]<<24);
55                 }
56         } else {
57                 if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) {
58                         tx_agc[RF_PATH_A] = 0x10101010;
59                         tx_agc[RF_PATH_B] = 0x10101010;
60                 } else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) {
61                         tx_agc[RF_PATH_A] = 0x00000000;
62                         tx_agc[RF_PATH_B] = 0x00000000;
63                 } else {
64                         for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
65                                 tx_agc[idx1] = powerlevel[idx1] |
66                                                (powerlevel[idx1]<<8) |
67                                                (powerlevel[idx1]<<16) |
68                                                (powerlevel[idx1]<<24);
69                         }
70                         if (hal_data->EEPROMRegulatory == 0) {
71                                 tmpval = hal_data->MCSTxPowerLevelOriginalOffset[0][6] +
72                                          (hal_data->MCSTxPowerLevelOriginalOffset[0][7]<<8);
73                                 tx_agc[RF_PATH_A] += tmpval;
74
75                                 tmpval = hal_data->MCSTxPowerLevelOriginalOffset[0][14] +
76                                          (hal_data->MCSTxPowerLevelOriginalOffset[0][15]<<24);
77                                 tx_agc[RF_PATH_B] += tmpval;
78                         }
79                 }
80         }
81         for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
82                 ptr = (u8 *)(&(tx_agc[idx1]));
83                 for (idx2 = 0; idx2 < 4; idx2++) {
84                         if (*ptr > RF6052_MAX_TX_PWR)
85                                 *ptr = RF6052_MAX_TX_PWR;
86                         ptr++;
87                 }
88         }
89         rtl88eu_dm_txpower_track_adjust(&hal_data->odmpriv, 1, &direction,
90                                         &pwrtrac_value);
91
92         if (direction == 1) {
93                 /*  Increase TX power */
94                 tx_agc[0] += pwrtrac_value;
95                 tx_agc[1] += pwrtrac_value;
96         } else if (direction == 2) {
97                 /*  Decrease TX power */
98                 tx_agc[0] -=  pwrtrac_value;
99                 tx_agc[1] -=  pwrtrac_value;
100         }
101
102         /*  rf-A cck tx power */
103         tmpval = tx_agc[RF_PATH_A]&0xff;
104         phy_set_bb_reg(adapt, rTxAGC_A_CCK1_Mcs32, bMaskByte1, tmpval);
105         tmpval = tx_agc[RF_PATH_A]>>8;
106         phy_set_bb_reg(adapt, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
107
108         /*  rf-B cck tx power */
109         tmpval = tx_agc[RF_PATH_B]>>24;
110         phy_set_bb_reg(adapt, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, tmpval);
111         tmpval = tx_agc[RF_PATH_B]&0x00ffffff;
112         phy_set_bb_reg(adapt, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval);
113 }
114
115 /*  powerbase0 for OFDM rates */
116 /*  powerbase1 for HT MCS rates */
117 static void getpowerbase88e(struct adapter *adapt, u8 *pwr_level_ofdm,
118                             u8 *pwr_level_bw20, u8 *pwr_level_bw40,
119                             u8 channel, u32 *ofdmbase, u32 *mcs_base)
120 {
121         u32 powerbase0, powerbase1;
122         u8 i, powerlevel[2];
123
124         for (i = 0; i < 2; i++) {
125                 powerbase0 = pwr_level_ofdm[i];
126
127                 powerbase0 = (powerbase0<<24) | (powerbase0<<16) |
128                              (powerbase0<<8) | powerbase0;
129                 *(ofdmbase+i) = powerbase0;
130         }
131         /* Check HT20 to HT40 diff */
132         if (adapt->HalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
133                 powerlevel[0] = pwr_level_bw20[0];
134         else
135                 powerlevel[0] = pwr_level_bw40[0];
136         powerbase1 = powerlevel[0];
137         powerbase1 = (powerbase1<<24) | (powerbase1<<16) |
138                      (powerbase1<<8) | powerbase1;
139         *mcs_base = powerbase1;
140 }
141 static void get_rx_power_val_by_reg(struct adapter *adapt, u8 channel,
142                                     u8 index, u32 *powerbase0, u32 *powerbase1,
143                                     u32 *out_val)
144 {
145         struct hal_data_8188e *hal_data = adapt->HalData;
146         struct dm_priv  *pdmpriv = &hal_data->dmpriv;
147         u8 i, chnlGroup = 0, pwr_diff_limit[4], customer_pwr_limit;
148         s8 pwr_diff = 0;
149         u32 write_val, customer_limit, rf;
150         u8 regulatory = hal_data->EEPROMRegulatory;
151
152         /*  Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */
153
154         for (rf = 0; rf < 2; rf++) {
155                 u8 j = index + (rf ? 8 : 0);
156
157                 switch (regulatory) {
158                 case 0:
159                         chnlGroup = 0;
160                         write_val = hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] +
161                                 ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
162                         break;
163                 case 1: /*  Realtek regulatory */
164                         /*  increase power diff defined by Realtek for regulatory */
165                         if (hal_data->pwrGroupCnt == 1)
166                                 chnlGroup = 0;
167                         if (hal_data->pwrGroupCnt >= hal_data->PGMaxGroup) {
168                                 if (channel < 3)
169                                         chnlGroup = 0;
170                                 else if (channel < 6)
171                                         chnlGroup = 1;
172                                 else if (channel < 9)
173                                         chnlGroup = 2;
174                                 else if (channel < 12)
175                                         chnlGroup = 3;
176                                 else if (channel < 14)
177                                         chnlGroup = 4;
178                                 else if (channel == 14)
179                                         chnlGroup = 5;
180                         }
181                         write_val = hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] +
182                                         ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
183                         break;
184                 case 2: /*  Better regulatory */
185                                 /*  don't increase any power diff */
186                         write_val = (index < 2) ? powerbase0[rf] : powerbase1[rf];
187                         break;
188                 case 3: /*  Customer defined power diff. */
189                                 /*  increase power diff defined by customer. */
190                         chnlGroup = 0;
191
192                         if (index < 2)
193                                 pwr_diff = hal_data->TxPwrLegacyHtDiff[rf][channel-1];
194                         else if (hal_data->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
195                                 pwr_diff = hal_data->TxPwrHt20Diff[rf][channel-1];
196
197                         if (hal_data->CurrentChannelBW == HT_CHANNEL_WIDTH_40)
198                                 customer_pwr_limit = hal_data->PwrGroupHT40[rf][channel-1];
199                         else
200                                 customer_pwr_limit = hal_data->PwrGroupHT20[rf][channel-1];
201
202                         if (pwr_diff >= customer_pwr_limit)
203                                 pwr_diff = 0;
204                         else
205                                 pwr_diff = customer_pwr_limit - pwr_diff;
206
207                         for (i = 0; i < 4; i++) {
208                                 pwr_diff_limit[i] = (u8)((hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][j] &
209                                                          (0x7f << (i * 8))) >> (i * 8));
210
211                                 if (pwr_diff_limit[i] > pwr_diff)
212                                         pwr_diff_limit[i] = pwr_diff;
213                         }
214                         customer_limit = (pwr_diff_limit[3]<<24) |
215                                          (pwr_diff_limit[2]<<16) |
216                                          (pwr_diff_limit[1]<<8) |
217                                          (pwr_diff_limit[0]);
218                         write_val = customer_limit + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
219                         break;
220                 default:
221                         chnlGroup = 0;
222                         write_val = hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][j] +
223                                         ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
224                         break;
225                 }
226 /*  20100427 Joseph: Driver dynamic Tx power shall not affect Tx power. It shall be determined by power training mechanism. */
227 /*  Currently, we cannot fully disable driver dynamic tx power mechanism because it is referenced by BT coexist mechanism. */
228 /*  In the future, two mechanism shall be separated from each other and maintained independently. Thanks for Lanhsin's reminder. */
229                 /* 92d do not need this */
230                 if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1)
231                         write_val = 0x14141414;
232                 else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2)
233                         write_val = 0x00000000;
234
235                 *(out_val+rf) = write_val;
236         }
237 }
238
239 static void write_ofdm_pwr_reg(struct adapter *adapt, u8 index, u32 *pvalue)
240 {
241         u16 regoffset_a[6] = { rTxAGC_A_Rate18_06, rTxAGC_A_Rate54_24,
242                                rTxAGC_A_Mcs03_Mcs00, rTxAGC_A_Mcs07_Mcs04,
243                                rTxAGC_A_Mcs11_Mcs08, rTxAGC_A_Mcs15_Mcs12 };
244         u16 regoffset_b[6] = { rTxAGC_B_Rate18_06, rTxAGC_B_Rate54_24,
245                                rTxAGC_B_Mcs03_Mcs00, rTxAGC_B_Mcs07_Mcs04,
246                                rTxAGC_B_Mcs11_Mcs08, rTxAGC_B_Mcs15_Mcs12 };
247         u8 i, rf, pwr_val[4];
248         u32 write_val;
249         u16 regoffset;
250
251         for (rf = 0; rf < 2; rf++) {
252                 write_val = pvalue[rf];
253                 for (i = 0; i < 4; i++) {
254                         pwr_val[i] = (u8)((write_val & (0x7f<<(i*8)))>>(i*8));
255                         if (pwr_val[i]  > RF6052_MAX_TX_PWR)
256                                 pwr_val[i]  = RF6052_MAX_TX_PWR;
257                 }
258                 write_val = (pwr_val[3]<<24) | (pwr_val[2]<<16) |
259                             (pwr_val[1]<<8) | pwr_val[0];
260
261                 if (rf == 0)
262                         regoffset = regoffset_a[index];
263                 else
264                         regoffset = regoffset_b[index];
265
266                 phy_set_bb_reg(adapt, regoffset, bMaskDWord, write_val);
267         }
268 }
269
270 void rtl88eu_phy_rf6052_set_ofdm_txpower(struct adapter *adapt,
271                                          u8 *pwr_level_ofdm,
272                                          u8 *pwr_level_bw20,
273                                          u8 *pwr_level_bw40, u8 channel)
274 {
275         u32 write_val[2], powerbase0[2], powerbase1[2], pwrtrac_value;
276         u8 direction;
277         u8 index = 0;
278
279         getpowerbase88e(adapt, pwr_level_ofdm, pwr_level_bw20, pwr_level_bw40,
280                         channel, &powerbase0[0], &powerbase1[0]);
281
282         rtl88eu_dm_txpower_track_adjust(&adapt->HalData->odmpriv, 0,
283                                         &direction, &pwrtrac_value);
284
285         for (index = 0; index < 6; index++) {
286                 get_rx_power_val_by_reg(adapt, channel, index,
287                                         &powerbase0[0], &powerbase1[0],
288                                         &write_val[0]);
289
290                 if (direction == 1) {
291                         write_val[0] += pwrtrac_value;
292                         write_val[1] += pwrtrac_value;
293                 } else if (direction == 2) {
294                         write_val[0] -= pwrtrac_value;
295                         write_val[1] -= pwrtrac_value;
296                 }
297                 write_ofdm_pwr_reg(adapt, index, &write_val[0]);
298         }
299 }