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