1 /******************************************************************************
2  *
3  * Copyright(c) 2009-2014  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  * The full GNU General Public License is included in this distribution in the
15  * file called LICENSE.
16  *
17  * Contact Information:
18  * wlanfae <wlanfae@realtek.com>
19  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
20  * Hsinchu 300, Taiwan.
21  *
22  * Larry Finger <Larry.Finger@lwfinger.net>
23  *
24  *****************************************************************************/
25 
26 #include "../wifi.h"
27 #include "../base.h"
28 #include "../pci.h"
29 #include "../core.h"
30 #include "reg.h"
31 #include "def.h"
32 #include "phy.h"
33 #include "dm.h"
34 #include "../rtl8723com/dm_common.h"
35 #include "fw.h"
36 #include "trx.h"
37 #include "../btcoexist/rtl_btc.h"
38 
39 static const u32 ofdmswing_table[] = {
40 	0x0b40002d, /* 0,  -15.0dB */
41 	0x0c000030, /* 1,  -14.5dB */
42 	0x0cc00033, /* 2,  -14.0dB */
43 	0x0d800036, /* 3,  -13.5dB */
44 	0x0e400039, /* 4,  -13.0dB */
45 	0x0f00003c, /* 5,  -12.5dB */
46 	0x10000040, /* 6,  -12.0dB */
47 	0x11000044, /* 7,  -11.5dB */
48 	0x12000048, /* 8,  -11.0dB */
49 	0x1300004c, /* 9,  -10.5dB */
50 	0x14400051, /* 10, -10.0dB */
51 	0x15800056, /* 11, -9.5dB */
52 	0x16c0005b, /* 12, -9.0dB */
53 	0x18000060, /* 13, -8.5dB */
54 	0x19800066, /* 14, -8.0dB */
55 	0x1b00006c, /* 15, -7.5dB */
56 	0x1c800072, /* 16, -7.0dB */
57 	0x1e400079, /* 17, -6.5dB */
58 	0x20000080, /* 18, -6.0dB */
59 	0x22000088, /* 19, -5.5dB */
60 	0x24000090, /* 20, -5.0dB */
61 	0x26000098, /* 21, -4.5dB */
62 	0x288000a2, /* 22, -4.0dB */
63 	0x2ac000ab, /* 23, -3.5dB */
64 	0x2d4000b5, /* 24, -3.0dB */
65 	0x300000c0, /* 25, -2.5dB */
66 	0x32c000cb, /* 26, -2.0dB */
67 	0x35c000d7, /* 27, -1.5dB */
68 	0x390000e4, /* 28, -1.0dB */
69 	0x3c8000f2, /* 29, -0.5dB */
70 	0x40000100, /* 30, +0dB */
71 	0x43c0010f, /* 31, +0.5dB */
72 	0x47c0011f, /* 32, +1.0dB */
73 	0x4c000130, /* 33, +1.5dB */
74 	0x50800142, /* 34, +2.0dB */
75 	0x55400155, /* 35, +2.5dB */
76 	0x5a400169, /* 36, +3.0dB */
77 	0x5fc0017f, /* 37, +3.5dB */
78 	0x65400195, /* 38, +4.0dB */
79 	0x6b8001ae, /* 39, +4.5dB */
80 	0x71c001c7, /* 40, +5.0dB */
81 	0x788001e2, /* 41, +5.5dB */
82 	0x7f8001fe  /* 42, +6.0dB */
83 };
84 
85 static const u8 cckswing_table_ch1ch13[CCK_TABLE_SIZE][8] = {
86 	{0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01}, /*  0, -16.0dB */
87 	{0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, /*  1, -15.5dB */
88 	{0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, /*  2, -15.0dB */
89 	{0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, /*  3, -14.5dB */
90 	{0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, /*  4, -14.0dB */
91 	{0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, /*  5, -13.5dB */
92 	{0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, /*  6, -13.0dB */
93 	{0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, /*  7, -12.5dB */
94 	{0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, /*  8, -12.0dB */
95 	{0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, /*  9, -11.5dB */
96 	{0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 10, -11.0dB */
97 	{0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 11, -10.5dB */
98 	{0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 12, -10.0dB */
99 	{0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 13, -9.5dB */
100 	{0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, /* 14, -9.0dB */
101 	{0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, /* 15, -8.5dB */
102 	{0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, /* 16, -8.0dB */
103 	{0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, /* 17, -7.5dB */
104 	{0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, /* 18, -7.0dB */
105 	{0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, /* 19, -6.5dB */
106 	{0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, /* 20, -6.0dB */
107 	{0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, /* 21, -5.5dB */
108 	{0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, /* 22, -5.0dB */
109 	{0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, /* 23, -4.5dB */
110 	{0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, /* 24, -4.0dB */
111 	{0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, /* 25, -3.5dB */
112 	{0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, /* 26, -3.0dB */
113 	{0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, /* 27, -2.5dB */
114 	{0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, /* 28, -2.0dB */
115 	{0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, /* 29, -1.5dB */
116 	{0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, /* 30, -1.0dB */
117 	{0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, /* 31, -0.5dB */
118 	{0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}  /* 32, +0dB */
119 };
120 
121 static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = {
122 	{0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00}, /*  0, -16.0dB */
123 	{0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /*  1, -15.5dB */
124 	{0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /*  2, -15.0dB */
125 	{0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /*  3, -14.5dB */
126 	{0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /*  4, -14.0dB */
127 	{0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /*  5, -13.5dB */
128 	{0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /*  6, -13.0dB */
129 	{0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, /*  7, -12.5dB */
130 	{0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /*  8, -12.0dB */
131 	{0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /*  9, -11.5dB */
132 	{0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 10, -11.0dB */
133 	{0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 11, -10.5dB */
134 	{0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 12, -10.0dB */
135 	{0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 13, -9.5dB */
136 	{0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 14, -9.0dB */
137 	{0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 15, -8.5dB */
138 	{0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 16, -8.0dB */
139 	{0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 17, -7.5dB */
140 	{0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, /* 18, -7.0dB */
141 	{0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, /* 19, -6.5dB */
142 	{0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 20, -6.0dB */
143 	{0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 21, -5.5dB */
144 	{0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, /* 22, -5.0dB */
145 	{0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, /* 23, -4.5dB */
146 	{0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, /* 24, -4.0dB */
147 	{0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, /* 25, -3.5dB */
148 	{0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, /* 26, -3.0dB */
149 	{0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, /* 27, -2.5dB */
150 	{0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, /* 28, -2.0dB */
151 	{0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, /* 29, -1.5dB */
152 	{0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, /* 30, -1.0dB */
153 	{0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, /* 31, -0.5dB */
154 	{0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}  /* 32, +0dB */
155 };
156 
157 static const u32 edca_setting_dl[PEER_MAX] = {
158 	0xa44f,		/* 0 UNKNOWN */
159 	0x5ea44f,	/* 1 REALTEK_90 */
160 	0x5e4322,	/* 2 REALTEK_92SE */
161 	0x5ea42b,	/* 3 BROAD */
162 	0xa44f,		/* 4 RAL */
163 	0xa630,		/* 5 ATH */
164 	0x5ea630,	/* 6 CISCO */
165 	0x5ea42b,	/* 7 MARVELL */
166 };
167 
168 static const u32 edca_setting_ul[PEER_MAX] = {
169 	0x5e4322,	/* 0 UNKNOWN */
170 	0xa44f,		/* 1 REALTEK_90 */
171 	0x5ea44f,	/* 2 REALTEK_92SE */
172 	0x5ea32b,	/* 3 BROAD */
173 	0x5ea422,	/* 4 RAL */
174 	0x5ea322,	/* 5 ATH */
175 	0x3ea430,	/* 6 CISCO */
176 	0x5ea44f,	/* 7 MARV */
177 };
178 
179 void rtl8723be_dm_txpower_track_adjust(struct ieee80211_hw *hw, u8 type,
180 				       u8 *pdirection, u32 *poutwrite_val)
181 {
182 	struct rtl_priv *rtlpriv = rtl_priv(hw);
183 	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
184 	u8 pwr_val = 0;
185 	u8 ofdm_base = rtlpriv->dm.swing_idx_ofdm_base[RF90_PATH_A];
186 	u8 ofdm_val = rtlpriv->dm.swing_idx_ofdm[RF90_PATH_A];
187 	u8 cck_base = rtldm->swing_idx_cck_base;
188 	u8 cck_val = rtldm->swing_idx_cck;
189 
190 	if (type == 0) {
191 		if (ofdm_val <= ofdm_base) {
192 			*pdirection = 1;
193 			pwr_val = ofdm_base - ofdm_val;
194 		} else {
195 			*pdirection = 2;
196 			pwr_val = ofdm_val - ofdm_base;
197 		}
198 	} else if (type == 1) {
199 		if (cck_val <= cck_base) {
200 			*pdirection = 1;
201 			pwr_val = cck_base - cck_val;
202 		} else {
203 			*pdirection = 2;
204 			pwr_val = cck_val - cck_base;
205 		}
206 	}
207 
208 	if (pwr_val >= TXPWRTRACK_MAX_IDX && (*pdirection == 1))
209 		pwr_val = TXPWRTRACK_MAX_IDX;
210 
211 	*poutwrite_val = pwr_val | (pwr_val << 8) |
212 		(pwr_val << 16) | (pwr_val << 24);
213 }
214 
215 void rtl8723be_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw)
216 {
217 	struct rtl_priv *rtlpriv = rtl_priv(hw);
218 	struct rate_adaptive *p_ra = &rtlpriv->ra;
219 
220 	p_ra->ratr_state = DM_RATR_STA_INIT;
221 	p_ra->pre_ratr_state = DM_RATR_STA_INIT;
222 
223 	if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER)
224 		rtlpriv->dm.useramask = true;
225 	else
226 		rtlpriv->dm.useramask = false;
227 
228 	p_ra->high_rssi_thresh_for_ra = 50;
229 	p_ra->low_rssi_thresh_for_ra40m = 20;
230 }
231 
232 static void rtl8723be_dm_init_txpower_tracking(struct ieee80211_hw *hw)
233 {
234 	struct rtl_priv *rtlpriv = rtl_priv(hw);
235 
236 	rtlpriv->dm.txpower_tracking = true;
237 	rtlpriv->dm.txpower_track_control = true;
238 	rtlpriv->dm.thermalvalue = 0;
239 
240 	rtlpriv->dm.ofdm_index[0] = 30;
241 	rtlpriv->dm.cck_index = 20;
242 
243 	rtlpriv->dm.swing_idx_cck_base = rtlpriv->dm.cck_index;
244 
245 	rtlpriv->dm.swing_idx_ofdm_base[0] = rtlpriv->dm.ofdm_index[0];
246 	rtlpriv->dm.delta_power_index[RF90_PATH_A] = 0;
247 	rtlpriv->dm.delta_power_index_last[RF90_PATH_A] = 0;
248 	rtlpriv->dm.power_index_offset[RF90_PATH_A] = 0;
249 
250 	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
251 		 "  rtlpriv->dm.txpower_tracking = %d\n",
252 		  rtlpriv->dm.txpower_tracking);
253 }
254 
255 static void rtl8723be_dm_init_dynamic_atc_switch(struct ieee80211_hw *hw)
256 {
257 	struct rtl_priv *rtlpriv = rtl_priv(hw);
258 
259 	rtlpriv->dm.crystal_cap = rtlpriv->efuse.crystalcap;
260 
261 	rtlpriv->dm.atc_status = rtl_get_bbreg(hw, ROFDM1_CFOTRACKING, 0x800);
262 	rtlpriv->dm.cfo_threshold = CFO_THRESHOLD_XTAL;
263 }
264 
265 void rtl8723be_dm_init(struct ieee80211_hw *hw)
266 {
267 	struct rtl_priv *rtlpriv = rtl_priv(hw);
268 	u32 cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f);
269 
270 	rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
271 	rtl_dm_diginit(hw, cur_igvalue);
272 	rtl8723be_dm_init_rate_adaptive_mask(hw);
273 	rtl8723_dm_init_edca_turbo(hw);
274 	rtl8723_dm_init_dynamic_bb_powersaving(hw);
275 	rtl8723_dm_init_dynamic_txpower(hw);
276 	rtl8723be_dm_init_txpower_tracking(hw);
277 	rtl8723be_dm_init_dynamic_atc_switch(hw);
278 }
279 
280 static void rtl8723be_dm_find_minimum_rssi(struct ieee80211_hw *hw)
281 {
282 	struct rtl_priv *rtlpriv = rtl_priv(hw);
283 	struct dig_t *rtl_dm_dig = &rtlpriv->dm_digtable;
284 	struct rtl_mac *mac = rtl_mac(rtlpriv);
285 
286 	/* Determine the minimum RSSI  */
287 	if ((mac->link_state < MAC80211_LINKED) &&
288 	    (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) {
289 		rtl_dm_dig->min_undec_pwdb_for_dm = 0;
290 		RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
291 			 "Not connected to any\n");
292 	}
293 	if (mac->link_state >= MAC80211_LINKED) {
294 		if (mac->opmode == NL80211_IFTYPE_AP ||
295 		    mac->opmode == NL80211_IFTYPE_ADHOC) {
296 			rtl_dm_dig->min_undec_pwdb_for_dm =
297 			    rtlpriv->dm.entry_min_undec_sm_pwdb;
298 			RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
299 				 "AP Client PWDB = 0x%lx\n",
300 			       rtlpriv->dm.entry_min_undec_sm_pwdb);
301 		} else {
302 			rtl_dm_dig->min_undec_pwdb_for_dm =
303 			    rtlpriv->dm.undec_sm_pwdb;
304 			RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
305 				 "STA Default Port PWDB = 0x%x\n",
306 				  rtl_dm_dig->min_undec_pwdb_for_dm);
307 		}
308 	} else {
309 		rtl_dm_dig->min_undec_pwdb_for_dm =
310 				rtlpriv->dm.entry_min_undec_sm_pwdb;
311 		RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
312 			 "AP Ext Port or disconnect PWDB = 0x%x\n",
313 			  rtl_dm_dig->min_undec_pwdb_for_dm);
314 	}
315 	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "MinUndecoratedPWDBForDM =%d\n",
316 		 rtl_dm_dig->min_undec_pwdb_for_dm);
317 }
318 
319 static void rtl8723be_dm_check_rssi_monitor(struct ieee80211_hw *hw)
320 {
321 	struct rtl_priv *rtlpriv = rtl_priv(hw);
322 	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
323 	struct rtl_sta_info *drv_priv;
324 	u8 h2c_parameter[3] = { 0 };
325 	long tmp_entry_max_pwdb = 0, tmp_entry_min_pwdb = 0xff;
326 
327 	/* AP & ADHOC & MESH */
328 	spin_lock_bh(&rtlpriv->locks.entry_list_lock);
329 	list_for_each_entry(drv_priv, &rtlpriv->entry_list, list) {
330 		if (drv_priv->rssi_stat.undec_sm_pwdb <
331 						tmp_entry_min_pwdb)
332 			tmp_entry_min_pwdb =
333 				drv_priv->rssi_stat.undec_sm_pwdb;
334 		if (drv_priv->rssi_stat.undec_sm_pwdb >
335 						tmp_entry_max_pwdb)
336 			tmp_entry_max_pwdb =
337 				drv_priv->rssi_stat.undec_sm_pwdb;
338 	}
339 	spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
340 
341 	/* If associated entry is found */
342 	if (tmp_entry_max_pwdb != 0) {
343 		rtlpriv->dm.entry_max_undec_sm_pwdb =
344 							tmp_entry_max_pwdb;
345 		RTPRINT(rtlpriv, FDM, DM_PWDB,
346 			"EntryMaxPWDB = 0x%lx(%ld)\n",
347 			 tmp_entry_max_pwdb, tmp_entry_max_pwdb);
348 	} else {
349 		rtlpriv->dm.entry_max_undec_sm_pwdb = 0;
350 	}
351 	/* If associated entry is found */
352 	if (tmp_entry_min_pwdb != 0xff) {
353 		rtlpriv->dm.entry_min_undec_sm_pwdb =
354 							tmp_entry_min_pwdb;
355 		RTPRINT(rtlpriv, FDM, DM_PWDB,
356 			"EntryMinPWDB = 0x%lx(%ld)\n",
357 			 tmp_entry_min_pwdb, tmp_entry_min_pwdb);
358 	} else {
359 		rtlpriv->dm.entry_min_undec_sm_pwdb = 0;
360 	}
361 	/* Indicate Rx signal strength to FW. */
362 	if (rtlpriv->dm.useramask) {
363 		h2c_parameter[2] =
364 			(u8)(rtlpriv->dm.undec_sm_pwdb & 0xFF);
365 		h2c_parameter[1] = 0x20;
366 		h2c_parameter[0] = 0;
367 		rtl8723be_fill_h2c_cmd(hw, H2C_RSSIBE_REPORT, 3, h2c_parameter);
368 	} else {
369 		rtl_write_byte(rtlpriv, 0x4fe,
370 			       rtlpriv->dm.undec_sm_pwdb);
371 	}
372 	rtl8723be_dm_find_minimum_rssi(hw);
373 	dm_digtable->rssi_val_min =
374 			rtlpriv->dm_digtable.min_undec_pwdb_for_dm;
375 }
376 
377 void rtl8723be_dm_write_dig(struct ieee80211_hw *hw, u8 current_igi)
378 {
379 	struct rtl_priv *rtlpriv = rtl_priv(hw);
380 	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
381 
382 	if (dm_digtable->stop_dig)
383 		return;
384 
385 	if (dm_digtable->cur_igvalue != current_igi) {
386 		rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f, current_igi);
387 		if (rtlpriv->phy.rf_type != RF_1T1R)
388 			rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1,
389 				      0x7f, current_igi);
390 	}
391 	dm_digtable->pre_igvalue = dm_digtable->cur_igvalue;
392 	dm_digtable->cur_igvalue = current_igi;
393 }
394 
395 static void rtl8723be_dm_dig(struct ieee80211_hw *hw)
396 {
397 	struct rtl_priv *rtlpriv = rtl_priv(hw);
398 	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
399 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
400 	u8 dig_min_0, dig_maxofmin;
401 	bool bfirstconnect, bfirstdisconnect;
402 	u8 dm_dig_max, dm_dig_min;
403 	u8 current_igi = dm_digtable->cur_igvalue;
404 	u8 offset;
405 
406 	/* AP,BT */
407 	if (mac->act_scanning)
408 		return;
409 
410 	dig_min_0 = dm_digtable->dig_min_0;
411 	bfirstconnect = (mac->link_state >= MAC80211_LINKED) &&
412 			!dm_digtable->media_connect_0;
413 	bfirstdisconnect = (mac->link_state < MAC80211_LINKED) &&
414 			(dm_digtable->media_connect_0);
415 
416 	dm_dig_max = 0x5a;
417 	dm_dig_min = DM_DIG_MIN;
418 	dig_maxofmin = DM_DIG_MAX_AP;
419 
420 	if (mac->link_state >= MAC80211_LINKED) {
421 		if ((dm_digtable->rssi_val_min + 10) > dm_dig_max)
422 			dm_digtable->rx_gain_max = dm_dig_max;
423 		else if ((dm_digtable->rssi_val_min + 10) < dm_dig_min)
424 			dm_digtable->rx_gain_max = dm_dig_min;
425 		else
426 			dm_digtable->rx_gain_max =
427 				dm_digtable->rssi_val_min + 10;
428 
429 		if (rtlpriv->dm.one_entry_only) {
430 			offset = 12;
431 			if (dm_digtable->rssi_val_min - offset < dm_dig_min)
432 				dig_min_0 = dm_dig_min;
433 			else if (dm_digtable->rssi_val_min - offset >
434 							dig_maxofmin)
435 				dig_min_0 = dig_maxofmin;
436 			else
437 				dig_min_0 =
438 					dm_digtable->rssi_val_min - offset;
439 		} else {
440 			dig_min_0 = dm_dig_min;
441 		}
442 
443 	} else {
444 		dm_digtable->rx_gain_max = dm_dig_max;
445 		dig_min_0 = dm_dig_min;
446 		RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "no link\n");
447 	}
448 
449 	if (rtlpriv->falsealm_cnt.cnt_all > 10000) {
450 		if (dm_digtable->large_fa_hit != 3)
451 			dm_digtable->large_fa_hit++;
452 		if (dm_digtable->forbidden_igi < current_igi) {
453 			dm_digtable->forbidden_igi = current_igi;
454 			dm_digtable->large_fa_hit = 1;
455 		}
456 
457 		if (dm_digtable->large_fa_hit >= 3) {
458 			if ((dm_digtable->forbidden_igi + 1) >
459 			     dm_digtable->rx_gain_max)
460 				dm_digtable->rx_gain_min =
461 						dm_digtable->rx_gain_max;
462 			else
463 				dm_digtable->rx_gain_min =
464 						dm_digtable->forbidden_igi + 1;
465 			dm_digtable->recover_cnt = 3600;
466 		}
467 	} else {
468 		if (dm_digtable->recover_cnt != 0) {
469 			dm_digtable->recover_cnt--;
470 		} else {
471 			if (dm_digtable->large_fa_hit < 3) {
472 				if ((dm_digtable->forbidden_igi - 1) <
473 				     dig_min_0) {
474 					dm_digtable->forbidden_igi =
475 							dig_min_0;
476 					dm_digtable->rx_gain_min =
477 							dig_min_0;
478 				} else {
479 					dm_digtable->forbidden_igi--;
480 					dm_digtable->rx_gain_min =
481 						dm_digtable->forbidden_igi + 1;
482 				}
483 			} else {
484 				dm_digtable->large_fa_hit = 0;
485 			}
486 		}
487 	}
488 	if (dm_digtable->rx_gain_min > dm_digtable->rx_gain_max)
489 		dm_digtable->rx_gain_min = dm_digtable->rx_gain_max;
490 
491 	if (mac->link_state >= MAC80211_LINKED) {
492 		if (bfirstconnect) {
493 			if (dm_digtable->rssi_val_min <= dig_maxofmin)
494 				current_igi = dm_digtable->rssi_val_min;
495 			else
496 				current_igi = dig_maxofmin;
497 
498 			dm_digtable->large_fa_hit = 0;
499 		} else {
500 			if (rtlpriv->falsealm_cnt.cnt_all > DM_DIG_FA_TH2)
501 				current_igi += 4;
502 			else if (rtlpriv->falsealm_cnt.cnt_all > DM_DIG_FA_TH1)
503 				current_igi += 2;
504 			else if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH0)
505 				current_igi -= 2;
506 		}
507 	} else {
508 		if (bfirstdisconnect) {
509 			current_igi = dm_digtable->rx_gain_min;
510 		} else {
511 			if (rtlpriv->falsealm_cnt.cnt_all > 10000)
512 				current_igi += 4;
513 			else if (rtlpriv->falsealm_cnt.cnt_all > 8000)
514 				current_igi += 2;
515 			else if (rtlpriv->falsealm_cnt.cnt_all < 500)
516 				current_igi -= 2;
517 		}
518 	}
519 
520 	if (current_igi > dm_digtable->rx_gain_max)
521 		current_igi = dm_digtable->rx_gain_max;
522 	else if (current_igi < dm_digtable->rx_gain_min)
523 		current_igi = dm_digtable->rx_gain_min;
524 
525 	rtl8723be_dm_write_dig(hw, current_igi);
526 	dm_digtable->media_connect_0 =
527 		((mac->link_state >= MAC80211_LINKED) ? true : false);
528 	dm_digtable->dig_min_0 = dig_min_0;
529 }
530 
531 static void rtl8723be_dm_false_alarm_counter_statistics(
532 					struct ieee80211_hw *hw)
533 {
534 	u32 ret_value;
535 	struct rtl_priv *rtlpriv = rtl_priv(hw);
536 	struct false_alarm_statistics *falsealm_cnt = &rtlpriv->falsealm_cnt;
537 
538 	rtl_set_bbreg(hw, DM_REG_OFDM_FA_HOLDC_11N, BIT(31), 1);
539 	rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(31), 1);
540 
541 	ret_value = rtl_get_bbreg(hw, DM_REG_OFDM_FA_TYPE1_11N, MASKDWORD);
542 	falsealm_cnt->cnt_fast_fsync_fail = ret_value & 0xffff;
543 	falsealm_cnt->cnt_sb_search_fail = (ret_value & 0xffff0000) >> 16;
544 
545 	ret_value = rtl_get_bbreg(hw, DM_REG_OFDM_FA_TYPE2_11N, MASKDWORD);
546 	falsealm_cnt->cnt_ofdm_cca = ret_value & 0xffff;
547 	falsealm_cnt->cnt_parity_fail = (ret_value & 0xffff0000) >> 16;
548 
549 	ret_value = rtl_get_bbreg(hw, DM_REG_OFDM_FA_TYPE3_11N, MASKDWORD);
550 	falsealm_cnt->cnt_rate_illegal = ret_value & 0xffff;
551 	falsealm_cnt->cnt_crc8_fail = (ret_value & 0xffff0000) >> 16;
552 
553 	ret_value = rtl_get_bbreg(hw, DM_REG_OFDM_FA_TYPE4_11N, MASKDWORD);
554 	falsealm_cnt->cnt_mcs_fail = ret_value & 0xffff;
555 
556 	falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail +
557 				      falsealm_cnt->cnt_rate_illegal +
558 				      falsealm_cnt->cnt_crc8_fail +
559 				      falsealm_cnt->cnt_mcs_fail +
560 				      falsealm_cnt->cnt_fast_fsync_fail +
561 				      falsealm_cnt->cnt_sb_search_fail;
562 
563 	rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(12), 1);
564 	rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(14), 1);
565 
566 	ret_value = rtl_get_bbreg(hw, DM_REG_CCK_FA_RST_11N, MASKBYTE0);
567 	falsealm_cnt->cnt_cck_fail = ret_value;
568 
569 	ret_value = rtl_get_bbreg(hw, DM_REG_CCK_FA_MSB_11N, MASKBYTE3);
570 	falsealm_cnt->cnt_cck_fail += (ret_value & 0xff) << 8;
571 
572 	ret_value = rtl_get_bbreg(hw, DM_REG_CCK_CCA_CNT_11N, MASKDWORD);
573 	falsealm_cnt->cnt_cck_cca = ((ret_value & 0xff) << 8) |
574 				    ((ret_value & 0xff00) >> 8);
575 
576 	falsealm_cnt->cnt_all = falsealm_cnt->cnt_fast_fsync_fail +
577 				falsealm_cnt->cnt_sb_search_fail +
578 				falsealm_cnt->cnt_parity_fail +
579 				falsealm_cnt->cnt_rate_illegal +
580 				falsealm_cnt->cnt_crc8_fail +
581 				falsealm_cnt->cnt_mcs_fail +
582 				falsealm_cnt->cnt_cck_fail;
583 
584 	falsealm_cnt->cnt_cca_all = falsealm_cnt->cnt_ofdm_cca +
585 				    falsealm_cnt->cnt_cck_cca;
586 
587 	rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTC_11N, BIT(31), 1);
588 	rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTC_11N, BIT(31), 0);
589 	rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(27), 1);
590 	rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(27), 0);
591 
592 	rtl_set_bbreg(hw, DM_REG_OFDM_FA_HOLDC_11N, BIT(31), 0);
593 	rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(31), 0);
594 
595 	rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(13) | BIT(12), 0);
596 	rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(13) | BIT(12), 2);
597 
598 	rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(15) | BIT(14), 0);
599 	rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(15) | BIT(14), 2);
600 
601 	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
602 		 "cnt_parity_fail = %d, cnt_rate_illegal = %d, cnt_crc8_fail = %d, cnt_mcs_fail = %d\n",
603 		 falsealm_cnt->cnt_parity_fail,
604 		 falsealm_cnt->cnt_rate_illegal,
605 		 falsealm_cnt->cnt_crc8_fail,
606 		 falsealm_cnt->cnt_mcs_fail);
607 
608 	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
609 		 "cnt_ofdm_fail = %x, cnt_cck_fail = %x, cnt_all = %x\n",
610 		 falsealm_cnt->cnt_ofdm_fail,
611 		 falsealm_cnt->cnt_cck_fail,
612 		 falsealm_cnt->cnt_all);
613 }
614 
615 static void rtl8723be_dm_dynamic_txpower(struct ieee80211_hw *hw)
616 {
617 	/* 8723BE does not support ODM_BB_DYNAMIC_TXPWR*/
618 	return;
619 }
620 
621 static void rtl8723be_set_iqk_matrix(struct ieee80211_hw *hw, u8 ofdm_index,
622 				     u8 rfpath, long iqk_result_x,
623 				     long iqk_result_y)
624 {
625 	long ele_a = 0, ele_d, ele_c = 0, value32;
626 
627 	if (ofdm_index >= 43)
628 		ofdm_index = 43 - 1;
629 
630 	ele_d = (ofdmswing_table[ofdm_index] & 0xFFC00000) >> 22;
631 
632 	if (iqk_result_x != 0) {
633 		if ((iqk_result_x & 0x00000200) != 0)
634 			iqk_result_x = iqk_result_x | 0xFFFFFC00;
635 		ele_a = ((iqk_result_x * ele_d) >> 8) & 0x000003FF;
636 
637 		if ((iqk_result_y & 0x00000200) != 0)
638 			iqk_result_y = iqk_result_y | 0xFFFFFC00;
639 		ele_c = ((iqk_result_y * ele_d) >> 8) & 0x000003FF;
640 
641 		switch (rfpath) {
642 		case RF90_PATH_A:
643 			value32 = (ele_d << 22) |
644 				((ele_c & 0x3F) << 16) | ele_a;
645 			rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, MASKDWORD,
646 				      value32);
647 			value32 = (ele_c & 0x000003C0) >> 6;
648 			rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS, value32);
649 			value32 = ((iqk_result_x * ele_d) >> 7) & 0x01;
650 			rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(24),
651 				      value32);
652 			break;
653 		default:
654 			break;
655 		}
656 	} else {
657 		switch (rfpath) {
658 		case RF90_PATH_A:
659 			rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, MASKDWORD,
660 				      ofdmswing_table[ofdm_index]);
661 			rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS, 0x00);
662 			rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(24), 0x00);
663 			break;
664 		default:
665 			break;
666 		}
667 	}
668 }
669 
670 static void rtl8723be_dm_tx_power_track_set_power(struct ieee80211_hw *hw,
671 					enum pwr_track_control_method method,
672 					u8 rfpath, u8 idx)
673 {
674 	struct rtl_priv *rtlpriv = rtl_priv(hw);
675 	struct rtl_phy *rtlphy = &rtlpriv->phy;
676 	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
677 	u8 swing_idx_ofdm_limit = 36;
678 
679 	if (method == TXAGC) {
680 		rtl8723be_phy_set_txpower_level(hw, rtlphy->current_channel);
681 	} else if (method == BBSWING) {
682 		if (rtldm->swing_idx_cck >= CCK_TABLE_SIZE)
683 			rtldm->swing_idx_cck = CCK_TABLE_SIZE - 1;
684 
685 		if (!rtldm->cck_inch14) {
686 			rtl_write_byte(rtlpriv, 0xa22,
687 			    cckswing_table_ch1ch13[rtldm->swing_idx_cck][0]);
688 			rtl_write_byte(rtlpriv, 0xa23,
689 			    cckswing_table_ch1ch13[rtldm->swing_idx_cck][1]);
690 			rtl_write_byte(rtlpriv, 0xa24,
691 			    cckswing_table_ch1ch13[rtldm->swing_idx_cck][2]);
692 			rtl_write_byte(rtlpriv, 0xa25,
693 			    cckswing_table_ch1ch13[rtldm->swing_idx_cck][3]);
694 			rtl_write_byte(rtlpriv, 0xa26,
695 			    cckswing_table_ch1ch13[rtldm->swing_idx_cck][4]);
696 			rtl_write_byte(rtlpriv, 0xa27,
697 			    cckswing_table_ch1ch13[rtldm->swing_idx_cck][5]);
698 			rtl_write_byte(rtlpriv, 0xa28,
699 			    cckswing_table_ch1ch13[rtldm->swing_idx_cck][6]);
700 			rtl_write_byte(rtlpriv, 0xa29,
701 			    cckswing_table_ch1ch13[rtldm->swing_idx_cck][7]);
702 		} else {
703 			rtl_write_byte(rtlpriv, 0xa22,
704 			    cckswing_table_ch14[rtldm->swing_idx_cck][0]);
705 			rtl_write_byte(rtlpriv, 0xa23,
706 			    cckswing_table_ch14[rtldm->swing_idx_cck][1]);
707 			rtl_write_byte(rtlpriv, 0xa24,
708 			    cckswing_table_ch14[rtldm->swing_idx_cck][2]);
709 			rtl_write_byte(rtlpriv, 0xa25,
710 			    cckswing_table_ch14[rtldm->swing_idx_cck][3]);
711 			rtl_write_byte(rtlpriv, 0xa26,
712 			    cckswing_table_ch14[rtldm->swing_idx_cck][4]);
713 			rtl_write_byte(rtlpriv, 0xa27,
714 			    cckswing_table_ch14[rtldm->swing_idx_cck][5]);
715 			rtl_write_byte(rtlpriv, 0xa28,
716 			    cckswing_table_ch14[rtldm->swing_idx_cck][6]);
717 			rtl_write_byte(rtlpriv, 0xa29,
718 			    cckswing_table_ch14[rtldm->swing_idx_cck][7]);
719 		}
720 
721 		if (rfpath == RF90_PATH_A) {
722 			if (rtldm->swing_idx_ofdm[RF90_PATH_A] <
723 			    swing_idx_ofdm_limit)
724 				swing_idx_ofdm_limit =
725 					rtldm->swing_idx_ofdm[RF90_PATH_A];
726 
727 			rtl8723be_set_iqk_matrix(hw,
728 				rtldm->swing_idx_ofdm[rfpath], rfpath,
729 				rtlphy->iqk_matrix[idx].value[0][0],
730 				rtlphy->iqk_matrix[idx].value[0][1]);
731 		} else if (rfpath == RF90_PATH_B) {
732 			if (rtldm->swing_idx_ofdm[RF90_PATH_B] <
733 			    swing_idx_ofdm_limit)
734 				swing_idx_ofdm_limit =
735 					rtldm->swing_idx_ofdm[RF90_PATH_B];
736 
737 			rtl8723be_set_iqk_matrix(hw,
738 				rtldm->swing_idx_ofdm[rfpath], rfpath,
739 				rtlphy->iqk_matrix[idx].value[0][4],
740 				rtlphy->iqk_matrix[idx].value[0][5]);
741 		}
742 	} else {
743 		return;
744 	}
745 }
746 
747 static void rtl8723be_dm_txpower_tracking_callback_thermalmeter(
748 							struct ieee80211_hw *hw)
749 {
750 	struct rtl_priv *rtlpriv = rtl_priv(hw);
751 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
752 	struct rtl_dm	*rtldm = rtl_dm(rtl_priv(hw));
753 	u8 thermalvalue = 0, delta, delta_lck, delta_iqk;
754 	u8 thermalvalue_avg_count = 0;
755 	u32 thermalvalue_avg = 0;
756 	int i = 0;
757 
758 	u8 ofdm_min_index = 6;
759 	u8 index_for_channel = 0;
760 
761 	s8 delta_swing_table_idx_tup_a[TXSCALE_TABLE_SIZE] = {
762 		0, 0, 1, 2, 2, 2, 3, 3, 3, 4,  5,
763 		5, 6, 6, 7, 7, 8, 8, 9, 9, 9, 10,
764 		10, 11, 11, 12, 12, 13, 14, 15};
765 	s8 delta_swing_table_idx_tdown_a[TXSCALE_TABLE_SIZE] = {
766 		0, 0, 1, 2, 2, 2, 3, 3, 3, 4,  5,
767 		5, 6, 6, 6, 6, 7, 7, 7, 8, 8,  9,
768 		9, 10, 10, 11, 12, 13, 14, 15};
769 
770 	/*Initilization ( 7 steps in total )*/
771 	rtlpriv->dm.txpower_trackinginit = true;
772 	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
773 		 "rtl8723be_dm_txpower_tracking_callback_thermalmeter\n");
774 
775 	thermalvalue = (u8)rtl_get_rfreg(hw,
776 		RF90_PATH_A, RF_T_METER, 0xfc00);
777 	if (!rtlpriv->dm.txpower_track_control || thermalvalue == 0 ||
778 	    rtlefuse->eeprom_thermalmeter == 0xFF)
779 		return;
780 	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
781 		 "Readback Thermal Meter = 0x%x pre thermal meter 0x%x eeprom_thermalmeter 0x%x\n",
782 		 thermalvalue, rtldm->thermalvalue,
783 		 rtlefuse->eeprom_thermalmeter);
784 	/*3 Initialize ThermalValues of RFCalibrateInfo*/
785 	if (!rtldm->thermalvalue) {
786 		rtlpriv->dm.thermalvalue_lck = thermalvalue;
787 		rtlpriv->dm.thermalvalue_iqk = thermalvalue;
788 	}
789 
790 	/*4 Calculate average thermal meter*/
791 	rtldm->thermalvalue_avg[rtldm->thermalvalue_avg_index] = thermalvalue;
792 	rtldm->thermalvalue_avg_index++;
793 	if (rtldm->thermalvalue_avg_index == AVG_THERMAL_NUM_8723BE)
794 		rtldm->thermalvalue_avg_index = 0;
795 
796 	for (i = 0; i < AVG_THERMAL_NUM_8723BE; i++) {
797 		if (rtldm->thermalvalue_avg[i]) {
798 			thermalvalue_avg += rtldm->thermalvalue_avg[i];
799 			thermalvalue_avg_count++;
800 		}
801 	}
802 
803 	if (thermalvalue_avg_count)
804 		thermalvalue = (u8)(thermalvalue_avg / thermalvalue_avg_count);
805 
806 	/* 5 Calculate delta, delta_LCK, delta_IQK.*/
807 	delta = (thermalvalue > rtlpriv->dm.thermalvalue) ?
808 		(thermalvalue - rtlpriv->dm.thermalvalue) :
809 		(rtlpriv->dm.thermalvalue - thermalvalue);
810 	delta_lck = (thermalvalue > rtlpriv->dm.thermalvalue_lck) ?
811 		    (thermalvalue - rtlpriv->dm.thermalvalue_lck) :
812 		    (rtlpriv->dm.thermalvalue_lck - thermalvalue);
813 	delta_iqk = (thermalvalue > rtlpriv->dm.thermalvalue_iqk) ?
814 		    (thermalvalue - rtlpriv->dm.thermalvalue_iqk) :
815 		    (rtlpriv->dm.thermalvalue_iqk - thermalvalue);
816 
817 	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
818 		 "Readback Thermal Meter = 0x%x pre thermal meter 0x%x eeprom_thermalmeter 0x%x delta 0x%x delta_lck 0x%x delta_iqk 0x%x\n",
819 		 thermalvalue, rtlpriv->dm.thermalvalue,
820 		 rtlefuse->eeprom_thermalmeter, delta, delta_lck, delta_iqk);
821 	/* 6 If necessary, do LCK.*/
822 	if (delta_lck >= IQK_THRESHOLD) {
823 		rtlpriv->dm.thermalvalue_lck = thermalvalue;
824 		rtl8723be_phy_lc_calibrate(hw);
825 	}
826 
827 	/* 7 If necessary, move the index of
828 	 * swing table to adjust Tx power.
829 	 */
830 	if (delta > 0 && rtlpriv->dm.txpower_track_control) {
831 		delta = (thermalvalue > rtlefuse->eeprom_thermalmeter) ?
832 			(thermalvalue - rtlefuse->eeprom_thermalmeter) :
833 			(rtlefuse->eeprom_thermalmeter - thermalvalue);
834 
835 		if (delta >= TXSCALE_TABLE_SIZE)
836 			delta = TXSCALE_TABLE_SIZE - 1;
837 		/* 7.1 Get the final CCK_index and
838 		 * OFDM_index for each swing table.
839 		 */
840 		if (thermalvalue > rtlefuse->eeprom_thermalmeter) {
841 			rtldm->delta_power_index_last[RF90_PATH_A] =
842 					rtldm->delta_power_index[RF90_PATH_A];
843 			rtldm->delta_power_index[RF90_PATH_A] =
844 					delta_swing_table_idx_tup_a[delta];
845 		} else {
846 			rtldm->delta_power_index_last[RF90_PATH_A] =
847 					rtldm->delta_power_index[RF90_PATH_A];
848 			rtldm->delta_power_index[RF90_PATH_A] =
849 				-1 * delta_swing_table_idx_tdown_a[delta];
850 		}
851 
852 		/* 7.2 Handle boundary conditions of index.*/
853 		if (rtldm->delta_power_index[RF90_PATH_A] ==
854 		    rtldm->delta_power_index_last[RF90_PATH_A])
855 			rtldm->power_index_offset[RF90_PATH_A] = 0;
856 		else
857 			rtldm->power_index_offset[RF90_PATH_A] =
858 				rtldm->delta_power_index[RF90_PATH_A] -
859 				rtldm->delta_power_index_last[RF90_PATH_A];
860 
861 		rtldm->ofdm_index[0] =
862 			rtldm->swing_idx_ofdm_base[RF90_PATH_A] +
863 			rtldm->power_index_offset[RF90_PATH_A];
864 		rtldm->cck_index = rtldm->swing_idx_cck_base +
865 				   rtldm->power_index_offset[RF90_PATH_A];
866 
867 		rtldm->swing_idx_cck = rtldm->cck_index;
868 		rtldm->swing_idx_ofdm[0] = rtldm->ofdm_index[0];
869 
870 		if (rtldm->ofdm_index[0] > OFDM_TABLE_SIZE - 1)
871 			rtldm->ofdm_index[0] = OFDM_TABLE_SIZE - 1;
872 		else if (rtldm->ofdm_index[0] < ofdm_min_index)
873 			rtldm->ofdm_index[0] = ofdm_min_index;
874 
875 		if (rtldm->cck_index > CCK_TABLE_SIZE - 1)
876 			rtldm->cck_index = CCK_TABLE_SIZE - 1;
877 		else if (rtldm->cck_index < 0)
878 			rtldm->cck_index = 0;
879 	} else {
880 		rtldm->power_index_offset[RF90_PATH_A] = 0;
881 	}
882 
883 	if ((rtldm->power_index_offset[RF90_PATH_A] != 0) &&
884 	    (rtldm->txpower_track_control)) {
885 		rtldm->done_txpower = true;
886 		rtl8723be_dm_tx_power_track_set_power(hw, BBSWING, 0,
887 						      index_for_channel);
888 
889 		rtldm->swing_idx_cck_base = rtldm->swing_idx_cck;
890 		rtldm->swing_idx_ofdm_base[RF90_PATH_A] =
891 						rtldm->swing_idx_ofdm[0];
892 		rtldm->thermalvalue = thermalvalue;
893 	}
894 
895 	if (delta_iqk >= IQK_THRESHOLD) {
896 		rtldm->thermalvalue_iqk = thermalvalue;
897 		rtl8723be_phy_iq_calibrate(hw, false);
898 	}
899 
900 	rtldm->txpowercount = 0;
901 	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "end\n");
902 
903 }
904 
905 void rtl8723be_dm_check_txpower_tracking(struct ieee80211_hw *hw)
906 {
907 	struct rtl_priv *rtlpriv = rtl_priv(hw);
908 
909 	if (!rtlpriv->dm.txpower_tracking)
910 		return;
911 
912 	if (!rtlpriv->dm.tm_trigger) {
913 		rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, BIT(17) | BIT(16),
914 			      0x03);
915 		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
916 			 "Trigger 8723be Thermal Meter!!\n");
917 		rtlpriv->dm.tm_trigger = 1;
918 		return;
919 	} else {
920 		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
921 			 "Schedule TxPowerTracking !!\n");
922 		rtl8723be_dm_txpower_tracking_callback_thermalmeter(hw);
923 		rtlpriv->dm.tm_trigger = 0;
924 	}
925 }
926 
927 static void rtl8723be_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
928 {
929 	struct rtl_priv *rtlpriv = rtl_priv(hw);
930 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
931 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
932 	struct rate_adaptive *p_ra = &rtlpriv->ra;
933 	u32 low_rssithresh_for_ra = p_ra->low2high_rssi_thresh_for_ra40m;
934 	u32 high_rssithresh_for_ra = p_ra->high_rssi_thresh_for_ra;
935 	u8 go_up_gap = 5;
936 	struct ieee80211_sta *sta = NULL;
937 
938 	if (is_hal_stop(rtlhal)) {
939 		RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
940 			 "driver is going to unload\n");
941 		return;
942 	}
943 
944 	if (!rtlpriv->dm.useramask) {
945 		RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
946 			 "driver does not control rate adaptive mask\n");
947 		return;
948 	}
949 
950 	if (mac->link_state == MAC80211_LINKED &&
951 		mac->opmode == NL80211_IFTYPE_STATION) {
952 		switch (p_ra->pre_ratr_state) {
953 		case DM_RATR_STA_MIDDLE:
954 			high_rssithresh_for_ra += go_up_gap;
955 			break;
956 		case DM_RATR_STA_LOW:
957 			high_rssithresh_for_ra += go_up_gap;
958 			low_rssithresh_for_ra += go_up_gap;
959 			break;
960 		default:
961 			break;
962 		}
963 
964 		if (rtlpriv->dm.undec_sm_pwdb >
965 		    (long)high_rssithresh_for_ra)
966 			p_ra->ratr_state = DM_RATR_STA_HIGH;
967 		else if (rtlpriv->dm.undec_sm_pwdb >
968 			 (long)low_rssithresh_for_ra)
969 			p_ra->ratr_state = DM_RATR_STA_MIDDLE;
970 		else
971 			p_ra->ratr_state = DM_RATR_STA_LOW;
972 
973 		if (p_ra->pre_ratr_state != p_ra->ratr_state) {
974 			RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
975 				 "RSSI = %ld\n",
976 				 rtlpriv->dm.undec_sm_pwdb);
977 			RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
978 				 "RSSI_LEVEL = %d\n", p_ra->ratr_state);
979 			RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
980 				 "PreState = %d, CurState = %d\n",
981 				  p_ra->pre_ratr_state, p_ra->ratr_state);
982 
983 			rcu_read_lock();
984 			sta = rtl_find_sta(hw, mac->bssid);
985 			if (sta)
986 				rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
987 							   p_ra->ratr_state);
988 			rcu_read_unlock();
989 
990 			p_ra->pre_ratr_state = p_ra->ratr_state;
991 		}
992 	}
993 }
994 
995 static bool rtl8723be_dm_is_edca_turbo_disable(struct ieee80211_hw *hw)
996 {
997 	struct rtl_priv *rtlpriv = rtl_priv(hw);
998 
999 	if (rtlpriv->mac80211.mode == WIRELESS_MODE_B)
1000 		return true;
1001 
1002 	return false;
1003 }
1004 
1005 static void rtl8723be_dm_check_edca_turbo(struct ieee80211_hw *hw)
1006 {
1007 	struct rtl_priv *rtlpriv = rtl_priv(hw);
1008 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
1009 
1010 	static u64 last_txok_cnt;
1011 	static u64 last_rxok_cnt;
1012 	u64 cur_txok_cnt = 0;
1013 	u64 cur_rxok_cnt = 0;
1014 	u32 edca_be_ul = 0x6ea42b;
1015 	u32 edca_be_dl = 0x6ea42b;/*not sure*/
1016 	u32 edca_be = 0x5ea42b;
1017 	u32 iot_peer = 0;
1018 	bool b_is_cur_rdlstate;
1019 	bool b_last_is_cur_rdlstate = false;
1020 	bool b_bias_on_rx = false;
1021 	bool b_edca_turbo_on = false;
1022 
1023 	b_last_is_cur_rdlstate = rtlpriv->dm.is_cur_rdlstate;
1024 
1025 	cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt;
1026 	cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt;
1027 
1028 	iot_peer = rtlpriv->mac80211.vendor;
1029 	b_bias_on_rx = (iot_peer == PEER_RAL || iot_peer == PEER_ATH) ?
1030 		       true : false;
1031 	b_edca_turbo_on = ((!rtlpriv->dm.is_any_nonbepkts) &&
1032 			   (!rtlpriv->dm.disable_framebursting)) ?
1033 			   true : false;
1034 
1035 	if ((iot_peer == PEER_CISCO) &&
1036 	    (mac->mode == WIRELESS_MODE_N_24G)) {
1037 		edca_be_dl = edca_setting_dl[iot_peer];
1038 		edca_be_ul = edca_setting_ul[iot_peer];
1039 	}
1040 	if (rtl8723be_dm_is_edca_turbo_disable(hw))
1041 		goto exit;
1042 
1043 	if (b_edca_turbo_on) {
1044 		if (b_bias_on_rx)
1045 			b_is_cur_rdlstate = (cur_txok_cnt > cur_rxok_cnt * 4) ?
1046 					    false : true;
1047 		else
1048 			b_is_cur_rdlstate = (cur_rxok_cnt > cur_txok_cnt * 4) ?
1049 					    true : false;
1050 
1051 		edca_be = (b_is_cur_rdlstate) ? edca_be_dl : edca_be_ul;
1052 		rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, edca_be);
1053 		rtlpriv->dm.is_cur_rdlstate = b_is_cur_rdlstate;
1054 		rtlpriv->dm.current_turbo_edca = true;
1055 	} else {
1056 		if (rtlpriv->dm.current_turbo_edca) {
1057 			u8 tmp = AC0_BE;
1058 			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
1059 						      (u8 *)(&tmp));
1060 		}
1061 		rtlpriv->dm.current_turbo_edca = false;
1062 	}
1063 
1064 exit:
1065 	rtlpriv->dm.is_any_nonbepkts = false;
1066 	last_txok_cnt = rtlpriv->stats.txbytesunicast;
1067 	last_rxok_cnt = rtlpriv->stats.rxbytesunicast;
1068 }
1069 
1070 static void rtl8723be_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
1071 {
1072 	struct rtl_priv *rtlpriv = rtl_priv(hw);
1073 	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
1074 	u8 cur_cck_cca_thresh;
1075 
1076 	if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) {
1077 		if (dm_digtable->rssi_val_min > 25) {
1078 			cur_cck_cca_thresh = 0xcd;
1079 		} else if ((dm_digtable->rssi_val_min <= 25) &&
1080 			   (dm_digtable->rssi_val_min > 10)) {
1081 			cur_cck_cca_thresh = 0x83;
1082 		} else {
1083 			if (rtlpriv->falsealm_cnt.cnt_cck_fail > 1000)
1084 				cur_cck_cca_thresh = 0x83;
1085 			else
1086 				cur_cck_cca_thresh = 0x40;
1087 		}
1088 	} else {
1089 		if (rtlpriv->falsealm_cnt.cnt_cck_fail > 1000)
1090 			cur_cck_cca_thresh = 0x83;
1091 		else
1092 			cur_cck_cca_thresh = 0x40;
1093 	}
1094 
1095 	if (dm_digtable->cur_cck_cca_thres != cur_cck_cca_thresh)
1096 		rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, cur_cck_cca_thresh);
1097 
1098 	dm_digtable->pre_cck_cca_thres = dm_digtable->cur_cck_cca_thres;
1099 	dm_digtable->cur_cck_cca_thres = cur_cck_cca_thresh;
1100 	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
1101 		 "CCK cca thresh hold =%x\n", dm_digtable->cur_cck_cca_thres);
1102 }
1103 
1104 static void rtl8723be_dm_dynamic_edcca(struct ieee80211_hw *hw)
1105 {
1106 	struct rtl_priv *rtlpriv = rtl_priv(hw);
1107 	u8 reg_c50, reg_c58;
1108 	bool fw_current_in_ps_mode = false;
1109 
1110 	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
1111 				      (u8 *)(&fw_current_in_ps_mode));
1112 	if (fw_current_in_ps_mode)
1113 		return;
1114 
1115 	reg_c50 = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0);
1116 	reg_c58 = rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0);
1117 
1118 	if (reg_c50 > 0x28 && reg_c58 > 0x28) {
1119 		if (!rtlpriv->rtlhal.pre_edcca_enable) {
1120 			rtl_write_byte(rtlpriv, ROFDM0_ECCATHRESHOLD, 0x03);
1121 			rtl_write_byte(rtlpriv, ROFDM0_ECCATHRESHOLD + 2, 0x00);
1122 		}
1123 	} else if (reg_c50 < 0x25 && reg_c58 < 0x25) {
1124 		if (rtlpriv->rtlhal.pre_edcca_enable) {
1125 			rtl_write_byte(rtlpriv, ROFDM0_ECCATHRESHOLD, 0x7f);
1126 			rtl_write_byte(rtlpriv, ROFDM0_ECCATHRESHOLD + 2, 0x7f);
1127 		}
1128 	}
1129 }
1130 
1131 static void rtl8723be_dm_dynamic_atc_switch(struct ieee80211_hw *hw)
1132 {
1133 	struct rtl_priv *rtlpriv = rtl_priv(hw);
1134 	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
1135 	u8 crystal_cap;
1136 	u32 packet_count;
1137 	int cfo_khz_a, cfo_khz_b, cfo_ave = 0, adjust_xtal = 0;
1138 	int cfo_ave_diff;
1139 
1140 	if (rtlpriv->mac80211.link_state < MAC80211_LINKED) {
1141 		if (rtldm->atc_status == ATC_STATUS_OFF) {
1142 			rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(11),
1143 				      ATC_STATUS_ON);
1144 			rtldm->atc_status = ATC_STATUS_ON;
1145 		}
1146 		if (rtlpriv->cfg->ops->get_btc_status()) {
1147 			if (!rtlpriv->btcoexist.btc_ops->btc_is_bt_disabled(rtlpriv)) {
1148 				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD,
1149 					 "odm_DynamicATCSwitch(): Disable CFO tracking for BT!!\n");
1150 				return;
1151 			}
1152 		}
1153 
1154 		if (rtldm->crystal_cap != rtlpriv->efuse.crystalcap) {
1155 			rtldm->crystal_cap = rtlpriv->efuse.crystalcap;
1156 			crystal_cap = rtldm->crystal_cap & 0x3f;
1157 			rtl_set_bbreg(hw, REG_MAC_PHY_CTRL, 0xFFF000,
1158 				      (crystal_cap | (crystal_cap << 6)));
1159 		}
1160 	} else {
1161 		cfo_khz_a = (int)(rtldm->cfo_tail[0] * 3125) / 1280;
1162 		cfo_khz_b = (int)(rtldm->cfo_tail[1] * 3125) / 1280;
1163 		packet_count = rtldm->packet_count;
1164 
1165 		if (packet_count == rtldm->packet_count_pre)
1166 			return;
1167 
1168 		rtldm->packet_count_pre = packet_count;
1169 
1170 		if (rtlpriv->phy.rf_type == RF_1T1R)
1171 			cfo_ave = cfo_khz_a;
1172 		else
1173 			cfo_ave = (int)(cfo_khz_a + cfo_khz_b) >> 1;
1174 
1175 		cfo_ave_diff = (rtldm->cfo_ave_pre >= cfo_ave) ?
1176 			       (rtldm->cfo_ave_pre - cfo_ave) :
1177 			       (cfo_ave - rtldm->cfo_ave_pre);
1178 
1179 		if (cfo_ave_diff > 20 && rtldm->large_cfo_hit == 0) {
1180 			rtldm->large_cfo_hit = 1;
1181 			return;
1182 		} else
1183 			rtldm->large_cfo_hit = 0;
1184 
1185 		rtldm->cfo_ave_pre = cfo_ave;
1186 
1187 		if (cfo_ave >= -rtldm->cfo_threshold &&
1188 		    cfo_ave <= rtldm->cfo_threshold && rtldm->is_freeze == 0) {
1189 			if (rtldm->cfo_threshold == CFO_THRESHOLD_XTAL) {
1190 				rtldm->cfo_threshold = CFO_THRESHOLD_XTAL + 10;
1191 				rtldm->is_freeze = 1;
1192 			} else {
1193 				rtldm->cfo_threshold = CFO_THRESHOLD_XTAL;
1194 			}
1195 		}
1196 
1197 		if (cfo_ave > rtldm->cfo_threshold && rtldm->crystal_cap < 0x3f)
1198 			adjust_xtal = ((cfo_ave - CFO_THRESHOLD_XTAL) >> 1) + 1;
1199 		else if ((cfo_ave < -rtlpriv->dm.cfo_threshold) &&
1200 					rtlpriv->dm.crystal_cap > 0)
1201 			adjust_xtal = ((cfo_ave + CFO_THRESHOLD_XTAL) >> 1) - 1;
1202 
1203 		if (adjust_xtal != 0) {
1204 			rtldm->is_freeze = 0;
1205 			rtldm->crystal_cap += adjust_xtal;
1206 
1207 			if (rtldm->crystal_cap > 0x3f)
1208 				rtldm->crystal_cap = 0x3f;
1209 			else if (rtldm->crystal_cap < 0)
1210 				rtldm->crystal_cap = 0;
1211 
1212 			crystal_cap = rtldm->crystal_cap & 0x3f;
1213 			rtl_set_bbreg(hw, REG_MAC_PHY_CTRL, 0xFFF000,
1214 				      (crystal_cap | (crystal_cap << 6)));
1215 		}
1216 
1217 		if (cfo_ave < CFO_THRESHOLD_ATC &&
1218 		    cfo_ave > -CFO_THRESHOLD_ATC) {
1219 			if (rtldm->atc_status == ATC_STATUS_ON) {
1220 				rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(11),
1221 					      ATC_STATUS_OFF);
1222 				rtldm->atc_status = ATC_STATUS_OFF;
1223 			}
1224 		} else {
1225 			if (rtldm->atc_status == ATC_STATUS_OFF) {
1226 				rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(11),
1227 					      ATC_STATUS_ON);
1228 				rtldm->atc_status = ATC_STATUS_ON;
1229 			}
1230 		}
1231 	}
1232 }
1233 
1234 static void rtl8723be_dm_common_info_self_update(struct ieee80211_hw *hw)
1235 {
1236 	struct rtl_priv *rtlpriv = rtl_priv(hw);
1237 	u8 cnt = 0;
1238 	struct rtl_sta_info *drv_priv;
1239 
1240 	rtlpriv->dm.one_entry_only = false;
1241 
1242 	if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_STATION &&
1243 		rtlpriv->mac80211.link_state >= MAC80211_LINKED) {
1244 		rtlpriv->dm.one_entry_only = true;
1245 		return;
1246 	}
1247 
1248 	if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP ||
1249 		rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC ||
1250 		rtlpriv->mac80211.opmode == NL80211_IFTYPE_MESH_POINT) {
1251 		spin_lock_bh(&rtlpriv->locks.entry_list_lock);
1252 		list_for_each_entry(drv_priv, &rtlpriv->entry_list, list) {
1253 			cnt++;
1254 		}
1255 		spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
1256 
1257 		if (cnt == 1)
1258 			rtlpriv->dm.one_entry_only = true;
1259 	}
1260 }
1261 
1262 void rtl8723be_dm_watchdog(struct ieee80211_hw *hw)
1263 {
1264 	struct rtl_priv *rtlpriv = rtl_priv(hw);
1265 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
1266 	bool fw_current_inpsmode = false;
1267 	bool fw_ps_awake = true;
1268 
1269 	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
1270 				      (u8 *)(&fw_current_inpsmode));
1271 
1272 	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FWLPS_RF_ON,
1273 				      (u8 *)(&fw_ps_awake));
1274 
1275 	if (ppsc->p2p_ps_info.p2p_ps_mode)
1276 		fw_ps_awake = false;
1277 
1278 	spin_lock(&rtlpriv->locks.rf_ps_lock);
1279 	if ((ppsc->rfpwr_state == ERFON) &&
1280 		((!fw_current_inpsmode) && fw_ps_awake) &&
1281 		(!ppsc->rfchange_inprogress)) {
1282 		rtl8723be_dm_common_info_self_update(hw);
1283 		rtl8723be_dm_false_alarm_counter_statistics(hw);
1284 		rtl8723be_dm_check_rssi_monitor(hw);
1285 		rtl8723be_dm_dig(hw);
1286 		rtl8723be_dm_dynamic_edcca(hw);
1287 		rtl8723be_dm_cck_packet_detection_thresh(hw);
1288 		rtl8723be_dm_refresh_rate_adaptive_mask(hw);
1289 		rtl8723be_dm_check_edca_turbo(hw);
1290 		rtl8723be_dm_dynamic_atc_switch(hw);
1291 		rtl8723be_dm_check_txpower_tracking(hw);
1292 		rtl8723be_dm_dynamic_txpower(hw);
1293 	}
1294 	spin_unlock(&rtlpriv->locks.rf_ps_lock);
1295 	rtlpriv->dm.dbginfo.num_qry_beacon_pkt = 0;
1296 }
1297