• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /******************************************************************************
3  *
4  * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
5  *
6  ******************************************************************************/
7 
8 #include <osdep_service.h>
9 #include <drv_types.h>
10 #include <phy.h>
11 #include <rf.h>
12 #include <rtl8188e_hal.h>
13 
rtl88eu_phy_rf6052_set_bandwidth(struct adapter * adapt,enum ht_channel_width bandwidth)14 void rtl88eu_phy_rf6052_set_bandwidth(struct adapter *adapt,
15 				      enum ht_channel_width bandwidth)
16 {
17 	struct hal_data_8188e *hal_data = adapt->HalData;
18 
19 	switch (bandwidth) {
20 	case HT_CHANNEL_WIDTH_20:
21 		hal_data->RfRegChnlVal[0] = ((hal_data->RfRegChnlVal[0] &
22 					      0xfffff3ff) | BIT(10) | BIT(11));
23 		phy_set_rf_reg(adapt, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask,
24 			       hal_data->RfRegChnlVal[0]);
25 		break;
26 	case HT_CHANNEL_WIDTH_40:
27 		hal_data->RfRegChnlVal[0] = ((hal_data->RfRegChnlVal[0] &
28 					      0xfffff3ff) | BIT(10));
29 		phy_set_rf_reg(adapt, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask,
30 			       hal_data->RfRegChnlVal[0]);
31 		break;
32 	default:
33 		break;
34 	}
35 }
36 
rtl88eu_phy_rf6052_set_cck_txpower(struct adapter * adapt,u8 * powerlevel)37 void rtl88eu_phy_rf6052_set_cck_txpower(struct adapter *adapt, u8 *powerlevel)
38 {
39 	struct hal_data_8188e *hal_data = adapt->HalData;
40 	struct dm_priv *pdmpriv = &hal_data->dmpriv;
41 	struct mlme_ext_priv *pmlmeext = &adapt->mlmeextpriv;
42 	u32 tx_agc[2] = {0, 0}, tmpval = 0, pwrtrac_value;
43 	u8 idx1, idx2;
44 	u8 *ptr;
45 	u8 direction;
46 
47 	if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
48 		tx_agc[RF_PATH_A] = 0x3f3f3f3f;
49 		tx_agc[RF_PATH_B] = 0x3f3f3f3f;
50 		for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
51 			tx_agc[idx1] = powerlevel[idx1] |
52 				      (powerlevel[idx1]<<8) |
53 				      (powerlevel[idx1]<<16) |
54 				      (powerlevel[idx1]<<24);
55 		}
56 	} else {
57 		if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) {
58 			tx_agc[RF_PATH_A] = 0x10101010;
59 			tx_agc[RF_PATH_B] = 0x10101010;
60 		} else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) {
61 			tx_agc[RF_PATH_A] = 0x00000000;
62 			tx_agc[RF_PATH_B] = 0x00000000;
63 		} else {
64 			for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
65 				tx_agc[idx1] = powerlevel[idx1] |
66 					       (powerlevel[idx1]<<8) |
67 					       (powerlevel[idx1]<<16) |
68 					       (powerlevel[idx1]<<24);
69 			}
70 			if (hal_data->EEPROMRegulatory == 0) {
71 				tmpval = hal_data->MCSTxPowerLevelOriginalOffset[0][6] +
72 					 (hal_data->MCSTxPowerLevelOriginalOffset[0][7]<<8);
73 				tx_agc[RF_PATH_A] += tmpval;
74 
75 				tmpval = hal_data->MCSTxPowerLevelOriginalOffset[0][14] +
76 					 (hal_data->MCSTxPowerLevelOriginalOffset[0][15]<<24);
77 				tx_agc[RF_PATH_B] += tmpval;
78 			}
79 		}
80 	}
81 	for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
82 		ptr = (u8 *)(&(tx_agc[idx1]));
83 		for (idx2 = 0; idx2 < 4; idx2++) {
84 			if (*ptr > RF6052_MAX_TX_PWR)
85 				*ptr = RF6052_MAX_TX_PWR;
86 			ptr++;
87 		}
88 	}
89 	rtl88eu_dm_txpower_track_adjust(&hal_data->odmpriv, 1, &direction,
90 					&pwrtrac_value);
91 
92 	if (direction == 1) {
93 		/*  Increase TX power */
94 		tx_agc[0] += pwrtrac_value;
95 		tx_agc[1] += pwrtrac_value;
96 	} else if (direction == 2) {
97 		/*  Decrease TX power */
98 		tx_agc[0] -=  pwrtrac_value;
99 		tx_agc[1] -=  pwrtrac_value;
100 	}
101 
102 	/*  rf-A cck tx power */
103 	tmpval = tx_agc[RF_PATH_A]&0xff;
104 	phy_set_bb_reg(adapt, rTxAGC_A_CCK1_Mcs32, bMaskByte1, tmpval);
105 	tmpval = tx_agc[RF_PATH_A]>>8;
106 	phy_set_bb_reg(adapt, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
107 
108 	/*  rf-B cck tx power */
109 	tmpval = tx_agc[RF_PATH_B]>>24;
110 	phy_set_bb_reg(adapt, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, tmpval);
111 	tmpval = tx_agc[RF_PATH_B]&0x00ffffff;
112 	phy_set_bb_reg(adapt, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval);
113 }
114 
115 /*  powerbase0 for OFDM rates */
116 /*  powerbase1 for HT MCS rates */
getpowerbase88e(struct adapter * adapt,u8 * pwr_level_ofdm,u8 * pwr_level_bw20,u8 * pwr_level_bw40,u8 channel,u32 * ofdmbase,u32 * mcs_base)117 static void getpowerbase88e(struct adapter *adapt, u8 *pwr_level_ofdm,
118 			    u8 *pwr_level_bw20, u8 *pwr_level_bw40,
119 			    u8 channel, u32 *ofdmbase, u32 *mcs_base)
120 {
121 	u32 powerbase0, powerbase1;
122 	u8 i, powerlevel[2];
123 
124 	for (i = 0; i < 2; i++) {
125 		powerbase0 = pwr_level_ofdm[i];
126 
127 		powerbase0 = (powerbase0<<24) | (powerbase0<<16) |
128 			     (powerbase0<<8) | powerbase0;
129 		*(ofdmbase+i) = powerbase0;
130 	}
131 	/* Check HT20 to HT40 diff */
132 	if (adapt->HalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
133 		powerlevel[0] = pwr_level_bw20[0];
134 	else
135 		powerlevel[0] = pwr_level_bw40[0];
136 	powerbase1 = powerlevel[0];
137 	powerbase1 = (powerbase1<<24) | (powerbase1<<16) |
138 		     (powerbase1<<8) | powerbase1;
139 	*mcs_base = powerbase1;
140 }
get_rx_power_val_by_reg(struct adapter * adapt,u8 channel,u8 index,u32 * powerbase0,u32 * powerbase1,u32 * out_val)141 static void get_rx_power_val_by_reg(struct adapter *adapt, u8 channel,
142 				    u8 index, u32 *powerbase0, u32 *powerbase1,
143 				    u32 *out_val)
144 {
145 	struct hal_data_8188e *hal_data = adapt->HalData;
146 	struct dm_priv	*pdmpriv = &hal_data->dmpriv;
147 	u8 i, chnlGroup = 0, pwr_diff_limit[4], customer_pwr_limit;
148 	s8 pwr_diff = 0;
149 	u32 write_val, customer_limit, rf;
150 	u8 regulatory = hal_data->EEPROMRegulatory;
151 
152 	/*  Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */
153 
154 	for (rf = 0; rf < 2; rf++) {
155 		u8 j = index + (rf ? 8 : 0);
156 
157 		switch (regulatory) {
158 		case 0:
159 			chnlGroup = 0;
160 			write_val = hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] +
161 				((index < 2) ? powerbase0[rf] : powerbase1[rf]);
162 			break;
163 		case 1: /*  Realtek regulatory */
164 			/*  increase power diff defined by Realtek for regulatory */
165 			if (hal_data->pwrGroupCnt == 1)
166 				chnlGroup = 0;
167 			if (hal_data->pwrGroupCnt >= hal_data->PGMaxGroup)
168 				Hal_GetChnlGroup88E(channel, &chnlGroup);
169 
170 			write_val = hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] +
171 					((index < 2) ? powerbase0[rf] : powerbase1[rf]);
172 			break;
173 		case 2:	/*  Better regulatory */
174 				/*  don't increase any power diff */
175 			write_val = (index < 2) ? powerbase0[rf] : powerbase1[rf];
176 			break;
177 		case 3:	/*  Customer defined power diff. */
178 				/*  increase power diff defined by customer. */
179 			chnlGroup = 0;
180 
181 			if (index < 2)
182 				pwr_diff = hal_data->TxPwrLegacyHtDiff[rf][channel-1];
183 			else if (hal_data->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
184 				pwr_diff = hal_data->TxPwrHt20Diff[rf][channel-1];
185 
186 			if (hal_data->CurrentChannelBW == HT_CHANNEL_WIDTH_40)
187 				customer_pwr_limit = hal_data->PwrGroupHT40[rf][channel-1];
188 			else
189 				customer_pwr_limit = hal_data->PwrGroupHT20[rf][channel-1];
190 
191 			if (pwr_diff >= customer_pwr_limit)
192 				pwr_diff = 0;
193 			else
194 				pwr_diff = customer_pwr_limit - pwr_diff;
195 
196 			for (i = 0; i < 4; i++) {
197 				pwr_diff_limit[i] = (u8)((hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][j] &
198 							 (0x7f << (i * 8))) >> (i * 8));
199 
200 				if (pwr_diff_limit[i] > pwr_diff)
201 					pwr_diff_limit[i] = pwr_diff;
202 			}
203 			customer_limit = (pwr_diff_limit[3]<<24) |
204 					 (pwr_diff_limit[2]<<16) |
205 					 (pwr_diff_limit[1]<<8) |
206 					 (pwr_diff_limit[0]);
207 			write_val = customer_limit + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
208 			break;
209 		default:
210 			chnlGroup = 0;
211 			write_val = hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][j] +
212 					((index < 2) ? powerbase0[rf] : powerbase1[rf]);
213 			break;
214 		}
215 /*  20100427 Joseph: Driver dynamic Tx power shall not affect Tx power. It shall be determined by power training mechanism. */
216 /*  Currently, we cannot fully disable driver dynamic tx power mechanism because it is referenced by BT coexist mechanism. */
217 /*  In the future, two mechanism shall be separated from each other and maintained independently. Thanks for Lanhsin's reminder. */
218 		/* 92d do not need this */
219 		if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1)
220 			write_val = 0x14141414;
221 		else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2)
222 			write_val = 0x00000000;
223 
224 		*(out_val+rf) = write_val;
225 	}
226 }
227 
write_ofdm_pwr_reg(struct adapter * adapt,u8 index,u32 * pvalue)228 static void write_ofdm_pwr_reg(struct adapter *adapt, u8 index, u32 *pvalue)
229 {
230 	u16 regoffset_a[6] = { rTxAGC_A_Rate18_06, rTxAGC_A_Rate54_24,
231 			       rTxAGC_A_Mcs03_Mcs00, rTxAGC_A_Mcs07_Mcs04,
232 			       rTxAGC_A_Mcs11_Mcs08, rTxAGC_A_Mcs15_Mcs12 };
233 	u16 regoffset_b[6] = { rTxAGC_B_Rate18_06, rTxAGC_B_Rate54_24,
234 			       rTxAGC_B_Mcs03_Mcs00, rTxAGC_B_Mcs07_Mcs04,
235 			       rTxAGC_B_Mcs11_Mcs08, rTxAGC_B_Mcs15_Mcs12 };
236 	u8 i, rf, pwr_val[4];
237 	u32 write_val;
238 	u16 regoffset;
239 
240 	for (rf = 0; rf < 2; rf++) {
241 		write_val = pvalue[rf];
242 		for (i = 0; i < 4; i++) {
243 			pwr_val[i] = (u8)((write_val & (0x7f<<(i*8)))>>(i*8));
244 			if (pwr_val[i]  > RF6052_MAX_TX_PWR)
245 				pwr_val[i]  = RF6052_MAX_TX_PWR;
246 		}
247 		write_val = (pwr_val[3]<<24) | (pwr_val[2]<<16) |
248 			    (pwr_val[1]<<8) | pwr_val[0];
249 
250 		if (rf == 0)
251 			regoffset = regoffset_a[index];
252 		else
253 			regoffset = regoffset_b[index];
254 
255 		phy_set_bb_reg(adapt, regoffset, bMaskDWord, write_val);
256 	}
257 }
258 
rtl88eu_phy_rf6052_set_ofdm_txpower(struct adapter * adapt,u8 * pwr_level_ofdm,u8 * pwr_level_bw20,u8 * pwr_level_bw40,u8 channel)259 void rtl88eu_phy_rf6052_set_ofdm_txpower(struct adapter *adapt,
260 					 u8 *pwr_level_ofdm,
261 					 u8 *pwr_level_bw20,
262 					 u8 *pwr_level_bw40, u8 channel)
263 {
264 	u32 write_val[2], powerbase0[2], powerbase1[2], pwrtrac_value;
265 	u8 direction;
266 	u8 index = 0;
267 
268 	getpowerbase88e(adapt, pwr_level_ofdm, pwr_level_bw20, pwr_level_bw40,
269 			channel, &powerbase0[0], &powerbase1[0]);
270 
271 	rtl88eu_dm_txpower_track_adjust(&adapt->HalData->odmpriv, 0,
272 					&direction, &pwrtrac_value);
273 
274 	for (index = 0; index < 6; index++) {
275 		get_rx_power_val_by_reg(adapt, channel, index,
276 					&powerbase0[0], &powerbase1[0],
277 					&write_val[0]);
278 
279 		if (direction == 1) {
280 			write_val[0] += pwrtrac_value;
281 			write_val[1] += pwrtrac_value;
282 		} else if (direction == 2) {
283 			write_val[0] -= pwrtrac_value;
284 			write_val[1] -= pwrtrac_value;
285 		}
286 		write_ofdm_pwr_reg(adapt, index, &write_val[0]);
287 	}
288 }
289