1 /******************************************************************************
2  *
3  * Copyright(c) 2009-2012  Realtek Corporation.
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  *
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
17  *
18  * The full GNU General Public License is included in this distribution in the
19  * file called LICENSE.
20  *
21  * Contact Information:
22  * wlanfae <wlanfae@realtek.com>
23  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
24  * Hsinchu 300, Taiwan.
25  *
26  * Larry Finger <Larry.Finger@lwfinger.net>
27  *
28  *****************************************************************************/
29 
30 #include "../wifi.h"
31 #include "../base.h"
32 #include "../core.h"
33 #include "reg.h"
34 #include "def.h"
35 #include "phy.h"
36 #include "dm.h"
37 #include "fw.h"
38 
39 static const u32 edca_setting_dl[PEER_MAX] = {
40 	0xa44f,		/* 0 UNKNOWN */
41 	0x5ea44f,	/* 1 REALTEK_90 */
42 	0x5ea44f,	/* 2 REALTEK_92SE */
43 	0xa630,		/* 3 BROAD	*/
44 	0xa44f,		/* 4 RAL */
45 	0xa630,		/* 5 ATH */
46 	0xa630,		/* 6 CISCO */
47 	0xa42b,		/* 7 MARV */
48 };
49 
50 static const u32 edca_setting_dl_gmode[PEER_MAX] = {
51 	0x4322,		/* 0 UNKNOWN */
52 	0xa44f,		/* 1 REALTEK_90 */
53 	0x5ea44f,	/* 2 REALTEK_92SE */
54 	0xa42b,		/* 3 BROAD */
55 	0x5e4322,	/* 4 RAL */
56 	0x4322,		/* 5 ATH */
57 	0xa430,		/* 6 CISCO */
58 	0x5ea44f,	/* 7 MARV */
59 };
60 
61 static const u32 edca_setting_ul[PEER_MAX] = {
62 	0x5e4322,	/* 0 UNKNOWN */
63 	0xa44f,		/* 1 REALTEK_90 */
64 	0x5ea44f,	/* 2 REALTEK_92SE */
65 	0x5ea322,	/* 3 BROAD */
66 	0x5ea422,	/* 4 RAL */
67 	0x5ea322,	/* 5 ATH */
68 	0x3ea44f,	/* 6 CISCO */
69 	0x5ea44f,	/* 7 MARV */
70 };
71 
72 static void _rtl92s_dm_check_edca_turbo(struct ieee80211_hw *hw)
73 {
74 	struct rtl_priv *rtlpriv = rtl_priv(hw);
75 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
76 
77 	static u64 last_txok_cnt;
78 	static u64 last_rxok_cnt;
79 	u64 cur_txok_cnt = 0;
80 	u64 cur_rxok_cnt = 0;
81 
82 	u32 edca_be_ul = edca_setting_ul[mac->vendor];
83 	u32 edca_be_dl = edca_setting_dl[mac->vendor];
84 	u32 edca_gmode = edca_setting_dl_gmode[mac->vendor];
85 
86 	if (mac->link_state != MAC80211_LINKED) {
87 		rtlpriv->dm.current_turbo_edca = false;
88 		goto dm_checkedcaturbo_exit;
89 	}
90 
91 	if ((!rtlpriv->dm.is_any_nonbepkts) &&
92 	    (!rtlpriv->dm.disable_framebursting)) {
93 		cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt;
94 		cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt;
95 
96 		if (rtlpriv->phy.rf_type == RF_1T2R) {
97 			if (cur_txok_cnt > 4 * cur_rxok_cnt) {
98 				/* Uplink TP is present. */
99 				if (rtlpriv->dm.is_cur_rdlstate ||
100 					!rtlpriv->dm.current_turbo_edca) {
101 					rtl_write_dword(rtlpriv, EDCAPARA_BE,
102 							edca_be_ul);
103 					rtlpriv->dm.is_cur_rdlstate = false;
104 				}
105 			} else {/* Balance TP is present. */
106 				if (!rtlpriv->dm.is_cur_rdlstate ||
107 					!rtlpriv->dm.current_turbo_edca) {
108 					if (mac->mode == WIRELESS_MODE_G ||
109 					    mac->mode == WIRELESS_MODE_B)
110 						rtl_write_dword(rtlpriv,
111 								EDCAPARA_BE,
112 								edca_gmode);
113 					else
114 						rtl_write_dword(rtlpriv,
115 								EDCAPARA_BE,
116 								edca_be_dl);
117 					rtlpriv->dm.is_cur_rdlstate = true;
118 				}
119 			}
120 			rtlpriv->dm.current_turbo_edca = true;
121 		} else {
122 			if (cur_rxok_cnt > 4 * cur_txok_cnt) {
123 				if (!rtlpriv->dm.is_cur_rdlstate ||
124 					!rtlpriv->dm.current_turbo_edca) {
125 					if (mac->mode == WIRELESS_MODE_G ||
126 					    mac->mode == WIRELESS_MODE_B)
127 						rtl_write_dword(rtlpriv,
128 								EDCAPARA_BE,
129 								edca_gmode);
130 					else
131 						rtl_write_dword(rtlpriv,
132 								EDCAPARA_BE,
133 								edca_be_dl);
134 					rtlpriv->dm.is_cur_rdlstate = true;
135 				}
136 			} else {
137 				if (rtlpriv->dm.is_cur_rdlstate ||
138 					!rtlpriv->dm.current_turbo_edca) {
139 					rtl_write_dword(rtlpriv, EDCAPARA_BE,
140 							edca_be_ul);
141 					rtlpriv->dm.is_cur_rdlstate = false;
142 				}
143 			}
144 			rtlpriv->dm.current_turbo_edca = true;
145 		}
146 	} else {
147 		if (rtlpriv->dm.current_turbo_edca) {
148 			u8 tmp = AC0_BE;
149 			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
150 						      &tmp);
151 			rtlpriv->dm.current_turbo_edca = false;
152 		}
153 	}
154 
155 dm_checkedcaturbo_exit:
156 	rtlpriv->dm.is_any_nonbepkts = false;
157 	last_txok_cnt = rtlpriv->stats.txbytesunicast;
158 	last_rxok_cnt = rtlpriv->stats.rxbytesunicast;
159 }
160 
161 static void _rtl92s_dm_txpowertracking_callback_thermalmeter(
162 					struct ieee80211_hw *hw)
163 {
164 	struct rtl_priv *rtlpriv = rtl_priv(hw);
165 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
166 	u8 thermalvalue = 0;
167 	u32 fw_cmd = 0;
168 
169 	rtlpriv->dm.txpower_trackinginit = true;
170 
171 	thermalvalue = (u8)rtl_get_rfreg(hw, RF90_PATH_A, RF_T_METER, 0x1f);
172 
173 	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
174 		 "Readback Thermal Meter = 0x%x pre thermal meter 0x%x eeprom_thermal meter 0x%x\n",
175 		 thermalvalue,
176 		 rtlpriv->dm.thermalvalue, rtlefuse->eeprom_thermalmeter);
177 
178 	if (thermalvalue) {
179 		rtlpriv->dm.thermalvalue = thermalvalue;
180 		if (hal_get_firmwareversion(rtlpriv) >= 0x35) {
181 			rtl92s_phy_set_fw_cmd(hw, FW_CMD_TXPWR_TRACK_THERMAL);
182 		} else {
183 			fw_cmd = (FW_TXPWR_TRACK_THERMAL |
184 				 (rtlpriv->efuse.thermalmeter[0] << 8) |
185 				 (thermalvalue << 16));
186 
187 			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
188 				 "Write to FW Thermal Val = 0x%x\n", fw_cmd);
189 
190 			rtl_write_dword(rtlpriv, WFM5, fw_cmd);
191 			rtl92s_phy_chk_fwcmd_iodone(hw);
192 		}
193 	}
194 
195 	rtlpriv->dm.txpowercount = 0;
196 }
197 
198 static void _rtl92s_dm_check_txpowertracking_thermalmeter(
199 					struct ieee80211_hw *hw)
200 {
201 	struct rtl_priv *rtlpriv = rtl_priv(hw);
202 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
203 	u8 tx_power_checkcnt = 5;
204 
205 	/* 2T2R TP issue */
206 	if (rtlphy->rf_type == RF_2T2R)
207 		return;
208 
209 	if (!rtlpriv->dm.txpower_tracking)
210 		return;
211 
212 	if (rtlpriv->dm.txpowercount <= tx_power_checkcnt) {
213 		rtlpriv->dm.txpowercount++;
214 		return;
215 	}
216 
217 	if (!rtlpriv->dm.tm_trigger) {
218 		rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER,
219 			      RFREG_OFFSET_MASK, 0x60);
220 		rtlpriv->dm.tm_trigger = 1;
221 	} else {
222 		_rtl92s_dm_txpowertracking_callback_thermalmeter(hw);
223 		rtlpriv->dm.tm_trigger = 0;
224 	}
225 }
226 
227 static void _rtl92s_dm_refresh_rateadaptive_mask(struct ieee80211_hw *hw)
228 {
229 	struct rtl_priv *rtlpriv = rtl_priv(hw);
230 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
231 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
232 	struct rate_adaptive *ra = &(rtlpriv->ra);
233 	struct ieee80211_sta *sta = NULL;
234 	u32 low_rssi_thresh = 0;
235 	u32 middle_rssi_thresh = 0;
236 	u32 high_rssi_thresh = 0;
237 
238 	if (is_hal_stop(rtlhal))
239 		return;
240 
241 	if (!rtlpriv->dm.useramask)
242 		return;
243 
244 	if (hal_get_firmwareversion(rtlpriv) >= 61 &&
245 	    !rtlpriv->dm.inform_fw_driverctrldm) {
246 		rtl92s_phy_set_fw_cmd(hw, FW_CMD_CTRL_DM_BY_DRIVER);
247 		rtlpriv->dm.inform_fw_driverctrldm = true;
248 	}
249 
250 	if ((mac->link_state == MAC80211_LINKED) &&
251 	    (mac->opmode == NL80211_IFTYPE_STATION)) {
252 		switch (ra->pre_ratr_state) {
253 		case DM_RATR_STA_HIGH:
254 			high_rssi_thresh = 40;
255 			middle_rssi_thresh = 30;
256 			low_rssi_thresh = 20;
257 			break;
258 		case DM_RATR_STA_MIDDLE:
259 			high_rssi_thresh = 44;
260 			middle_rssi_thresh = 30;
261 			low_rssi_thresh = 20;
262 			break;
263 		case DM_RATR_STA_LOW:
264 			high_rssi_thresh = 44;
265 			middle_rssi_thresh = 34;
266 			low_rssi_thresh = 20;
267 			break;
268 		case DM_RATR_STA_ULTRALOW:
269 			high_rssi_thresh = 44;
270 			middle_rssi_thresh = 34;
271 			low_rssi_thresh = 24;
272 			break;
273 		default:
274 			high_rssi_thresh = 44;
275 			middle_rssi_thresh = 34;
276 			low_rssi_thresh = 24;
277 			break;
278 		}
279 
280 		if (rtlpriv->dm.undec_sm_pwdb > (long)high_rssi_thresh) {
281 			ra->ratr_state = DM_RATR_STA_HIGH;
282 		} else if (rtlpriv->dm.undec_sm_pwdb >
283 			   (long)middle_rssi_thresh) {
284 			ra->ratr_state = DM_RATR_STA_LOW;
285 		} else if (rtlpriv->dm.undec_sm_pwdb >
286 			   (long)low_rssi_thresh) {
287 			ra->ratr_state = DM_RATR_STA_LOW;
288 		} else {
289 			ra->ratr_state = DM_RATR_STA_ULTRALOW;
290 		}
291 
292 		if (ra->pre_ratr_state != ra->ratr_state) {
293 			RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
294 				 "RSSI = %ld RSSI_LEVEL = %d PreState = %d, CurState = %d\n",
295 				 rtlpriv->dm.undec_sm_pwdb, ra->ratr_state,
296 				 ra->pre_ratr_state, ra->ratr_state);
297 
298 			rcu_read_lock();
299 			sta = rtl_find_sta(hw, mac->bssid);
300 			if (sta)
301 				rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
302 							   ra->ratr_state);
303 			rcu_read_unlock();
304 
305 			ra->pre_ratr_state = ra->ratr_state;
306 		}
307 	}
308 }
309 
310 static void _rtl92s_dm_switch_baseband_mrc(struct ieee80211_hw *hw)
311 {
312 	struct rtl_priv *rtlpriv = rtl_priv(hw);
313 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
314 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
315 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
316 	bool current_mrc;
317 	bool enable_mrc = true;
318 	long tmpentry_maxpwdb = 0;
319 	u8 rssi_a = 0;
320 	u8 rssi_b = 0;
321 
322 	if (is_hal_stop(rtlhal))
323 		return;
324 
325 	if ((rtlphy->rf_type == RF_1T1R) || (rtlphy->rf_type == RF_2T2R))
326 		return;
327 
328 	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_MRC, (u8 *)(&current_mrc));
329 
330 	if (mac->link_state >= MAC80211_LINKED) {
331 		if (rtlpriv->dm.undec_sm_pwdb > tmpentry_maxpwdb) {
332 			rssi_a = rtlpriv->stats.rx_rssi_percentage[RF90_PATH_A];
333 			rssi_b = rtlpriv->stats.rx_rssi_percentage[RF90_PATH_B];
334 		}
335 	}
336 
337 	/* MRC settings would NOT affect TP on Wireless B mode. */
338 	if (mac->mode != WIRELESS_MODE_B) {
339 		if ((rssi_a == 0) && (rssi_b == 0)) {
340 			enable_mrc = true;
341 		} else if (rssi_b > 30) {
342 			/* Turn on B-Path */
343 			enable_mrc = true;
344 		} else if (rssi_b < 5) {
345 			/* Turn off B-path  */
346 			enable_mrc = false;
347 		/* Take care of RSSI differentiation. */
348 		} else if (rssi_a > 15 && (rssi_a >= rssi_b)) {
349 			if ((rssi_a - rssi_b) > 15)
350 				/* Turn off B-path  */
351 				enable_mrc = false;
352 			else if ((rssi_a - rssi_b) < 10)
353 				/* Turn on B-Path */
354 				enable_mrc = true;
355 			else
356 				enable_mrc = current_mrc;
357 		} else {
358 			/* Turn on B-Path */
359 			enable_mrc = true;
360 		}
361 	}
362 
363 	/* Update MRC settings if needed. */
364 	if (enable_mrc != current_mrc)
365 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_MRC,
366 					      (u8 *)&enable_mrc);
367 
368 }
369 
370 void rtl92s_dm_init_edca_turbo(struct ieee80211_hw *hw)
371 {
372 	struct rtl_priv *rtlpriv = rtl_priv(hw);
373 
374 	rtlpriv->dm.current_turbo_edca = false;
375 	rtlpriv->dm.is_any_nonbepkts = false;
376 	rtlpriv->dm.is_cur_rdlstate = false;
377 }
378 
379 static void _rtl92s_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw)
380 {
381 	struct rtl_priv *rtlpriv = rtl_priv(hw);
382 	struct rate_adaptive *ra = &(rtlpriv->ra);
383 
384 	ra->ratr_state = DM_RATR_STA_MAX;
385 	ra->pre_ratr_state = DM_RATR_STA_MAX;
386 
387 	if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER &&
388 	    hal_get_firmwareversion(rtlpriv) >= 60)
389 		rtlpriv->dm.useramask = true;
390 	else
391 		rtlpriv->dm.useramask = false;
392 
393 	rtlpriv->dm.useramask = false;
394 	rtlpriv->dm.inform_fw_driverctrldm = false;
395 }
396 
397 static void _rtl92s_dm_init_txpowertracking_thermalmeter(
398 				struct ieee80211_hw *hw)
399 {
400 	struct rtl_priv *rtlpriv = rtl_priv(hw);
401 
402 	rtlpriv->dm.txpower_tracking = true;
403 	rtlpriv->dm.txpowercount = 0;
404 	rtlpriv->dm.txpower_trackinginit = false;
405 }
406 
407 static void _rtl92s_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
408 {
409 	struct rtl_priv *rtlpriv = rtl_priv(hw);
410 	struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt);
411 	u32 ret_value;
412 
413 	ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER1, MASKDWORD);
414 	falsealm_cnt->cnt_parity_fail = ((ret_value & 0xffff0000) >> 16);
415 
416 	ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, MASKDWORD);
417 	falsealm_cnt->cnt_rate_illegal = (ret_value & 0xffff);
418 	falsealm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16);
419 	ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, MASKDWORD);
420 	falsealm_cnt->cnt_mcs_fail = (ret_value & 0xffff);
421 
422 	falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail +
423 		falsealm_cnt->cnt_rate_illegal + falsealm_cnt->cnt_crc8_fail +
424 		falsealm_cnt->cnt_mcs_fail;
425 
426 	/* read CCK false alarm */
427 	ret_value = rtl_get_bbreg(hw, 0xc64, MASKDWORD);
428 	falsealm_cnt->cnt_cck_fail = (ret_value & 0xffff);
429 	falsealm_cnt->cnt_all =	falsealm_cnt->cnt_ofdm_fail +
430 		falsealm_cnt->cnt_cck_fail;
431 }
432 
433 static void rtl92s_backoff_enable_flag(struct ieee80211_hw *hw)
434 {
435 	struct rtl_priv *rtlpriv = rtl_priv(hw);
436 	struct dig_t *digtable = &rtlpriv->dm_digtable;
437 	struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt);
438 
439 	if (falsealm_cnt->cnt_all > digtable->fa_highthresh) {
440 		if ((digtable->back_val - 6) <
441 			digtable->backoffval_range_min)
442 			digtable->back_val = digtable->backoffval_range_min;
443 		else
444 			digtable->back_val -= 6;
445 	} else if (falsealm_cnt->cnt_all < digtable->fa_lowthresh) {
446 		if ((digtable->back_val + 6) >
447 			digtable->backoffval_range_max)
448 			digtable->back_val =
449 				 digtable->backoffval_range_max;
450 		else
451 			digtable->back_val += 6;
452 	}
453 }
454 
455 static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw)
456 {
457 	struct rtl_priv *rtlpriv = rtl_priv(hw);
458 	struct dig_t *digtable = &rtlpriv->dm_digtable;
459 	struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt);
460 	static u8 initialized, force_write;
461 	u8 initial_gain = 0;
462 
463 	if ((digtable->pre_sta_cstate == digtable->cur_sta_cstate) ||
464 	    (digtable->cur_sta_cstate == DIG_STA_BEFORE_CONNECT)) {
465 		if (digtable->cur_sta_cstate == DIG_STA_BEFORE_CONNECT) {
466 			if (rtlpriv->psc.rfpwr_state != ERFON)
467 				return;
468 
469 			if (digtable->backoff_enable_flag)
470 				rtl92s_backoff_enable_flag(hw);
471 			else
472 				digtable->back_val = DM_DIG_BACKOFF_MAX;
473 
474 			if ((digtable->rssi_val + 10 - digtable->back_val) >
475 				digtable->rx_gain_max)
476 				digtable->cur_igvalue =
477 						digtable->rx_gain_max;
478 			else if ((digtable->rssi_val + 10 - digtable->back_val)
479 				 < digtable->rx_gain_min)
480 				digtable->cur_igvalue =
481 						digtable->rx_gain_min;
482 			else
483 				digtable->cur_igvalue = digtable->rssi_val + 10
484 					- digtable->back_val;
485 
486 			if (falsealm_cnt->cnt_all > 10000)
487 				digtable->cur_igvalue =
488 					 (digtable->cur_igvalue > 0x33) ?
489 					 digtable->cur_igvalue : 0x33;
490 
491 			if (falsealm_cnt->cnt_all > 16000)
492 				digtable->cur_igvalue =
493 						 digtable->rx_gain_max;
494 		/* connected -> connected or disconnected -> disconnected  */
495 		} else {
496 			/* Firmware control DIG, do nothing in driver dm */
497 			return;
498 		}
499 		/* disconnected -> connected or connected ->
500 		 * disconnected or beforeconnect->(dis)connected */
501 	} else {
502 		/* Enable FW DIG */
503 		digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
504 		rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_ENABLE);
505 
506 		digtable->back_val = DM_DIG_BACKOFF_MAX;
507 		digtable->cur_igvalue = rtlpriv->phy.default_initialgain[0];
508 		digtable->pre_igvalue = 0;
509 		return;
510 	}
511 
512 	/* Forced writing to prevent from fw-dig overwriting. */
513 	if (digtable->pre_igvalue != rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1,
514 						  MASKBYTE0))
515 		force_write = 1;
516 
517 	if ((digtable->pre_igvalue != digtable->cur_igvalue) ||
518 	    !initialized || force_write) {
519 		/* Disable FW DIG */
520 		rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_DISABLE);
521 
522 		initial_gain = (u8)digtable->cur_igvalue;
523 
524 		/* Set initial gain. */
525 		rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0, initial_gain);
526 		rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0, initial_gain);
527 		digtable->pre_igvalue = digtable->cur_igvalue;
528 		initialized = 1;
529 		force_write = 0;
530 	}
531 }
532 
533 static void _rtl92s_dm_ctrl_initgain_bytwoport(struct ieee80211_hw *hw)
534 {
535 	struct rtl_priv *rtlpriv = rtl_priv(hw);
536 	struct dig_t *dig = &rtlpriv->dm_digtable;
537 
538 	if (rtlpriv->mac80211.act_scanning)
539 		return;
540 
541 	/* Decide the current status and if modify initial gain or not */
542 	if (rtlpriv->mac80211.link_state >= MAC80211_LINKED ||
543 	    rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC)
544 		dig->cur_sta_cstate = DIG_STA_CONNECT;
545 	else
546 		dig->cur_sta_cstate = DIG_STA_DISCONNECT;
547 
548 	dig->rssi_val = rtlpriv->dm.undec_sm_pwdb;
549 
550 	/* Change dig mode to rssi */
551 	if (dig->cur_sta_cstate != DIG_STA_DISCONNECT) {
552 		if (dig->dig_twoport_algorithm ==
553 		    DIG_TWO_PORT_ALGO_FALSE_ALARM) {
554 			dig->dig_twoport_algorithm = DIG_TWO_PORT_ALGO_RSSI;
555 			rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_MODE_SS);
556 		}
557 	}
558 
559 	_rtl92s_dm_false_alarm_counter_statistics(hw);
560 	_rtl92s_dm_initial_gain_sta_beforeconnect(hw);
561 
562 	dig->pre_sta_cstate = dig->cur_sta_cstate;
563 }
564 
565 static void _rtl92s_dm_ctrl_initgain_byrssi(struct ieee80211_hw *hw)
566 {
567 	struct rtl_priv *rtlpriv = rtl_priv(hw);
568 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
569 	struct dig_t *digtable = &rtlpriv->dm_digtable;
570 
571 	/* 2T2R TP issue */
572 	if (rtlphy->rf_type == RF_2T2R)
573 		return;
574 
575 	if (!rtlpriv->dm.dm_initialgain_enable)
576 		return;
577 
578 	if (digtable->dig_enable_flag == false)
579 		return;
580 
581 	_rtl92s_dm_ctrl_initgain_bytwoport(hw);
582 }
583 
584 static void _rtl92s_dm_dynamic_txpower(struct ieee80211_hw *hw)
585 {
586 	struct rtl_priv *rtlpriv = rtl_priv(hw);
587 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
588 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
589 	long undec_sm_pwdb;
590 	long txpwr_threshold_lv1, txpwr_threshold_lv2;
591 
592 	/* 2T2R TP issue */
593 	if (rtlphy->rf_type == RF_2T2R)
594 		return;
595 
596 	if (!rtlpriv->dm.dynamic_txpower_enable ||
597 	    rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) {
598 		rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL;
599 		return;
600 	}
601 
602 	if ((mac->link_state < MAC80211_LINKED) &&
603 	    (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) {
604 		RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
605 			 "Not connected to any\n");
606 
607 		rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL;
608 
609 		rtlpriv->dm.last_dtp_lvl = TX_HIGHPWR_LEVEL_NORMAL;
610 		return;
611 	}
612 
613 	if (mac->link_state >= MAC80211_LINKED) {
614 		if (mac->opmode == NL80211_IFTYPE_ADHOC) {
615 			undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;
616 			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
617 				 "AP Client PWDB = 0x%lx\n",
618 				 undec_sm_pwdb);
619 		} else {
620 			undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;
621 			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
622 				 "STA Default Port PWDB = 0x%lx\n",
623 				 undec_sm_pwdb);
624 		}
625 	} else {
626 		undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;
627 
628 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
629 			 "AP Ext Port PWDB = 0x%lx\n",
630 			 undec_sm_pwdb);
631 	}
632 
633 	txpwr_threshold_lv2 = TX_POWER_NEAR_FIELD_THRESH_LVL2;
634 	txpwr_threshold_lv1 = TX_POWER_NEAR_FIELD_THRESH_LVL1;
635 
636 	if (rtl_get_bbreg(hw, 0xc90, MASKBYTE0) == 1)
637 		rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL;
638 	else if (undec_sm_pwdb >= txpwr_threshold_lv2)
639 		rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL2;
640 	else if ((undec_sm_pwdb < (txpwr_threshold_lv2 - 3)) &&
641 		(undec_sm_pwdb >= txpwr_threshold_lv1))
642 		rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL1;
643 	else if (undec_sm_pwdb < (txpwr_threshold_lv1 - 3))
644 		rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL;
645 
646 	if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl))
647 		rtl92s_phy_set_txpower(hw, rtlphy->current_channel);
648 
649 	rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl;
650 }
651 
652 static void _rtl92s_dm_init_dig(struct ieee80211_hw *hw)
653 {
654 	struct rtl_priv *rtlpriv = rtl_priv(hw);
655 	struct dig_t *digtable = &rtlpriv->dm_digtable;
656 
657 	/* Disable DIG scheme now.*/
658 	digtable->dig_enable_flag = true;
659 	digtable->backoff_enable_flag = true;
660 
661 	if ((rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER) &&
662 	    (hal_get_firmwareversion(rtlpriv) >= 0x3c))
663 		digtable->dig_algorithm = DIG_ALGO_BY_TOW_PORT;
664 	else
665 		digtable->dig_algorithm =
666 			 DIG_ALGO_BEFORE_CONNECT_BY_RSSI_AND_ALARM;
667 
668 	digtable->dig_twoport_algorithm = DIG_TWO_PORT_ALGO_RSSI;
669 	digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
670 	/* off=by real rssi value, on=by digtable->rssi_val for new dig */
671 	digtable->dig_dbgmode = DM_DBG_OFF;
672 	digtable->dig_slgorithm_switch = 0;
673 
674 	/* 2007/10/04 MH Define init gain threshol. */
675 	digtable->dig_state = DM_STA_DIG_MAX;
676 	digtable->dig_highpwrstate = DM_STA_DIG_MAX;
677 
678 	digtable->cur_sta_cstate = DIG_STA_DISCONNECT;
679 	digtable->pre_sta_cstate = DIG_STA_DISCONNECT;
680 	digtable->cur_ap_cstate = DIG_AP_DISCONNECT;
681 	digtable->pre_ap_cstate = DIG_AP_DISCONNECT;
682 
683 	digtable->rssi_lowthresh = DM_DIG_THRESH_LOW;
684 	digtable->rssi_highthresh = DM_DIG_THRESH_HIGH;
685 
686 	digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
687 	digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
688 
689 	digtable->rssi_highpower_lowthresh = DM_DIG_HIGH_PWR_THRESH_LOW;
690 	digtable->rssi_highpower_highthresh = DM_DIG_HIGH_PWR_THRESH_HIGH;
691 
692 	/* for dig debug rssi value */
693 	digtable->rssi_val = 50;
694 	digtable->back_val = DM_DIG_BACKOFF_MAX;
695 	digtable->rx_gain_max = DM_DIG_MAX;
696 
697 	digtable->rx_gain_min = DM_DIG_MIN;
698 
699 	digtable->backoffval_range_max = DM_DIG_BACKOFF_MAX;
700 	digtable->backoffval_range_min = DM_DIG_BACKOFF_MIN;
701 }
702 
703 static void _rtl92s_dm_init_dynamic_txpower(struct ieee80211_hw *hw)
704 {
705 	struct rtl_priv *rtlpriv = rtl_priv(hw);
706 
707 	if ((hal_get_firmwareversion(rtlpriv) >= 60) &&
708 	    (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER))
709 		rtlpriv->dm.dynamic_txpower_enable = true;
710 	else
711 		rtlpriv->dm.dynamic_txpower_enable = false;
712 
713 	rtlpriv->dm.last_dtp_lvl = TX_HIGHPWR_LEVEL_NORMAL;
714 	rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL;
715 }
716 
717 void rtl92s_dm_init(struct ieee80211_hw *hw)
718 {
719 	struct rtl_priv *rtlpriv = rtl_priv(hw);
720 
721 	rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
722 	rtlpriv->dm.undec_sm_pwdb = -1;
723 
724 	_rtl92s_dm_init_dynamic_txpower(hw);
725 	rtl92s_dm_init_edca_turbo(hw);
726 	_rtl92s_dm_init_rate_adaptive_mask(hw);
727 	_rtl92s_dm_init_txpowertracking_thermalmeter(hw);
728 	_rtl92s_dm_init_dig(hw);
729 
730 	rtl_write_dword(rtlpriv, WFM5, FW_CCA_CHK_ENABLE);
731 }
732 
733 void rtl92s_dm_watchdog(struct ieee80211_hw *hw)
734 {
735 	_rtl92s_dm_check_edca_turbo(hw);
736 	_rtl92s_dm_check_txpowertracking_thermalmeter(hw);
737 	_rtl92s_dm_ctrl_initgain_byrssi(hw);
738 	_rtl92s_dm_dynamic_txpower(hw);
739 	_rtl92s_dm_refresh_rateadaptive_mask(hw);
740 	_rtl92s_dm_switch_baseband_mrc(hw);
741 }
742 
743