1 /******************************************************************************
3 * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
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 ******************************************************************************/
20 #include <osdep_service.h>
21 #include <drv_types.h>
24 #include <rtl8188e_hal.h>
26 void rtl88eu_phy_rf6052_set_bandwidth(struct adapter
*adapt
,
27 enum ht_channel_width bandwidth
)
29 struct hal_data_8188e
*hal_data
= GET_HAL_DATA(adapt
);
32 case HT_CHANNEL_WIDTH_20
:
33 hal_data
->RfRegChnlVal
[0] = ((hal_data
->RfRegChnlVal
[0] &
34 0xfffff3ff) | BIT(10) | BIT(11));
35 phy_set_rf_reg(adapt
, RF_PATH_A
, RF_CHNLBW
, bRFRegOffsetMask
,
36 hal_data
->RfRegChnlVal
[0]);
38 case HT_CHANNEL_WIDTH_40
:
39 hal_data
->RfRegChnlVal
[0] = ((hal_data
->RfRegChnlVal
[0] &
40 0xfffff3ff) | BIT(10));
41 phy_set_rf_reg(adapt
, RF_PATH_A
, RF_CHNLBW
, bRFRegOffsetMask
,
42 hal_data
->RfRegChnlVal
[0]);
49 void rtl88eu_phy_rf6052_set_cck_txpower(struct adapter
*adapt
, u8
*powerlevel
)
51 struct hal_data_8188e
*hal_data
= GET_HAL_DATA(adapt
);
52 struct dm_priv
*pdmpriv
= &hal_data
->dmpriv
;
53 struct mlme_ext_priv
*pmlmeext
= &adapt
->mlmeextpriv
;
54 u32 tx_agc
[2] = {0, 0}, tmpval
= 0, pwrtrac_value
;
60 if (pmlmeext
->sitesurvey_res
.state
== SCAN_PROCESS
) {
61 tx_agc
[RF_PATH_A
] = 0x3f3f3f3f;
62 tx_agc
[RF_PATH_B
] = 0x3f3f3f3f;
63 for (idx1
= RF_PATH_A
; idx1
<= RF_PATH_B
; idx1
++) {
64 tx_agc
[idx1
] = powerlevel
[idx1
] |
65 (powerlevel
[idx1
]<<8) |
66 (powerlevel
[idx1
]<<16) |
67 (powerlevel
[idx1
]<<24);
68 if (tx_agc
[idx1
] > 0x20 && hal_data
->ExternalPA
)
72 if (pdmpriv
->DynamicTxHighPowerLvl
== TxHighPwrLevel_Level1
) {
73 tx_agc
[RF_PATH_A
] = 0x10101010;
74 tx_agc
[RF_PATH_B
] = 0x10101010;
75 } else if (pdmpriv
->DynamicTxHighPowerLvl
== TxHighPwrLevel_Level2
) {
76 tx_agc
[RF_PATH_A
] = 0x00000000;
77 tx_agc
[RF_PATH_B
] = 0x00000000;
79 for (idx1
= RF_PATH_A
; idx1
<= RF_PATH_B
; idx1
++) {
80 tx_agc
[idx1
] = powerlevel
[idx1
] |
81 (powerlevel
[idx1
]<<8) |
82 (powerlevel
[idx1
]<<16) |
83 (powerlevel
[idx1
]<<24);
85 if (hal_data
->EEPROMRegulatory
== 0) {
86 tmpval
= hal_data
->MCSTxPowerLevelOriginalOffset
[0][6] +
87 (hal_data
->MCSTxPowerLevelOriginalOffset
[0][7]<<8);
88 tx_agc
[RF_PATH_A
] += tmpval
;
90 tmpval
= hal_data
->MCSTxPowerLevelOriginalOffset
[0][14] +
91 (hal_data
->MCSTxPowerLevelOriginalOffset
[0][15]<<24);
92 tx_agc
[RF_PATH_B
] += tmpval
;
96 for (idx1
= RF_PATH_A
; idx1
<= RF_PATH_B
; idx1
++) {
97 ptr
= (u8
*)(&(tx_agc
[idx1
]));
98 for (idx2
= 0; idx2
< 4; idx2
++) {
99 if (*ptr
> RF6052_MAX_TX_PWR
)
100 *ptr
= RF6052_MAX_TX_PWR
;
104 rtl88eu_dm_txpower_track_adjust(&hal_data
->odmpriv
, 1, &direction
,
107 if (direction
== 1) {
108 /* Increase TX power */
109 tx_agc
[0] += pwrtrac_value
;
110 tx_agc
[1] += pwrtrac_value
;
111 } else if (direction
== 2) {
112 /* Decrease TX power */
113 tx_agc
[0] -= pwrtrac_value
;
114 tx_agc
[1] -= pwrtrac_value
;
117 /* rf-A cck tx power */
118 tmpval
= tx_agc
[RF_PATH_A
]&0xff;
119 phy_set_bb_reg(adapt
, rTxAGC_A_CCK1_Mcs32
, bMaskByte1
, tmpval
);
120 tmpval
= tx_agc
[RF_PATH_A
]>>8;
121 phy_set_bb_reg(adapt
, rTxAGC_B_CCK11_A_CCK2_11
, 0xffffff00, tmpval
);
123 /* rf-B cck tx power */
124 tmpval
= tx_agc
[RF_PATH_B
]>>24;
125 phy_set_bb_reg(adapt
, rTxAGC_B_CCK11_A_CCK2_11
, bMaskByte0
, tmpval
);
126 tmpval
= tx_agc
[RF_PATH_B
]&0x00ffffff;
127 phy_set_bb_reg(adapt
, rTxAGC_B_CCK1_55_Mcs32
, 0xffffff00, tmpval
);
130 /* powerbase0 for OFDM rates */
131 /* powerbase1 for HT MCS rates */
132 static void getpowerbase88e(struct adapter
*adapt
, u8
*pwr_level_ofdm
,
133 u8
*pwr_level_bw20
, u8
*pwr_level_bw40
,
134 u8 channel
, u32
*ofdmbase
, u32
*mcs_base
)
136 struct hal_data_8188e
*hal_data
= GET_HAL_DATA(adapt
);
137 u32 powerbase0
, powerbase1
;
140 for (i
= 0; i
< 2; i
++) {
141 powerbase0
= pwr_level_ofdm
[i
];
143 powerbase0
= (powerbase0
<<24) | (powerbase0
<<16) |
144 (powerbase0
<<8) | powerbase0
;
145 *(ofdmbase
+i
) = powerbase0
;
147 for (i
= 0; i
< hal_data
->NumTotalRFPath
; i
++) {
148 /* Check HT20 to HT40 diff */
149 if (hal_data
->CurrentChannelBW
== HT_CHANNEL_WIDTH_20
)
150 powerlevel
[i
] = pwr_level_bw20
[i
];
152 powerlevel
[i
] = pwr_level_bw40
[i
];
153 powerbase1
= powerlevel
[i
];
154 powerbase1
= (powerbase1
<<24) | (powerbase1
<<16) |
155 (powerbase1
<<8) | powerbase1
;
156 *(mcs_base
+i
) = powerbase1
;
159 static void get_rx_power_val_by_reg(struct adapter
*adapt
, u8 channel
,
160 u8 index
, u32
*powerbase0
, u32
*powerbase1
,
163 struct hal_data_8188e
*hal_data
= GET_HAL_DATA(adapt
);
164 struct dm_priv
*pdmpriv
= &hal_data
->dmpriv
;
165 u8 i
, chnlGroup
= 0, pwr_diff_limit
[4], customer_pwr_limit
;
167 u32 write_val
, customer_limit
, rf
;
168 u8 regulatory
= hal_data
->EEPROMRegulatory
;
170 /* Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */
172 for (rf
= 0; rf
< 2; rf
++) {
173 u8 j
= index
+ (rf
? 8 : 0);
175 switch (regulatory
) {
178 write_val
= hal_data
->MCSTxPowerLevelOriginalOffset
[chnlGroup
][index
+(rf
? 8 : 0)] +
179 ((index
< 2) ? powerbase0
[rf
] : powerbase1
[rf
]);
181 case 1: /* Realtek regulatory */
182 /* increase power diff defined by Realtek for regulatory */
183 if (hal_data
->pwrGroupCnt
== 1)
185 if (hal_data
->pwrGroupCnt
>= hal_data
->PGMaxGroup
) {
188 else if (channel
< 6)
190 else if (channel
< 9)
192 else if (channel
< 12)
194 else if (channel
< 14)
196 else if (channel
== 14)
199 write_val
= hal_data
->MCSTxPowerLevelOriginalOffset
[chnlGroup
][index
+(rf
? 8 : 0)] +
200 ((index
< 2) ? powerbase0
[rf
] : powerbase1
[rf
]);
202 case 2: /* Better regulatory */
203 /* don't increase any power diff */
204 write_val
= (index
< 2) ? powerbase0
[rf
] : powerbase1
[rf
];
206 case 3: /* Customer defined power diff. */
207 /* increase power diff defined by customer. */
211 pwr_diff
= hal_data
->TxPwrLegacyHtDiff
[rf
][channel
-1];
212 else if (hal_data
->CurrentChannelBW
== HT_CHANNEL_WIDTH_20
)
213 pwr_diff
= hal_data
->TxPwrHt20Diff
[rf
][channel
-1];
215 if (hal_data
->CurrentChannelBW
== HT_CHANNEL_WIDTH_40
)
216 customer_pwr_limit
= hal_data
->PwrGroupHT40
[rf
][channel
-1];
218 customer_pwr_limit
= hal_data
->PwrGroupHT20
[rf
][channel
-1];
220 if (pwr_diff
>= customer_pwr_limit
)
223 pwr_diff
= customer_pwr_limit
- pwr_diff
;
225 for (i
= 0; i
< 4; i
++) {
226 pwr_diff_limit
[i
] = (u8
)((hal_data
->MCSTxPowerLevelOriginalOffset
[chnlGroup
][j
] &
227 (0x7f << (i
* 8))) >> (i
* 8));
229 if (pwr_diff_limit
[i
] > pwr_diff
)
230 pwr_diff_limit
[i
] = pwr_diff
;
232 customer_limit
= (pwr_diff_limit
[3]<<24) |
233 (pwr_diff_limit
[2]<<16) |
234 (pwr_diff_limit
[1]<<8) |
236 write_val
= customer_limit
+ ((index
< 2) ? powerbase0
[rf
] : powerbase1
[rf
]);
240 write_val
= hal_data
->MCSTxPowerLevelOriginalOffset
[chnlGroup
][j
] +
241 ((index
< 2) ? powerbase0
[rf
] : powerbase1
[rf
]);
244 /* 20100427 Joseph: Driver dynamic Tx power shall not affect Tx power. It shall be determined by power training mechanism. */
245 /* Currently, we cannot fully disable driver dynamic tx power mechanism because it is referenced by BT coexist mechanism. */
246 /* In the future, two mechanism shall be separated from each other and maintained independently. Thanks for Lanhsin's reminder. */
247 /* 92d do not need this */
248 if (pdmpriv
->DynamicTxHighPowerLvl
== TxHighPwrLevel_Level1
)
249 write_val
= 0x14141414;
250 else if (pdmpriv
->DynamicTxHighPowerLvl
== TxHighPwrLevel_Level2
)
251 write_val
= 0x00000000;
253 *(out_val
+rf
) = write_val
;
257 static void write_ofdm_pwr_reg(struct adapter
*adapt
, u8 index
, u32
*pvalue
)
259 u16 regoffset_a
[6] = { rTxAGC_A_Rate18_06
, rTxAGC_A_Rate54_24
,
260 rTxAGC_A_Mcs03_Mcs00
, rTxAGC_A_Mcs07_Mcs04
,
261 rTxAGC_A_Mcs11_Mcs08
, rTxAGC_A_Mcs15_Mcs12
};
262 u16 regoffset_b
[6] = { rTxAGC_B_Rate18_06
, rTxAGC_B_Rate54_24
,
263 rTxAGC_B_Mcs03_Mcs00
, rTxAGC_B_Mcs07_Mcs04
,
264 rTxAGC_B_Mcs11_Mcs08
, rTxAGC_B_Mcs15_Mcs12
};
265 u8 i
, rf
, pwr_val
[4];
269 for (rf
= 0; rf
< 2; rf
++) {
270 write_val
= pvalue
[rf
];
271 for (i
= 0; i
< 4; i
++) {
272 pwr_val
[i
] = (u8
)((write_val
& (0x7f<<(i
*8)))>>(i
*8));
273 if (pwr_val
[i
] > RF6052_MAX_TX_PWR
)
274 pwr_val
[i
] = RF6052_MAX_TX_PWR
;
276 write_val
= (pwr_val
[3]<<24) | (pwr_val
[2]<<16) |
277 (pwr_val
[1]<<8) | pwr_val
[0];
280 regoffset
= regoffset_a
[index
];
282 regoffset
= regoffset_b
[index
];
284 phy_set_bb_reg(adapt
, regoffset
, bMaskDWord
, write_val
);
288 void rtl88eu_phy_rf6052_set_ofdm_txpower(struct adapter
*adapt
,
291 u8
*pwr_level_bw40
, u8 channel
)
293 struct hal_data_8188e
*hal_data
= GET_HAL_DATA(adapt
);
294 u32 write_val
[2], powerbase0
[2], powerbase1
[2], pwrtrac_value
;
298 getpowerbase88e(adapt
, pwr_level_ofdm
, pwr_level_bw20
, pwr_level_bw40
,
299 channel
, &powerbase0
[0], &powerbase1
[0]);
301 rtl88eu_dm_txpower_track_adjust(&hal_data
->odmpriv
, 0, &direction
,
304 for (index
= 0; index
< 6; index
++) {
305 get_rx_power_val_by_reg(adapt
, channel
, index
,
306 &powerbase0
[0], &powerbase1
[0],
309 if (direction
== 1) {
310 write_val
[0] += pwrtrac_value
;
311 write_val
[1] += pwrtrac_value
;
312 } else if (direction
== 2) {
313 write_val
[0] -= pwrtrac_value
;
314 write_val
[1] -= pwrtrac_value
;
316 write_ofdm_pwr_reg(adapt
, index
, &write_val
[0]);