Linux-libre 5.3.12-gnu
[librecmc/linux-libre.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                                 Hal_GetChnlGroup88E(channel, &chnlGroup);
169
170                         write_val = hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] +
171                                         ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
172                         break;
173                 case 2: /*  Better regulatory */
174                                 /*  don't increase any power diff */
175                         write_val = (index < 2) ? powerbase0[rf] : powerbase1[rf];
176                         break;
177                 case 3: /*  Customer defined power diff. */
178                                 /*  increase power diff defined by customer. */
179                         chnlGroup = 0;
180
181                         if (index < 2)
182                                 pwr_diff = hal_data->TxPwrLegacyHtDiff[rf][channel-1];
183                         else if (hal_data->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
184                                 pwr_diff = hal_data->TxPwrHt20Diff[rf][channel-1];
185
186                         if (hal_data->CurrentChannelBW == HT_CHANNEL_WIDTH_40)
187                                 customer_pwr_limit = hal_data->PwrGroupHT40[rf][channel-1];
188                         else
189                                 customer_pwr_limit = hal_data->PwrGroupHT20[rf][channel-1];
190
191                         if (pwr_diff >= customer_pwr_limit)
192                                 pwr_diff = 0;
193                         else
194                                 pwr_diff = customer_pwr_limit - pwr_diff;
195
196                         for (i = 0; i < 4; i++) {
197                                 pwr_diff_limit[i] = (u8)((hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][j] &
198                                                          (0x7f << (i * 8))) >> (i * 8));
199
200                                 if (pwr_diff_limit[i] > pwr_diff)
201                                         pwr_diff_limit[i] = pwr_diff;
202                         }
203                         customer_limit = (pwr_diff_limit[3]<<24) |
204                                          (pwr_diff_limit[2]<<16) |
205                                          (pwr_diff_limit[1]<<8) |
206                                          (pwr_diff_limit[0]);
207                         write_val = customer_limit + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
208                         break;
209                 default:
210                         chnlGroup = 0;
211                         write_val = hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][j] +
212                                         ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
213                         break;
214                 }
215 /*  20100427 Joseph: Driver dynamic Tx power shall not affect Tx power. It shall be determined by power training mechanism. */
216 /*  Currently, we cannot fully disable driver dynamic tx power mechanism because it is referenced by BT coexist mechanism. */
217 /*  In the future, two mechanism shall be separated from each other and maintained independently. Thanks for Lanhsin's reminder. */
218                 /* 92d do not need this */
219                 if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1)
220                         write_val = 0x14141414;
221                 else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2)
222                         write_val = 0x00000000;
223
224                 *(out_val+rf) = write_val;
225         }
226 }
227
228 static void write_ofdm_pwr_reg(struct adapter *adapt, u8 index, u32 *pvalue)
229 {
230         u16 regoffset_a[6] = { rTxAGC_A_Rate18_06, rTxAGC_A_Rate54_24,
231                                rTxAGC_A_Mcs03_Mcs00, rTxAGC_A_Mcs07_Mcs04,
232                                rTxAGC_A_Mcs11_Mcs08, rTxAGC_A_Mcs15_Mcs12 };
233         u16 regoffset_b[6] = { rTxAGC_B_Rate18_06, rTxAGC_B_Rate54_24,
234                                rTxAGC_B_Mcs03_Mcs00, rTxAGC_B_Mcs07_Mcs04,
235                                rTxAGC_B_Mcs11_Mcs08, rTxAGC_B_Mcs15_Mcs12 };
236         u8 i, rf, pwr_val[4];
237         u32 write_val;
238         u16 regoffset;
239
240         for (rf = 0; rf < 2; rf++) {
241                 write_val = pvalue[rf];
242                 for (i = 0; i < 4; i++) {
243                         pwr_val[i] = (u8)((write_val & (0x7f<<(i*8)))>>(i*8));
244                         if (pwr_val[i]  > RF6052_MAX_TX_PWR)
245                                 pwr_val[i]  = RF6052_MAX_TX_PWR;
246                 }
247                 write_val = (pwr_val[3]<<24) | (pwr_val[2]<<16) |
248                             (pwr_val[1]<<8) | pwr_val[0];
249
250                 if (rf == 0)
251                         regoffset = regoffset_a[index];
252                 else
253                         regoffset = regoffset_b[index];
254
255                 phy_set_bb_reg(adapt, regoffset, bMaskDWord, write_val);
256         }
257 }
258
259 void rtl88eu_phy_rf6052_set_ofdm_txpower(struct adapter *adapt,
260                                          u8 *pwr_level_ofdm,
261                                          u8 *pwr_level_bw20,
262                                          u8 *pwr_level_bw40, u8 channel)
263 {
264         u32 write_val[2], powerbase0[2], powerbase1[2], pwrtrac_value;
265         u8 direction;
266         u8 index = 0;
267
268         getpowerbase88e(adapt, pwr_level_ofdm, pwr_level_bw20, pwr_level_bw40,
269                         channel, &powerbase0[0], &powerbase1[0]);
270
271         rtl88eu_dm_txpower_track_adjust(&adapt->HalData->odmpriv, 0,
272                                         &direction, &pwrtrac_value);
273
274         for (index = 0; index < 6; index++) {
275                 get_rx_power_val_by_reg(adapt, channel, index,
276                                         &powerbase0[0], &powerbase1[0],
277                                         &write_val[0]);
278
279                 if (direction == 1) {
280                         write_val[0] += pwrtrac_value;
281                         write_val[1] += pwrtrac_value;
282                 } else if (direction == 2) {
283                         write_val[0] -= pwrtrac_value;
284                         write_val[1] -= pwrtrac_value;
285                 }
286                 write_ofdm_pwr_reg(adapt, index, &write_val[0]);
287         }
288 }