GNU Linux-libre 4.14.290-gnu1
[releases.git] / drivers / net / wireless / realtek / rtlwifi / rtl8192se / rf.c
1 /******************************************************************************
2  *
3  * Copyright(c) 2009-2012  Realtek Corporation.
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  * The full GNU General Public License is included in this distribution in the
15  * file called LICENSE.
16  *
17  * Contact Information:
18  * wlanfae <wlanfae@realtek.com>
19  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
20  * Hsinchu 300, Taiwan.
21  *
22  * Larry Finger <Larry.Finger@lwfinger.net>
23  *
24  *****************************************************************************/
25
26 #include "../wifi.h"
27 #include "reg.h"
28 #include "def.h"
29 #include "phy.h"
30 #include "rf.h"
31 #include "dm.h"
32
33
34 static void _rtl92s_get_powerbase(struct ieee80211_hw *hw, u8 *p_pwrlevel,
35                                   u8 chnl, u32 *ofdmbase, u32 *mcsbase,
36                                   u8 *p_final_pwridx)
37 {
38         struct rtl_priv *rtlpriv = rtl_priv(hw);
39         struct rtl_phy *rtlphy = &(rtlpriv->phy);
40         struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
41         u32 pwrbase0, pwrbase1;
42         u8 legacy_pwrdiff = 0, ht20_pwrdiff = 0;
43         u8 i, pwrlevel[4];
44
45         for (i = 0; i < 2; i++)
46                 pwrlevel[i] = p_pwrlevel[i];
47
48         /* We only care about the path A for legacy. */
49         if (rtlefuse->eeprom_version < 2) {
50                 pwrbase0 = pwrlevel[0] + (rtlefuse->legacy_httxpowerdiff & 0xf);
51         } else {
52                 legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff
53                                                 [RF90_PATH_A][chnl - 1];
54
55                 /* For legacy OFDM, tx pwr always > HT OFDM pwr.
56                  * We do not care Path B
57                  * legacy OFDM pwr diff. NO BB register
58                  * to notify HW. */
59                 pwrbase0 = pwrlevel[0] + legacy_pwrdiff;
60         }
61
62         pwrbase0 = (pwrbase0 << 24) | (pwrbase0 << 16) | (pwrbase0 << 8) |
63                     pwrbase0;
64         *ofdmbase = pwrbase0;
65
66         /* MCS rates */
67         if (rtlefuse->eeprom_version >= 2) {
68                 /* Check HT20 to HT40 diff      */
69                 if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) {
70                         for (i = 0; i < 2; i++) {
71                                 /* rf-A, rf-B */
72                                 /* HT 20<->40 pwr diff */
73                                 ht20_pwrdiff = rtlefuse->txpwr_ht20diff
74                                                         [i][chnl - 1];
75
76                                 if (ht20_pwrdiff < 8) /* 0~+7 */
77                                         pwrlevel[i] += ht20_pwrdiff;
78                                 else /* index8-15=-8~-1 */
79                                         pwrlevel[i] -= (16 - ht20_pwrdiff);
80                         }
81                 }
82         }
83
84         /* use index of rf-A */
85         pwrbase1 = pwrlevel[0];
86         pwrbase1 = (pwrbase1 << 24) | (pwrbase1 << 16) | (pwrbase1 << 8) |
87                                 pwrbase1;
88         *mcsbase = pwrbase1;
89
90         /* The following is for Antenna
91          * diff from Ant-B to Ant-A */
92         p_final_pwridx[0] = pwrlevel[0];
93         p_final_pwridx[1] = pwrlevel[1];
94
95         switch (rtlefuse->eeprom_regulatory) {
96         case 3:
97                 /* The following is for calculation
98                  * of the power diff for Ant-B to Ant-A. */
99                 if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
100                         p_final_pwridx[0] += rtlefuse->pwrgroup_ht40
101                                                 [RF90_PATH_A][
102                                                 chnl - 1];
103                         p_final_pwridx[1] += rtlefuse->pwrgroup_ht40
104                                                 [RF90_PATH_B][
105                                                 chnl - 1];
106                 } else {
107                         p_final_pwridx[0] += rtlefuse->pwrgroup_ht20
108                                                 [RF90_PATH_A][
109                                                 chnl - 1];
110                         p_final_pwridx[1] += rtlefuse->pwrgroup_ht20
111                                                 [RF90_PATH_B][
112                                                 chnl - 1];
113                 }
114                 break;
115         default:
116                 break;
117         }
118
119         if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
120                 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
121                          "40MHz finalpwr_idx (A / B) = 0x%x / 0x%x\n",
122                          p_final_pwridx[0], p_final_pwridx[1]);
123         } else {
124                 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
125                          "20MHz finalpwr_idx (A / B) = 0x%x / 0x%x\n",
126                          p_final_pwridx[0], p_final_pwridx[1]);
127         }
128 }
129
130 static void _rtl92s_set_antennadiff(struct ieee80211_hw *hw,
131                                     u8 *p_final_pwridx)
132 {
133         struct rtl_priv *rtlpriv = rtl_priv(hw);
134         struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
135         struct rtl_phy *rtlphy = &(rtlpriv->phy);
136         s8 ant_pwr_diff = 0;
137         u32     u4reg_val = 0;
138
139         if (rtlphy->rf_type == RF_2T2R) {
140                 ant_pwr_diff = p_final_pwridx[1] - p_final_pwridx[0];
141
142                 /* range is from 7~-8,
143                  * index = 0x0~0xf */
144                 if (ant_pwr_diff > 7)
145                         ant_pwr_diff = 7;
146                 if (ant_pwr_diff < -8)
147                         ant_pwr_diff = -8;
148
149                 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
150                          "Antenna Diff from RF-B to RF-A = %d (0x%x)\n",
151                          ant_pwr_diff, ant_pwr_diff & 0xf);
152
153                 ant_pwr_diff &= 0xf;
154         }
155
156         /* Antenna TX power difference */
157         rtlefuse->antenna_txpwdiff[2] = 0;/* RF-D, don't care */
158         rtlefuse->antenna_txpwdiff[1] = 0;/* RF-C, don't care */
159         rtlefuse->antenna_txpwdiff[0] = (u8)(ant_pwr_diff);     /* RF-B */
160
161         u4reg_val = rtlefuse->antenna_txpwdiff[2] << 8 |
162                                 rtlefuse->antenna_txpwdiff[1] << 4 |
163                                 rtlefuse->antenna_txpwdiff[0];
164
165         rtl_set_bbreg(hw, RFPGA0_TXGAINSTAGE, (BXBTXAGC | BXCTXAGC | BXDTXAGC),
166                       u4reg_val);
167
168         RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "Write BCD-Diff(0x%x) = 0x%x\n",
169                  RFPGA0_TXGAINSTAGE, u4reg_val);
170 }
171
172 static void _rtl92s_get_txpower_writeval_byregulatory(struct ieee80211_hw *hw,
173                                                       u8 chnl, u8 index,
174                                                       u32 pwrbase0,
175                                                       u32 pwrbase1,
176                                                       u32 *p_outwrite_val)
177 {
178         struct rtl_priv *rtlpriv = rtl_priv(hw);
179         struct rtl_phy *rtlphy = &(rtlpriv->phy);
180         struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
181         u8 i, chnlgroup, pwrdiff_limit[4];
182         u32 writeval, customer_limit;
183
184         /* Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */
185         switch (rtlefuse->eeprom_regulatory) {
186         case 0:
187                 /* Realtek better performance increase power diff
188                  * defined by Realtek for large power */
189                 chnlgroup = 0;
190
191                 writeval = rtlphy->mcs_offset[chnlgroup][index] +
192                                 ((index < 2) ? pwrbase0 : pwrbase1);
193
194                 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
195                          "RTK better performance, writeval = 0x%x\n", writeval);
196                 break;
197         case 1:
198                 /* Realtek regulatory increase power diff defined
199                  * by Realtek for regulatory */
200                 if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
201                         writeval = ((index < 2) ? pwrbase0 : pwrbase1);
202
203                         RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
204                                  "Realtek regulatory, 40MHz, writeval = 0x%x\n",
205                                  writeval);
206                 } else {
207                         chnlgroup = 0;
208
209                         if (rtlphy->pwrgroup_cnt >= 3) {
210                                 if (chnl <= 3)
211                                         chnlgroup = 0;
212                                 else if (chnl >= 4 && chnl <= 8)
213                                         chnlgroup = 1;
214                                 else if (chnl > 8)
215                                         chnlgroup = 2;
216                                 if (rtlphy->pwrgroup_cnt == 4)
217                                         chnlgroup++;
218                         }
219
220                         writeval = rtlphy->mcs_offset[chnlgroup][index]
221                                         + ((index < 2) ?
222                                         pwrbase0 : pwrbase1);
223
224                         RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
225                                  "Realtek regulatory, 20MHz, writeval = 0x%x\n",
226                                  writeval);
227                 }
228                 break;
229         case 2:
230                 /* Better regulatory don't increase any power diff */
231                 writeval = ((index < 2) ? pwrbase0 : pwrbase1);
232                 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
233                          "Better regulatory, writeval = 0x%x\n", writeval);
234                 break;
235         case 3:
236                 /* Customer defined power diff. increase power diff
237                   defined by customer. */
238                 chnlgroup = 0;
239
240                 if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
241                         RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
242                                  "customer's limit, 40MHz = 0x%x\n",
243                                  rtlefuse->pwrgroup_ht40
244                                  [RF90_PATH_A][chnl - 1]);
245                 } else {
246                         RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
247                                  "customer's limit, 20MHz = 0x%x\n",
248                                  rtlefuse->pwrgroup_ht20
249                                  [RF90_PATH_A][chnl - 1]);
250                 }
251
252                 for (i = 0; i < 4; i++) {
253                         pwrdiff_limit[i] = (u8)((rtlphy->mcs_offset
254                                 [chnlgroup][index] & (0x7f << (i * 8)))
255                                 >> (i * 8));
256
257                         if (rtlphy->current_chan_bw ==
258                             HT_CHANNEL_WIDTH_20_40) {
259                                 if (pwrdiff_limit[i] >
260                                     rtlefuse->pwrgroup_ht40
261                                     [RF90_PATH_A][chnl - 1]) {
262                                         pwrdiff_limit[i] =
263                                           rtlefuse->pwrgroup_ht40
264                                           [RF90_PATH_A][chnl - 1];
265                                 }
266                         } else {
267                                 if (pwrdiff_limit[i] >
268                                     rtlefuse->pwrgroup_ht20
269                                     [RF90_PATH_A][chnl - 1]) {
270                                         pwrdiff_limit[i] =
271                                             rtlefuse->pwrgroup_ht20
272                                             [RF90_PATH_A][chnl - 1];
273                                 }
274                         }
275                 }
276
277                 customer_limit = (pwrdiff_limit[3] << 24) |
278                                 (pwrdiff_limit[2] << 16) |
279                                 (pwrdiff_limit[1] << 8) |
280                                 (pwrdiff_limit[0]);
281                 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
282                          "Customer's limit = 0x%x\n", customer_limit);
283
284                 writeval = customer_limit + ((index < 2) ?
285                                              pwrbase0 : pwrbase1);
286                 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
287                          "Customer, writeval = 0x%x\n", writeval);
288                 break;
289         default:
290                 chnlgroup = 0;
291                 writeval = rtlphy->mcs_offset[chnlgroup][index] +
292                                 ((index < 2) ? pwrbase0 : pwrbase1);
293                 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
294                          "RTK better performance, writeval = 0x%x\n", writeval);
295                 break;
296         }
297
298         if (rtlpriv->dm.dynamic_txhighpower_lvl == TX_HIGH_PWR_LEVEL_LEVEL1)
299                 writeval = 0x10101010;
300         else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
301                  TX_HIGH_PWR_LEVEL_LEVEL2)
302                 writeval = 0x0;
303
304         *p_outwrite_val = writeval;
305
306 }
307
308 static void _rtl92s_write_ofdm_powerreg(struct ieee80211_hw *hw,
309                                         u8 index, u32 val)
310 {
311         struct rtl_priv *rtlpriv = rtl_priv(hw);
312         struct rtl_phy *rtlphy = &(rtlpriv->phy);
313         struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
314         u16 regoffset[6] = {0xe00, 0xe04, 0xe10, 0xe14, 0xe18, 0xe1c};
315         u8 i, rfa_pwr[4];
316         u8 rfa_lower_bound = 0, rfa_upper_bound = 0, rf_pwr_diff = 0;
317         u32 writeval = val;
318
319         /* If path A and Path B coexist, we must limit Path A tx power.
320          * Protect Path B pwr over or under flow. We need to calculate
321          * upper and lower bound of path A tx power. */
322         if (rtlphy->rf_type == RF_2T2R) {
323                 rf_pwr_diff = rtlefuse->antenna_txpwdiff[0];
324
325                 /* Diff=-8~-1 */
326                 if (rf_pwr_diff >= 8) {
327                         /* Prevent underflow!! */
328                         rfa_lower_bound = 0x10 - rf_pwr_diff;
329                 /* if (rf_pwr_diff >= 0) Diff = 0-7 */
330                 } else {
331                         rfa_upper_bound = RF6052_MAX_TX_PWR - rf_pwr_diff;
332                 }
333         }
334
335         for (i = 0; i < 4; i++) {
336                 rfa_pwr[i] = (u8)((writeval & (0x7f << (i * 8))) >> (i * 8));
337                 if (rfa_pwr[i]  > RF6052_MAX_TX_PWR)
338                         rfa_pwr[i]  = RF6052_MAX_TX_PWR;
339
340                 /* If path A and Path B coexist, we must limit Path A tx power.
341                  * Protect Path B pwr over or under flow. We need to calculate
342                  * upper and lower bound of path A tx power. */
343                 if (rtlphy->rf_type == RF_2T2R) {
344                         /* Diff=-8~-1 */
345                         if (rf_pwr_diff >= 8) {
346                                 /* Prevent underflow!! */
347                                 if (rfa_pwr[i] < rfa_lower_bound)
348                                         rfa_pwr[i] = rfa_lower_bound;
349                         /* Diff = 0-7 */
350                         } else if (rf_pwr_diff >= 1) {
351                                 /* Prevent overflow */
352                                 if (rfa_pwr[i] > rfa_upper_bound)
353                                         rfa_pwr[i] = rfa_upper_bound;
354                         }
355                 }
356
357         }
358
359         writeval = (rfa_pwr[3] << 24) | (rfa_pwr[2] << 16) | (rfa_pwr[1] << 8) |
360                                 rfa_pwr[0];
361
362         rtl_set_bbreg(hw, regoffset[index], 0x7f7f7f7f, writeval);
363 }
364
365 void rtl92s_phy_rf6052_set_ofdmtxpower(struct ieee80211_hw *hw,
366                                        u8 *p_pwrlevel, u8 chnl)
367 {
368         u32 writeval, pwrbase0, pwrbase1;
369         u8 index = 0;
370         u8 finalpwr_idx[4];
371
372         _rtl92s_get_powerbase(hw, p_pwrlevel, chnl, &pwrbase0, &pwrbase1,
373                         &finalpwr_idx[0]);
374         _rtl92s_set_antennadiff(hw, &finalpwr_idx[0]);
375
376         for (index = 0; index < 6; index++) {
377                 _rtl92s_get_txpower_writeval_byregulatory(hw, chnl, index,
378                                 pwrbase0, pwrbase1, &writeval);
379
380                 _rtl92s_write_ofdm_powerreg(hw, index, writeval);
381         }
382 }
383
384 void rtl92s_phy_rf6052_set_ccktxpower(struct ieee80211_hw *hw, u8 pwrlevel)
385 {
386         struct rtl_priv *rtlpriv = rtl_priv(hw);
387         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
388         struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
389         u32 txagc = 0;
390         bool dont_inc_cck_or_turboscanoff = false;
391
392         if (((rtlefuse->eeprom_version >= 2) &&
393               (rtlefuse->txpwr_safetyflag == 1)) ||
394               ((rtlefuse->eeprom_version >= 2) &&
395               (rtlefuse->eeprom_regulatory != 0)))
396                 dont_inc_cck_or_turboscanoff = true;
397
398         if (mac->act_scanning) {
399                 txagc = 0x3f;
400                 if (dont_inc_cck_or_turboscanoff)
401                         txagc = pwrlevel;
402         } else {
403                 txagc = pwrlevel;
404
405                 if (rtlpriv->dm.dynamic_txhighpower_lvl ==
406                     TX_HIGH_PWR_LEVEL_LEVEL1)
407                         txagc = 0x10;
408                 else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
409                         TX_HIGH_PWR_LEVEL_LEVEL2)
410                         txagc = 0x0;
411         }
412
413         if (txagc > RF6052_MAX_TX_PWR)
414                 txagc = RF6052_MAX_TX_PWR;
415
416         rtl_set_bbreg(hw, RTXAGC_CCK_MCS32, BTX_AGCRATECCK, txagc);
417
418 }
419
420 bool rtl92s_phy_rf6052_config(struct ieee80211_hw *hw)
421 {
422         struct rtl_priv *rtlpriv = rtl_priv(hw);
423         struct rtl_phy *rtlphy = &(rtlpriv->phy);
424         u32 u4reg_val = 0;
425         u8 rfpath;
426         bool rtstatus = true;
427         struct bb_reg_def *pphyreg;
428
429         /* Initialize RF */
430         for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {
431
432                 pphyreg = &rtlphy->phyreg_def[rfpath];
433
434                 /* Store original RFENV control type */
435                 switch (rfpath) {
436                 case RF90_PATH_A:
437                 case RF90_PATH_C:
438                         u4reg_val = rtl92s_phy_query_bb_reg(hw,
439                                                             pphyreg->rfintfs,
440                                                             BRFSI_RFENV);
441                         break;
442                 case RF90_PATH_B:
443                 case RF90_PATH_D:
444                         u4reg_val = rtl92s_phy_query_bb_reg(hw,
445                                                             pphyreg->rfintfs,
446                                                             BRFSI_RFENV << 16);
447                         break;
448                 }
449
450                 /* Set RF_ENV enable */
451                 rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfe,
452                                       BRFSI_RFENV << 16, 0x1);
453
454                 /* Set RF_ENV output high */
455                 rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1);
456
457                 /* Set bit number of Address and Data for RF register */
458                 rtl92s_phy_set_bb_reg(hw, pphyreg->rfhssi_para2,
459                                 B3WIRE_ADDRESSLENGTH, 0x0);
460                 rtl92s_phy_set_bb_reg(hw, pphyreg->rfhssi_para2,
461                                 B3WIRE_DATALENGTH, 0x0);
462
463                 /* Initialize RF fom connfiguration file */
464                 switch (rfpath) {
465                 case RF90_PATH_A:
466                         rtstatus = rtl92s_phy_config_rf(hw,
467                                                 (enum radio_path)rfpath);
468                         break;
469                 case RF90_PATH_B:
470                         rtstatus = rtl92s_phy_config_rf(hw,
471                                                 (enum radio_path)rfpath);
472                         break;
473                 case RF90_PATH_C:
474                         break;
475                 case RF90_PATH_D:
476                         break;
477                 }
478
479                 /* Restore RFENV control type */
480                 switch (rfpath) {
481                 case RF90_PATH_A:
482                 case RF90_PATH_C:
483                         rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfs, BRFSI_RFENV,
484                                               u4reg_val);
485                         break;
486                 case RF90_PATH_B:
487                 case RF90_PATH_D:
488                         rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfs,
489                                               BRFSI_RFENV << 16,
490                                               u4reg_val);
491                         break;
492                 }
493
494                 if (!rtstatus) {
495                         pr_err("Radio[%d] Fail!!\n", rfpath);
496                         goto fail;
497                 }
498
499         }
500
501         return rtstatus;
502
503 fail:
504         return rtstatus;
505 }
506
507 void rtl92s_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
508 {
509         struct rtl_priv *rtlpriv = rtl_priv(hw);
510         struct rtl_phy *rtlphy = &(rtlpriv->phy);
511
512         switch (bandwidth) {
513         case HT_CHANNEL_WIDTH_20:
514                 rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
515                                            0xfffff3ff) | 0x0400);
516                 rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
517                                         rtlphy->rfreg_chnlval[0]);
518                 break;
519         case HT_CHANNEL_WIDTH_20_40:
520                 rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
521                                             0xfffff3ff));
522                 rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
523                                         rtlphy->rfreg_chnlval[0]);
524                 break;
525         default:
526                 pr_err("unknown bandwidth: %#X\n", bandwidth);
527                 break;
528         }
529 }