blob: 1596274eefc5e1c6817266e792ddcf87aa3af313 [file] [log] [blame]
Larry Finger615a4d12013-08-21 22:33:56 -05001/******************************************************************************
2 *
3 * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
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 *
Larry Finger615a4d12013-08-21 22:33:56 -050014 ******************************************************************************/
Larry Finger615a4d12013-08-21 22:33:56 -050015
16#include <osdep_service.h>
17#include <drv_types.h>
navin patidar9c6db652014-08-31 12:14:19 +053018#include <phy.h>
navin patidar6b361e52014-08-31 14:08:27 +053019#include <rf.h>
Larry Finger615a4d12013-08-21 22:33:56 -050020#include <rtl8188e_hal.h>
21
navin patidar20273242014-08-31 14:08:21 +053022void rtl88eu_phy_rf6052_set_bandwidth(struct adapter *adapt,
23 enum ht_channel_width bandwidth)
Larry Finger615a4d12013-08-21 22:33:56 -050024{
navin patidar20273242014-08-31 14:08:21 +053025 struct hal_data_8188e *hal_data = GET_HAL_DATA(adapt);
Larry Finger615a4d12013-08-21 22:33:56 -050026
navin patidar20273242014-08-31 14:08:21 +053027 switch (bandwidth) {
Larry Finger615a4d12013-08-21 22:33:56 -050028 case HT_CHANNEL_WIDTH_20:
navin patidar20273242014-08-31 14:08:21 +053029 hal_data->RfRegChnlVal[0] = ((hal_data->RfRegChnlVal[0] &
30 0xfffff3ff) | BIT(10) | BIT(11));
31 phy_set_rf_reg(adapt, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask,
32 hal_data->RfRegChnlVal[0]);
Larry Finger615a4d12013-08-21 22:33:56 -050033 break;
34 case HT_CHANNEL_WIDTH_40:
navin patidar20273242014-08-31 14:08:21 +053035 hal_data->RfRegChnlVal[0] = ((hal_data->RfRegChnlVal[0] &
36 0xfffff3ff) | BIT(10));
37 phy_set_rf_reg(adapt, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask,
38 hal_data->RfRegChnlVal[0]);
Larry Finger615a4d12013-08-21 22:33:56 -050039 break;
40 default:
41 break;
42 }
43}
44
navin patidarc5db81ac2014-08-31 14:08:22 +053045void rtl88eu_phy_rf6052_set_cck_txpower(struct adapter *adapt, u8 *powerlevel)
Larry Finger615a4d12013-08-21 22:33:56 -050046{
navin patidarc5db81ac2014-08-31 14:08:22 +053047 struct hal_data_8188e *hal_data = GET_HAL_DATA(adapt);
48 struct dm_priv *pdmpriv = &hal_data->dmpriv;
49 struct mlme_ext_priv *pmlmeext = &adapt->mlmeextpriv;
50 u32 tx_agc[2] = {0, 0}, tmpval = 0, pwrtrac_value;
Larry Finger615a4d12013-08-21 22:33:56 -050051 u8 idx1, idx2;
52 u8 *ptr;
53 u8 direction;
Larry Finger615a4d12013-08-21 22:33:56 -050054
55
56 if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
navin patidarc5db81ac2014-08-31 14:08:22 +053057 tx_agc[RF_PATH_A] = 0x3f3f3f3f;
58 tx_agc[RF_PATH_B] = 0x3f3f3f3f;
59 for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
60 tx_agc[idx1] = powerlevel[idx1] |
61 (powerlevel[idx1]<<8) |
62 (powerlevel[idx1]<<16) |
63 (powerlevel[idx1]<<24);
64 if (tx_agc[idx1] > 0x20 && hal_data->ExternalPA)
65 tx_agc[idx1] = 0x20;
Larry Finger615a4d12013-08-21 22:33:56 -050066 }
67 } else {
Larry Finger615a4d12013-08-21 22:33:56 -050068 if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) {
navin patidarc5db81ac2014-08-31 14:08:22 +053069 tx_agc[RF_PATH_A] = 0x10101010;
70 tx_agc[RF_PATH_B] = 0x10101010;
Larry Finger615a4d12013-08-21 22:33:56 -050071 } else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) {
navin patidarc5db81ac2014-08-31 14:08:22 +053072 tx_agc[RF_PATH_A] = 0x00000000;
73 tx_agc[RF_PATH_B] = 0x00000000;
Larry Finger615a4d12013-08-21 22:33:56 -050074 } else {
75 for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
navin patidarc5db81ac2014-08-31 14:08:22 +053076 tx_agc[idx1] = powerlevel[idx1] |
77 (powerlevel[idx1]<<8) |
78 (powerlevel[idx1]<<16) |
79 (powerlevel[idx1]<<24);
Larry Finger615a4d12013-08-21 22:33:56 -050080 }
navin patidarc5db81ac2014-08-31 14:08:22 +053081 if (hal_data->EEPROMRegulatory == 0) {
82 tmpval = hal_data->MCSTxPowerLevelOriginalOffset[0][6] +
83 (hal_data->MCSTxPowerLevelOriginalOffset[0][7]<<8);
84 tx_agc[RF_PATH_A] += tmpval;
Larry Finger615a4d12013-08-21 22:33:56 -050085
navin patidarc5db81ac2014-08-31 14:08:22 +053086 tmpval = hal_data->MCSTxPowerLevelOriginalOffset[0][14] +
87 (hal_data->MCSTxPowerLevelOriginalOffset[0][15]<<24);
88 tx_agc[RF_PATH_B] += tmpval;
Larry Finger615a4d12013-08-21 22:33:56 -050089 }
90 }
91 }
92 for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
navin patidarc5db81ac2014-08-31 14:08:22 +053093 ptr = (u8 *)(&(tx_agc[idx1]));
Larry Finger615a4d12013-08-21 22:33:56 -050094 for (idx2 = 0; idx2 < 4; idx2++) {
95 if (*ptr > RF6052_MAX_TX_PWR)
96 *ptr = RF6052_MAX_TX_PWR;
97 ptr++;
98 }
99 }
navin patidar4de93b12014-09-07 16:37:40 +0530100 rtl88eu_dm_txpower_track_adjust(&hal_data->odmpriv, 1, &direction,
Mayank Barejacfa48d92015-07-28 05:50:12 +0000101 &pwrtrac_value);
Larry Finger615a4d12013-08-21 22:33:56 -0500102
103 if (direction == 1) {
Masanari Iida5e809e52013-09-27 00:11:45 +0900104 /* Increase TX power */
navin patidarc5db81ac2014-08-31 14:08:22 +0530105 tx_agc[0] += pwrtrac_value;
106 tx_agc[1] += pwrtrac_value;
Larry Finger615a4d12013-08-21 22:33:56 -0500107 } else if (direction == 2) {
Masanari Iida5e809e52013-09-27 00:11:45 +0900108 /* Decrease TX power */
navin patidarc5db81ac2014-08-31 14:08:22 +0530109 tx_agc[0] -= pwrtrac_value;
110 tx_agc[1] -= pwrtrac_value;
Larry Finger615a4d12013-08-21 22:33:56 -0500111 }
112
113 /* rf-A cck tx power */
navin patidarc5db81ac2014-08-31 14:08:22 +0530114 tmpval = tx_agc[RF_PATH_A]&0xff;
115 phy_set_bb_reg(adapt, rTxAGC_A_CCK1_Mcs32, bMaskByte1, tmpval);
116 tmpval = tx_agc[RF_PATH_A]>>8;
117 phy_set_bb_reg(adapt, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
Larry Finger615a4d12013-08-21 22:33:56 -0500118
119 /* rf-B cck tx power */
navin patidarc5db81ac2014-08-31 14:08:22 +0530120 tmpval = tx_agc[RF_PATH_B]>>24;
121 phy_set_bb_reg(adapt, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, tmpval);
122 tmpval = tx_agc[RF_PATH_B]&0x00ffffff;
123 phy_set_bb_reg(adapt, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval);
124}
Larry Finger615a4d12013-08-21 22:33:56 -0500125
Larry Finger615a4d12013-08-21 22:33:56 -0500126/* powerbase0 for OFDM rates */
127/* powerbase1 for HT MCS rates */
navin patidarc1adeba2014-08-31 14:08:23 +0530128static void getpowerbase88e(struct adapter *adapt, u8 *pwr_level_ofdm,
129 u8 *pwr_level_bw20, u8 *pwr_level_bw40,
Jia He7be921a22014-11-04 09:39:58 +0800130 u8 channel, u32 *ofdmbase, u32 *mcs_base)
Larry Finger615a4d12013-08-21 22:33:56 -0500131{
navin patidarc1adeba2014-08-31 14:08:23 +0530132 struct hal_data_8188e *hal_data = GET_HAL_DATA(adapt);
133 u32 powerbase0, powerbase1;
Larry Finger615a4d12013-08-21 22:33:56 -0500134 u8 i, powerlevel[2];
135
136 for (i = 0; i < 2; i++) {
navin patidarc1adeba2014-08-31 14:08:23 +0530137 powerbase0 = pwr_level_ofdm[i];
Larry Finger615a4d12013-08-21 22:33:56 -0500138
navin patidarc1adeba2014-08-31 14:08:23 +0530139 powerbase0 = (powerbase0<<24) | (powerbase0<<16) |
140 (powerbase0<<8) | powerbase0;
141 *(ofdmbase+i) = powerbase0;
Larry Finger615a4d12013-08-21 22:33:56 -0500142 }
navin patidarc1adeba2014-08-31 14:08:23 +0530143 for (i = 0; i < hal_data->NumTotalRFPath; i++) {
Larry Finger615a4d12013-08-21 22:33:56 -0500144 /* Check HT20 to HT40 diff */
navin patidarc1adeba2014-08-31 14:08:23 +0530145 if (hal_data->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
146 powerlevel[i] = pwr_level_bw20[i];
Larry Finger615a4d12013-08-21 22:33:56 -0500147 else
navin patidarc1adeba2014-08-31 14:08:23 +0530148 powerlevel[i] = pwr_level_bw40[i];
149 powerbase1 = powerlevel[i];
150 powerbase1 = (powerbase1<<24) | (powerbase1<<16) |
151 (powerbase1<<8) | powerbase1;
152 *(mcs_base+i) = powerbase1;
Larry Finger615a4d12013-08-21 22:33:56 -0500153 }
154}
navin patidard8571352014-08-31 14:08:26 +0530155static void get_rx_power_val_by_reg(struct adapter *adapt, u8 channel,
156 u8 index, u32 *powerbase0, u32 *powerbase1,
157 u32 *out_val)
Larry Finger615a4d12013-08-21 22:33:56 -0500158{
navin patidard8571352014-08-31 14:08:26 +0530159 struct hal_data_8188e *hal_data = GET_HAL_DATA(adapt);
160 struct dm_priv *pdmpriv = &hal_data->dmpriv;
161 u8 i, chnlGroup = 0, pwr_diff_limit[4], customer_pwr_limit;
162 s8 pwr_diff = 0;
163 u32 write_val, customer_limit, rf;
164 u8 regulatory = hal_data->EEPROMRegulatory;
Larry Finger615a4d12013-08-21 22:33:56 -0500165
166 /* Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */
167
168 for (rf = 0; rf < 2; rf++) {
navin patidard8571352014-08-31 14:08:26 +0530169 u8 j = index + (rf ? 8 : 0);
170
171 switch (regulatory) {
172 case 0:
Larry Finger615a4d12013-08-21 22:33:56 -0500173 chnlGroup = 0;
navin patidard8571352014-08-31 14:08:26 +0530174 write_val = hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] +
175 ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
Larry Finger615a4d12013-08-21 22:33:56 -0500176 break;
navin patidard8571352014-08-31 14:08:26 +0530177 case 1: /* Realtek regulatory */
Larry Finger615a4d12013-08-21 22:33:56 -0500178 /* increase power diff defined by Realtek for regulatory */
navin patidard8571352014-08-31 14:08:26 +0530179 if (hal_data->pwrGroupCnt == 1)
Larry Finger615a4d12013-08-21 22:33:56 -0500180 chnlGroup = 0;
navin patidard8571352014-08-31 14:08:26 +0530181 if (hal_data->pwrGroupCnt >= hal_data->PGMaxGroup) {
182 if (channel < 3)
Larry Finger615a4d12013-08-21 22:33:56 -0500183 chnlGroup = 0;
navin patidard8571352014-08-31 14:08:26 +0530184 else if (channel < 6)
Larry Finger615a4d12013-08-21 22:33:56 -0500185 chnlGroup = 1;
navin patidard8571352014-08-31 14:08:26 +0530186 else if (channel < 9)
Larry Finger615a4d12013-08-21 22:33:56 -0500187 chnlGroup = 2;
navin patidard8571352014-08-31 14:08:26 +0530188 else if (channel < 12)
Larry Finger615a4d12013-08-21 22:33:56 -0500189 chnlGroup = 3;
navin patidard8571352014-08-31 14:08:26 +0530190 else if (channel < 14)
Larry Finger615a4d12013-08-21 22:33:56 -0500191 chnlGroup = 4;
navin patidard8571352014-08-31 14:08:26 +0530192 else if (channel == 14)
Larry Finger615a4d12013-08-21 22:33:56 -0500193 chnlGroup = 5;
194 }
navin patidard8571352014-08-31 14:08:26 +0530195 write_val = hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] +
196 ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
Larry Finger615a4d12013-08-21 22:33:56 -0500197 break;
198 case 2: /* Better regulatory */
199 /* don't increase any power diff */
Haneen Mohammedadb3d772015-03-13 19:55:55 +0300200 write_val = (index < 2) ? powerbase0[rf] : powerbase1[rf];
Larry Finger615a4d12013-08-21 22:33:56 -0500201 break;
202 case 3: /* Customer defined power diff. */
203 /* increase power diff defined by customer. */
204 chnlGroup = 0;
205
206 if (index < 2)
navin patidard8571352014-08-31 14:08:26 +0530207 pwr_diff = hal_data->TxPwrLegacyHtDiff[rf][channel-1];
208 else if (hal_data->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
209 pwr_diff = hal_data->TxPwrHt20Diff[rf][channel-1];
Larry Finger615a4d12013-08-21 22:33:56 -0500210
navin patidard8571352014-08-31 14:08:26 +0530211 if (hal_data->CurrentChannelBW == HT_CHANNEL_WIDTH_40)
212 customer_pwr_limit = hal_data->PwrGroupHT40[rf][channel-1];
Larry Finger615a4d12013-08-21 22:33:56 -0500213 else
navin patidard8571352014-08-31 14:08:26 +0530214 customer_pwr_limit = hal_data->PwrGroupHT20[rf][channel-1];
Larry Finger615a4d12013-08-21 22:33:56 -0500215
216 if (pwr_diff >= customer_pwr_limit)
217 pwr_diff = 0;
218 else
219 pwr_diff = customer_pwr_limit - pwr_diff;
220
221 for (i = 0; i < 4; i++) {
navin patidard8571352014-08-31 14:08:26 +0530222 pwr_diff_limit[i] = (u8)((hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][j] &
223 (0x7f << (i * 8))) >> (i * 8));
Larry Finger615a4d12013-08-21 22:33:56 -0500224
225 if (pwr_diff_limit[i] > pwr_diff)
226 pwr_diff_limit[i] = pwr_diff;
227 }
navin patidard8571352014-08-31 14:08:26 +0530228 customer_limit = (pwr_diff_limit[3]<<24) |
229 (pwr_diff_limit[2]<<16) |
230 (pwr_diff_limit[1]<<8) |
231 (pwr_diff_limit[0]);
232 write_val = customer_limit + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
Larry Finger615a4d12013-08-21 22:33:56 -0500233 break;
234 default:
235 chnlGroup = 0;
navin patidard8571352014-08-31 14:08:26 +0530236 write_val = hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][j] +
237 ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
Larry Finger615a4d12013-08-21 22:33:56 -0500238 break;
239 }
240/* 20100427 Joseph: Driver dynamic Tx power shall not affect Tx power. It shall be determined by power training mechanism. */
241/* Currently, we cannot fully disable driver dynamic tx power mechanism because it is referenced by BT coexist mechanism. */
Masanari Iida5e809e52013-09-27 00:11:45 +0900242/* In the future, two mechanism shall be separated from each other and maintained independently. Thanks for Lanhsin's reminder. */
Larry Finger615a4d12013-08-21 22:33:56 -0500243 /* 92d do not need this */
244 if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1)
navin patidard8571352014-08-31 14:08:26 +0530245 write_val = 0x14141414;
Larry Finger615a4d12013-08-21 22:33:56 -0500246 else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2)
navin patidard8571352014-08-31 14:08:26 +0530247 write_val = 0x00000000;
Larry Finger615a4d12013-08-21 22:33:56 -0500248
navin patidard8571352014-08-31 14:08:26 +0530249 *(out_val+rf) = write_val;
Larry Finger615a4d12013-08-21 22:33:56 -0500250 }
251}
navin patidar1faec152014-08-31 14:08:25 +0530252
253static void write_ofdm_pwr_reg(struct adapter *adapt, u8 index, u32 *pvalue)
Larry Finger615a4d12013-08-21 22:33:56 -0500254{
navin patidar1faec152014-08-31 14:08:25 +0530255 u16 regoffset_a[6] = { rTxAGC_A_Rate18_06, rTxAGC_A_Rate54_24,
256 rTxAGC_A_Mcs03_Mcs00, rTxAGC_A_Mcs07_Mcs04,
257 rTxAGC_A_Mcs11_Mcs08, rTxAGC_A_Mcs15_Mcs12 };
258 u16 regoffset_b[6] = { rTxAGC_B_Rate18_06, rTxAGC_B_Rate54_24,
259 rTxAGC_B_Mcs03_Mcs00, rTxAGC_B_Mcs07_Mcs04,
260 rTxAGC_B_Mcs11_Mcs08, rTxAGC_B_Mcs15_Mcs12 };
Larry Finger615a4d12013-08-21 22:33:56 -0500261 u8 i, rf, pwr_val[4];
navin patidar1faec152014-08-31 14:08:25 +0530262 u32 write_val;
Larry Finger615a4d12013-08-21 22:33:56 -0500263 u16 regoffset;
264
265 for (rf = 0; rf < 2; rf++) {
navin patidar1faec152014-08-31 14:08:25 +0530266 write_val = pvalue[rf];
Larry Finger615a4d12013-08-21 22:33:56 -0500267 for (i = 0; i < 4; i++) {
navin patidar1faec152014-08-31 14:08:25 +0530268 pwr_val[i] = (u8)((write_val & (0x7f<<(i*8)))>>(i*8));
Larry Finger615a4d12013-08-21 22:33:56 -0500269 if (pwr_val[i] > RF6052_MAX_TX_PWR)
270 pwr_val[i] = RF6052_MAX_TX_PWR;
271 }
navin patidar1faec152014-08-31 14:08:25 +0530272 write_val = (pwr_val[3]<<24) | (pwr_val[2]<<16) |
273 (pwr_val[1]<<8) | pwr_val[0];
Larry Finger615a4d12013-08-21 22:33:56 -0500274
275 if (rf == 0)
276 regoffset = regoffset_a[index];
277 else
278 regoffset = regoffset_b[index];
279
navin patidar1faec152014-08-31 14:08:25 +0530280 phy_set_bb_reg(adapt, regoffset, bMaskDWord, write_val);
Larry Finger615a4d12013-08-21 22:33:56 -0500281 }
282}
283
navin patidarfb393d22014-08-31 14:08:24 +0530284void rtl88eu_phy_rf6052_set_ofdm_txpower(struct adapter *adapt,
285 u8 *pwr_level_ofdm,
286 u8 *pwr_level_bw20,
287 u8 *pwr_level_bw40, u8 channel)
Larry Finger615a4d12013-08-21 22:33:56 -0500288{
navin patidarfb393d22014-08-31 14:08:24 +0530289 struct hal_data_8188e *hal_data = GET_HAL_DATA(adapt);
290 u32 write_val[2], powerbase0[2], powerbase1[2], pwrtrac_value;
Larry Finger615a4d12013-08-21 22:33:56 -0500291 u8 direction;
292 u8 index = 0;
293
navin patidarfb393d22014-08-31 14:08:24 +0530294 getpowerbase88e(adapt, pwr_level_ofdm, pwr_level_bw20, pwr_level_bw40,
295 channel, &powerbase0[0], &powerbase1[0]);
Larry Finger615a4d12013-08-21 22:33:56 -0500296
navin patidar4de93b12014-09-07 16:37:40 +0530297 rtl88eu_dm_txpower_track_adjust(&hal_data->odmpriv, 0, &direction,
298 &pwrtrac_value);
Larry Finger615a4d12013-08-21 22:33:56 -0500299
300 for (index = 0; index < 6; index++) {
navin patidarfb393d22014-08-31 14:08:24 +0530301 get_rx_power_val_by_reg(adapt, channel, index,
302 &powerbase0[0], &powerbase1[0],
303 &write_val[0]);
Larry Finger615a4d12013-08-21 22:33:56 -0500304
305 if (direction == 1) {
navin patidarfb393d22014-08-31 14:08:24 +0530306 write_val[0] += pwrtrac_value;
307 write_val[1] += pwrtrac_value;
Larry Finger615a4d12013-08-21 22:33:56 -0500308 } else if (direction == 2) {
navin patidarfb393d22014-08-31 14:08:24 +0530309 write_val[0] -= pwrtrac_value;
310 write_val[1] -= pwrtrac_value;
Larry Finger615a4d12013-08-21 22:33:56 -0500311 }
navin patidar1faec152014-08-31 14:08:25 +0530312 write_ofdm_pwr_reg(adapt, index, &write_val[0]);
Larry Finger615a4d12013-08-21 22:33:56 -0500313 }
314}