1 /******************************************************************************
3 * Copyright(c) 2009-2012 Realtek Corporation.
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.
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
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
18 * The full GNU General Public License is included in this distribution in the
19 * file called LICENSE.
21 * Contact Information:
22 * wlanfae <wlanfae@realtek.com>
23 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
24 * Hsinchu 300, Taiwan.
26 * Larry Finger <Larry.Finger@lwfinger.net>
28 *****************************************************************************/
37 static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw
*hw
);
39 void rtl92cu_phy_rf6052_set_bandwidth(struct ieee80211_hw
*hw
, u8 bandwidth
)
41 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
42 struct rtl_phy
*rtlphy
= &(rtlpriv
->phy
);
45 case HT_CHANNEL_WIDTH_20
:
46 rtlphy
->rfreg_chnlval
[0] = ((rtlphy
->rfreg_chnlval
[0] &
47 0xfffff3ff) | 0x0400);
48 rtl_set_rfreg(hw
, RF90_PATH_A
, RF_CHNLBW
, RFREG_OFFSET_MASK
,
49 rtlphy
->rfreg_chnlval
[0]);
51 case HT_CHANNEL_WIDTH_20_40
:
52 rtlphy
->rfreg_chnlval
[0] = ((rtlphy
->rfreg_chnlval
[0] &
54 rtl_set_rfreg(hw
, RF90_PATH_A
, RF_CHNLBW
, RFREG_OFFSET_MASK
,
55 rtlphy
->rfreg_chnlval
[0]);
58 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_EMERG
,
59 "unknown bandwidth: %#X\n", bandwidth
);
64 void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw
*hw
,
67 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
68 struct rtl_phy
*rtlphy
= &(rtlpriv
->phy
);
69 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
70 struct rtl_efuse
*rtlefuse
= rtl_efuse(rtl_priv(hw
));
71 u32 tx_agc
[2] = { 0, 0 }, tmpval
= 0;
72 bool turbo_scanoff
= false;
76 if ((rtlefuse
->eeprom_regulatory
!= 0) || (rtlefuse
->external_pa
))
78 if (mac
->act_scanning
) {
79 tx_agc
[RF90_PATH_A
] = 0x3f3f3f3f;
80 tx_agc
[RF90_PATH_B
] = 0x3f3f3f3f;
81 for (idx1
= RF90_PATH_A
; idx1
<= RF90_PATH_B
; idx1
++) {
82 tx_agc
[idx1
] = ppowerlevel
[idx1
] |
83 (ppowerlevel
[idx1
] << 8) |
84 (ppowerlevel
[idx1
] << 16) |
85 (ppowerlevel
[idx1
] << 24);
86 if (tx_agc
[idx1
] > 0x20 && rtlefuse
->external_pa
)
90 if (rtlpriv
->dm
.dynamic_txhighpower_lvl
==
91 TXHIGHPWRLEVEL_LEVEL1
) {
92 tx_agc
[RF90_PATH_A
] = 0x10101010;
93 tx_agc
[RF90_PATH_B
] = 0x10101010;
94 } else if (rtlpriv
->dm
.dynamic_txhighpower_lvl
==
95 TXHIGHPWRLEVEL_LEVEL2
) {
96 tx_agc
[RF90_PATH_A
] = 0x00000000;
97 tx_agc
[RF90_PATH_B
] = 0x00000000;
99 for (idx1
= RF90_PATH_A
; idx1
<= RF90_PATH_B
; idx1
++) {
100 tx_agc
[idx1
] = ppowerlevel
[idx1
] |
101 (ppowerlevel
[idx1
] << 8) |
102 (ppowerlevel
[idx1
] << 16) |
103 (ppowerlevel
[idx1
] << 24);
105 if (rtlefuse
->eeprom_regulatory
== 0) {
106 tmpval
= (rtlphy
->mcs_offset
[0][6]) +
107 (rtlphy
->mcs_offset
[0][7] << 8);
108 tx_agc
[RF90_PATH_A
] += tmpval
;
109 tmpval
= (rtlphy
->mcs_offset
[0][14]) +
110 (rtlphy
->mcs_offset
[0][15] << 24);
111 tx_agc
[RF90_PATH_B
] += tmpval
;
115 for (idx1
= RF90_PATH_A
; idx1
<= RF90_PATH_B
; idx1
++) {
116 ptr
= (u8
*) (&(tx_agc
[idx1
]));
117 for (idx2
= 0; idx2
< 4; idx2
++) {
118 if (*ptr
> RF6052_MAX_TX_PWR
)
119 *ptr
= RF6052_MAX_TX_PWR
;
123 tmpval
= tx_agc
[RF90_PATH_A
] & 0xff;
124 rtl_set_bbreg(hw
, RTXAGC_A_CCK1_MCS32
, MASKBYTE1
, tmpval
);
126 RTPRINT(rtlpriv
, FPHY
, PHY_TXPWR
,
127 "CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n",
128 tmpval
, RTXAGC_A_CCK1_MCS32
);
130 tmpval
= tx_agc
[RF90_PATH_A
] >> 8;
131 if (mac
->mode
== WIRELESS_MODE_B
)
132 tmpval
= tmpval
& 0xff00ffff;
133 rtl_set_bbreg(hw
, RTXAGC_B_CCK11_A_CCK2_11
, 0xffffff00, tmpval
);
134 RTPRINT(rtlpriv
, FPHY
, PHY_TXPWR
,
135 "CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n",
136 tmpval
, RTXAGC_B_CCK11_A_CCK2_11
);
137 tmpval
= tx_agc
[RF90_PATH_B
] >> 24;
138 rtl_set_bbreg(hw
, RTXAGC_B_CCK11_A_CCK2_11
, MASKBYTE0
, tmpval
);
139 RTPRINT(rtlpriv
, FPHY
, PHY_TXPWR
,
140 "CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n",
141 tmpval
, RTXAGC_B_CCK11_A_CCK2_11
);
142 tmpval
= tx_agc
[RF90_PATH_B
] & 0x00ffffff;
143 rtl_set_bbreg(hw
, RTXAGC_B_CCK1_55_MCS32
, 0xffffff00, tmpval
);
144 RTPRINT(rtlpriv
, FPHY
, PHY_TXPWR
,
145 "CCK PWR 1~5.5M (rf-B) = 0x%x (reg 0x%x)\n",
146 tmpval
, RTXAGC_B_CCK1_55_MCS32
);
149 static void rtl92c_phy_get_power_base(struct ieee80211_hw
*hw
,
150 u8
*ppowerlevel
, u8 channel
,
151 u32
*ofdmbase
, u32
*mcsbase
)
153 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
154 struct rtl_phy
*rtlphy
= &(rtlpriv
->phy
);
155 struct rtl_efuse
*rtlefuse
= rtl_efuse(rtl_priv(hw
));
156 u32 powerBase0
, powerBase1
;
157 u8 legacy_pwrdiff
= 0, ht20_pwrdiff
= 0;
160 for (i
= 0; i
< 2; i
++) {
161 powerlevel
[i
] = ppowerlevel
[i
];
162 legacy_pwrdiff
= rtlefuse
->txpwr_legacyhtdiff
[i
][channel
- 1];
163 powerBase0
= powerlevel
[i
] + legacy_pwrdiff
;
164 powerBase0
= (powerBase0
<< 24) | (powerBase0
<< 16) |
165 (powerBase0
<< 8) | powerBase0
;
166 *(ofdmbase
+ i
) = powerBase0
;
167 RTPRINT(rtlpriv
, FPHY
, PHY_TXPWR
,
168 " [OFDM power base index rf(%c) = 0x%x]\n",
169 i
== 0 ? 'A' : 'B', *(ofdmbase
+ i
));
171 for (i
= 0; i
< 2; i
++) {
172 if (rtlphy
->current_chan_bw
== HT_CHANNEL_WIDTH_20
) {
173 ht20_pwrdiff
= rtlefuse
->txpwr_ht20diff
[i
][channel
- 1];
174 powerlevel
[i
] += ht20_pwrdiff
;
176 powerBase1
= powerlevel
[i
];
177 powerBase1
= (powerBase1
<< 24) |
178 (powerBase1
<< 16) | (powerBase1
<< 8) | powerBase1
;
179 *(mcsbase
+ i
) = powerBase1
;
180 RTPRINT(rtlpriv
, FPHY
, PHY_TXPWR
,
181 " [MCS power base index rf(%c) = 0x%x]\n",
182 i
== 0 ? 'A' : 'B', *(mcsbase
+ i
));
186 static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw
*hw
,
187 u8 channel
, u8 index
,
192 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
193 struct rtl_phy
*rtlphy
= &(rtlpriv
->phy
);
194 struct rtl_efuse
*rtlefuse
= rtl_efuse(rtl_priv(hw
));
195 u8 i
, chnlgroup
= 0, pwr_diff_limit
[4];
196 u32 writeVal
, customer_limit
, rf
;
198 for (rf
= 0; rf
< 2; rf
++) {
199 switch (rtlefuse
->eeprom_regulatory
) {
202 writeVal
= rtlphy
->mcs_offset
203 [chnlgroup
][index
+ (rf
? 8 : 0)]
204 + ((index
< 2) ? powerBase0
[rf
] : powerBase1
[rf
]);
205 RTPRINT(rtlpriv
, FPHY
, PHY_TXPWR
,
206 "RTK better performance,writeVal(%c) = 0x%x\n",
207 rf
== 0 ? 'A' : 'B', writeVal
);
210 if (rtlphy
->pwrgroup_cnt
== 1)
212 if (rtlphy
->pwrgroup_cnt
>= 3) {
215 else if (channel
>= 4 && channel
<= 9)
217 else if (channel
> 9)
219 if (rtlphy
->current_chan_bw
==
225 writeVal
= rtlphy
->mcs_offset
[chnlgroup
][index
+
227 ((index
< 2) ? powerBase0
[rf
] :
229 RTPRINT(rtlpriv
, FPHY
, PHY_TXPWR
,
230 "Realtek regulatory, 20MHz, writeVal(%c) = 0x%x\n",
231 rf
== 0 ? 'A' : 'B', writeVal
);
234 writeVal
= ((index
< 2) ? powerBase0
[rf
] :
236 RTPRINT(rtlpriv
, FPHY
, PHY_TXPWR
,
237 "Better regulatory,writeVal(%c) = 0x%x\n",
238 rf
== 0 ? 'A' : 'B', writeVal
);
242 if (rtlphy
->current_chan_bw
==
243 HT_CHANNEL_WIDTH_20_40
) {
244 RTPRINT(rtlpriv
, FPHY
, PHY_TXPWR
,
245 "customer's limit, 40MHzrf(%c) = 0x%x\n",
247 rtlefuse
->pwrgroup_ht40
[rf
]
250 RTPRINT(rtlpriv
, FPHY
, PHY_TXPWR
,
251 "customer's limit, 20MHz rf(%c) = 0x%x\n",
253 rtlefuse
->pwrgroup_ht20
[rf
]
256 for (i
= 0; i
< 4; i
++) {
257 pwr_diff_limit
[i
] = (u8
) ((rtlphy
->mcs_offset
258 [chnlgroup
][index
+ (rf
? 8 : 0)]
259 & (0x7f << (i
* 8))) >> (i
* 8));
260 if (rtlphy
->current_chan_bw
==
261 HT_CHANNEL_WIDTH_20_40
) {
262 if (pwr_diff_limit
[i
] >
263 rtlefuse
->pwrgroup_ht40
[rf
]
265 pwr_diff_limit
[i
] = rtlefuse
->
269 if (pwr_diff_limit
[i
] >
270 rtlefuse
->pwrgroup_ht20
[rf
]
273 rtlefuse
->pwrgroup_ht20
[rf
]
277 customer_limit
= (pwr_diff_limit
[3] << 24) |
278 (pwr_diff_limit
[2] << 16) |
279 (pwr_diff_limit
[1] << 8) | (pwr_diff_limit
[0]);
280 RTPRINT(rtlpriv
, FPHY
, PHY_TXPWR
,
281 "Customer's limit rf(%c) = 0x%x\n",
282 rf
== 0 ? 'A' : 'B', customer_limit
);
283 writeVal
= customer_limit
+ ((index
< 2) ?
284 powerBase0
[rf
] : powerBase1
[rf
]);
285 RTPRINT(rtlpriv
, FPHY
, PHY_TXPWR
,
286 "Customer, writeVal rf(%c)= 0x%x\n",
287 rf
== 0 ? 'A' : 'B', writeVal
);
291 writeVal
= rtlphy
->mcs_offset
[chnlgroup
]
292 [index
+ (rf
? 8 : 0)] + ((index
< 2) ?
293 powerBase0
[rf
] : powerBase1
[rf
]);
294 RTPRINT(rtlpriv
, FPHY
, PHY_TXPWR
,
295 "RTK better performance, writeValrf(%c) = 0x%x\n",
296 rf
== 0 ? 'A' : 'B', writeVal
);
299 if (rtlpriv
->dm
.dynamic_txhighpower_lvl
==
300 TXHIGHPWRLEVEL_LEVEL1
)
301 writeVal
= 0x14141414;
302 else if (rtlpriv
->dm
.dynamic_txhighpower_lvl
==
303 TXHIGHPWRLEVEL_LEVEL2
)
304 writeVal
= 0x00000000;
305 if (rtlpriv
->dm
.dynamic_txhighpower_lvl
== TXHIGHPWRLEVEL_BT1
)
306 writeVal
= writeVal
- 0x06060606;
307 else if (rtlpriv
->dm
.dynamic_txhighpower_lvl
==
310 *(p_outwriteval
+ rf
) = writeVal
;
314 static void _rtl92c_write_ofdm_power_reg(struct ieee80211_hw
*hw
,
315 u8 index
, u32
*pValue
)
317 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
318 struct rtl_phy
*rtlphy
= &(rtlpriv
->phy
);
319 u16 regoffset_a
[6] = {
320 RTXAGC_A_RATE18_06
, RTXAGC_A_RATE54_24
,
321 RTXAGC_A_MCS03_MCS00
, RTXAGC_A_MCS07_MCS04
,
322 RTXAGC_A_MCS11_MCS08
, RTXAGC_A_MCS15_MCS12
324 u16 regoffset_b
[6] = {
325 RTXAGC_B_RATE18_06
, RTXAGC_B_RATE54_24
,
326 RTXAGC_B_MCS03_MCS00
, RTXAGC_B_MCS07_MCS04
,
327 RTXAGC_B_MCS11_MCS08
, RTXAGC_B_MCS15_MCS12
329 u8 i
, rf
, pwr_val
[4];
333 for (rf
= 0; rf
< 2; rf
++) {
334 writeVal
= pValue
[rf
];
335 for (i
= 0; i
< 4; i
++) {
336 pwr_val
[i
] = (u8
)((writeVal
& (0x7f << (i
* 8))) >>
338 if (pwr_val
[i
] > RF6052_MAX_TX_PWR
)
339 pwr_val
[i
] = RF6052_MAX_TX_PWR
;
341 writeVal
= (pwr_val
[3] << 24) | (pwr_val
[2] << 16) |
342 (pwr_val
[1] << 8) | pwr_val
[0];
344 regoffset
= regoffset_a
[index
];
346 regoffset
= regoffset_b
[index
];
347 rtl_set_bbreg(hw
, regoffset
, MASKDWORD
, writeVal
);
348 RTPRINT(rtlpriv
, FPHY
, PHY_TXPWR
,
349 "Set 0x%x = %08x\n", regoffset
, writeVal
);
350 if (((get_rf_type(rtlphy
) == RF_2T2R
) &&
351 (regoffset
== RTXAGC_A_MCS15_MCS12
||
352 regoffset
== RTXAGC_B_MCS15_MCS12
)) ||
353 ((get_rf_type(rtlphy
) != RF_2T2R
) &&
354 (regoffset
== RTXAGC_A_MCS07_MCS04
||
355 regoffset
== RTXAGC_B_MCS07_MCS04
))) {
356 writeVal
= pwr_val
[3];
357 if (regoffset
== RTXAGC_A_MCS15_MCS12
||
358 regoffset
== RTXAGC_A_MCS07_MCS04
)
360 if (regoffset
== RTXAGC_B_MCS15_MCS12
||
361 regoffset
== RTXAGC_B_MCS07_MCS04
)
363 for (i
= 0; i
< 3; i
++) {
365 writeVal
= (writeVal
> 8) ?
368 writeVal
= (writeVal
> 6) ?
370 rtl_write_byte(rtlpriv
, (u32
)(regoffset
+ i
),
377 void rtl92cu_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw
*hw
,
378 u8
*ppowerlevel
, u8 channel
)
380 u32 writeVal
[2], powerBase0
[2], powerBase1
[2];
383 rtl92c_phy_get_power_base(hw
, ppowerlevel
,
384 channel
, &powerBase0
[0], &powerBase1
[0]);
385 for (index
= 0; index
< 6; index
++) {
386 _rtl92c_get_txpower_writeval_by_regulatory(hw
,
391 _rtl92c_write_ofdm_power_reg(hw
, index
, &writeVal
[0]);
395 bool rtl92cu_phy_rf6052_config(struct ieee80211_hw
*hw
)
397 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
398 struct rtl_phy
*rtlphy
= &(rtlpriv
->phy
);
399 bool rtstatus
= true;
400 u8 b_reg_hwparafile
= 1;
402 if (rtlphy
->rf_type
== RF_1T1R
)
403 rtlphy
->num_total_rfpath
= 1;
405 rtlphy
->num_total_rfpath
= 2;
406 if (b_reg_hwparafile
== 1)
407 rtstatus
= _rtl92c_phy_rf6052_config_parafile(hw
);
411 static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw
*hw
)
413 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
414 struct rtl_phy
*rtlphy
= &(rtlpriv
->phy
);
417 bool rtstatus
= true;
418 struct bb_reg_def
*pphyreg
;
420 for (rfpath
= 0; rfpath
< rtlphy
->num_total_rfpath
; rfpath
++) {
421 pphyreg
= &rtlphy
->phyreg_def
[rfpath
];
425 u4_regvalue
= rtl_get_bbreg(hw
, pphyreg
->rfintfs
,
430 u4_regvalue
= rtl_get_bbreg(hw
, pphyreg
->rfintfs
,
434 rtl_set_bbreg(hw
, pphyreg
->rfintfe
, BRFSI_RFENV
<< 16, 0x1);
436 rtl_set_bbreg(hw
, pphyreg
->rfintfo
, BRFSI_RFENV
, 0x1);
438 rtl_set_bbreg(hw
, pphyreg
->rfhssi_para2
,
439 B3WIREADDREAALENGTH
, 0x0);
441 rtl_set_bbreg(hw
, pphyreg
->rfhssi_para2
, B3WIREDATALENGTH
, 0x0);
446 rtstatus
= rtl92cu_phy_config_rf_with_headerfile(hw
,
447 (enum radio_path
) rfpath
);
457 rtl_set_bbreg(hw
, pphyreg
->rfintfs
,
458 BRFSI_RFENV
, u4_regvalue
);
462 rtl_set_bbreg(hw
, pphyreg
->rfintfs
,
463 BRFSI_RFENV
<< 16, u4_regvalue
);
467 RT_TRACE(rtlpriv
, COMP_INIT
, DBG_TRACE
,
468 "Radio[%d] Fail!!", rfpath
);
469 goto phy_rf_cfg_fail
;
472 RT_TRACE(rtlpriv
, COMP_INIT
, DBG_TRACE
, "<---\n");