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]);