1 | // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause |
2 | /* Copyright(c) 2018-2019 Realtek Corporation |
3 | */ |
4 | |
5 | #include "main.h" |
6 | #include "coex.h" |
7 | #include "fw.h" |
8 | #include "ps.h" |
9 | #include "debug.h" |
10 | #include "reg.h" |
11 | #include "phy.h" |
12 | |
13 | static u8 (struct rtw_dev *rtwdev, u8 pre_state, |
14 | u8 , u8 ) |
15 | { |
16 | const struct rtw_chip_info *chip = rtwdev->chip; |
17 | u8 tol = chip->rssi_tolerance; |
18 | u8 next_state; |
19 | |
20 | if (pre_state == COEX_RSSI_STATE_LOW || |
21 | pre_state == COEX_RSSI_STATE_STAY_LOW) { |
22 | if (rssi >= (rssi_thresh + tol)) |
23 | next_state = COEX_RSSI_STATE_HIGH; |
24 | else |
25 | next_state = COEX_RSSI_STATE_STAY_LOW; |
26 | } else { |
27 | if (rssi < rssi_thresh) |
28 | next_state = COEX_RSSI_STATE_LOW; |
29 | else |
30 | next_state = COEX_RSSI_STATE_STAY_HIGH; |
31 | } |
32 | |
33 | return next_state; |
34 | } |
35 | |
36 | static void rtw_coex_limited_tx(struct rtw_dev *rtwdev, |
37 | bool tx_limit_en, bool ampdu_limit_en) |
38 | { |
39 | const struct rtw_chip_info *chip = rtwdev->chip; |
40 | struct rtw_coex *coex = &rtwdev->coex; |
41 | struct rtw_coex_stat *coex_stat = &coex->stat; |
42 | u8 num_of_active_port = 1; |
43 | |
44 | if (!chip->scbd_support) |
45 | return; |
46 | |
47 | /* force max tx retry limit = 8 */ |
48 | if (coex_stat->wl_tx_limit_en == tx_limit_en && |
49 | coex_stat->wl_ampdu_limit_en == ampdu_limit_en) |
50 | return; |
51 | |
52 | if (!coex_stat->wl_tx_limit_en) { |
53 | coex_stat->darfrc = rtw_read32(rtwdev, REG_DARFRC); |
54 | coex_stat->darfrch = rtw_read32(rtwdev, REG_DARFRCH); |
55 | coex_stat->retry_limit = rtw_read16(rtwdev, REG_RETRY_LIMIT); |
56 | } |
57 | |
58 | if (!coex_stat->wl_ampdu_limit_en) |
59 | coex_stat->ampdu_max_time = |
60 | rtw_read8(rtwdev, REG_AMPDU_MAX_TIME_V1); |
61 | |
62 | coex_stat->wl_tx_limit_en = tx_limit_en; |
63 | coex_stat->wl_ampdu_limit_en = ampdu_limit_en; |
64 | |
65 | if (tx_limit_en) { |
66 | /* set BT polluted packet on for tx rate adaptive, |
67 | * not including tx retry broken by PTA |
68 | */ |
69 | rtw_write8_set(rtwdev, REG_TX_HANG_CTRL, BIT_EN_GNT_BT_AWAKE); |
70 | |
71 | /* set queue life time to avoid can't reach tx retry limit |
72 | * if tx is always broken by GNT_BT |
73 | */ |
74 | if (num_of_active_port <= 1) |
75 | rtw_write8_set(rtwdev, REG_LIFETIME_EN, bit: 0xf); |
76 | rtw_write16(rtwdev, REG_RETRY_LIMIT, val: 0x0808); |
77 | |
78 | /* auto rate fallback step within 8 retries */ |
79 | rtw_write32(rtwdev, REG_DARFRC, val: 0x1000000); |
80 | rtw_write32(rtwdev, REG_DARFRCH, val: 0x4030201); |
81 | } else { |
82 | rtw_write8_clr(rtwdev, REG_TX_HANG_CTRL, BIT_EN_GNT_BT_AWAKE); |
83 | rtw_write8_clr(rtwdev, REG_LIFETIME_EN, bit: 0xf); |
84 | |
85 | rtw_write16(rtwdev, REG_RETRY_LIMIT, val: coex_stat->retry_limit); |
86 | rtw_write32(rtwdev, REG_DARFRC, val: coex_stat->darfrc); |
87 | rtw_write32(rtwdev, REG_DARFRCH, val: coex_stat->darfrch); |
88 | } |
89 | |
90 | if (ampdu_limit_en) |
91 | rtw_write8(rtwdev, REG_AMPDU_MAX_TIME_V1, val: 0x20); |
92 | else |
93 | rtw_write8(rtwdev, REG_AMPDU_MAX_TIME_V1, |
94 | val: coex_stat->ampdu_max_time); |
95 | } |
96 | |
97 | static void rtw_coex_limited_wl(struct rtw_dev *rtwdev) |
98 | { |
99 | struct rtw_coex *coex = &rtwdev->coex; |
100 | struct rtw_coex_dm *coex_dm = &coex->dm; |
101 | bool tx_limit = false; |
102 | bool tx_agg_ctrl = false; |
103 | |
104 | if (!coex->under_5g && coex_dm->bt_status != COEX_BTSTATUS_NCON_IDLE) { |
105 | tx_limit = true; |
106 | tx_agg_ctrl = true; |
107 | } |
108 | |
109 | rtw_coex_limited_tx(rtwdev, tx_limit_en: tx_limit, ampdu_limit_en: tx_agg_ctrl); |
110 | } |
111 | |
112 | static bool rtw_coex_freerun_check(struct rtw_dev *rtwdev) |
113 | { |
114 | struct rtw_coex *coex = &rtwdev->coex; |
115 | struct rtw_coex_dm *coex_dm = &coex->dm; |
116 | struct rtw_coex_stat *coex_stat = &coex->stat; |
117 | struct rtw_efuse *efuse = &rtwdev->efuse; |
118 | u8 ; |
119 | u8 ant_distance = 10; |
120 | |
121 | if (coex_stat->bt_disabled) |
122 | return false; |
123 | |
124 | if (efuse->share_ant || ant_distance <= 5 || !coex_stat->wl_gl_busy) |
125 | return false; |
126 | |
127 | if (ant_distance >= 40 || coex_stat->bt_hid_pair_num >= 2) |
128 | return true; |
129 | |
130 | /* ant_distance = 5 ~ 40 */ |
131 | if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1]) && |
132 | COEX_RSSI_HIGH(coex_dm->bt_rssi_state[0])) |
133 | return true; |
134 | |
135 | if (coex_stat->wl_tput_dir == COEX_WL_TPUT_TX) |
136 | bt_rssi = coex_dm->bt_rssi_state[0]; |
137 | else |
138 | bt_rssi = coex_dm->bt_rssi_state[1]; |
139 | |
140 | if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[3]) && |
141 | COEX_RSSI_HIGH(bt_rssi) && |
142 | coex_stat->cnt_wl[COEX_CNT_WL_SCANAP] <= 5) |
143 | return true; |
144 | |
145 | return false; |
146 | } |
147 | |
148 | static void rtw_coex_wl_slot_extend(struct rtw_dev *rtwdev, bool enable) |
149 | { |
150 | struct rtw_coex *coex = &rtwdev->coex; |
151 | struct rtw_coex_stat *coex_stat = &coex->stat; |
152 | u8 para[6] = {0}; |
153 | |
154 | para[0] = COEX_H2C69_WL_LEAKAP; |
155 | para[1] = PARA1_H2C69_DIS_5MS; |
156 | |
157 | if (enable) |
158 | para[1] = PARA1_H2C69_EN_5MS; |
159 | else |
160 | coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] = 0; |
161 | |
162 | coex_stat->wl_slot_extend = enable; |
163 | rtw_fw_bt_wifi_control(rtwdev, op_code: para[0], data: ¶[1]); |
164 | } |
165 | |
166 | static void rtw_coex_wl_ccklock_action(struct rtw_dev *rtwdev) |
167 | { |
168 | struct rtw_coex *coex = &rtwdev->coex; |
169 | struct rtw_coex_stat *coex_stat = &coex->stat; |
170 | |
171 | if (coex->manual_control || coex->stop_dm) |
172 | return; |
173 | |
174 | |
175 | if (coex_stat->tdma_timer_base == 3 && coex_stat->wl_slot_extend) { |
176 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
177 | fmt: "[BTCoex], set h2c 0x69 opcode 12 to turn off 5ms WL slot extend!!\n" ); |
178 | rtw_coex_wl_slot_extend(rtwdev, enable: false); |
179 | return; |
180 | } |
181 | |
182 | if (coex_stat->wl_slot_extend && coex_stat->wl_force_lps_ctrl && |
183 | !coex_stat->wl_cck_lock_ever) { |
184 | if (coex_stat->wl_fw_dbg_info[7] <= 5) |
185 | coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND]++; |
186 | else |
187 | coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] = 0; |
188 | |
189 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
190 | fmt: "[BTCoex], 5ms WL slot extend cnt = %d!!\n" , |
191 | coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND]); |
192 | |
193 | if (coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] == 7) { |
194 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
195 | fmt: "[BTCoex], set h2c 0x69 opcode 12 to turn off 5ms WL slot extend!!\n" ); |
196 | rtw_coex_wl_slot_extend(rtwdev, enable: false); |
197 | } |
198 | } else if (!coex_stat->wl_slot_extend && coex_stat->wl_cck_lock) { |
199 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
200 | fmt: "[BTCoex], set h2c 0x69 opcode 12 to turn on 5ms WL slot extend!!\n" ); |
201 | |
202 | rtw_coex_wl_slot_extend(rtwdev, enable: true); |
203 | } |
204 | } |
205 | |
206 | static void rtw_coex_wl_ccklock_detect(struct rtw_dev *rtwdev) |
207 | { |
208 | struct rtw_coex *coex = &rtwdev->coex; |
209 | struct rtw_coex_stat *coex_stat = &coex->stat; |
210 | struct rtw_coex_dm *coex_dm = &coex->dm; |
211 | |
212 | bool is_cck_lock_rate = false; |
213 | |
214 | if (coex_stat->wl_coex_mode != COEX_WLINK_2G1PORT && |
215 | coex_stat->wl_coex_mode != COEX_WLINK_2GFREE) |
216 | return; |
217 | |
218 | if (coex_dm->bt_status == COEX_BTSTATUS_INQ_PAGE || |
219 | coex_stat->bt_setup_link) { |
220 | coex_stat->wl_cck_lock = false; |
221 | coex_stat->wl_cck_lock_pre = false; |
222 | return; |
223 | } |
224 | |
225 | if (coex_stat->wl_rx_rate <= COEX_CCK_2 || |
226 | coex_stat->wl_rts_rx_rate <= COEX_CCK_2) |
227 | is_cck_lock_rate = true; |
228 | |
229 | if (coex_stat->wl_connected && coex_stat->wl_gl_busy && |
230 | COEX_RSSI_HIGH(coex_dm->wl_rssi_state[3]) && |
231 | (coex_dm->bt_status == COEX_BTSTATUS_ACL_BUSY || |
232 | coex_dm->bt_status == COEX_BTSTATUS_ACL_SCO_BUSY || |
233 | coex_dm->bt_status == COEX_BTSTATUS_SCO_BUSY)) { |
234 | if (is_cck_lock_rate) { |
235 | coex_stat->wl_cck_lock = true; |
236 | |
237 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
238 | fmt: "[BTCoex], cck locking...\n" ); |
239 | |
240 | } else { |
241 | coex_stat->wl_cck_lock = false; |
242 | |
243 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
244 | fmt: "[BTCoex], cck unlock...\n" ); |
245 | } |
246 | } else { |
247 | coex_stat->wl_cck_lock = false; |
248 | } |
249 | |
250 | /* CCK lock identification */ |
251 | if (coex_stat->wl_cck_lock && !coex_stat->wl_cck_lock_pre) |
252 | ieee80211_queue_delayed_work(hw: rtwdev->hw, dwork: &coex->wl_ccklock_work, |
253 | delay: 3 * HZ); |
254 | |
255 | coex_stat->wl_cck_lock_pre = coex_stat->wl_cck_lock; |
256 | } |
257 | |
258 | static void rtw_coex_wl_noisy_detect(struct rtw_dev *rtwdev) |
259 | { |
260 | struct rtw_coex *coex = &rtwdev->coex; |
261 | struct rtw_coex_stat *coex_stat = &coex->stat; |
262 | struct rtw_dm_info *dm_info = &rtwdev->dm_info; |
263 | u32 cnt_cck; |
264 | bool wl_cck_lock = false; |
265 | |
266 | /* wifi noisy environment identification */ |
267 | cnt_cck = dm_info->cck_ok_cnt + dm_info->cck_err_cnt; |
268 | |
269 | if (!coex_stat->wl_gl_busy && !wl_cck_lock) { |
270 | if (cnt_cck > 250) { |
271 | if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] < 5) |
272 | coex_stat->cnt_wl[COEX_CNT_WL_NOISY2]++; |
273 | |
274 | if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] == 5) { |
275 | coex_stat->cnt_wl[COEX_CNT_WL_NOISY0] = 0; |
276 | coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] = 0; |
277 | } |
278 | } else if (cnt_cck < 100) { |
279 | if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY0] < 5) |
280 | coex_stat->cnt_wl[COEX_CNT_WL_NOISY0]++; |
281 | |
282 | if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY0] == 5) { |
283 | coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] = 0; |
284 | coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] = 0; |
285 | } |
286 | } else { |
287 | if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] < 5) |
288 | coex_stat->cnt_wl[COEX_CNT_WL_NOISY1]++; |
289 | |
290 | if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] == 5) { |
291 | coex_stat->cnt_wl[COEX_CNT_WL_NOISY0] = 0; |
292 | coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] = 0; |
293 | } |
294 | } |
295 | |
296 | if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] == 5) |
297 | coex_stat->wl_noisy_level = 2; |
298 | else if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] == 5) |
299 | coex_stat->wl_noisy_level = 1; |
300 | else |
301 | coex_stat->wl_noisy_level = 0; |
302 | |
303 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], wl_noisy_level = %d\n" , |
304 | coex_stat->wl_noisy_level); |
305 | } |
306 | } |
307 | |
308 | static void rtw_coex_tdma_timer_base(struct rtw_dev *rtwdev, u8 type) |
309 | { |
310 | struct rtw_coex *coex = &rtwdev->coex; |
311 | struct rtw_coex_stat *coex_stat = &coex->stat; |
312 | u8 para[2] = {0}; |
313 | u8 times; |
314 | u16 tbtt_interval = coex_stat->wl_beacon_interval; |
315 | |
316 | if (coex_stat->tdma_timer_base == type) |
317 | return; |
318 | |
319 | coex_stat->tdma_timer_base = type; |
320 | |
321 | para[0] = COEX_H2C69_TDMA_SLOT; |
322 | |
323 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], tbtt_interval = %d\n" , |
324 | tbtt_interval); |
325 | |
326 | if (type == TDMA_TIMER_TYPE_4SLOT && tbtt_interval < 120) { |
327 | para[1] = PARA1_H2C69_TDMA_4SLOT; /* 4-slot */ |
328 | } else if (tbtt_interval < 80 && tbtt_interval > 0) { |
329 | times = 100 / tbtt_interval; |
330 | if (100 % tbtt_interval != 0) |
331 | times++; |
332 | |
333 | para[1] = FIELD_PREP(PARA1_H2C69_TBTT_TIMES, times); |
334 | } else if (tbtt_interval >= 180) { |
335 | times = tbtt_interval / 100; |
336 | if (tbtt_interval % 100 <= 80) |
337 | times--; |
338 | |
339 | para[1] = FIELD_PREP(PARA1_H2C69_TBTT_TIMES, times) | |
340 | FIELD_PREP(PARA1_H2C69_TBTT_DIV100, 1); |
341 | } else { |
342 | para[1] = PARA1_H2C69_TDMA_2SLOT; |
343 | } |
344 | |
345 | rtw_fw_bt_wifi_control(rtwdev, op_code: para[0], data: ¶[1]); |
346 | |
347 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s(): h2c_0x69 = 0x%x\n" , |
348 | __func__, para[1]); |
349 | |
350 | /* no 5ms_wl_slot_extend for 4-slot mode */ |
351 | if (coex_stat->tdma_timer_base == 3) |
352 | rtw_coex_wl_ccklock_action(rtwdev); |
353 | } |
354 | |
355 | static void rtw_coex_set_wl_pri_mask(struct rtw_dev *rtwdev, u8 bitmap, |
356 | u8 data) |
357 | { |
358 | u32 addr; |
359 | |
360 | addr = REG_BT_COEX_TABLE_H + (bitmap / 8); |
361 | bitmap = bitmap % 8; |
362 | |
363 | rtw_write8_mask(rtwdev, addr, BIT(bitmap), data); |
364 | } |
365 | |
366 | void rtw_coex_write_scbd(struct rtw_dev *rtwdev, u16 bitpos, bool set) |
367 | { |
368 | const struct rtw_chip_info *chip = rtwdev->chip; |
369 | struct rtw_coex *coex = &rtwdev->coex; |
370 | struct rtw_coex_stat *coex_stat = &coex->stat; |
371 | u16 val = 0x2; |
372 | |
373 | if (!chip->scbd_support) |
374 | return; |
375 | |
376 | val |= coex_stat->score_board; |
377 | |
378 | /* for 8822b, scbd[10] is CQDDR on |
379 | * for 8822c, scbd[10] is no fix 2M |
380 | */ |
381 | if (!chip->new_scbd10_def && (bitpos & COEX_SCBD_FIX2M)) { |
382 | if (set) |
383 | val &= ~COEX_SCBD_FIX2M; |
384 | else |
385 | val |= COEX_SCBD_FIX2M; |
386 | } else { |
387 | if (set) |
388 | val |= bitpos; |
389 | else |
390 | val &= ~bitpos; |
391 | } |
392 | |
393 | if (val != coex_stat->score_board) { |
394 | coex_stat->score_board = val; |
395 | val |= BIT_BT_INT_EN; |
396 | rtw_write16(rtwdev, REG_WIFI_BT_INFO, val); |
397 | } |
398 | } |
399 | EXPORT_SYMBOL(rtw_coex_write_scbd); |
400 | |
401 | static u16 rtw_coex_read_scbd(struct rtw_dev *rtwdev) |
402 | { |
403 | const struct rtw_chip_info *chip = rtwdev->chip; |
404 | |
405 | if (!chip->scbd_support) |
406 | return 0; |
407 | |
408 | return (rtw_read16(rtwdev, REG_WIFI_BT_INFO)) & ~(BIT_BT_INT_EN); |
409 | } |
410 | |
411 | static void rtw_coex_check_rfk(struct rtw_dev *rtwdev) |
412 | { |
413 | const struct rtw_chip_info *chip = rtwdev->chip; |
414 | struct rtw_coex *coex = &rtwdev->coex; |
415 | struct rtw_coex_stat *coex_stat = &coex->stat; |
416 | struct rtw_coex_rfe *coex_rfe = &coex->rfe; |
417 | u8 cnt = 0; |
418 | u32 wait_cnt; |
419 | bool btk, wlk; |
420 | |
421 | if (coex_rfe->wlg_at_btg && chip->scbd_support && |
422 | coex_stat->bt_iqk_state != 0xff) { |
423 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
424 | fmt: "[BTCoex], (Before Ant Setup) Delay by IQK\n" ); |
425 | |
426 | wait_cnt = COEX_RFK_TIMEOUT / COEX_MIN_DELAY; |
427 | do { |
428 | /* BT RFK */ |
429 | btk = !!(rtw_coex_read_scbd(rtwdev) & COEX_SCBD_BT_RFK); |
430 | |
431 | /* WL RFK */ |
432 | wlk = !!(rtw_read8(rtwdev, REG_ARFR4) & BIT_WL_RFK); |
433 | |
434 | if (!btk && !wlk) |
435 | break; |
436 | |
437 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
438 | fmt: "[BTCoex], (Before Ant Setup) wlk = %d, btk = %d\n" , |
439 | wlk, btk); |
440 | |
441 | mdelay(COEX_MIN_DELAY); |
442 | } while (++cnt < wait_cnt); |
443 | |
444 | if (cnt >= wait_cnt) |
445 | coex_stat->bt_iqk_state = 0xff; |
446 | } |
447 | } |
448 | |
449 | static void rtw_coex_query_bt_info(struct rtw_dev *rtwdev) |
450 | { |
451 | struct rtw_coex *coex = &rtwdev->coex; |
452 | struct rtw_coex_stat *coex_stat = &coex->stat; |
453 | |
454 | if (coex_stat->bt_disabled) |
455 | return; |
456 | |
457 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
458 | |
459 | rtw_fw_query_bt_info(rtwdev); |
460 | } |
461 | |
462 | static void rtw_coex_gnt_workaround(struct rtw_dev *rtwdev, bool force, u8 mode) |
463 | { |
464 | rtw_coex_set_gnt_fix(rtwdev); |
465 | } |
466 | |
467 | static void rtw_coex_monitor_bt_ctr(struct rtw_dev *rtwdev) |
468 | { |
469 | struct rtw_coex *coex = &rtwdev->coex; |
470 | struct rtw_coex_stat *coex_stat = &coex->stat; |
471 | u32 tmp; |
472 | |
473 | tmp = rtw_read32(rtwdev, REG_BT_ACT_STATISTICS); |
474 | coex_stat->hi_pri_tx = FIELD_GET(MASKLWORD, tmp); |
475 | coex_stat->hi_pri_rx = FIELD_GET(MASKHWORD, tmp); |
476 | |
477 | tmp = rtw_read32(rtwdev, REG_BT_ACT_STATISTICS_1); |
478 | coex_stat->lo_pri_tx = FIELD_GET(MASKLWORD, tmp); |
479 | coex_stat->lo_pri_rx = FIELD_GET(MASKHWORD, tmp); |
480 | |
481 | rtw_write8(rtwdev, REG_BT_COEX_ENH_INTR_CTRL, |
482 | BIT_R_GRANTALL_WLMASK | BIT_STATIS_BT_EN); |
483 | |
484 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
485 | fmt: "[BTCoex], Hi-Pri Rx/Tx: %d/%d, Lo-Pri Rx/Tx: %d/%d\n" , |
486 | coex_stat->hi_pri_rx, coex_stat->hi_pri_tx, |
487 | coex_stat->lo_pri_rx, coex_stat->lo_pri_tx); |
488 | } |
489 | |
490 | static void rtw_coex_monitor_bt_enable(struct rtw_dev *rtwdev) |
491 | { |
492 | const struct rtw_chip_info *chip = rtwdev->chip; |
493 | struct rtw_coex *coex = &rtwdev->coex; |
494 | struct rtw_coex_stat *coex_stat = &coex->stat; |
495 | struct rtw_coex_dm *coex_dm = &coex->dm; |
496 | bool bt_disabled = false; |
497 | u16 score_board; |
498 | |
499 | if (chip->scbd_support) { |
500 | score_board = rtw_coex_read_scbd(rtwdev); |
501 | bt_disabled = !(score_board & COEX_SCBD_ONOFF); |
502 | } |
503 | |
504 | if (coex_stat->bt_disabled != bt_disabled) { |
505 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
506 | fmt: "[BTCoex], BT state changed (%d) -> (%d)\n" , |
507 | coex_stat->bt_disabled, bt_disabled); |
508 | |
509 | coex_stat->bt_disabled = bt_disabled; |
510 | coex_stat->bt_ble_scan_type = 0; |
511 | coex_dm->cur_bt_lna_lvl = 0; |
512 | |
513 | if (!coex_stat->bt_disabled) { |
514 | coex_stat->bt_reenable = true; |
515 | ieee80211_queue_delayed_work(hw: rtwdev->hw, |
516 | dwork: &coex->bt_reenable_work, |
517 | delay: 15 * HZ); |
518 | } else { |
519 | coex_stat->bt_mailbox_reply = false; |
520 | coex_stat->bt_reenable = false; |
521 | } |
522 | } |
523 | } |
524 | |
525 | static void rtw_coex_update_wl_link_info(struct rtw_dev *rtwdev, u8 reason) |
526 | { |
527 | const struct rtw_chip_info *chip = rtwdev->chip; |
528 | struct rtw_coex *coex = &rtwdev->coex; |
529 | struct rtw_coex_stat *coex_stat = &coex->stat; |
530 | struct rtw_coex_dm *coex_dm = &coex->dm; |
531 | struct rtw_traffic_stats *stats = &rtwdev->stats; |
532 | bool is_5G = false; |
533 | bool wl_busy = false; |
534 | bool scan = false, link = false; |
535 | int i; |
536 | u8 ; |
537 | u8 ; |
538 | u8 ; |
539 | |
540 | scan = test_bit(RTW_FLAG_SCANNING, rtwdev->flags); |
541 | coex_stat->wl_connected = !!rtwdev->sta_cnt; |
542 | |
543 | wl_busy = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); |
544 | if (wl_busy != coex_stat->wl_gl_busy) { |
545 | if (wl_busy) |
546 | coex_stat->wl_gl_busy = true; |
547 | else |
548 | ieee80211_queue_delayed_work(hw: rtwdev->hw, |
549 | dwork: &coex->wl_remain_work, |
550 | delay: 12 * HZ); |
551 | } |
552 | |
553 | if (stats->tx_throughput > stats->rx_throughput) |
554 | coex_stat->wl_tput_dir = COEX_WL_TPUT_TX; |
555 | else |
556 | coex_stat->wl_tput_dir = COEX_WL_TPUT_RX; |
557 | |
558 | if (scan || link || reason == COEX_RSN_2GCONSTART || |
559 | reason == COEX_RSN_2GSCANSTART || reason == COEX_RSN_2GSWITCHBAND) |
560 | coex_stat->wl_linkscan_proc = true; |
561 | else |
562 | coex_stat->wl_linkscan_proc = false; |
563 | |
564 | rtw_coex_wl_noisy_detect(rtwdev); |
565 | |
566 | for (i = 0; i < 4; i++) { |
567 | rssi_state = coex_dm->wl_rssi_state[i]; |
568 | rssi_step = chip->wl_rssi_step[i]; |
569 | rssi = rtwdev->dm_info.min_rssi; |
570 | rssi_state = rtw_coex_next_rssi_state(rtwdev, pre_state: rssi_state, |
571 | rssi, rssi_thresh: rssi_step); |
572 | coex_dm->wl_rssi_state[i] = rssi_state; |
573 | } |
574 | |
575 | if (coex_stat->wl_linkscan_proc || coex_stat->wl_hi_pri_task1 || |
576 | coex_stat->wl_hi_pri_task2 || coex_stat->wl_gl_busy) |
577 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_SCAN, true); |
578 | else |
579 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_SCAN, false); |
580 | |
581 | switch (reason) { |
582 | case COEX_RSN_5GSCANSTART: |
583 | case COEX_RSN_5GSWITCHBAND: |
584 | case COEX_RSN_5GCONSTART: |
585 | |
586 | is_5G = true; |
587 | break; |
588 | case COEX_RSN_2GSCANSTART: |
589 | case COEX_RSN_2GSWITCHBAND: |
590 | case COEX_RSN_2GCONSTART: |
591 | |
592 | is_5G = false; |
593 | break; |
594 | default: |
595 | if (rtwdev->hal.current_band_type == RTW_BAND_5G) |
596 | is_5G = true; |
597 | else |
598 | is_5G = false; |
599 | break; |
600 | } |
601 | |
602 | coex->under_5g = is_5G; |
603 | } |
604 | |
605 | static inline u8 *get_payload_from_coex_resp(struct sk_buff *resp) |
606 | { |
607 | struct rtw_c2h_cmd *c2h; |
608 | u32 pkt_offset; |
609 | |
610 | pkt_offset = *((u32 *)resp->cb); |
611 | c2h = (struct rtw_c2h_cmd *)(resp->data + pkt_offset); |
612 | |
613 | return c2h->payload; |
614 | } |
615 | |
616 | void rtw_coex_info_response(struct rtw_dev *rtwdev, struct sk_buff *skb) |
617 | { |
618 | struct rtw_coex *coex = &rtwdev->coex; |
619 | u8 *payload = get_payload_from_coex_resp(resp: skb); |
620 | |
621 | if (payload[0] != COEX_RESP_ACK_BY_WL_FW) { |
622 | dev_kfree_skb_any(skb); |
623 | return; |
624 | } |
625 | |
626 | skb_queue_tail(list: &coex->queue, newsk: skb); |
627 | wake_up(&coex->wait); |
628 | } |
629 | |
630 | static struct sk_buff *rtw_coex_info_request(struct rtw_dev *rtwdev, |
631 | struct rtw_coex_info_req *req) |
632 | { |
633 | struct rtw_coex *coex = &rtwdev->coex; |
634 | struct sk_buff *skb_resp = NULL; |
635 | |
636 | lockdep_assert_held(&rtwdev->mutex); |
637 | |
638 | rtw_fw_query_bt_mp_info(rtwdev, req); |
639 | |
640 | if (!wait_event_timeout(coex->wait, !skb_queue_empty(&coex->queue), |
641 | COEX_REQUEST_TIMEOUT)) { |
642 | rtw_err(rtwdev, "coex request time out\n" ); |
643 | goto out; |
644 | } |
645 | |
646 | skb_resp = skb_dequeue(list: &coex->queue); |
647 | if (!skb_resp) { |
648 | rtw_err(rtwdev, "failed to get coex info response\n" ); |
649 | goto out; |
650 | } |
651 | |
652 | out: |
653 | return skb_resp; |
654 | } |
655 | |
656 | static bool rtw_coex_get_bt_scan_type(struct rtw_dev *rtwdev, u8 *scan_type) |
657 | { |
658 | struct rtw_coex_info_req req = {0}; |
659 | struct sk_buff *skb; |
660 | u8 *payload; |
661 | |
662 | req.op_code = BT_MP_INFO_OP_SCAN_TYPE; |
663 | skb = rtw_coex_info_request(rtwdev, req: &req); |
664 | if (!skb) |
665 | return false; |
666 | |
667 | payload = get_payload_from_coex_resp(resp: skb); |
668 | *scan_type = GET_COEX_RESP_BT_SCAN_TYPE(payload); |
669 | dev_kfree_skb_any(skb); |
670 | return true; |
671 | } |
672 | |
673 | static bool rtw_coex_set_lna_constrain_level(struct rtw_dev *rtwdev, |
674 | u8 lna_constrain_level) |
675 | { |
676 | struct rtw_coex_info_req req = {0}; |
677 | struct sk_buff *skb; |
678 | |
679 | req.op_code = BT_MP_INFO_OP_LNA_CONSTRAINT; |
680 | req.para1 = lna_constrain_level; |
681 | skb = rtw_coex_info_request(rtwdev, req: &req); |
682 | if (!skb) |
683 | return false; |
684 | |
685 | dev_kfree_skb_any(skb); |
686 | return true; |
687 | } |
688 | |
689 | #define case_BTSTATUS(src) \ |
690 | case COEX_BTSTATUS_##src: return #src |
691 | |
692 | static const char *rtw_coex_get_bt_status_string(u8 bt_status) |
693 | { |
694 | switch (bt_status) { |
695 | case_BTSTATUS(NCON_IDLE); |
696 | case_BTSTATUS(CON_IDLE); |
697 | case_BTSTATUS(INQ_PAGE); |
698 | case_BTSTATUS(ACL_BUSY); |
699 | case_BTSTATUS(SCO_BUSY); |
700 | case_BTSTATUS(ACL_SCO_BUSY); |
701 | default: |
702 | return "Unknown" ; |
703 | } |
704 | } |
705 | |
706 | static void rtw_coex_update_bt_link_info(struct rtw_dev *rtwdev) |
707 | { |
708 | const struct rtw_chip_info *chip = rtwdev->chip; |
709 | struct rtw_coex *coex = &rtwdev->coex; |
710 | struct rtw_coex_stat *coex_stat = &coex->stat; |
711 | struct rtw_coex_dm *coex_dm = &coex->dm; |
712 | u8 i; |
713 | u8 ; |
714 | u8 ; |
715 | u8 ; |
716 | |
717 | /* update wl/bt rssi by btinfo */ |
718 | for (i = 0; i < COEX_RSSI_STEP; i++) { |
719 | rssi_state = coex_dm->bt_rssi_state[i]; |
720 | rssi_step = chip->bt_rssi_step[i]; |
721 | rssi = coex_stat->bt_rssi; |
722 | rssi_state = rtw_coex_next_rssi_state(rtwdev, pre_state: rssi_state, rssi, |
723 | rssi_thresh: rssi_step); |
724 | coex_dm->bt_rssi_state[i] = rssi_state; |
725 | } |
726 | |
727 | if (coex_stat->bt_ble_scan_en && |
728 | coex_stat->cnt_bt[COEX_CNT_BT_INFOUPDATE] % 3 == 0) { |
729 | u8 scan_type; |
730 | |
731 | if (rtw_coex_get_bt_scan_type(rtwdev, scan_type: &scan_type)) { |
732 | coex_stat->bt_ble_scan_type = scan_type; |
733 | if ((coex_stat->bt_ble_scan_type & 0x1) == 0x1) |
734 | coex_stat->bt_init_scan = true; |
735 | else |
736 | coex_stat->bt_init_scan = false; |
737 | } |
738 | } |
739 | |
740 | coex_stat->bt_profile_num = 0; |
741 | |
742 | /* set link exist status */ |
743 | if (!(coex_stat->bt_info_lb2 & COEX_INFO_CONNECTION)) { |
744 | coex_stat->bt_link_exist = false; |
745 | coex_stat->bt_pan_exist = false; |
746 | coex_stat->bt_a2dp_exist = false; |
747 | coex_stat->bt_hid_exist = false; |
748 | coex_stat->bt_hfp_exist = false; |
749 | } else { |
750 | /* connection exists */ |
751 | coex_stat->bt_link_exist = true; |
752 | if (coex_stat->bt_info_lb2 & COEX_INFO_FTP) { |
753 | coex_stat->bt_pan_exist = true; |
754 | coex_stat->bt_profile_num++; |
755 | } else { |
756 | coex_stat->bt_pan_exist = false; |
757 | } |
758 | |
759 | if (coex_stat->bt_info_lb2 & COEX_INFO_A2DP) { |
760 | coex_stat->bt_a2dp_exist = true; |
761 | coex_stat->bt_profile_num++; |
762 | } else { |
763 | coex_stat->bt_a2dp_exist = false; |
764 | } |
765 | |
766 | if (coex_stat->bt_info_lb2 & COEX_INFO_HID) { |
767 | coex_stat->bt_hid_exist = true; |
768 | coex_stat->bt_profile_num++; |
769 | } else { |
770 | coex_stat->bt_hid_exist = false; |
771 | } |
772 | |
773 | if (coex_stat->bt_info_lb2 & COEX_INFO_SCO_ESCO) { |
774 | coex_stat->bt_hfp_exist = true; |
775 | coex_stat->bt_profile_num++; |
776 | } else { |
777 | coex_stat->bt_hfp_exist = false; |
778 | } |
779 | } |
780 | |
781 | if (coex_stat->bt_info_lb2 & COEX_INFO_INQ_PAGE) { |
782 | coex_dm->bt_status = COEX_BTSTATUS_INQ_PAGE; |
783 | } else if (!(coex_stat->bt_info_lb2 & COEX_INFO_CONNECTION)) { |
784 | coex_dm->bt_status = COEX_BTSTATUS_NCON_IDLE; |
785 | coex_stat->bt_multi_link_remain = false; |
786 | } else if (coex_stat->bt_info_lb2 == COEX_INFO_CONNECTION) { |
787 | coex_dm->bt_status = COEX_BTSTATUS_CON_IDLE; |
788 | } else if ((coex_stat->bt_info_lb2 & COEX_INFO_SCO_ESCO) || |
789 | (coex_stat->bt_info_lb2 & COEX_INFO_SCO_BUSY)) { |
790 | if (coex_stat->bt_info_lb2 & COEX_INFO_ACL_BUSY) |
791 | coex_dm->bt_status = COEX_BTSTATUS_ACL_SCO_BUSY; |
792 | else |
793 | coex_dm->bt_status = COEX_BTSTATUS_SCO_BUSY; |
794 | } else if (coex_stat->bt_info_lb2 & COEX_INFO_ACL_BUSY) { |
795 | coex_dm->bt_status = COEX_BTSTATUS_ACL_BUSY; |
796 | } else { |
797 | coex_dm->bt_status = COEX_BTSTATUS_MAX; |
798 | } |
799 | |
800 | coex_stat->cnt_bt[COEX_CNT_BT_INFOUPDATE]++; |
801 | |
802 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s(), %s!!!\n" , __func__, |
803 | rtw_coex_get_bt_status_string(bt_status: coex_dm->bt_status)); |
804 | } |
805 | |
806 | static void rtw_coex_update_wl_ch_info(struct rtw_dev *rtwdev, u8 type) |
807 | { |
808 | const struct rtw_chip_info *chip = rtwdev->chip; |
809 | struct rtw_efuse *efuse = &rtwdev->efuse; |
810 | struct rtw_coex_dm *coex_dm = &rtwdev->coex.dm; |
811 | struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat; |
812 | u8 link = 0; |
813 | u8 center_chan = 0; |
814 | u8 bw; |
815 | int i; |
816 | |
817 | bw = rtwdev->hal.current_band_width; |
818 | |
819 | if (type != COEX_MEDIA_DISCONNECT) |
820 | center_chan = rtwdev->hal.current_channel; |
821 | |
822 | if (center_chan == 0 || |
823 | (efuse->share_ant && center_chan <= 14 && |
824 | coex_stat->wl_coex_mode != COEX_WLINK_2GFREE)) { |
825 | link = 0; |
826 | center_chan = 0; |
827 | bw = 0; |
828 | } else if (center_chan <= 14) { |
829 | link = 0x1; |
830 | |
831 | if (bw == RTW_CHANNEL_WIDTH_40) |
832 | bw = chip->bt_afh_span_bw40; |
833 | else |
834 | bw = chip->bt_afh_span_bw20; |
835 | } else if (chip->afh_5g_num > 1) { |
836 | for (i = 0; i < chip->afh_5g_num; i++) { |
837 | if (center_chan == chip->afh_5g[i].wl_5g_ch) { |
838 | link = 0x3; |
839 | center_chan = chip->afh_5g[i].bt_skip_ch; |
840 | bw = chip->afh_5g[i].bt_skip_span; |
841 | break; |
842 | } |
843 | } |
844 | } |
845 | |
846 | coex_dm->wl_ch_info[0] = link; |
847 | coex_dm->wl_ch_info[1] = center_chan; |
848 | coex_dm->wl_ch_info[2] = bw; |
849 | |
850 | rtw_fw_wl_ch_info(rtwdev, link, ch: center_chan, bw); |
851 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
852 | fmt: "[BTCoex], %s: para[0:2] = 0x%x 0x%x 0x%x\n" , __func__, link, |
853 | center_chan, bw); |
854 | } |
855 | |
856 | static void rtw_coex_set_bt_tx_power(struct rtw_dev *rtwdev, u8 bt_pwr_dec_lvl) |
857 | { |
858 | struct rtw_coex *coex = &rtwdev->coex; |
859 | struct rtw_coex_dm *coex_dm = &coex->dm; |
860 | |
861 | if (bt_pwr_dec_lvl == coex_dm->cur_bt_pwr_lvl) |
862 | return; |
863 | |
864 | coex_dm->cur_bt_pwr_lvl = bt_pwr_dec_lvl; |
865 | |
866 | rtw_fw_force_bt_tx_power(rtwdev, bt_pwr_dec_lvl); |
867 | } |
868 | |
869 | static void rtw_coex_set_bt_rx_gain(struct rtw_dev *rtwdev, u8 bt_lna_lvl) |
870 | { |
871 | struct rtw_coex *coex = &rtwdev->coex; |
872 | struct rtw_coex_dm *coex_dm = &coex->dm; |
873 | |
874 | if (bt_lna_lvl == coex_dm->cur_bt_lna_lvl) |
875 | return; |
876 | |
877 | coex_dm->cur_bt_lna_lvl = bt_lna_lvl; |
878 | |
879 | /* notify BT rx gain table changed */ |
880 | if (bt_lna_lvl < 7) { |
881 | rtw_coex_set_lna_constrain_level(rtwdev, lna_constrain_level: bt_lna_lvl); |
882 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_RXGAIN, true); |
883 | } else { |
884 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_RXGAIN, false); |
885 | } |
886 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s(): bt_rx_LNA_level = %d\n" , |
887 | __func__, bt_lna_lvl); |
888 | } |
889 | |
890 | static void rtw_coex_set_rf_para(struct rtw_dev *rtwdev, |
891 | struct coex_rf_para para) |
892 | { |
893 | struct rtw_coex *coex = &rtwdev->coex; |
894 | struct rtw_coex_stat *coex_stat = &coex->stat; |
895 | u8 offset = 0; |
896 | |
897 | if (coex->freerun && coex_stat->cnt_wl[COEX_CNT_WL_SCANAP] <= 5) |
898 | offset = 3; |
899 | |
900 | rtw_coex_set_wl_tx_power(rtwdev, wl_pwr: para.wl_pwr_dec_lvl); |
901 | rtw_coex_set_bt_tx_power(rtwdev, bt_pwr_dec_lvl: para.bt_pwr_dec_lvl + offset); |
902 | rtw_coex_set_wl_rx_gain(rtwdev, low_gain: para.wl_low_gain_en); |
903 | rtw_coex_set_bt_rx_gain(rtwdev, bt_lna_lvl: para.bt_lna_lvl); |
904 | } |
905 | |
906 | u32 rtw_coex_read_indirect_reg(struct rtw_dev *rtwdev, u16 addr) |
907 | { |
908 | u32 val; |
909 | |
910 | if (!ltecoex_read_reg(rtwdev, offset: addr, val: &val)) { |
911 | rtw_err(rtwdev, "failed to read indirect register\n" ); |
912 | return 0; |
913 | } |
914 | |
915 | return val; |
916 | } |
917 | EXPORT_SYMBOL(rtw_coex_read_indirect_reg); |
918 | |
919 | void rtw_coex_write_indirect_reg(struct rtw_dev *rtwdev, u16 addr, |
920 | u32 mask, u32 val) |
921 | { |
922 | u32 shift = __ffs(mask); |
923 | u32 tmp; |
924 | |
925 | tmp = rtw_coex_read_indirect_reg(rtwdev, addr); |
926 | tmp = (tmp & (~mask)) | ((val << shift) & mask); |
927 | |
928 | if (!ltecoex_reg_write(rtwdev, offset: addr, value: tmp)) |
929 | rtw_err(rtwdev, "failed to write indirect register\n" ); |
930 | } |
931 | EXPORT_SYMBOL(rtw_coex_write_indirect_reg); |
932 | |
933 | static void rtw_coex_coex_ctrl_owner(struct rtw_dev *rtwdev, bool wifi_control) |
934 | { |
935 | const struct rtw_chip_info *chip = rtwdev->chip; |
936 | const struct rtw_hw_reg *btg_reg = chip->btg_reg; |
937 | |
938 | if (wifi_control) { |
939 | rtw_write8_set(rtwdev, REG_SYS_SDIO_CTRL + 3, |
940 | BIT_LTE_MUX_CTRL_PATH >> 24); |
941 | if (btg_reg) |
942 | rtw_write8_set(rtwdev, addr: btg_reg->addr, bit: btg_reg->mask); |
943 | } else { |
944 | rtw_write8_clr(rtwdev, REG_SYS_SDIO_CTRL + 3, |
945 | BIT_LTE_MUX_CTRL_PATH >> 24); |
946 | if (btg_reg) |
947 | rtw_write8_clr(rtwdev, addr: btg_reg->addr, bit: btg_reg->mask); |
948 | } |
949 | } |
950 | |
951 | static void rtw_coex_set_gnt_bt(struct rtw_dev *rtwdev, u8 state) |
952 | { |
953 | rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0xc000, state); |
954 | rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0x0c00, state); |
955 | } |
956 | |
957 | static void rtw_coex_set_gnt_wl(struct rtw_dev *rtwdev, u8 state) |
958 | { |
959 | rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0x3000, state); |
960 | rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0x0300, state); |
961 | } |
962 | |
963 | static void rtw_coex_mimo_ps(struct rtw_dev *rtwdev, bool force, bool state) |
964 | { |
965 | struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat; |
966 | |
967 | if (!force && state == coex_stat->wl_mimo_ps) |
968 | return; |
969 | |
970 | coex_stat->wl_mimo_ps = state; |
971 | |
972 | rtw_set_txrx_1ss(rtwdev, config_1ss: state); |
973 | |
974 | rtw_coex_update_wl_ch_info(rtwdev, type: (u8)coex_stat->wl_connected); |
975 | |
976 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
977 | fmt: "[BTCoex], %s(): state = %d\n" , __func__, state); |
978 | } |
979 | |
980 | static void rtw_btc_wltoggle_table_a(struct rtw_dev *rtwdev, bool force, |
981 | u8 table_case) |
982 | { |
983 | const struct rtw_chip_info *chip = rtwdev->chip; |
984 | struct rtw_efuse *efuse = &rtwdev->efuse; |
985 | u8 h2c_para[6] = {0}; |
986 | u32 table_wl = 0x5a5a5a5a; |
987 | |
988 | h2c_para[0] = COEX_H2C69_TOGGLE_TABLE_A; |
989 | /* no definition */ |
990 | h2c_para[1] = 0x1; |
991 | |
992 | if (efuse->share_ant) { |
993 | if (table_case < chip->table_sant_num) |
994 | table_wl = chip->table_sant[table_case].wl; |
995 | } else { |
996 | if (table_case < chip->table_nsant_num) |
997 | table_wl = chip->table_nsant[table_case].wl; |
998 | } |
999 | |
1000 | /* tell WL FW WL slot toggle table-A*/ |
1001 | h2c_para[2] = (u8)u32_get_bits(v: table_wl, GENMASK(7, 0)); |
1002 | h2c_para[3] = (u8)u32_get_bits(v: table_wl, GENMASK(15, 8)); |
1003 | h2c_para[4] = (u8)u32_get_bits(v: table_wl, GENMASK(23, 16)); |
1004 | h2c_para[5] = (u8)u32_get_bits(v: table_wl, GENMASK(31, 24)); |
1005 | |
1006 | rtw_fw_bt_wifi_control(rtwdev, op_code: h2c_para[0], data: &h2c_para[1]); |
1007 | |
1008 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1009 | fmt: "[BTCoex], %s(): H2C = [%02x %02x %02x %02x %02x %02x]\n" , |
1010 | __func__, h2c_para[0], h2c_para[1], h2c_para[2], |
1011 | h2c_para[3], h2c_para[4], h2c_para[5]); |
1012 | } |
1013 | |
1014 | #define COEX_WL_SLOT_TOGLLE 0x5a5a5aaa |
1015 | static void rtw_btc_wltoggle_table_b(struct rtw_dev *rtwdev, bool force, |
1016 | u8 interval, u32 table) |
1017 | { |
1018 | struct rtw_coex *coex = &rtwdev->coex; |
1019 | struct rtw_coex_stat *coex_stat = &coex->stat; |
1020 | u8 cur_h2c_para[6] = {0}; |
1021 | u8 i; |
1022 | |
1023 | cur_h2c_para[0] = COEX_H2C69_TOGGLE_TABLE_B; |
1024 | cur_h2c_para[1] = interval; |
1025 | cur_h2c_para[2] = (u8)u32_get_bits(v: table, GENMASK(7, 0)); |
1026 | cur_h2c_para[3] = (u8)u32_get_bits(v: table, GENMASK(15, 8)); |
1027 | cur_h2c_para[4] = (u8)u32_get_bits(v: table, GENMASK(23, 16)); |
1028 | cur_h2c_para[5] = (u8)u32_get_bits(v: table, GENMASK(31, 24)); |
1029 | |
1030 | coex_stat->wl_toggle_interval = interval; |
1031 | |
1032 | for (i = 0; i <= 5; i++) |
1033 | coex_stat->wl_toggle_para[i] = cur_h2c_para[i]; |
1034 | |
1035 | rtw_fw_bt_wifi_control(rtwdev, op_code: cur_h2c_para[0], data: &cur_h2c_para[1]); |
1036 | |
1037 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1038 | fmt: "[BTCoex], %s(): H2C = [%02x %02x %02x %02x %02x %02x]\n" , |
1039 | __func__, cur_h2c_para[0], cur_h2c_para[1], cur_h2c_para[2], |
1040 | cur_h2c_para[3], cur_h2c_para[4], cur_h2c_para[5]); |
1041 | } |
1042 | |
1043 | static void rtw_coex_set_table(struct rtw_dev *rtwdev, bool force, u32 table0, |
1044 | u32 table1) |
1045 | { |
1046 | #define DEF_BRK_TABLE_VAL 0xf0ffffff |
1047 | struct rtw_coex *coex = &rtwdev->coex; |
1048 | struct rtw_coex_dm *coex_dm = &coex->dm; |
1049 | |
1050 | /* If last tdma is wl slot toggle, force write table*/ |
1051 | if (!force && coex_dm->reason != COEX_RSN_LPS) { |
1052 | if (table0 == rtw_read32(rtwdev, REG_BT_COEX_TABLE0) && |
1053 | table1 == rtw_read32(rtwdev, REG_BT_COEX_TABLE1)) |
1054 | return; |
1055 | } |
1056 | rtw_write32(rtwdev, REG_BT_COEX_TABLE0, val: table0); |
1057 | rtw_write32(rtwdev, REG_BT_COEX_TABLE1, val: table1); |
1058 | rtw_write32(rtwdev, REG_BT_COEX_BRK_TABLE, DEF_BRK_TABLE_VAL); |
1059 | |
1060 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1061 | fmt: "[BTCoex], %s(): 0x6c0 = %x, 0x6c4 = %x\n" , __func__, table0, |
1062 | table1); |
1063 | } |
1064 | |
1065 | static void rtw_coex_table(struct rtw_dev *rtwdev, bool force, u8 type) |
1066 | { |
1067 | const struct rtw_chip_info *chip = rtwdev->chip; |
1068 | struct rtw_coex *coex = &rtwdev->coex; |
1069 | struct rtw_coex_dm *coex_dm = &coex->dm; |
1070 | struct rtw_efuse *efuse = &rtwdev->efuse; |
1071 | struct rtw_coex_stat *coex_stat = &coex->stat; |
1072 | |
1073 | coex_dm->cur_table = type; |
1074 | |
1075 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], Coex_Table - %d\n" , type); |
1076 | |
1077 | if (efuse->share_ant) { |
1078 | if (type < chip->table_sant_num) |
1079 | rtw_coex_set_table(rtwdev, force, |
1080 | table0: chip->table_sant[type].bt, |
1081 | table1: chip->table_sant[type].wl); |
1082 | } else { |
1083 | type = type - 100; |
1084 | if (type < chip->table_nsant_num) |
1085 | rtw_coex_set_table(rtwdev, force, |
1086 | table0: chip->table_nsant[type].bt, |
1087 | table1: chip->table_nsant[type].wl); |
1088 | } |
1089 | if (coex_stat->wl_slot_toggle_change) |
1090 | rtw_btc_wltoggle_table_a(rtwdev, force: true, table_case: type); |
1091 | } |
1092 | |
1093 | static void rtw_coex_ignore_wlan_act(struct rtw_dev *rtwdev, bool enable) |
1094 | { |
1095 | struct rtw_coex *coex = &rtwdev->coex; |
1096 | |
1097 | if (coex->manual_control || coex->stop_dm) |
1098 | return; |
1099 | |
1100 | rtw_fw_bt_ignore_wlan_action(rtwdev, enable); |
1101 | } |
1102 | |
1103 | static void rtw_coex_power_save_state(struct rtw_dev *rtwdev, u8 ps_type, |
1104 | u8 lps_val, u8 rpwm_val) |
1105 | { |
1106 | struct rtw_coex *coex = &rtwdev->coex; |
1107 | struct rtw_coex_stat *coex_stat = &coex->stat; |
1108 | u8 lps_mode = 0x0; |
1109 | |
1110 | lps_mode = rtwdev->lps_conf.mode; |
1111 | |
1112 | switch (ps_type) { |
1113 | case COEX_PS_WIFI_NATIVE: |
1114 | /* recover to original 32k low power setting */ |
1115 | coex_stat->wl_force_lps_ctrl = false; |
1116 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1117 | fmt: "[BTCoex], %s(): COEX_PS_WIFI_NATIVE\n" , __func__); |
1118 | rtw_leave_lps(rtwdev); |
1119 | break; |
1120 | case COEX_PS_LPS_OFF: |
1121 | coex_stat->wl_force_lps_ctrl = true; |
1122 | if (lps_mode) |
1123 | rtw_fw_coex_tdma_type(rtwdev, para1: 0, para2: 0, para3: 0, para4: 0, para5: 0); |
1124 | |
1125 | rtw_leave_lps(rtwdev); |
1126 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1127 | fmt: "[BTCoex], %s(): COEX_PS_LPS_OFF\n" , __func__); |
1128 | break; |
1129 | default: |
1130 | break; |
1131 | } |
1132 | } |
1133 | |
1134 | static void rtw_coex_set_tdma(struct rtw_dev *rtwdev, u8 byte1, u8 byte2, |
1135 | u8 byte3, u8 byte4, u8 byte5) |
1136 | { |
1137 | const struct rtw_chip_info *chip = rtwdev->chip; |
1138 | struct rtw_coex *coex = &rtwdev->coex; |
1139 | struct rtw_coex_dm *coex_dm = &coex->dm; |
1140 | struct rtw_coex_stat *coex_stat = &coex->stat; |
1141 | u8 ps_type = COEX_PS_WIFI_NATIVE; |
1142 | bool ap_enable = false; |
1143 | |
1144 | if (ap_enable && (byte1 & BIT(4) && !(byte1 & BIT(5)))) { |
1145 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s(): AP mode\n" , |
1146 | __func__); |
1147 | |
1148 | byte1 &= ~BIT(4); |
1149 | byte1 |= BIT(5); |
1150 | |
1151 | byte5 |= BIT(5); |
1152 | byte5 &= ~BIT(6); |
1153 | |
1154 | ps_type = COEX_PS_WIFI_NATIVE; |
1155 | rtw_coex_power_save_state(rtwdev, ps_type, lps_val: 0x0, rpwm_val: 0x0); |
1156 | } else if ((byte1 & BIT(4) && !(byte1 & BIT(5))) || |
1157 | coex_stat->wl_coex_mode == COEX_WLINK_2GFREE) { |
1158 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1159 | fmt: "[BTCoex], %s(): Force LPS (byte1 = 0x%x)\n" , __func__, |
1160 | byte1); |
1161 | |
1162 | if (chip->pstdma_type == COEX_PSTDMA_FORCE_LPSOFF) |
1163 | ps_type = COEX_PS_LPS_OFF; |
1164 | else |
1165 | ps_type = COEX_PS_LPS_ON; |
1166 | rtw_coex_power_save_state(rtwdev, ps_type, lps_val: 0x50, rpwm_val: 0x4); |
1167 | } else { |
1168 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1169 | fmt: "[BTCoex], %s(): native power save (byte1 = 0x%x)\n" , |
1170 | __func__, byte1); |
1171 | |
1172 | ps_type = COEX_PS_WIFI_NATIVE; |
1173 | rtw_coex_power_save_state(rtwdev, ps_type, lps_val: 0x0, rpwm_val: 0x0); |
1174 | } |
1175 | |
1176 | coex_dm->ps_tdma_para[0] = byte1; |
1177 | coex_dm->ps_tdma_para[1] = byte2; |
1178 | coex_dm->ps_tdma_para[2] = byte3; |
1179 | coex_dm->ps_tdma_para[3] = byte4; |
1180 | coex_dm->ps_tdma_para[4] = byte5; |
1181 | |
1182 | rtw_fw_coex_tdma_type(rtwdev, para1: byte1, para2: byte2, para3: byte3, para4: byte4, para5: byte5); |
1183 | |
1184 | if (byte1 & BIT(2)) { |
1185 | coex_stat->wl_slot_toggle = true; |
1186 | coex_stat->wl_slot_toggle_change = false; |
1187 | } else { |
1188 | coex_stat->wl_slot_toggle_change = coex_stat->wl_slot_toggle; |
1189 | coex_stat->wl_slot_toggle = false; |
1190 | } |
1191 | } |
1192 | |
1193 | static void rtw_coex_tdma(struct rtw_dev *rtwdev, bool force, u32 tcase) |
1194 | { |
1195 | const struct rtw_chip_info *chip = rtwdev->chip; |
1196 | struct rtw_coex *coex = &rtwdev->coex; |
1197 | struct rtw_coex_dm *coex_dm = &coex->dm; |
1198 | struct rtw_coex_stat *coex_stat = &coex->stat; |
1199 | struct rtw_efuse *efuse = &rtwdev->efuse; |
1200 | u8 n, type; |
1201 | bool turn_on; |
1202 | bool wl_busy = false; |
1203 | |
1204 | if (tcase & TDMA_4SLOT) /* 4-slot (50ms) mode */ |
1205 | rtw_coex_tdma_timer_base(rtwdev, TDMA_TIMER_TYPE_4SLOT); |
1206 | else |
1207 | rtw_coex_tdma_timer_base(rtwdev, TDMA_TIMER_TYPE_2SLOT); |
1208 | |
1209 | type = (u8)(tcase & 0xff); |
1210 | |
1211 | turn_on = (type == 0 || type == 100) ? false : true; |
1212 | |
1213 | if (!force && turn_on == coex_dm->cur_ps_tdma_on && |
1214 | type == coex_dm->cur_ps_tdma) { |
1215 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1216 | fmt: "[BTCoex], Skip TDMA because no change TDMA(%s, %d)\n" , |
1217 | (coex_dm->cur_ps_tdma_on ? "on" : "off" ), |
1218 | coex_dm->cur_ps_tdma); |
1219 | |
1220 | return; |
1221 | } |
1222 | wl_busy = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); |
1223 | |
1224 | if ((coex_stat->bt_a2dp_exist && |
1225 | (coex_stat->bt_inq_remain || coex_stat->bt_multi_link)) || |
1226 | !wl_busy) |
1227 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_TDMA, false); |
1228 | else |
1229 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_TDMA, true); |
1230 | |
1231 | /* update pre state */ |
1232 | coex_dm->cur_ps_tdma_on = turn_on; |
1233 | coex_dm->cur_ps_tdma = type; |
1234 | |
1235 | if (efuse->share_ant) { |
1236 | if (type < chip->tdma_sant_num) |
1237 | rtw_coex_set_tdma(rtwdev, |
1238 | byte1: chip->tdma_sant[type].para[0], |
1239 | byte2: chip->tdma_sant[type].para[1], |
1240 | byte3: chip->tdma_sant[type].para[2], |
1241 | byte4: chip->tdma_sant[type].para[3], |
1242 | byte5: chip->tdma_sant[type].para[4]); |
1243 | } else { |
1244 | n = type - 100; |
1245 | if (n < chip->tdma_nsant_num) |
1246 | rtw_coex_set_tdma(rtwdev, |
1247 | byte1: chip->tdma_nsant[n].para[0], |
1248 | byte2: chip->tdma_nsant[n].para[1], |
1249 | byte3: chip->tdma_nsant[n].para[2], |
1250 | byte4: chip->tdma_nsant[n].para[3], |
1251 | byte5: chip->tdma_nsant[n].para[4]); |
1252 | } |
1253 | |
1254 | |
1255 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], coex tdma type(%s, %d)\n" , |
1256 | turn_on ? "on" : "off" , type); |
1257 | } |
1258 | |
1259 | static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase) |
1260 | { |
1261 | struct rtw_coex *coex = &rtwdev->coex; |
1262 | struct rtw_coex_stat *coex_stat = &coex->stat; |
1263 | struct rtw_coex_rfe *coex_rfe = &coex->rfe; |
1264 | struct rtw_coex_dm *coex_dm = &coex->dm; |
1265 | u8 ctrl_type = COEX_SWITCH_CTRL_MAX; |
1266 | u8 pos_type = COEX_SWITCH_TO_MAX; |
1267 | |
1268 | if (!force && coex_dm->cur_ant_pos_type == phase) |
1269 | return; |
1270 | |
1271 | coex_dm->cur_ant_pos_type = phase; |
1272 | |
1273 | /* avoid switch coex_ctrl_owner during BT IQK */ |
1274 | rtw_coex_check_rfk(rtwdev); |
1275 | |
1276 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1277 | fmt: "[BTCoex], coex_stat->bt_disabled = 0x%x\n" , |
1278 | coex_stat->bt_disabled); |
1279 | |
1280 | switch (phase) { |
1281 | case COEX_SET_ANT_POWERON: |
1282 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1283 | fmt: "[BTCoex], %s() - PHASE_COEX_POWERON\n" , __func__); |
1284 | /* set path control owner to BT at power-on */ |
1285 | if (coex_stat->bt_disabled) |
1286 | rtw_coex_coex_ctrl_owner(rtwdev, wifi_control: true); |
1287 | else |
1288 | rtw_coex_coex_ctrl_owner(rtwdev, wifi_control: false); |
1289 | |
1290 | ctrl_type = COEX_SWITCH_CTRL_BY_BBSW; |
1291 | pos_type = COEX_SWITCH_TO_BT; |
1292 | break; |
1293 | case COEX_SET_ANT_INIT: |
1294 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1295 | fmt: "[BTCoex], %s() - PHASE_COEX_INIT\n" , __func__); |
1296 | if (coex_stat->bt_disabled) { |
1297 | /* set GNT_BT to SW low */ |
1298 | rtw_coex_set_gnt_bt(rtwdev, state: COEX_GNT_SET_SW_LOW); |
1299 | |
1300 | /* set GNT_WL to SW high */ |
1301 | rtw_coex_set_gnt_wl(rtwdev, state: COEX_GNT_SET_SW_HIGH); |
1302 | } else { |
1303 | /* set GNT_BT to SW high */ |
1304 | rtw_coex_set_gnt_bt(rtwdev, state: COEX_GNT_SET_SW_HIGH); |
1305 | |
1306 | /* set GNT_WL to SW low */ |
1307 | rtw_coex_set_gnt_wl(rtwdev, state: COEX_GNT_SET_SW_LOW); |
1308 | } |
1309 | |
1310 | /* set path control owner to wl at initial step */ |
1311 | rtw_coex_coex_ctrl_owner(rtwdev, wifi_control: true); |
1312 | |
1313 | ctrl_type = COEX_SWITCH_CTRL_BY_BBSW; |
1314 | pos_type = COEX_SWITCH_TO_BT; |
1315 | break; |
1316 | case COEX_SET_ANT_WONLY: |
1317 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1318 | fmt: "[BTCoex], %s() - PHASE_WLANONLY_INIT\n" , __func__); |
1319 | /* set GNT_BT to SW Low */ |
1320 | rtw_coex_set_gnt_bt(rtwdev, state: COEX_GNT_SET_SW_LOW); |
1321 | |
1322 | /* set GNT_WL to SW high */ |
1323 | rtw_coex_set_gnt_wl(rtwdev, state: COEX_GNT_SET_SW_HIGH); |
1324 | |
1325 | /* set path control owner to wl at initial step */ |
1326 | rtw_coex_coex_ctrl_owner(rtwdev, wifi_control: true); |
1327 | |
1328 | ctrl_type = COEX_SWITCH_CTRL_BY_BBSW; |
1329 | pos_type = COEX_SWITCH_TO_WLG; |
1330 | break; |
1331 | case COEX_SET_ANT_WOFF: |
1332 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1333 | fmt: "[BTCoex], %s() - PHASE_WLAN_OFF\n" , __func__); |
1334 | /* set path control owner to BT */ |
1335 | rtw_coex_coex_ctrl_owner(rtwdev, wifi_control: false); |
1336 | |
1337 | ctrl_type = COEX_SWITCH_CTRL_BY_BT; |
1338 | pos_type = COEX_SWITCH_TO_NOCARE; |
1339 | break; |
1340 | case COEX_SET_ANT_2G: |
1341 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1342 | fmt: "[BTCoex], %s() - PHASE_2G_RUNTIME\n" , __func__); |
1343 | /* set GNT_BT to PTA */ |
1344 | rtw_coex_set_gnt_bt(rtwdev, state: COEX_GNT_SET_HW_PTA); |
1345 | |
1346 | /* set GNT_WL to PTA */ |
1347 | rtw_coex_set_gnt_wl(rtwdev, state: COEX_GNT_SET_HW_PTA); |
1348 | |
1349 | /* set path control owner to wl at runtime step */ |
1350 | rtw_coex_coex_ctrl_owner(rtwdev, wifi_control: true); |
1351 | |
1352 | ctrl_type = COEX_SWITCH_CTRL_BY_PTA; |
1353 | pos_type = COEX_SWITCH_TO_NOCARE; |
1354 | break; |
1355 | case COEX_SET_ANT_5G: |
1356 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1357 | fmt: "[BTCoex], %s() - PHASE_5G_RUNTIME\n" , __func__); |
1358 | |
1359 | /* set GNT_BT to HW PTA */ |
1360 | rtw_coex_set_gnt_bt(rtwdev, state: COEX_GNT_SET_HW_PTA); |
1361 | |
1362 | /* set GNT_WL to SW high */ |
1363 | rtw_coex_set_gnt_wl(rtwdev, state: COEX_GNT_SET_SW_HIGH); |
1364 | |
1365 | /* set path control owner to wl at runtime step */ |
1366 | rtw_coex_coex_ctrl_owner(rtwdev, wifi_control: true); |
1367 | |
1368 | ctrl_type = COEX_SWITCH_CTRL_BY_BBSW; |
1369 | pos_type = COEX_SWITCH_TO_WLA; |
1370 | break; |
1371 | case COEX_SET_ANT_2G_FREERUN: |
1372 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1373 | fmt: "[BTCoex], %s() - PHASE_2G_FREERUN\n" , __func__); |
1374 | |
1375 | /* set GNT_BT to HW PTA */ |
1376 | rtw_coex_set_gnt_bt(rtwdev, state: COEX_GNT_SET_HW_PTA); |
1377 | |
1378 | /* Set GNT_WL to SW high */ |
1379 | rtw_coex_set_gnt_wl(rtwdev, state: COEX_GNT_SET_SW_HIGH); |
1380 | |
1381 | /* set path control owner to wl at runtime step */ |
1382 | rtw_coex_coex_ctrl_owner(rtwdev, wifi_control: true); |
1383 | |
1384 | ctrl_type = COEX_SWITCH_CTRL_BY_BBSW; |
1385 | pos_type = COEX_SWITCH_TO_WLG_BT; |
1386 | break; |
1387 | case COEX_SET_ANT_2G_WLBT: |
1388 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1389 | fmt: "[BTCoex], %s() - PHASE_2G_WLBT\n" , __func__); |
1390 | /* set GNT_BT to HW PTA */ |
1391 | rtw_coex_set_gnt_bt(rtwdev, state: COEX_GNT_SET_HW_PTA); |
1392 | |
1393 | /* Set GNT_WL to HW PTA */ |
1394 | rtw_coex_set_gnt_wl(rtwdev, state: COEX_GNT_SET_HW_PTA); |
1395 | |
1396 | /* set path control owner to wl at runtime step */ |
1397 | rtw_coex_coex_ctrl_owner(rtwdev, wifi_control: true); |
1398 | |
1399 | ctrl_type = COEX_SWITCH_CTRL_BY_BBSW; |
1400 | pos_type = COEX_SWITCH_TO_WLG_BT; |
1401 | break; |
1402 | default: |
1403 | WARN(1, "unknown phase when setting antenna path\n" ); |
1404 | return; |
1405 | } |
1406 | |
1407 | if (ctrl_type < COEX_SWITCH_CTRL_MAX && pos_type < COEX_SWITCH_TO_MAX && |
1408 | coex_rfe->ant_switch_exist) |
1409 | rtw_coex_set_ant_switch(rtwdev, ctrl_type, pos_type); |
1410 | } |
1411 | |
1412 | #define case_ALGO(src) \ |
1413 | case COEX_ALGO_##src: return #src |
1414 | |
1415 | static const char *rtw_coex_get_algo_string(u8 algo) |
1416 | { |
1417 | switch (algo) { |
1418 | case_ALGO(NOPROFILE); |
1419 | case_ALGO(HFP); |
1420 | case_ALGO(HID); |
1421 | case_ALGO(A2DP); |
1422 | case_ALGO(PAN); |
1423 | case_ALGO(A2DP_HID); |
1424 | case_ALGO(A2DP_PAN); |
1425 | case_ALGO(PAN_HID); |
1426 | case_ALGO(A2DP_PAN_HID); |
1427 | default: |
1428 | return "Unknown" ; |
1429 | } |
1430 | } |
1431 | |
1432 | #define case_BT_PROFILE(src) \ |
1433 | case BPM_##src: return #src |
1434 | |
1435 | static const char *rtw_coex_get_bt_profile_string(u8 bt_profile) |
1436 | { |
1437 | switch (bt_profile) { |
1438 | case_BT_PROFILE(NOPROFILE); |
1439 | case_BT_PROFILE(HFP); |
1440 | case_BT_PROFILE(HID); |
1441 | case_BT_PROFILE(A2DP); |
1442 | case_BT_PROFILE(PAN); |
1443 | case_BT_PROFILE(HID_HFP); |
1444 | case_BT_PROFILE(A2DP_HFP); |
1445 | case_BT_PROFILE(A2DP_HID); |
1446 | case_BT_PROFILE(A2DP_HID_HFP); |
1447 | case_BT_PROFILE(PAN_HFP); |
1448 | case_BT_PROFILE(PAN_HID); |
1449 | case_BT_PROFILE(PAN_HID_HFP); |
1450 | case_BT_PROFILE(PAN_A2DP); |
1451 | case_BT_PROFILE(PAN_A2DP_HFP); |
1452 | case_BT_PROFILE(PAN_A2DP_HID); |
1453 | case_BT_PROFILE(PAN_A2DP_HID_HFP); |
1454 | default: |
1455 | return "Unknown" ; |
1456 | } |
1457 | } |
1458 | |
1459 | static u8 rtw_coex_algorithm(struct rtw_dev *rtwdev) |
1460 | { |
1461 | struct rtw_coex *coex = &rtwdev->coex; |
1462 | struct rtw_coex_stat *coex_stat = &coex->stat; |
1463 | u8 algorithm = COEX_ALGO_NOPROFILE; |
1464 | u8 profile_map = 0; |
1465 | |
1466 | if (coex_stat->bt_hfp_exist) |
1467 | profile_map |= BPM_HFP; |
1468 | if (coex_stat->bt_hid_exist) |
1469 | profile_map |= BPM_HID; |
1470 | if (coex_stat->bt_a2dp_exist) |
1471 | profile_map |= BPM_A2DP; |
1472 | if (coex_stat->bt_pan_exist) |
1473 | profile_map |= BPM_PAN; |
1474 | |
1475 | switch (profile_map) { |
1476 | case BPM_HFP: |
1477 | algorithm = COEX_ALGO_HFP; |
1478 | break; |
1479 | case BPM_HID: |
1480 | case BPM_HFP + BPM_HID: |
1481 | algorithm = COEX_ALGO_HID; |
1482 | break; |
1483 | case BPM_HFP + BPM_A2DP: |
1484 | case BPM_HID + BPM_A2DP: |
1485 | case BPM_HFP + BPM_HID + BPM_A2DP: |
1486 | algorithm = COEX_ALGO_A2DP_HID; |
1487 | break; |
1488 | case BPM_HFP + BPM_PAN: |
1489 | case BPM_HID + BPM_PAN: |
1490 | case BPM_HFP + BPM_HID + BPM_PAN: |
1491 | algorithm = COEX_ALGO_PAN_HID; |
1492 | break; |
1493 | case BPM_HFP + BPM_A2DP + BPM_PAN: |
1494 | case BPM_HID + BPM_A2DP + BPM_PAN: |
1495 | case BPM_HFP + BPM_HID + BPM_A2DP + BPM_PAN: |
1496 | algorithm = COEX_ALGO_A2DP_PAN_HID; |
1497 | break; |
1498 | case BPM_PAN: |
1499 | algorithm = COEX_ALGO_PAN; |
1500 | break; |
1501 | case BPM_A2DP + BPM_PAN: |
1502 | algorithm = COEX_ALGO_A2DP_PAN; |
1503 | break; |
1504 | case BPM_A2DP: |
1505 | if (coex_stat->bt_multi_link) { |
1506 | if (coex_stat->bt_hid_pair_num > 0) |
1507 | algorithm = COEX_ALGO_A2DP_HID; |
1508 | else |
1509 | algorithm = COEX_ALGO_A2DP_PAN; |
1510 | } else { |
1511 | algorithm = COEX_ALGO_A2DP; |
1512 | } |
1513 | break; |
1514 | default: |
1515 | algorithm = COEX_ALGO_NOPROFILE; |
1516 | break; |
1517 | } |
1518 | |
1519 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1520 | fmt: "[BTCoex], BT Profile = %s => Algorithm = %s\n" , |
1521 | rtw_coex_get_bt_profile_string(bt_profile: profile_map), |
1522 | rtw_coex_get_algo_string(algo: algorithm)); |
1523 | return algorithm; |
1524 | } |
1525 | |
1526 | static void rtw_coex_action_coex_all_off(struct rtw_dev *rtwdev) |
1527 | { |
1528 | const struct rtw_chip_info *chip = rtwdev->chip; |
1529 | struct rtw_efuse *efuse = &rtwdev->efuse; |
1530 | u8 table_case, tdma_case; |
1531 | |
1532 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
1533 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[0]); |
1534 | |
1535 | if (efuse->share_ant) { |
1536 | /* Shared-Ant */ |
1537 | table_case = 2; |
1538 | tdma_case = 0; |
1539 | } else { |
1540 | /* Non-Shared-Ant */ |
1541 | table_case = 100; |
1542 | tdma_case = 100; |
1543 | } |
1544 | |
1545 | rtw_coex_table(rtwdev, force: false, type: table_case); |
1546 | rtw_coex_tdma(rtwdev, force: false, tcase: tdma_case); |
1547 | } |
1548 | |
1549 | static void rtw_coex_action_freerun(struct rtw_dev *rtwdev) |
1550 | { |
1551 | const struct rtw_chip_info *chip = rtwdev->chip; |
1552 | struct rtw_coex *coex = &rtwdev->coex; |
1553 | struct rtw_coex_stat *coex_stat = &coex->stat; |
1554 | struct rtw_coex_dm *coex_dm = &coex->dm; |
1555 | struct rtw_efuse *efuse = &rtwdev->efuse; |
1556 | u8 level = 0; |
1557 | bool bt_afh_loss = true; |
1558 | |
1559 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
1560 | |
1561 | if (efuse->share_ant) |
1562 | return; |
1563 | |
1564 | coex->freerun = true; |
1565 | |
1566 | if (bt_afh_loss) |
1567 | rtw_coex_update_wl_ch_info(rtwdev, type: COEX_MEDIA_CONNECT); |
1568 | |
1569 | rtw_coex_set_ant_path(rtwdev, force: false, phase: COEX_SET_ANT_2G_FREERUN); |
1570 | |
1571 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_FIX2M, false); |
1572 | |
1573 | if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[0])) |
1574 | level = 2; |
1575 | else if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1])) |
1576 | level = 3; |
1577 | else if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[2])) |
1578 | level = 4; |
1579 | else |
1580 | level = 5; |
1581 | |
1582 | if (level > chip->wl_rf_para_num - 1) |
1583 | level = chip->wl_rf_para_num - 1; |
1584 | |
1585 | if (coex_stat->wl_tput_dir == COEX_WL_TPUT_TX) |
1586 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_tx[level]); |
1587 | else |
1588 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[level]); |
1589 | |
1590 | rtw_coex_table(rtwdev, force: false, type: 100); |
1591 | rtw_coex_tdma(rtwdev, force: false, tcase: 100); |
1592 | } |
1593 | |
1594 | static void rtw_coex_action_rf4ce(struct rtw_dev *rtwdev) |
1595 | { |
1596 | const struct rtw_chip_info *chip = rtwdev->chip; |
1597 | struct rtw_efuse *efuse = &rtwdev->efuse; |
1598 | u8 table_case, tdma_case; |
1599 | |
1600 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
1601 | |
1602 | rtw_coex_set_ant_path(rtwdev, force: false, phase: COEX_SET_ANT_2G); |
1603 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[0]); |
1604 | |
1605 | if (efuse->share_ant) { |
1606 | /* Shared-Ant */ |
1607 | table_case = 9; |
1608 | tdma_case = 16; |
1609 | } else { |
1610 | /* Non-Shared-Ant */ |
1611 | table_case = 100; |
1612 | tdma_case = 100; |
1613 | } |
1614 | |
1615 | rtw_coex_table(rtwdev, force: false, type: table_case); |
1616 | rtw_coex_tdma(rtwdev, force: false, tcase: tdma_case); |
1617 | } |
1618 | |
1619 | static void rtw_coex_action_bt_whql_test(struct rtw_dev *rtwdev) |
1620 | { |
1621 | const struct rtw_chip_info *chip = rtwdev->chip; |
1622 | struct rtw_efuse *efuse = &rtwdev->efuse; |
1623 | u8 table_case, tdma_case; |
1624 | |
1625 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
1626 | |
1627 | rtw_coex_set_ant_path(rtwdev, force: false, phase: COEX_SET_ANT_2G); |
1628 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[0]); |
1629 | |
1630 | if (efuse->share_ant) { |
1631 | /* Shared-Ant */ |
1632 | table_case = 2; |
1633 | tdma_case = 0; |
1634 | } else { |
1635 | /* Non-Shared-Ant */ |
1636 | table_case = 100; |
1637 | tdma_case = 100; |
1638 | } |
1639 | |
1640 | rtw_coex_table(rtwdev, force: false, type: table_case); |
1641 | rtw_coex_tdma(rtwdev, force: false, tcase: tdma_case); |
1642 | } |
1643 | |
1644 | static void rtw_coex_action_bt_relink(struct rtw_dev *rtwdev) |
1645 | { |
1646 | const struct rtw_chip_info *chip = rtwdev->chip; |
1647 | struct rtw_coex *coex = &rtwdev->coex; |
1648 | struct rtw_coex_stat *coex_stat = &coex->stat; |
1649 | struct rtw_efuse *efuse = &rtwdev->efuse; |
1650 | u8 table_case, tdma_case; |
1651 | u32 slot_type = 0; |
1652 | |
1653 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
1654 | |
1655 | rtw_coex_set_ant_path(rtwdev, force: false, phase: COEX_SET_ANT_2G); |
1656 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[0]); |
1657 | |
1658 | if (efuse->share_ant) { /* Shared-Ant */ |
1659 | if (coex_stat->wl_gl_busy) { |
1660 | table_case = 26; |
1661 | if (coex_stat->bt_hid_exist && |
1662 | coex_stat->bt_profile_num == 1) { |
1663 | slot_type = TDMA_4SLOT; |
1664 | tdma_case = 20; |
1665 | } else { |
1666 | tdma_case = 20; |
1667 | } |
1668 | } else { |
1669 | table_case = 1; |
1670 | tdma_case = 0; |
1671 | } |
1672 | } else { /* Non-Shared-Ant */ |
1673 | if (coex_stat->wl_gl_busy) |
1674 | table_case = 115; |
1675 | else |
1676 | table_case = 100; |
1677 | tdma_case = 100; |
1678 | } |
1679 | |
1680 | rtw_coex_table(rtwdev, force: false, type: table_case); |
1681 | rtw_coex_tdma(rtwdev, force: false, tcase: tdma_case | slot_type); |
1682 | } |
1683 | |
1684 | static void rtw_coex_action_bt_idle(struct rtw_dev *rtwdev) |
1685 | { |
1686 | const struct rtw_chip_info *chip = rtwdev->chip; |
1687 | struct rtw_coex *coex = &rtwdev->coex; |
1688 | struct rtw_coex_stat *coex_stat = &coex->stat; |
1689 | struct rtw_coex_dm *coex_dm = &coex->dm; |
1690 | struct rtw_efuse *efuse = &rtwdev->efuse; |
1691 | struct rtw_coex_rfe *coex_rfe = &coex->rfe; |
1692 | u8 table_case = 0xff, tdma_case = 0xff; |
1693 | |
1694 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
1695 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[0]); |
1696 | |
1697 | if (coex_rfe->ant_switch_with_bt && |
1698 | coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) { |
1699 | if (efuse->share_ant && |
1700 | COEX_RSSI_HIGH(coex_dm->wl_rssi_state[3]) && |
1701 | coex_stat->wl_gl_busy) { |
1702 | table_case = 0; |
1703 | tdma_case = 0; |
1704 | } else if (!efuse->share_ant) { |
1705 | table_case = 100; |
1706 | tdma_case = 100; |
1707 | } |
1708 | } |
1709 | |
1710 | if (table_case != 0xff && tdma_case != 0xff) { |
1711 | rtw_coex_set_ant_path(rtwdev, force: false, phase: COEX_SET_ANT_2G_FREERUN); |
1712 | goto exit; |
1713 | } |
1714 | |
1715 | rtw_coex_set_ant_path(rtwdev, force: false, phase: COEX_SET_ANT_2G); |
1716 | |
1717 | if (efuse->share_ant) { |
1718 | /* Shared-Ant */ |
1719 | if (!coex_stat->wl_gl_busy) { |
1720 | table_case = 10; |
1721 | tdma_case = 3; |
1722 | } else if (coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) { |
1723 | table_case = 11; |
1724 | |
1725 | if (coex_stat->lo_pri_rx + coex_stat->lo_pri_tx > 250) |
1726 | tdma_case = 17; |
1727 | else |
1728 | tdma_case = 7; |
1729 | } else { |
1730 | table_case = 12; |
1731 | tdma_case = 7; |
1732 | } |
1733 | } else { |
1734 | /* Non-Shared-Ant */ |
1735 | if (!coex_stat->wl_gl_busy) { |
1736 | table_case = 112; |
1737 | tdma_case = 104; |
1738 | } else if ((coex_stat->bt_ble_scan_type & 0x2) && |
1739 | coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) { |
1740 | table_case = 114; |
1741 | tdma_case = 103; |
1742 | } else { |
1743 | table_case = 112; |
1744 | tdma_case = 103; |
1745 | } |
1746 | } |
1747 | |
1748 | exit: |
1749 | rtw_coex_table(rtwdev, force: false, type: table_case); |
1750 | rtw_coex_tdma(rtwdev, force: false, tcase: tdma_case); |
1751 | } |
1752 | |
1753 | static void rtw_coex_action_bt_inquiry(struct rtw_dev *rtwdev) |
1754 | { |
1755 | const struct rtw_chip_info *chip = rtwdev->chip; |
1756 | struct rtw_coex *coex = &rtwdev->coex; |
1757 | struct rtw_coex_stat *coex_stat = &coex->stat; |
1758 | struct rtw_efuse *efuse = &rtwdev->efuse; |
1759 | bool wl_hi_pri = false; |
1760 | u8 table_case, tdma_case; |
1761 | u32 slot_type = 0; |
1762 | |
1763 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
1764 | rtw_coex_set_ant_path(rtwdev, force: false, phase: COEX_SET_ANT_2G); |
1765 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[0]); |
1766 | |
1767 | if (coex_stat->wl_linkscan_proc || coex_stat->wl_hi_pri_task1 || |
1768 | coex_stat->wl_hi_pri_task2) |
1769 | wl_hi_pri = true; |
1770 | |
1771 | if (efuse->share_ant) { |
1772 | /* Shared-Ant */ |
1773 | if (wl_hi_pri) { |
1774 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1775 | fmt: "[BTCoex], bt inq/page + wifi hi-pri task\n" ); |
1776 | table_case = 15; |
1777 | |
1778 | if (coex_stat->bt_profile_num > 0) |
1779 | tdma_case = 10; |
1780 | else if (coex_stat->wl_hi_pri_task1) |
1781 | tdma_case = 6; |
1782 | else if (!coex_stat->bt_page) |
1783 | tdma_case = 8; |
1784 | else |
1785 | tdma_case = 9; |
1786 | } else if (coex_stat->wl_gl_busy) { |
1787 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1788 | fmt: "[BTCoex], bt inq/page + wifi busy\n" ); |
1789 | if (coex_stat->bt_profile_num == 0) { |
1790 | table_case = 12; |
1791 | tdma_case = 18; |
1792 | } else if (coex_stat->bt_profile_num == 1 && |
1793 | !coex_stat->bt_a2dp_exist) { |
1794 | slot_type = TDMA_4SLOT; |
1795 | table_case = 12; |
1796 | tdma_case = 20; |
1797 | } else { |
1798 | slot_type = TDMA_4SLOT; |
1799 | table_case = 12; |
1800 | tdma_case = 26; |
1801 | } |
1802 | } else if (coex_stat->wl_connected) { |
1803 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1804 | fmt: "[BTCoex], bt inq/page + wifi connected\n" ); |
1805 | table_case = 9; |
1806 | tdma_case = 27; |
1807 | } else { |
1808 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1809 | fmt: "[BTCoex], bt inq/page + wifi not-connected\n" ); |
1810 | table_case = 1; |
1811 | tdma_case = 0; |
1812 | } |
1813 | } else { |
1814 | /* Non_Shared-Ant */ |
1815 | if (wl_hi_pri) { |
1816 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1817 | fmt: "[BTCoex], bt inq/page + wifi hi-pri task\n" ); |
1818 | table_case = 114; |
1819 | |
1820 | if (coex_stat->bt_profile_num > 0) |
1821 | tdma_case = 110; |
1822 | else if (coex_stat->wl_hi_pri_task1) |
1823 | tdma_case = 106; |
1824 | else if (!coex_stat->bt_page) |
1825 | tdma_case = 108; |
1826 | else |
1827 | tdma_case = 109; |
1828 | } else if (coex_stat->wl_gl_busy) { |
1829 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1830 | fmt: "[BTCoex], bt inq/page + wifi busy\n" ); |
1831 | table_case = 114; |
1832 | tdma_case = 121; |
1833 | } else if (coex_stat->wl_connected) { |
1834 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1835 | fmt: "[BTCoex], bt inq/page + wifi connected\n" ); |
1836 | table_case = 101; |
1837 | tdma_case = 100; |
1838 | } else { |
1839 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
1840 | fmt: "[BTCoex], bt inq/page + wifi not-connected\n" ); |
1841 | table_case = 101; |
1842 | tdma_case = 100; |
1843 | } |
1844 | } |
1845 | |
1846 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], wifi hi(%d), bt page(%d)\n" , |
1847 | wl_hi_pri, coex_stat->bt_page); |
1848 | |
1849 | rtw_coex_table(rtwdev, force: false, type: table_case); |
1850 | rtw_coex_tdma(rtwdev, force: false, tcase: tdma_case | slot_type); |
1851 | } |
1852 | |
1853 | static void rtw_coex_action_bt_game_hid(struct rtw_dev *rtwdev) |
1854 | { |
1855 | const struct rtw_chip_info *chip = rtwdev->chip; |
1856 | struct rtw_coex *coex = &rtwdev->coex; |
1857 | struct rtw_coex_stat *coex_stat = &coex->stat; |
1858 | struct rtw_efuse *efuse = &rtwdev->efuse; |
1859 | struct rtw_coex_dm *coex_dm = &coex->dm; |
1860 | u8 table_case, tdma_case; |
1861 | |
1862 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
1863 | rtw_coex_set_ant_path(rtwdev, force: false, phase: COEX_SET_ANT_2G); |
1864 | |
1865 | if (efuse->share_ant) { |
1866 | coex_stat->wl_coex_mode = COEX_WLINK_2GFREE; |
1867 | if (coex_stat->bt_whck_test) |
1868 | table_case = 2; |
1869 | else if (coex_stat->wl_linkscan_proc || coex_stat->bt_hid_exist) |
1870 | table_case = 33; |
1871 | else if (coex_stat->bt_setup_link || coex_stat->bt_inq_page) |
1872 | table_case = 0; |
1873 | else if (coex_stat->bt_a2dp_exist) |
1874 | table_case = 34; |
1875 | else |
1876 | table_case = 33; |
1877 | |
1878 | tdma_case = 0; |
1879 | } else { |
1880 | if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1])) |
1881 | tdma_case = 112; |
1882 | else |
1883 | tdma_case = 113; |
1884 | |
1885 | table_case = 121; |
1886 | } |
1887 | |
1888 | if (coex_stat->wl_coex_mode == COEX_WLINK_2GFREE) { |
1889 | if (coex_stat->wl_tput_dir == COEX_WL_TPUT_TX) |
1890 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_tx[6]); |
1891 | else |
1892 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[5]); |
1893 | } else { |
1894 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[0]); |
1895 | } |
1896 | |
1897 | rtw_coex_table(rtwdev, force: false, type: table_case); |
1898 | rtw_coex_tdma(rtwdev, force: false, tcase: tdma_case); |
1899 | } |
1900 | |
1901 | static void rtw_coex_action_bt_hfp(struct rtw_dev *rtwdev) |
1902 | { |
1903 | const struct rtw_chip_info *chip = rtwdev->chip; |
1904 | struct rtw_coex *coex = &rtwdev->coex; |
1905 | struct rtw_coex_stat *coex_stat = &coex->stat; |
1906 | struct rtw_efuse *efuse = &rtwdev->efuse; |
1907 | u8 table_case, tdma_case; |
1908 | |
1909 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
1910 | rtw_coex_set_ant_path(rtwdev, force: false, phase: COEX_SET_ANT_2G); |
1911 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[0]); |
1912 | |
1913 | if (efuse->share_ant) { |
1914 | /* Shared-Ant */ |
1915 | table_case = 10; |
1916 | tdma_case = 5; |
1917 | } else { |
1918 | /* Non-Shared-Ant */ |
1919 | if (coex_stat->bt_multi_link) { |
1920 | table_case = 112; |
1921 | tdma_case = 117; |
1922 | } else { |
1923 | table_case = 105; |
1924 | tdma_case = 100; |
1925 | } |
1926 | } |
1927 | |
1928 | rtw_coex_table(rtwdev, force: false, type: table_case); |
1929 | rtw_coex_tdma(rtwdev, force: false, tcase: tdma_case); |
1930 | } |
1931 | |
1932 | static void rtw_coex_action_bt_hid(struct rtw_dev *rtwdev) |
1933 | { |
1934 | const struct rtw_chip_info *chip = rtwdev->chip; |
1935 | struct rtw_coex *coex = &rtwdev->coex; |
1936 | struct rtw_coex_stat *coex_stat = &coex->stat; |
1937 | struct rtw_efuse *efuse = &rtwdev->efuse; |
1938 | u8 table_case, tdma_case; |
1939 | u32 slot_type = 0; |
1940 | bool bt_multi_link_remain = false, is_toggle_table = false; |
1941 | |
1942 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
1943 | rtw_coex_set_ant_path(rtwdev, force: false, phase: COEX_SET_ANT_2G); |
1944 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[0]); |
1945 | |
1946 | if (efuse->share_ant) { |
1947 | /* Shared-Ant */ |
1948 | if (coex_stat->bt_ble_exist) { |
1949 | /* RCU */ |
1950 | if (coex_stat->cnt_wl[COEX_CNT_WL_SCANAP] > 5) { |
1951 | table_case = 26; |
1952 | tdma_case = 2; |
1953 | } else { |
1954 | table_case = 27; |
1955 | tdma_case = 9; |
1956 | } |
1957 | } else { |
1958 | /* Legacy HID */ |
1959 | if (coex_stat->bt_profile_num == 1 && |
1960 | (coex_stat->bt_multi_link || |
1961 | (coex_stat->lo_pri_rx + |
1962 | coex_stat->lo_pri_tx > 360) || |
1963 | coex_stat->bt_slave || |
1964 | bt_multi_link_remain)) { |
1965 | slot_type = TDMA_4SLOT; |
1966 | table_case = 12; |
1967 | tdma_case = 20; |
1968 | } else if (coex_stat->bt_a2dp_active) { |
1969 | table_case = 9; |
1970 | tdma_case = 18; |
1971 | } else if (coex_stat->bt_418_hid_exist && |
1972 | coex_stat->wl_gl_busy) { |
1973 | is_toggle_table = true; |
1974 | slot_type = TDMA_4SLOT; |
1975 | table_case = 9; |
1976 | tdma_case = 24; |
1977 | } else if (coex_stat->bt_ble_hid_exist && |
1978 | coex_stat->wl_gl_busy) { |
1979 | table_case = 32; |
1980 | tdma_case = 9; |
1981 | } else { |
1982 | table_case = 9; |
1983 | tdma_case = 9; |
1984 | } |
1985 | } |
1986 | } else { |
1987 | /* Non-Shared-Ant */ |
1988 | if (coex_stat->bt_ble_exist) { |
1989 | /* BLE */ |
1990 | if (coex_stat->cnt_wl[COEX_CNT_WL_SCANAP] > 5) { |
1991 | table_case = 121; |
1992 | tdma_case = 102; |
1993 | } else { |
1994 | table_case = 122; |
1995 | tdma_case = 109; |
1996 | } |
1997 | } else if (coex_stat->bt_a2dp_active) { |
1998 | table_case = 113; |
1999 | tdma_case = 118; |
2000 | } else { |
2001 | table_case = 113; |
2002 | tdma_case = 104; |
2003 | } |
2004 | } |
2005 | |
2006 | rtw_coex_table(rtwdev, force: false, type: table_case); |
2007 | if (is_toggle_table) { |
2008 | rtw_btc_wltoggle_table_a(rtwdev, force: true, table_case); |
2009 | rtw_btc_wltoggle_table_b(rtwdev, force: false, interval: 1, COEX_WL_SLOT_TOGLLE); |
2010 | } |
2011 | |
2012 | rtw_coex_tdma(rtwdev, force: false, tcase: tdma_case | slot_type); |
2013 | } |
2014 | |
2015 | static void rtw_coex_action_bt_a2dp(struct rtw_dev *rtwdev) |
2016 | { |
2017 | const struct rtw_chip_info *chip = rtwdev->chip; |
2018 | struct rtw_coex *coex = &rtwdev->coex; |
2019 | struct rtw_coex_stat *coex_stat = &coex->stat; |
2020 | struct rtw_coex_dm *coex_dm = &coex->dm; |
2021 | struct rtw_efuse *efuse = &rtwdev->efuse; |
2022 | u8 table_case, tdma_case; |
2023 | u32 slot_type = 0; |
2024 | |
2025 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
2026 | |
2027 | rtw_coex_set_ant_path(rtwdev, force: false, phase: COEX_SET_ANT_2G); |
2028 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[0]); |
2029 | |
2030 | slot_type = TDMA_4SLOT; |
2031 | |
2032 | if (efuse->share_ant) { |
2033 | /* Shared-Ant */ |
2034 | if (coex_stat->wl_gl_busy && coex_stat->wl_noisy_level == 0) |
2035 | table_case = 12; |
2036 | else |
2037 | table_case = 9; |
2038 | |
2039 | if (coex_stat->wl_connecting || !coex_stat->wl_gl_busy) |
2040 | tdma_case = 14; |
2041 | else |
2042 | tdma_case = 13; |
2043 | } else { |
2044 | /* Non-Shared-Ant */ |
2045 | table_case = 112; |
2046 | |
2047 | if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1])) |
2048 | tdma_case = 112; |
2049 | else |
2050 | tdma_case = 113; |
2051 | } |
2052 | |
2053 | rtw_coex_table(rtwdev, force: false, type: table_case); |
2054 | rtw_coex_tdma(rtwdev, force: false, tcase: tdma_case | slot_type); |
2055 | } |
2056 | |
2057 | static void rtw_coex_action_bt_a2dpsink(struct rtw_dev *rtwdev) |
2058 | { |
2059 | const struct rtw_chip_info *chip = rtwdev->chip; |
2060 | struct rtw_coex *coex = &rtwdev->coex; |
2061 | struct rtw_coex_stat *coex_stat = &coex->stat; |
2062 | struct rtw_efuse *efuse = &rtwdev->efuse; |
2063 | u8 table_case, tdma_case; |
2064 | bool ap_enable = false; |
2065 | |
2066 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
2067 | |
2068 | rtw_coex_set_ant_path(rtwdev, force: false, phase: COEX_SET_ANT_2G); |
2069 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[0]); |
2070 | |
2071 | if (efuse->share_ant) { /* Shared-Ant */ |
2072 | if (ap_enable) { |
2073 | table_case = 2; |
2074 | tdma_case = 0; |
2075 | } else if (coex_stat->wl_gl_busy) { |
2076 | table_case = 28; |
2077 | tdma_case = 20; |
2078 | } else { |
2079 | table_case = 28; |
2080 | tdma_case = 26; |
2081 | } |
2082 | } else { /* Non-Shared-Ant */ |
2083 | if (ap_enable) { |
2084 | table_case = 100; |
2085 | tdma_case = 100; |
2086 | } else { |
2087 | table_case = 119; |
2088 | tdma_case = 120; |
2089 | } |
2090 | } |
2091 | |
2092 | rtw_coex_table(rtwdev, force: false, type: table_case); |
2093 | rtw_coex_tdma(rtwdev, force: false, tcase: tdma_case); |
2094 | } |
2095 | |
2096 | static void rtw_coex_action_bt_pan(struct rtw_dev *rtwdev) |
2097 | { |
2098 | const struct rtw_chip_info *chip = rtwdev->chip; |
2099 | struct rtw_coex *coex = &rtwdev->coex; |
2100 | struct rtw_coex_stat *coex_stat = &coex->stat; |
2101 | struct rtw_efuse *efuse = &rtwdev->efuse; |
2102 | u8 table_case, tdma_case; |
2103 | |
2104 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
2105 | rtw_coex_set_ant_path(rtwdev, force: false, phase: COEX_SET_ANT_2G); |
2106 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[0]); |
2107 | |
2108 | if (efuse->share_ant) { |
2109 | /* Shared-Ant */ |
2110 | if (coex_stat->wl_gl_busy && coex_stat->wl_noisy_level == 0) |
2111 | table_case = 14; |
2112 | else |
2113 | table_case = 10; |
2114 | |
2115 | if (coex_stat->wl_gl_busy) |
2116 | tdma_case = 17; |
2117 | else |
2118 | tdma_case = 20; |
2119 | } else { |
2120 | /* Non-Shared-Ant */ |
2121 | table_case = 112; |
2122 | |
2123 | if (coex_stat->wl_gl_busy) |
2124 | tdma_case = 117; |
2125 | else |
2126 | tdma_case = 119; |
2127 | } |
2128 | |
2129 | rtw_coex_table(rtwdev, force: false, type: table_case); |
2130 | rtw_coex_tdma(rtwdev, force: false, tcase: tdma_case); |
2131 | } |
2132 | |
2133 | static void rtw_coex_action_bt_a2dp_hid(struct rtw_dev *rtwdev) |
2134 | { |
2135 | const struct rtw_chip_info *chip = rtwdev->chip; |
2136 | struct rtw_coex *coex = &rtwdev->coex; |
2137 | struct rtw_coex_stat *coex_stat = &coex->stat; |
2138 | struct rtw_coex_dm *coex_dm = &coex->dm; |
2139 | struct rtw_efuse *efuse = &rtwdev->efuse; |
2140 | u8 table_case, tdma_case, interval = 0; |
2141 | u32 slot_type = 0; |
2142 | bool is_toggle_table = false; |
2143 | |
2144 | slot_type = TDMA_4SLOT; |
2145 | |
2146 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
2147 | rtw_coex_set_ant_path(rtwdev, force: false, phase: COEX_SET_ANT_2G); |
2148 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[0]); |
2149 | |
2150 | if (efuse->share_ant) { |
2151 | /* Shared-Ant */ |
2152 | if (coex_stat->bt_ble_exist) { |
2153 | table_case = 26; /* for RCU */ |
2154 | } else if (coex_stat->bt_418_hid_exist) { |
2155 | table_case = 9; |
2156 | interval = 1; |
2157 | } else { |
2158 | table_case = 9; |
2159 | } |
2160 | |
2161 | if (coex_stat->wl_connecting || !coex_stat->wl_gl_busy) { |
2162 | tdma_case = 14; |
2163 | } else if (coex_stat->bt_418_hid_exist) { |
2164 | is_toggle_table = true; |
2165 | tdma_case = 23; |
2166 | } else { |
2167 | tdma_case = 13; |
2168 | } |
2169 | } else { |
2170 | /* Non-Shared-Ant */ |
2171 | if (coex_stat->bt_ble_exist) |
2172 | table_case = 121; |
2173 | else |
2174 | table_case = 113; |
2175 | |
2176 | if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1])) |
2177 | tdma_case = 112; |
2178 | else |
2179 | tdma_case = 113; |
2180 | } |
2181 | |
2182 | rtw_coex_table(rtwdev, force: false, type: table_case); |
2183 | if (is_toggle_table) { |
2184 | rtw_btc_wltoggle_table_a(rtwdev, force: true, table_case); |
2185 | rtw_btc_wltoggle_table_b(rtwdev, force: false, interval, COEX_WL_SLOT_TOGLLE); |
2186 | } |
2187 | rtw_coex_tdma(rtwdev, force: false, tcase: tdma_case | slot_type); |
2188 | } |
2189 | |
2190 | static void rtw_coex_action_bt_a2dp_pan(struct rtw_dev *rtwdev) |
2191 | { |
2192 | const struct rtw_chip_info *chip = rtwdev->chip; |
2193 | struct rtw_coex *coex = &rtwdev->coex; |
2194 | struct rtw_coex_stat *coex_stat = &coex->stat; |
2195 | struct rtw_efuse *efuse = &rtwdev->efuse; |
2196 | u8 table_case, tdma_case; |
2197 | bool wl_cpt_test = false, bt_cpt_test = false; |
2198 | |
2199 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
2200 | |
2201 | rtw_coex_set_ant_path(rtwdev, force: false, phase: COEX_SET_ANT_2G); |
2202 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[0]); |
2203 | if (efuse->share_ant) { |
2204 | /* Shared-Ant */ |
2205 | if (wl_cpt_test) { |
2206 | if (coex_stat->wl_gl_busy) { |
2207 | table_case = 20; |
2208 | tdma_case = 17; |
2209 | } else { |
2210 | table_case = 10; |
2211 | tdma_case = 15; |
2212 | } |
2213 | } else if (bt_cpt_test) { |
2214 | table_case = 26; |
2215 | tdma_case = 26; |
2216 | } else { |
2217 | if (coex_stat->wl_gl_busy && |
2218 | coex_stat->wl_noisy_level == 0) |
2219 | table_case = 14; |
2220 | else |
2221 | table_case = 10; |
2222 | |
2223 | if (coex_stat->wl_gl_busy) |
2224 | tdma_case = 15; |
2225 | else |
2226 | tdma_case = 20; |
2227 | } |
2228 | } else { |
2229 | /* Non-Shared-Ant */ |
2230 | table_case = 112; |
2231 | |
2232 | if (coex_stat->wl_gl_busy) |
2233 | tdma_case = 115; |
2234 | else |
2235 | tdma_case = 120; |
2236 | } |
2237 | |
2238 | if (wl_cpt_test) |
2239 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[1]); |
2240 | else |
2241 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[0]); |
2242 | |
2243 | rtw_coex_table(rtwdev, force: false, type: table_case); |
2244 | rtw_coex_tdma(rtwdev, force: false, tcase: tdma_case); |
2245 | } |
2246 | |
2247 | static void rtw_coex_action_bt_pan_hid(struct rtw_dev *rtwdev) |
2248 | { |
2249 | const struct rtw_chip_info *chip = rtwdev->chip; |
2250 | struct rtw_coex *coex = &rtwdev->coex; |
2251 | struct rtw_coex_stat *coex_stat = &coex->stat; |
2252 | struct rtw_efuse *efuse = &rtwdev->efuse; |
2253 | u8 table_case, tdma_case; |
2254 | |
2255 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
2256 | |
2257 | rtw_coex_set_ant_path(rtwdev, force: false, phase: COEX_SET_ANT_2G); |
2258 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[0]); |
2259 | |
2260 | if (efuse->share_ant) { |
2261 | /* Shared-Ant */ |
2262 | table_case = 9; |
2263 | |
2264 | if (coex_stat->wl_gl_busy) |
2265 | tdma_case = 18; |
2266 | else |
2267 | tdma_case = 19; |
2268 | } else { |
2269 | /* Non-Shared-Ant */ |
2270 | table_case = 113; |
2271 | |
2272 | if (coex_stat->wl_gl_busy) |
2273 | tdma_case = 117; |
2274 | else |
2275 | tdma_case = 119; |
2276 | } |
2277 | |
2278 | rtw_coex_table(rtwdev, force: false, type: table_case); |
2279 | rtw_coex_tdma(rtwdev, force: false, tcase: tdma_case); |
2280 | } |
2281 | |
2282 | static void rtw_coex_action_bt_a2dp_pan_hid(struct rtw_dev *rtwdev) |
2283 | { |
2284 | const struct rtw_chip_info *chip = rtwdev->chip; |
2285 | struct rtw_coex *coex = &rtwdev->coex; |
2286 | struct rtw_coex_stat *coex_stat = &coex->stat; |
2287 | struct rtw_efuse *efuse = &rtwdev->efuse; |
2288 | u8 table_case, tdma_case; |
2289 | |
2290 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
2291 | rtw_coex_set_ant_path(rtwdev, force: false, phase: COEX_SET_ANT_2G); |
2292 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[0]); |
2293 | |
2294 | if (efuse->share_ant) { |
2295 | /* Shared-Ant */ |
2296 | table_case = 10; |
2297 | |
2298 | if (coex_stat->wl_gl_busy) |
2299 | tdma_case = 15; |
2300 | else |
2301 | tdma_case = 20; |
2302 | } else { |
2303 | /* Non-Shared-Ant */ |
2304 | table_case = 113; |
2305 | |
2306 | if (coex_stat->wl_gl_busy) |
2307 | tdma_case = 115; |
2308 | else |
2309 | tdma_case = 120; |
2310 | } |
2311 | |
2312 | rtw_coex_table(rtwdev, force: false, type: table_case); |
2313 | rtw_coex_tdma(rtwdev, force: false, tcase: tdma_case); |
2314 | } |
2315 | |
2316 | static void rtw_coex_action_wl_under5g(struct rtw_dev *rtwdev) |
2317 | { |
2318 | const struct rtw_chip_info *chip = rtwdev->chip; |
2319 | struct rtw_coex *coex = &rtwdev->coex; |
2320 | struct rtw_efuse *efuse = &rtwdev->efuse; |
2321 | struct rtw_coex_stat *coex_stat = &coex->stat; |
2322 | u8 table_case, tdma_case; |
2323 | |
2324 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
2325 | |
2326 | rtw_coex_set_ant_path(rtwdev, force: true, phase: COEX_SET_ANT_5G); |
2327 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[0]); |
2328 | |
2329 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_FIX2M, false); |
2330 | |
2331 | if (coex_stat->bt_game_hid_exist && coex_stat->wl_linkscan_proc) |
2332 | coex_stat->wl_coex_mode = COEX_WLINK_2GFREE; |
2333 | |
2334 | if (efuse->share_ant) { |
2335 | /* Shared-Ant */ |
2336 | table_case = 0; |
2337 | tdma_case = 0; |
2338 | } else { |
2339 | /* Non-Shared-Ant */ |
2340 | table_case = 100; |
2341 | tdma_case = 100; |
2342 | } |
2343 | |
2344 | rtw_coex_table(rtwdev, force: false, type: table_case); |
2345 | rtw_coex_tdma(rtwdev, force: false, tcase: tdma_case); |
2346 | } |
2347 | |
2348 | static void rtw_coex_action_wl_only(struct rtw_dev *rtwdev) |
2349 | { |
2350 | const struct rtw_chip_info *chip = rtwdev->chip; |
2351 | struct rtw_efuse *efuse = &rtwdev->efuse; |
2352 | u8 table_case, tdma_case; |
2353 | |
2354 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
2355 | rtw_coex_set_ant_path(rtwdev, force: false, phase: COEX_SET_ANT_2G); |
2356 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[0]); |
2357 | |
2358 | if (efuse->share_ant) { |
2359 | /* Shared-Ant */ |
2360 | table_case = 2; |
2361 | tdma_case = 0; |
2362 | } else { |
2363 | /* Non-Shared-Ant */ |
2364 | table_case = 100; |
2365 | tdma_case = 100; |
2366 | } |
2367 | |
2368 | rtw_coex_table(rtwdev, force: false, type: table_case); |
2369 | rtw_coex_tdma(rtwdev, force: false, tcase: tdma_case); |
2370 | } |
2371 | |
2372 | static void rtw_coex_action_wl_native_lps(struct rtw_dev *rtwdev) |
2373 | { |
2374 | const struct rtw_chip_info *chip = rtwdev->chip; |
2375 | struct rtw_coex *coex = &rtwdev->coex; |
2376 | struct rtw_efuse *efuse = &rtwdev->efuse; |
2377 | struct rtw_coex_stat *coex_stat = &coex->stat; |
2378 | u8 table_case, tdma_case; |
2379 | |
2380 | if (coex->under_5g) |
2381 | return; |
2382 | |
2383 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
2384 | |
2385 | rtw_coex_set_ant_path(rtwdev, force: false, phase: COEX_SET_ANT_2G); |
2386 | |
2387 | if (efuse->share_ant) { |
2388 | /* Shared-Ant */ |
2389 | table_case = 28; |
2390 | tdma_case = 0; |
2391 | } else { |
2392 | /* Non-Shared-Ant */ |
2393 | table_case = 100; |
2394 | tdma_case = 100; |
2395 | } |
2396 | |
2397 | if (coex_stat->bt_game_hid_exist) { |
2398 | coex_stat->wl_coex_mode = COEX_WLINK_2GFREE; |
2399 | if (coex_stat->wl_tput_dir == COEX_WL_TPUT_TX) |
2400 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_tx[6]); |
2401 | else |
2402 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[5]); |
2403 | } else { |
2404 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[0]); |
2405 | } |
2406 | |
2407 | rtw_coex_table(rtwdev, force: false, type: table_case); |
2408 | rtw_coex_tdma(rtwdev, force: false, tcase: tdma_case); |
2409 | } |
2410 | |
2411 | static void rtw_coex_action_wl_linkscan(struct rtw_dev *rtwdev) |
2412 | { |
2413 | const struct rtw_chip_info *chip = rtwdev->chip; |
2414 | struct rtw_coex *coex = &rtwdev->coex; |
2415 | struct rtw_coex_stat *coex_stat = &coex->stat; |
2416 | struct rtw_efuse *efuse = &rtwdev->efuse; |
2417 | u8 table_case, tdma_case; |
2418 | u32 slot_type = 0; |
2419 | |
2420 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
2421 | rtw_coex_set_ant_path(rtwdev, force: false, phase: COEX_SET_ANT_2G); |
2422 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[0]); |
2423 | |
2424 | if (efuse->share_ant) { /* Shared-Ant */ |
2425 | if (coex_stat->bt_a2dp_exist) { |
2426 | slot_type = TDMA_4SLOT; |
2427 | tdma_case = 11; |
2428 | if (coex_stat->wl_gl_busy) |
2429 | table_case = 26; |
2430 | else |
2431 | table_case = 9; |
2432 | } else { |
2433 | table_case = 9; |
2434 | tdma_case = 7; |
2435 | } |
2436 | } else { /* Non-Shared-Ant */ |
2437 | if (coex_stat->bt_a2dp_exist) { |
2438 | slot_type = TDMA_4SLOT; |
2439 | table_case = 112; |
2440 | tdma_case = 111; |
2441 | } else { |
2442 | table_case = 112; |
2443 | tdma_case = 107; |
2444 | } |
2445 | } |
2446 | |
2447 | rtw_coex_table(rtwdev, force: false, type: table_case); |
2448 | rtw_coex_tdma(rtwdev, force: false, tcase: tdma_case | slot_type); |
2449 | } |
2450 | |
2451 | static void rtw_coex_action_wl_not_connected(struct rtw_dev *rtwdev) |
2452 | { |
2453 | const struct rtw_chip_info *chip = rtwdev->chip; |
2454 | struct rtw_efuse *efuse = &rtwdev->efuse; |
2455 | u8 table_case, tdma_case; |
2456 | |
2457 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
2458 | rtw_coex_set_ant_path(rtwdev, force: false, phase: COEX_SET_ANT_2G); |
2459 | rtw_coex_set_rf_para(rtwdev, para: chip->wl_rf_para_rx[0]); |
2460 | |
2461 | if (efuse->share_ant) { |
2462 | /* Shared-Ant */ |
2463 | table_case = 1; |
2464 | tdma_case = 0; |
2465 | } else { |
2466 | /* Non-Shared-Ant */ |
2467 | table_case = 100; |
2468 | tdma_case = 100; |
2469 | } |
2470 | |
2471 | rtw_coex_table(rtwdev, force: false, type: table_case); |
2472 | rtw_coex_tdma(rtwdev, force: false, tcase: tdma_case); |
2473 | } |
2474 | |
2475 | static void rtw_coex_action_wl_connected(struct rtw_dev *rtwdev) |
2476 | { |
2477 | struct rtw_coex *coex = &rtwdev->coex; |
2478 | struct rtw_coex_stat *coex_stat = &coex->stat; |
2479 | u8 algorithm; |
2480 | |
2481 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
2482 | |
2483 | algorithm = rtw_coex_algorithm(rtwdev); |
2484 | |
2485 | switch (algorithm) { |
2486 | case COEX_ALGO_HFP: |
2487 | rtw_coex_action_bt_hfp(rtwdev); |
2488 | break; |
2489 | case COEX_ALGO_HID: |
2490 | if (rtw_coex_freerun_check(rtwdev)) |
2491 | rtw_coex_action_freerun(rtwdev); |
2492 | else |
2493 | rtw_coex_action_bt_hid(rtwdev); |
2494 | break; |
2495 | case COEX_ALGO_A2DP: |
2496 | if (rtw_coex_freerun_check(rtwdev)) |
2497 | rtw_coex_action_freerun(rtwdev); |
2498 | else if (coex_stat->bt_a2dp_sink) |
2499 | rtw_coex_action_bt_a2dpsink(rtwdev); |
2500 | else |
2501 | rtw_coex_action_bt_a2dp(rtwdev); |
2502 | break; |
2503 | case COEX_ALGO_PAN: |
2504 | rtw_coex_action_bt_pan(rtwdev); |
2505 | break; |
2506 | case COEX_ALGO_A2DP_HID: |
2507 | if (rtw_coex_freerun_check(rtwdev)) |
2508 | rtw_coex_action_freerun(rtwdev); |
2509 | else |
2510 | rtw_coex_action_bt_a2dp_hid(rtwdev); |
2511 | break; |
2512 | case COEX_ALGO_A2DP_PAN: |
2513 | rtw_coex_action_bt_a2dp_pan(rtwdev); |
2514 | break; |
2515 | case COEX_ALGO_PAN_HID: |
2516 | rtw_coex_action_bt_pan_hid(rtwdev); |
2517 | break; |
2518 | case COEX_ALGO_A2DP_PAN_HID: |
2519 | rtw_coex_action_bt_a2dp_pan_hid(rtwdev); |
2520 | break; |
2521 | default: |
2522 | case COEX_ALGO_NOPROFILE: |
2523 | rtw_coex_action_bt_idle(rtwdev); |
2524 | break; |
2525 | } |
2526 | } |
2527 | |
2528 | static void rtw_coex_run_coex(struct rtw_dev *rtwdev, u8 reason) |
2529 | { |
2530 | const struct rtw_chip_info *chip = rtwdev->chip; |
2531 | struct rtw_coex *coex = &rtwdev->coex; |
2532 | struct rtw_coex_dm *coex_dm = &coex->dm; |
2533 | struct rtw_coex_stat *coex_stat = &coex->stat; |
2534 | bool rf4ce_en = false; |
2535 | |
2536 | lockdep_assert_held(&rtwdev->mutex); |
2537 | |
2538 | if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags)) |
2539 | return; |
2540 | |
2541 | coex_dm->reason = reason; |
2542 | |
2543 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s(): reason = %d\n" , __func__, |
2544 | reason); |
2545 | |
2546 | /* update wifi_link_info_ext variable */ |
2547 | rtw_coex_update_wl_link_info(rtwdev, reason); |
2548 | |
2549 | rtw_coex_monitor_bt_enable(rtwdev); |
2550 | |
2551 | if (coex->manual_control) { |
2552 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
2553 | fmt: "[BTCoex], return for Manual CTRL!!\n" ); |
2554 | return; |
2555 | } |
2556 | |
2557 | if (coex->stop_dm) { |
2558 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
2559 | fmt: "[BTCoex], return for Stop Coex DM!!\n" ); |
2560 | return; |
2561 | } |
2562 | |
2563 | if (coex_stat->wl_under_ips) { |
2564 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
2565 | fmt: "[BTCoex], return for wifi is under IPS!!\n" ); |
2566 | return; |
2567 | } |
2568 | |
2569 | if (coex->freeze && coex_dm->reason == COEX_RSN_BTINFO && |
2570 | !coex_stat->bt_setup_link) { |
2571 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
2572 | fmt: "[BTCoex], return for coex_freeze!!\n" ); |
2573 | return; |
2574 | } |
2575 | |
2576 | coex_stat->cnt_wl[COEX_CNT_WL_COEXRUN]++; |
2577 | coex->freerun = false; |
2578 | |
2579 | /* Pure-5G Coex Process */ |
2580 | if (coex->under_5g) { |
2581 | coex_stat->wl_coex_mode = COEX_WLINK_5G; |
2582 | rtw_coex_action_wl_under5g(rtwdev); |
2583 | goto exit; |
2584 | } |
2585 | |
2586 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], WiFi is single-port 2G!!\n" ); |
2587 | coex_stat->wl_coex_mode = COEX_WLINK_2G1PORT; |
2588 | |
2589 | if (coex_stat->bt_disabled) { |
2590 | if (coex_stat->wl_connected && rf4ce_en) |
2591 | rtw_coex_action_rf4ce(rtwdev); |
2592 | else if (!coex_stat->wl_connected) |
2593 | rtw_coex_action_wl_not_connected(rtwdev); |
2594 | else |
2595 | rtw_coex_action_wl_only(rtwdev); |
2596 | goto exit; |
2597 | } |
2598 | |
2599 | if (coex_stat->wl_under_lps && !coex_stat->wl_force_lps_ctrl) { |
2600 | rtw_coex_action_wl_native_lps(rtwdev); |
2601 | goto exit; |
2602 | } |
2603 | |
2604 | if (coex_stat->bt_game_hid_exist && coex_stat->wl_connected) { |
2605 | rtw_coex_action_bt_game_hid(rtwdev); |
2606 | goto exit; |
2607 | } |
2608 | |
2609 | if (coex_stat->bt_whck_test) { |
2610 | rtw_coex_action_bt_whql_test(rtwdev); |
2611 | goto exit; |
2612 | } |
2613 | |
2614 | if (coex_stat->bt_setup_link) { |
2615 | rtw_coex_action_bt_relink(rtwdev); |
2616 | goto exit; |
2617 | } |
2618 | |
2619 | if (coex_stat->bt_inq_page) { |
2620 | rtw_coex_action_bt_inquiry(rtwdev); |
2621 | goto exit; |
2622 | } |
2623 | |
2624 | if ((coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE || |
2625 | coex_dm->bt_status == COEX_BTSTATUS_CON_IDLE) && |
2626 | coex_stat->wl_connected) { |
2627 | rtw_coex_action_bt_idle(rtwdev); |
2628 | goto exit; |
2629 | } |
2630 | |
2631 | if (coex_stat->wl_linkscan_proc && !coex->freerun) { |
2632 | rtw_coex_action_wl_linkscan(rtwdev); |
2633 | goto exit; |
2634 | } |
2635 | |
2636 | if (coex_stat->wl_connected) { |
2637 | rtw_coex_action_wl_connected(rtwdev); |
2638 | goto exit; |
2639 | } else { |
2640 | rtw_coex_action_wl_not_connected(rtwdev); |
2641 | goto exit; |
2642 | } |
2643 | |
2644 | exit: |
2645 | |
2646 | if (chip->wl_mimo_ps_support) { |
2647 | if (coex_stat->wl_coex_mode == COEX_WLINK_2GFREE) { |
2648 | if (coex_dm->reason == COEX_RSN_2GMEDIA) |
2649 | rtw_coex_mimo_ps(rtwdev, force: true, state: true); |
2650 | else |
2651 | rtw_coex_mimo_ps(rtwdev, force: false, state: true); |
2652 | } else { |
2653 | rtw_coex_mimo_ps(rtwdev, force: false, state: false); |
2654 | } |
2655 | } |
2656 | |
2657 | rtw_coex_gnt_workaround(rtwdev, force: false, mode: coex_stat->wl_coex_mode); |
2658 | rtw_coex_limited_wl(rtwdev); |
2659 | } |
2660 | |
2661 | static void rtw_coex_init_coex_var(struct rtw_dev *rtwdev) |
2662 | { |
2663 | struct rtw_coex *coex = &rtwdev->coex; |
2664 | struct rtw_coex_stat *coex_stat = &coex->stat; |
2665 | struct rtw_coex_dm *coex_dm = &coex->dm; |
2666 | u8 i; |
2667 | |
2668 | memset(coex_dm, 0, sizeof(*coex_dm)); |
2669 | memset(coex_stat, 0, sizeof(*coex_stat)); |
2670 | |
2671 | for (i = 0; i < COEX_CNT_WL_MAX; i++) |
2672 | coex_stat->cnt_wl[i] = 0; |
2673 | |
2674 | for (i = 0; i < COEX_CNT_BT_MAX; i++) |
2675 | coex_stat->cnt_bt[i] = 0; |
2676 | |
2677 | for (i = 0; i < ARRAY_SIZE(coex_dm->bt_rssi_state); i++) |
2678 | coex_dm->bt_rssi_state[i] = COEX_RSSI_STATE_LOW; |
2679 | |
2680 | for (i = 0; i < ARRAY_SIZE(coex_dm->wl_rssi_state); i++) |
2681 | coex_dm->wl_rssi_state[i] = COEX_RSSI_STATE_LOW; |
2682 | |
2683 | coex_stat->wl_coex_mode = COEX_WLINK_MAX; |
2684 | coex_stat->wl_rx_rate = DESC_RATE5_5M; |
2685 | coex_stat->wl_rts_rx_rate = DESC_RATE5_5M; |
2686 | } |
2687 | |
2688 | static void __rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only) |
2689 | { |
2690 | struct rtw_coex *coex = &rtwdev->coex; |
2691 | struct rtw_coex_stat *coex_stat = &coex->stat; |
2692 | |
2693 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
2694 | |
2695 | rtw_coex_init_coex_var(rtwdev); |
2696 | |
2697 | coex_stat->kt_ver = u8_get_bits(v: rtw_read8(rtwdev, addr: 0xf1), GENMASK(7, 4)); |
2698 | |
2699 | rtw_coex_monitor_bt_enable(rtwdev); |
2700 | rtw_coex_wl_slot_extend(rtwdev, enable: coex_stat->wl_slot_extend); |
2701 | |
2702 | rtw_write8_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION); |
2703 | |
2704 | rtw_coex_set_rfe_type(rtwdev); |
2705 | rtw_coex_set_init(rtwdev); |
2706 | |
2707 | /* set Tx response = Hi-Pri (ex: Transmitting ACK,BA,CTS) */ |
2708 | rtw_coex_set_wl_pri_mask(rtwdev, bitmap: COEX_WLPRI_TX_RSP, data: 1); |
2709 | |
2710 | /* set Tx beacon = Hi-Pri */ |
2711 | rtw_coex_set_wl_pri_mask(rtwdev, bitmap: COEX_WLPRI_TX_BEACON, data: 1); |
2712 | |
2713 | /* set Tx beacon queue = Hi-Pri */ |
2714 | rtw_coex_set_wl_pri_mask(rtwdev, bitmap: COEX_WLPRI_TX_BEACONQ, data: 1); |
2715 | |
2716 | /* antenna config */ |
2717 | if (coex->wl_rf_off) { |
2718 | rtw_coex_set_ant_path(rtwdev, force: true, phase: COEX_SET_ANT_WOFF); |
2719 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ALL, false); |
2720 | coex->stop_dm = true; |
2721 | |
2722 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s(): RF Off\n" , |
2723 | __func__); |
2724 | } else if (wifi_only) { |
2725 | rtw_coex_set_ant_path(rtwdev, force: true, phase: COEX_SET_ANT_WONLY); |
2726 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF, |
2727 | true); |
2728 | coex->stop_dm = true; |
2729 | } else { |
2730 | rtw_coex_set_ant_path(rtwdev, force: true, phase: COEX_SET_ANT_INIT); |
2731 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF, |
2732 | true); |
2733 | coex->stop_dm = false; |
2734 | coex->freeze = true; |
2735 | } |
2736 | |
2737 | /* PTA parameter */ |
2738 | rtw_coex_table(rtwdev, force: true, type: 1); |
2739 | rtw_coex_tdma(rtwdev, force: true, tcase: 0); |
2740 | rtw_coex_query_bt_info(rtwdev); |
2741 | } |
2742 | |
2743 | void rtw_coex_power_on_setting(struct rtw_dev *rtwdev) |
2744 | { |
2745 | struct rtw_coex *coex = &rtwdev->coex; |
2746 | u8 table_case = 1; |
2747 | |
2748 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
2749 | |
2750 | coex->stop_dm = true; |
2751 | coex->wl_rf_off = false; |
2752 | |
2753 | /* enable BB, we can write 0x948 */ |
2754 | rtw_write8_set(rtwdev, REG_SYS_FUNC_EN, |
2755 | BIT_FEN_BB_GLB_RST | BIT_FEN_BB_RSTB); |
2756 | |
2757 | rtw_coex_monitor_bt_enable(rtwdev); |
2758 | rtw_coex_set_rfe_type(rtwdev); |
2759 | |
2760 | /* set antenna path to BT */ |
2761 | rtw_coex_set_ant_path(rtwdev, force: true, phase: COEX_SET_ANT_POWERON); |
2762 | |
2763 | rtw_coex_table(rtwdev, force: true, type: table_case); |
2764 | /* red x issue */ |
2765 | rtw_write8(rtwdev, addr: 0xff1a, val: 0x0); |
2766 | rtw_coex_set_gnt_debug(rtwdev); |
2767 | } |
2768 | |
2769 | void rtw_coex_power_off_setting(struct rtw_dev *rtwdev) |
2770 | { |
2771 | rtw_write16(rtwdev, REG_WIFI_BT_INFO, BIT_BT_INT_EN); |
2772 | } |
2773 | |
2774 | void rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only) |
2775 | { |
2776 | __rtw_coex_init_hw_config(rtwdev, wifi_only); |
2777 | } |
2778 | |
2779 | void rtw_coex_ips_notify(struct rtw_dev *rtwdev, u8 type) |
2780 | { |
2781 | struct rtw_coex *coex = &rtwdev->coex; |
2782 | struct rtw_coex_stat *coex_stat = &coex->stat; |
2783 | |
2784 | if (coex->manual_control || coex->stop_dm) |
2785 | return; |
2786 | |
2787 | if (type == COEX_IPS_ENTER) { |
2788 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], IPS ENTER notify\n" ); |
2789 | |
2790 | coex_stat->wl_under_ips = true; |
2791 | |
2792 | /* for lps off */ |
2793 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ALL, false); |
2794 | |
2795 | rtw_coex_set_ant_path(rtwdev, force: true, phase: COEX_SET_ANT_WOFF); |
2796 | rtw_coex_action_coex_all_off(rtwdev); |
2797 | } else if (type == COEX_IPS_LEAVE) { |
2798 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], IPS LEAVE notify\n" ); |
2799 | |
2800 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF, true); |
2801 | /* run init hw config (exclude wifi only) */ |
2802 | __rtw_coex_init_hw_config(rtwdev, wifi_only: false); |
2803 | |
2804 | coex_stat->wl_under_ips = false; |
2805 | } |
2806 | } |
2807 | |
2808 | void rtw_coex_lps_notify(struct rtw_dev *rtwdev, u8 type) |
2809 | { |
2810 | struct rtw_coex *coex = &rtwdev->coex; |
2811 | struct rtw_coex_stat *coex_stat = &coex->stat; |
2812 | |
2813 | if (coex->manual_control || coex->stop_dm) |
2814 | return; |
2815 | |
2816 | if (type == COEX_LPS_ENABLE) { |
2817 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], LPS ENABLE notify\n" ); |
2818 | |
2819 | coex_stat->wl_under_lps = true; |
2820 | |
2821 | if (coex_stat->wl_force_lps_ctrl) { |
2822 | /* for ps-tdma */ |
2823 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true); |
2824 | } else { |
2825 | /* for native ps */ |
2826 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, false); |
2827 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_WLBUSY, false); |
2828 | |
2829 | rtw_coex_run_coex(rtwdev, reason: COEX_RSN_LPS); |
2830 | } |
2831 | } else if (type == COEX_LPS_DISABLE) { |
2832 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], LPS DISABLE notify\n" ); |
2833 | |
2834 | coex_stat->wl_under_lps = false; |
2835 | |
2836 | /* for lps off */ |
2837 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true); |
2838 | |
2839 | if (!coex_stat->wl_force_lps_ctrl) |
2840 | rtw_coex_query_bt_info(rtwdev); |
2841 | |
2842 | rtw_coex_run_coex(rtwdev, reason: COEX_RSN_LPS); |
2843 | } |
2844 | } |
2845 | |
2846 | void rtw_coex_scan_notify(struct rtw_dev *rtwdev, u8 type) |
2847 | { |
2848 | struct rtw_coex *coex = &rtwdev->coex; |
2849 | struct rtw_coex_stat *coex_stat = &coex->stat; |
2850 | |
2851 | if (coex->manual_control || coex->stop_dm) |
2852 | return; |
2853 | |
2854 | coex->freeze = false; |
2855 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF, true); |
2856 | |
2857 | if (type == COEX_SCAN_START_5G) { |
2858 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
2859 | fmt: "[BTCoex], SCAN START notify (5G)\n" ); |
2860 | |
2861 | rtw_coex_set_ant_path(rtwdev, force: true, phase: COEX_SET_ANT_5G); |
2862 | rtw_coex_run_coex(rtwdev, reason: COEX_RSN_5GSCANSTART); |
2863 | } else if ((type == COEX_SCAN_START_2G) || (type == COEX_SCAN_START)) { |
2864 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
2865 | fmt: "[BTCoex], SCAN START notify (2G)\n" ); |
2866 | |
2867 | coex_stat->wl_hi_pri_task2 = true; |
2868 | |
2869 | /* Force antenna setup for no scan result issue */ |
2870 | rtw_coex_set_ant_path(rtwdev, force: true, phase: COEX_SET_ANT_2G); |
2871 | rtw_coex_run_coex(rtwdev, reason: COEX_RSN_2GSCANSTART); |
2872 | } else { |
2873 | coex_stat->cnt_wl[COEX_CNT_WL_SCANAP] = 30; /* To do */ |
2874 | |
2875 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
2876 | fmt: "[BTCoex], SCAN FINISH notify (Scan-AP = %d)\n" , |
2877 | coex_stat->cnt_wl[COEX_CNT_WL_SCANAP]); |
2878 | |
2879 | coex_stat->wl_hi_pri_task2 = false; |
2880 | rtw_coex_run_coex(rtwdev, reason: COEX_RSN_SCANFINISH); |
2881 | } |
2882 | } |
2883 | |
2884 | void rtw_coex_switchband_notify(struct rtw_dev *rtwdev, u8 type) |
2885 | { |
2886 | struct rtw_coex *coex = &rtwdev->coex; |
2887 | |
2888 | if (coex->manual_control || coex->stop_dm) |
2889 | return; |
2890 | |
2891 | if (type == COEX_SWITCH_TO_5G) { |
2892 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s(): TO_5G\n" , |
2893 | __func__); |
2894 | } else if (type == COEX_SWITCH_TO_24G_NOFORSCAN) { |
2895 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
2896 | fmt: "[BTCoex], %s(): TO_24G_NOFORSCAN\n" , __func__); |
2897 | } else { |
2898 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s(): TO_2G\n" , |
2899 | __func__); |
2900 | } |
2901 | |
2902 | if (type == COEX_SWITCH_TO_5G) |
2903 | rtw_coex_run_coex(rtwdev, reason: COEX_RSN_5GSWITCHBAND); |
2904 | else if (type == COEX_SWITCH_TO_24G_NOFORSCAN) |
2905 | rtw_coex_run_coex(rtwdev, reason: COEX_RSN_2GSWITCHBAND); |
2906 | else |
2907 | rtw_coex_scan_notify(rtwdev, type: COEX_SCAN_START_2G); |
2908 | } |
2909 | |
2910 | void rtw_coex_connect_notify(struct rtw_dev *rtwdev, u8 type) |
2911 | { |
2912 | struct rtw_coex *coex = &rtwdev->coex; |
2913 | struct rtw_coex_stat *coex_stat = &coex->stat; |
2914 | |
2915 | if (coex->manual_control || coex->stop_dm) |
2916 | return; |
2917 | |
2918 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF, true); |
2919 | |
2920 | if (type == COEX_ASSOCIATE_5G_START) { |
2921 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s(): 5G start\n" , |
2922 | __func__); |
2923 | |
2924 | rtw_coex_set_ant_path(rtwdev, force: true, phase: COEX_SET_ANT_5G); |
2925 | rtw_coex_run_coex(rtwdev, reason: COEX_RSN_5GCONSTART); |
2926 | } else if (type == COEX_ASSOCIATE_5G_FINISH) { |
2927 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s(): 5G finish\n" , |
2928 | __func__); |
2929 | |
2930 | rtw_coex_set_ant_path(rtwdev, force: true, phase: COEX_SET_ANT_5G); |
2931 | rtw_coex_run_coex(rtwdev, reason: COEX_RSN_5GCONFINISH); |
2932 | } else if (type == COEX_ASSOCIATE_START) { |
2933 | coex_stat->wl_hi_pri_task1 = true; |
2934 | coex_stat->wl_connecting = true; |
2935 | coex_stat->cnt_wl[COEX_CNT_WL_CONNPKT] = 2; |
2936 | coex_stat->wl_connecting = true; |
2937 | ieee80211_queue_delayed_work(hw: rtwdev->hw, |
2938 | dwork: &coex->wl_connecting_work, delay: 2 * HZ); |
2939 | |
2940 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s(): 2G start\n" , |
2941 | __func__); |
2942 | /* Force antenna setup for no scan result issue */ |
2943 | rtw_coex_set_ant_path(rtwdev, force: true, phase: COEX_SET_ANT_2G); |
2944 | |
2945 | rtw_coex_run_coex(rtwdev, reason: COEX_RSN_2GCONSTART); |
2946 | |
2947 | /* To keep TDMA case during connect process, |
2948 | * to avoid changed by Btinfo and runcoexmechanism |
2949 | */ |
2950 | coex->freeze = true; |
2951 | ieee80211_queue_delayed_work(hw: rtwdev->hw, dwork: &coex->defreeze_work, |
2952 | delay: 5 * HZ); |
2953 | } else { |
2954 | coex_stat->wl_hi_pri_task1 = false; |
2955 | coex->freeze = false; |
2956 | coex_stat->wl_connecting = false; |
2957 | |
2958 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s(): 2G finish\n" , |
2959 | __func__); |
2960 | rtw_coex_run_coex(rtwdev, reason: COEX_RSN_2GCONFINISH); |
2961 | } |
2962 | } |
2963 | |
2964 | void rtw_coex_media_status_notify(struct rtw_dev *rtwdev, u8 type) |
2965 | { |
2966 | struct rtw_coex *coex = &rtwdev->coex; |
2967 | struct rtw_coex_stat *coex_stat = &coex->stat; |
2968 | |
2969 | if (coex->manual_control || coex->stop_dm) |
2970 | return; |
2971 | |
2972 | if (type == COEX_MEDIA_CONNECT_5G) { |
2973 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s(): 5G\n" , __func__); |
2974 | |
2975 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true); |
2976 | |
2977 | rtw_coex_set_ant_path(rtwdev, force: true, phase: COEX_SET_ANT_5G); |
2978 | rtw_coex_run_coex(rtwdev, reason: COEX_RSN_5GMEDIA); |
2979 | } else if (type == COEX_MEDIA_CONNECT) { |
2980 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s(): 2G\n" , __func__); |
2981 | |
2982 | coex_stat->wl_connecting = false; |
2983 | |
2984 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true); |
2985 | |
2986 | /* Force antenna setup for no scan result issue */ |
2987 | rtw_coex_set_ant_path(rtwdev, force: true, phase: COEX_SET_ANT_2G); |
2988 | |
2989 | /* Set CCK Rx high Pri */ |
2990 | rtw_coex_set_wl_pri_mask(rtwdev, bitmap: COEX_WLPRI_RX_CCK, data: 1); |
2991 | rtw_coex_run_coex(rtwdev, reason: COEX_RSN_2GMEDIA); |
2992 | } else { |
2993 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s(): disconnect!!\n" , |
2994 | __func__); |
2995 | rtw_coex_set_wl_pri_mask(rtwdev, bitmap: COEX_WLPRI_RX_CCK, data: 0); |
2996 | rtw_coex_run_coex(rtwdev, reason: COEX_RSN_MEDIADISCON); |
2997 | } |
2998 | |
2999 | rtw_coex_update_wl_ch_info(rtwdev, type); |
3000 | } |
3001 | |
3002 | void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length) |
3003 | { |
3004 | const struct rtw_chip_info *chip = rtwdev->chip; |
3005 | struct rtw_coex *coex = &rtwdev->coex; |
3006 | struct rtw_coex_stat *coex_stat = &coex->stat; |
3007 | struct rtw_coex_dm *coex_dm = &coex->dm; |
3008 | u32 bt_relink_time; |
3009 | u8 i, rsp_source = 0, type; |
3010 | bool inq_page = false; |
3011 | |
3012 | rsp_source = buf[0] & 0xf; |
3013 | if (rsp_source >= COEX_BTINFO_SRC_MAX) |
3014 | return; |
3015 | coex_stat->cnt_bt_info_c2h[rsp_source]++; |
3016 | |
3017 | if (rsp_source == COEX_BTINFO_SRC_BT_IQK) { |
3018 | coex_stat->bt_iqk_state = buf[1]; |
3019 | if (coex_stat->bt_iqk_state == 0) |
3020 | coex_stat->cnt_bt[COEX_CNT_BT_IQK]++; |
3021 | else if (coex_stat->bt_iqk_state == 2) |
3022 | coex_stat->cnt_bt[COEX_CNT_BT_IQKFAIL]++; |
3023 | |
3024 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
3025 | fmt: "[BTCoex], BT IQK by bt_info, data0 = 0x%02x\n" , |
3026 | buf[1]); |
3027 | |
3028 | return; |
3029 | } |
3030 | |
3031 | if (rsp_source == COEX_BTINFO_SRC_BT_SCBD) { |
3032 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
3033 | fmt: "[BTCoex], BT Scoreboard change notify by WL FW c2h, 0xaa = 0x%02x, 0xab = 0x%02x\n" , |
3034 | buf[1], buf[2]); |
3035 | |
3036 | rtw_coex_monitor_bt_enable(rtwdev); |
3037 | if (coex_stat->bt_disabled != coex_stat->bt_disabled_pre) { |
3038 | coex_stat->bt_disabled_pre = coex_stat->bt_disabled; |
3039 | rtw_coex_run_coex(rtwdev, reason: COEX_RSN_BTINFO); |
3040 | } |
3041 | return; |
3042 | } |
3043 | |
3044 | if (rsp_source == COEX_BTINFO_SRC_H2C60) { |
3045 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
3046 | fmt: "[BTCoex], H2C 0x60 content replied by WL FW: H2C_0x60 = [%02x %02x %02x %02x %02x]\n" , |
3047 | buf[1], buf[2], buf[3], buf[4], buf[5]); |
3048 | |
3049 | for (i = 1; i <= COEX_WL_TDMA_PARA_LENGTH; i++) |
3050 | coex_dm->fw_tdma_para[i - 1] = buf[i]; |
3051 | return; |
3052 | } |
3053 | |
3054 | if (rsp_source == COEX_BTINFO_SRC_WL_FW) { |
3055 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
3056 | fmt: "[BTCoex], bt_info reply by WL FW\n" ); |
3057 | |
3058 | rtw_coex_update_bt_link_info(rtwdev); |
3059 | return; |
3060 | } |
3061 | |
3062 | if (rsp_source == COEX_BTINFO_SRC_BT_RSP || |
3063 | rsp_source == COEX_BTINFO_SRC_BT_ACT) { |
3064 | if (coex_stat->bt_disabled) { |
3065 | coex_stat->bt_disabled = false; |
3066 | coex_stat->bt_reenable = true; |
3067 | ieee80211_queue_delayed_work(hw: rtwdev->hw, |
3068 | dwork: &coex->bt_reenable_work, |
3069 | delay: 15 * HZ); |
3070 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
3071 | fmt: "[BTCoex], BT enable detected by bt_info\n" ); |
3072 | } |
3073 | } |
3074 | |
3075 | if (length != COEX_BTINFO_LENGTH) { |
3076 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
3077 | fmt: "[BTCoex], Bt_info length = %d invalid!!\n" , length); |
3078 | |
3079 | return; |
3080 | } |
3081 | |
3082 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
3083 | fmt: "[BTCoex], Bt_info[%d], len=%d, data=[%02x %02x %02x %02x %02x %02x]\n" , |
3084 | buf[0], length, buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); |
3085 | |
3086 | for (i = 0; i < COEX_BTINFO_LENGTH; i++) |
3087 | coex_stat->bt_info_c2h[rsp_source][i] = buf[i]; |
3088 | |
3089 | /* get the same info from bt, skip it */ |
3090 | if (coex_stat->bt_info_c2h[rsp_source][1] == coex_stat->bt_info_lb2 && |
3091 | coex_stat->bt_info_c2h[rsp_source][2] == coex_stat->bt_info_lb3 && |
3092 | coex_stat->bt_info_c2h[rsp_source][3] == coex_stat->bt_info_hb0 && |
3093 | coex_stat->bt_info_c2h[rsp_source][4] == coex_stat->bt_info_hb1 && |
3094 | coex_stat->bt_info_c2h[rsp_source][5] == coex_stat->bt_info_hb2 && |
3095 | coex_stat->bt_info_c2h[rsp_source][6] == coex_stat->bt_info_hb3) { |
3096 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
3097 | fmt: "[BTCoex], Return because Btinfo duplicate!!\n" ); |
3098 | return; |
3099 | } |
3100 | |
3101 | coex_stat->bt_info_lb2 = coex_stat->bt_info_c2h[rsp_source][1]; |
3102 | coex_stat->bt_info_lb3 = coex_stat->bt_info_c2h[rsp_source][2]; |
3103 | coex_stat->bt_info_hb0 = coex_stat->bt_info_c2h[rsp_source][3]; |
3104 | coex_stat->bt_info_hb1 = coex_stat->bt_info_c2h[rsp_source][4]; |
3105 | coex_stat->bt_info_hb2 = coex_stat->bt_info_c2h[rsp_source][5]; |
3106 | coex_stat->bt_info_hb3 = coex_stat->bt_info_c2h[rsp_source][6]; |
3107 | |
3108 | /* 0xff means BT is under WHCK test */ |
3109 | coex_stat->bt_whck_test = (coex_stat->bt_info_lb2 == 0xff); |
3110 | |
3111 | inq_page = ((coex_stat->bt_info_lb2 & BIT(2)) == BIT(2)); |
3112 | |
3113 | if (inq_page != coex_stat->bt_inq_page) { |
3114 | cancel_delayed_work_sync(dwork: &coex->bt_remain_work); |
3115 | coex_stat->bt_inq_page = inq_page; |
3116 | |
3117 | if (inq_page) |
3118 | coex_stat->bt_inq_remain = true; |
3119 | else |
3120 | ieee80211_queue_delayed_work(hw: rtwdev->hw, |
3121 | dwork: &coex->bt_remain_work, |
3122 | delay: 4 * HZ); |
3123 | } |
3124 | coex_stat->bt_acl_busy = ((coex_stat->bt_info_lb2 & BIT(3)) == BIT(3)); |
3125 | if (chip->ble_hid_profile_support) { |
3126 | if (coex_stat->bt_info_lb2 & BIT(5)) { |
3127 | if (coex_stat->bt_info_hb1 & BIT(0)) { |
3128 | /*BLE HID*/ |
3129 | coex_stat->bt_ble_hid_exist = true; |
3130 | } else { |
3131 | coex_stat->bt_ble_hid_exist = false; |
3132 | } |
3133 | coex_stat->bt_ble_exist = false; |
3134 | } else if (coex_stat->bt_info_hb1 & BIT(0)) { |
3135 | /*RCU*/ |
3136 | coex_stat->bt_ble_hid_exist = false; |
3137 | coex_stat->bt_ble_exist = true; |
3138 | } else { |
3139 | coex_stat->bt_ble_hid_exist = false; |
3140 | coex_stat->bt_ble_exist = false; |
3141 | } |
3142 | } else { |
3143 | if (coex_stat->bt_info_hb1 & BIT(0)) { |
3144 | if (coex_stat->bt_hid_slot == 1 && |
3145 | coex_stat->hi_pri_rx + 100 < coex_stat->hi_pri_tx && |
3146 | coex_stat->hi_pri_rx < 100) { |
3147 | coex_stat->bt_ble_hid_exist = true; |
3148 | coex_stat->bt_ble_exist = false; |
3149 | } else { |
3150 | coex_stat->bt_ble_hid_exist = false; |
3151 | coex_stat->bt_ble_exist = true; |
3152 | } |
3153 | } else { |
3154 | coex_stat->bt_ble_hid_exist = false; |
3155 | coex_stat->bt_ble_exist = false; |
3156 | } |
3157 | } |
3158 | |
3159 | coex_stat->cnt_bt[COEX_CNT_BT_RETRY] = coex_stat->bt_info_lb3 & 0xf; |
3160 | if (coex_stat->cnt_bt[COEX_CNT_BT_RETRY] >= 1) |
3161 | coex_stat->cnt_bt[COEX_CNT_BT_POPEVENT]++; |
3162 | |
3163 | coex_stat->bt_fix_2M = ((coex_stat->bt_info_lb3 & BIT(4)) == BIT(4)); |
3164 | coex_stat->bt_inq = ((coex_stat->bt_info_lb3 & BIT(5)) == BIT(5)); |
3165 | if (coex_stat->bt_inq) |
3166 | coex_stat->cnt_bt[COEX_CNT_BT_INQ]++; |
3167 | |
3168 | coex_stat->bt_page = ((coex_stat->bt_info_lb3 & BIT(7)) == BIT(7)); |
3169 | if (coex_stat->bt_page) |
3170 | coex_stat->cnt_bt[COEX_CNT_BT_PAGE]++; |
3171 | |
3172 | /* unit: % (value-100 to translate to unit: dBm in coex info) */ |
3173 | if (chip->bt_rssi_type == COEX_BTRSSI_RATIO) { |
3174 | coex_stat->bt_rssi = coex_stat->bt_info_hb0 * 2 + 10; |
3175 | } else { |
3176 | if (coex_stat->bt_info_hb0 <= 127) |
3177 | coex_stat->bt_rssi = 100; |
3178 | else if (256 - coex_stat->bt_info_hb0 <= 100) |
3179 | coex_stat->bt_rssi = 100 - (256 - coex_stat->bt_info_hb0); |
3180 | else |
3181 | coex_stat->bt_rssi = 0; |
3182 | } |
3183 | |
3184 | if (coex_stat->bt_info_hb1 & BIT(1)) |
3185 | coex_stat->cnt_bt[COEX_CNT_BT_REINIT]++; |
3186 | |
3187 | if (coex_stat->bt_info_hb1 & BIT(2)) { |
3188 | coex_stat->cnt_bt[COEX_CNT_BT_SETUPLINK]++; |
3189 | coex_stat->bt_setup_link = true; |
3190 | if (coex_stat->bt_reenable) |
3191 | bt_relink_time = 6 * HZ; |
3192 | else |
3193 | bt_relink_time = 1 * HZ; |
3194 | |
3195 | ieee80211_queue_delayed_work(hw: rtwdev->hw, |
3196 | dwork: &coex->bt_relink_work, |
3197 | delay: bt_relink_time); |
3198 | |
3199 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
3200 | fmt: "[BTCoex], Re-Link start in BT info!!\n" ); |
3201 | } |
3202 | |
3203 | if (coex_stat->bt_info_hb1 & BIT(3)) |
3204 | coex_stat->cnt_bt[COEX_CNT_BT_IGNWLANACT]++; |
3205 | |
3206 | coex_stat->bt_ble_voice = ((coex_stat->bt_info_hb1 & BIT(4)) == BIT(4)); |
3207 | coex_stat->bt_ble_scan_en = ((coex_stat->bt_info_hb1 & BIT(5)) == BIT(5)); |
3208 | if (coex_stat->bt_info_hb1 & BIT(6)) |
3209 | coex_stat->cnt_bt[COEX_CNT_BT_ROLESWITCH]++; |
3210 | |
3211 | coex_stat->bt_multi_link = ((coex_stat->bt_info_hb1 & BIT(7)) == BIT(7)); |
3212 | /* for multi_link = 0 but bt pkt remain exist */ |
3213 | /* Use PS-TDMA to protect WL RX */ |
3214 | if (!coex_stat->bt_multi_link && coex_stat->bt_multi_link_pre) { |
3215 | coex_stat->bt_multi_link_remain = true; |
3216 | ieee80211_queue_delayed_work(hw: rtwdev->hw, |
3217 | dwork: &coex->bt_multi_link_remain_work, |
3218 | delay: 3 * HZ); |
3219 | } |
3220 | coex_stat->bt_multi_link_pre = coex_stat->bt_multi_link; |
3221 | |
3222 | /* resend wifi info to bt, it is reset and lost the info */ |
3223 | if (coex_stat->bt_info_hb1 & BIT(1)) { |
3224 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
3225 | fmt: "[BTCoex], BT Re-init, send wifi BW & Chnl to BT!!\n" ); |
3226 | |
3227 | if (coex_stat->wl_connected) |
3228 | type = COEX_MEDIA_CONNECT; |
3229 | else |
3230 | type = COEX_MEDIA_DISCONNECT; |
3231 | rtw_coex_update_wl_ch_info(rtwdev, type); |
3232 | } |
3233 | |
3234 | /* if ignore_wlan_act && not set_up_link */ |
3235 | if ((coex_stat->bt_info_hb1 & BIT(3)) && |
3236 | (!(coex_stat->bt_info_hb1 & BIT(2)))) { |
3237 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
3238 | fmt: "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n" ); |
3239 | rtw_coex_ignore_wlan_act(rtwdev, enable: false); |
3240 | } |
3241 | |
3242 | coex_stat->bt_opp_exist = ((coex_stat->bt_info_hb2 & BIT(0)) == BIT(0)); |
3243 | if (coex_stat->bt_info_hb2 & BIT(1)) |
3244 | coex_stat->cnt_bt[COEX_CNT_BT_AFHUPDATE]++; |
3245 | |
3246 | coex_stat->bt_a2dp_active = (coex_stat->bt_info_hb2 & BIT(2)) == BIT(2); |
3247 | coex_stat->bt_slave = ((coex_stat->bt_info_hb2 & BIT(3)) == BIT(3)); |
3248 | coex_stat->bt_hid_slot = (coex_stat->bt_info_hb2 & 0x30) >> 4; |
3249 | coex_stat->bt_hid_pair_num = (coex_stat->bt_info_hb2 & 0xc0) >> 6; |
3250 | if (coex_stat->bt_hid_pair_num > 0 && coex_stat->bt_hid_slot >= 2) |
3251 | coex_stat->bt_418_hid_exist = true; |
3252 | else if (coex_stat->bt_hid_pair_num == 0 || coex_stat->bt_hid_slot == 1) |
3253 | coex_stat->bt_418_hid_exist = false; |
3254 | |
3255 | if ((coex_stat->bt_info_lb2 & 0x49) == 0x49) |
3256 | coex_stat->bt_a2dp_bitpool = (coex_stat->bt_info_hb3 & 0x7f); |
3257 | else |
3258 | coex_stat->bt_a2dp_bitpool = 0; |
3259 | |
3260 | coex_stat->bt_a2dp_sink = ((coex_stat->bt_info_hb3 & BIT(7)) == BIT(7)); |
3261 | |
3262 | rtw_coex_update_bt_link_info(rtwdev); |
3263 | rtw_coex_run_coex(rtwdev, reason: COEX_RSN_BTINFO); |
3264 | } |
3265 | |
3266 | #define COEX_BT_HIDINFO_MTK 0x46 |
3267 | static const u8 coex_bt_hidinfo_ps[] = {0x57, 0x69, 0x72}; |
3268 | static const u8 coex_bt_hidinfo_xb[] = {0x58, 0x62, 0x6f}; |
3269 | |
3270 | void rtw_coex_bt_hid_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length) |
3271 | { |
3272 | const struct rtw_chip_info *chip = rtwdev->chip; |
3273 | struct rtw_coex *coex = &rtwdev->coex; |
3274 | struct rtw_coex_stat *coex_stat = &coex->stat; |
3275 | struct rtw_coex_hid *hidinfo; |
3276 | struct rtw_coex_hid_info_a *hida; |
3277 | struct rtw_coex_hid_handle_list *hl, *bhl; |
3278 | u8 sub_id = buf[2], gamehid_cnt = 0, handle, i; |
3279 | bool cur_game_hid_exist, complete; |
3280 | |
3281 | if (!chip->wl_mimo_ps_support && |
3282 | (sub_id == COEX_BT_HIDINFO_LIST || sub_id == COEX_BT_HIDINFO_A)) |
3283 | return; |
3284 | |
3285 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
3286 | fmt: "[BTCoex], HID info notify, sub_id = 0x%x\n" , sub_id); |
3287 | |
3288 | switch (sub_id) { |
3289 | case COEX_BT_HIDINFO_LIST: |
3290 | hl = &coex_stat->hid_handle_list; |
3291 | bhl = (struct rtw_coex_hid_handle_list *)buf; |
3292 | if (!memcmp(p: hl, q: bhl, size: sizeof(*hl))) |
3293 | return; |
3294 | coex_stat->hid_handle_list = *bhl; |
3295 | memset(&coex_stat->hid_info, 0, sizeof(coex_stat->hid_info)); |
3296 | for (i = 0; i < COEX_BT_HIDINFO_HANDLE_NUM; i++) { |
3297 | hidinfo = &coex_stat->hid_info[i]; |
3298 | if (hl->handle[i] != COEX_BT_HIDINFO_NOTCON && |
3299 | hl->handle[i] != 0) |
3300 | hidinfo->hid_handle = hl->handle[i]; |
3301 | } |
3302 | break; |
3303 | case COEX_BT_HIDINFO_A: |
3304 | hida = (struct rtw_coex_hid_info_a *)buf; |
3305 | handle = hida->handle; |
3306 | for (i = 0; i < COEX_BT_HIDINFO_HANDLE_NUM; i++) { |
3307 | hidinfo = &coex_stat->hid_info[i]; |
3308 | if (hidinfo->hid_handle == handle) { |
3309 | hidinfo->hid_vendor = hida->vendor; |
3310 | memcpy(hidinfo->hid_name, hida->name, |
3311 | sizeof(hidinfo->hid_name)); |
3312 | hidinfo->hid_info_completed = true; |
3313 | break; |
3314 | } |
3315 | } |
3316 | break; |
3317 | } |
3318 | for (i = 0; i < COEX_BT_HIDINFO_HANDLE_NUM; i++) { |
3319 | hidinfo = &coex_stat->hid_info[i]; |
3320 | complete = hidinfo->hid_info_completed; |
3321 | handle = hidinfo->hid_handle; |
3322 | if (!complete || handle == COEX_BT_HIDINFO_NOTCON || |
3323 | handle == 0 || handle >= COEX_BT_BLE_HANDLE_THRS) { |
3324 | hidinfo->is_game_hid = false; |
3325 | continue; |
3326 | } |
3327 | |
3328 | if (hidinfo->hid_vendor == COEX_BT_HIDINFO_MTK) { |
3329 | if ((memcmp(p: hidinfo->hid_name, |
3330 | q: coex_bt_hidinfo_ps, |
3331 | COEX_BT_HIDINFO_NAME)) == 0) |
3332 | hidinfo->is_game_hid = true; |
3333 | else if ((memcmp(p: hidinfo->hid_name, |
3334 | q: coex_bt_hidinfo_xb, |
3335 | COEX_BT_HIDINFO_NAME)) == 0) |
3336 | hidinfo->is_game_hid = true; |
3337 | else |
3338 | hidinfo->is_game_hid = false; |
3339 | } else { |
3340 | hidinfo->is_game_hid = false; |
3341 | } |
3342 | if (hidinfo->is_game_hid) |
3343 | gamehid_cnt++; |
3344 | } |
3345 | |
3346 | if (gamehid_cnt > 0) |
3347 | cur_game_hid_exist = true; |
3348 | else |
3349 | cur_game_hid_exist = false; |
3350 | |
3351 | if (cur_game_hid_exist != coex_stat->bt_game_hid_exist) { |
3352 | coex_stat->bt_game_hid_exist = cur_game_hid_exist; |
3353 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
3354 | fmt: "[BTCoex], HID info changed!bt_game_hid_exist = %d!\n" , |
3355 | coex_stat->bt_game_hid_exist); |
3356 | rtw_coex_run_coex(rtwdev, reason: COEX_RSN_BTSTATUS); |
3357 | } |
3358 | } |
3359 | |
3360 | void rtw_coex_query_bt_hid_list(struct rtw_dev *rtwdev) |
3361 | { |
3362 | const struct rtw_chip_info *chip = rtwdev->chip; |
3363 | struct rtw_coex *coex = &rtwdev->coex; |
3364 | struct rtw_coex_stat *coex_stat = &coex->stat; |
3365 | struct rtw_coex_hid *hidinfo; |
3366 | u8 i, handle; |
3367 | bool complete; |
3368 | |
3369 | if (!chip->wl_mimo_ps_support || coex_stat->wl_under_ips || |
3370 | (coex_stat->wl_under_lps && !coex_stat->wl_force_lps_ctrl)) |
3371 | return; |
3372 | |
3373 | if (!coex_stat->bt_hid_exist && |
3374 | !((coex_stat->bt_info_lb2 & COEX_INFO_CONNECTION) && |
3375 | (coex_stat->hi_pri_tx + coex_stat->hi_pri_rx > |
3376 | COEX_BT_GAMEHID_CNT))) |
3377 | return; |
3378 | |
3379 | rtw_fw_coex_query_hid_info(rtwdev, COEX_BT_HIDINFO_LIST, data: 0); |
3380 | |
3381 | for (i = 0; i < COEX_BT_HIDINFO_HANDLE_NUM; i++) { |
3382 | hidinfo = &coex_stat->hid_info[i]; |
3383 | complete = hidinfo->hid_info_completed; |
3384 | handle = hidinfo->hid_handle; |
3385 | if (handle == 0 || handle == COEX_BT_HIDINFO_NOTCON || |
3386 | handle >= COEX_BT_BLE_HANDLE_THRS || complete) |
3387 | continue; |
3388 | |
3389 | rtw_fw_coex_query_hid_info(rtwdev, |
3390 | COEX_BT_HIDINFO_A, |
3391 | data: handle); |
3392 | } |
3393 | } |
3394 | |
3395 | void rtw_coex_wl_fwdbginfo_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length) |
3396 | { |
3397 | struct rtw_coex *coex = &rtwdev->coex; |
3398 | struct rtw_coex_stat *coex_stat = &coex->stat; |
3399 | u8 val; |
3400 | int i; |
3401 | |
3402 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, |
3403 | fmt: "[BTCoex], WiFi Fw Dbg info = %8ph (len = %d)\n" , |
3404 | buf, length); |
3405 | if (WARN(length < 8, "invalid wl info c2h length\n" )) |
3406 | return; |
3407 | |
3408 | if (buf[0] != 0x08) |
3409 | return; |
3410 | |
3411 | for (i = 1; i < 8; i++) { |
3412 | val = coex_stat->wl_fw_dbg_info_pre[i]; |
3413 | if (buf[i] >= val) |
3414 | coex_stat->wl_fw_dbg_info[i] = buf[i] - val; |
3415 | else |
3416 | coex_stat->wl_fw_dbg_info[i] = 255 - val + buf[i]; |
3417 | |
3418 | coex_stat->wl_fw_dbg_info_pre[i] = buf[i]; |
3419 | } |
3420 | |
3421 | coex_stat->cnt_wl[COEX_CNT_WL_FW_NOTIFY]++; |
3422 | rtw_coex_wl_ccklock_action(rtwdev); |
3423 | rtw_coex_wl_ccklock_detect(rtwdev); |
3424 | } |
3425 | |
3426 | void rtw_coex_wl_status_change_notify(struct rtw_dev *rtwdev, u32 type) |
3427 | { |
3428 | rtw_coex_run_coex(rtwdev, reason: COEX_RSN_WLSTATUS); |
3429 | } |
3430 | |
3431 | void rtw_coex_wl_status_check(struct rtw_dev *rtwdev) |
3432 | { |
3433 | struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat; |
3434 | |
3435 | if ((coex_stat->wl_under_lps && !coex_stat->wl_force_lps_ctrl) || |
3436 | coex_stat->wl_under_ips) |
3437 | return; |
3438 | |
3439 | rtw_coex_monitor_bt_ctr(rtwdev); |
3440 | } |
3441 | |
3442 | void rtw_coex_bt_relink_work(struct work_struct *work) |
3443 | { |
3444 | struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, |
3445 | coex.bt_relink_work.work); |
3446 | struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat; |
3447 | |
3448 | mutex_lock(&rtwdev->mutex); |
3449 | coex_stat->bt_setup_link = false; |
3450 | rtw_coex_run_coex(rtwdev, reason: COEX_RSN_WLSTATUS); |
3451 | mutex_unlock(lock: &rtwdev->mutex); |
3452 | } |
3453 | |
3454 | void rtw_coex_bt_reenable_work(struct work_struct *work) |
3455 | { |
3456 | struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, |
3457 | coex.bt_reenable_work.work); |
3458 | struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat; |
3459 | |
3460 | mutex_lock(&rtwdev->mutex); |
3461 | coex_stat->bt_reenable = false; |
3462 | mutex_unlock(lock: &rtwdev->mutex); |
3463 | } |
3464 | |
3465 | void rtw_coex_defreeze_work(struct work_struct *work) |
3466 | { |
3467 | struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, |
3468 | coex.defreeze_work.work); |
3469 | struct rtw_coex *coex = &rtwdev->coex; |
3470 | struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat; |
3471 | |
3472 | mutex_lock(&rtwdev->mutex); |
3473 | coex->freeze = false; |
3474 | coex_stat->wl_hi_pri_task1 = false; |
3475 | rtw_coex_run_coex(rtwdev, reason: COEX_RSN_WLSTATUS); |
3476 | mutex_unlock(lock: &rtwdev->mutex); |
3477 | } |
3478 | |
3479 | void rtw_coex_wl_remain_work(struct work_struct *work) |
3480 | { |
3481 | struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, |
3482 | coex.wl_remain_work.work); |
3483 | struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat; |
3484 | |
3485 | mutex_lock(&rtwdev->mutex); |
3486 | coex_stat->wl_gl_busy = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); |
3487 | rtw_coex_run_coex(rtwdev, reason: COEX_RSN_WLSTATUS); |
3488 | mutex_unlock(lock: &rtwdev->mutex); |
3489 | } |
3490 | |
3491 | void rtw_coex_bt_remain_work(struct work_struct *work) |
3492 | { |
3493 | struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, |
3494 | coex.bt_remain_work.work); |
3495 | struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat; |
3496 | |
3497 | mutex_lock(&rtwdev->mutex); |
3498 | coex_stat->bt_inq_remain = coex_stat->bt_inq_page; |
3499 | rtw_coex_run_coex(rtwdev, reason: COEX_RSN_BTSTATUS); |
3500 | mutex_unlock(lock: &rtwdev->mutex); |
3501 | } |
3502 | |
3503 | void rtw_coex_wl_connecting_work(struct work_struct *work) |
3504 | { |
3505 | struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, |
3506 | coex.wl_connecting_work.work); |
3507 | struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat; |
3508 | |
3509 | mutex_lock(&rtwdev->mutex); |
3510 | coex_stat->wl_connecting = false; |
3511 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], WL connecting stop!!\n" ); |
3512 | rtw_coex_run_coex(rtwdev, reason: COEX_RSN_WLSTATUS); |
3513 | mutex_unlock(lock: &rtwdev->mutex); |
3514 | } |
3515 | |
3516 | void rtw_coex_bt_multi_link_remain_work(struct work_struct *work) |
3517 | { |
3518 | struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, |
3519 | coex.bt_multi_link_remain_work.work); |
3520 | struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat; |
3521 | |
3522 | mutex_lock(&rtwdev->mutex); |
3523 | coex_stat->bt_multi_link_remain = false; |
3524 | mutex_unlock(lock: &rtwdev->mutex); |
3525 | } |
3526 | |
3527 | void rtw_coex_wl_ccklock_work(struct work_struct *work) |
3528 | { |
3529 | struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, |
3530 | coex.wl_ccklock_work.work); |
3531 | struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat; |
3532 | |
3533 | mutex_lock(&rtwdev->mutex); |
3534 | coex_stat->wl_cck_lock = false; |
3535 | mutex_unlock(lock: &rtwdev->mutex); |
3536 | } |
3537 | |
3538 | #ifdef CONFIG_RTW88_DEBUGFS |
3539 | #define INFO_SIZE 80 |
3540 | |
3541 | #define case_BTINFO(src) \ |
3542 | case COEX_BTINFO_SRC_##src: return #src |
3543 | |
3544 | static const char *rtw_coex_get_bt_info_src_string(u8 bt_info_src) |
3545 | { |
3546 | switch (bt_info_src) { |
3547 | case_BTINFO(WL_FW); |
3548 | case_BTINFO(BT_RSP); |
3549 | case_BTINFO(BT_ACT); |
3550 | default: |
3551 | return "Unknown" ; |
3552 | } |
3553 | } |
3554 | |
3555 | #define case_RSN(src) \ |
3556 | case COEX_RSN_##src: return #src |
3557 | |
3558 | static const char *rtw_coex_get_reason_string(u8 reason) |
3559 | { |
3560 | switch (reason) { |
3561 | case_RSN(2GSCANSTART); |
3562 | case_RSN(5GSCANSTART); |
3563 | case_RSN(SCANFINISH); |
3564 | case_RSN(2GSWITCHBAND); |
3565 | case_RSN(5GSWITCHBAND); |
3566 | case_RSN(2GCONSTART); |
3567 | case_RSN(5GCONSTART); |
3568 | case_RSN(2GCONFINISH); |
3569 | case_RSN(5GCONFINISH); |
3570 | case_RSN(2GMEDIA); |
3571 | case_RSN(5GMEDIA); |
3572 | case_RSN(MEDIADISCON); |
3573 | case_RSN(BTINFO); |
3574 | case_RSN(LPS); |
3575 | case_RSN(WLSTATUS); |
3576 | default: |
3577 | return "Unknown" ; |
3578 | } |
3579 | } |
3580 | |
3581 | static u8 rtw_coex_get_table_index(struct rtw_dev *rtwdev, u32 wl_reg_6c0, |
3582 | u32 wl_reg_6c4) |
3583 | { |
3584 | const struct rtw_chip_info *chip = rtwdev->chip; |
3585 | struct rtw_efuse *efuse = &rtwdev->efuse; |
3586 | u8 ans = 0xFF; |
3587 | u8 n, i; |
3588 | u32 load_bt_val; |
3589 | u32 load_wl_val; |
3590 | bool share_ant = efuse->share_ant; |
3591 | |
3592 | if (share_ant) |
3593 | n = chip->table_sant_num; |
3594 | else |
3595 | n = chip->table_nsant_num; |
3596 | |
3597 | for (i = 0; i < n; i++) { |
3598 | if (share_ant) { |
3599 | load_bt_val = chip->table_sant[i].bt; |
3600 | load_wl_val = chip->table_sant[i].wl; |
3601 | } else { |
3602 | load_bt_val = chip->table_nsant[i].bt; |
3603 | load_wl_val = chip->table_nsant[i].wl; |
3604 | } |
3605 | |
3606 | if (wl_reg_6c0 == load_bt_val && |
3607 | wl_reg_6c4 == load_wl_val) { |
3608 | ans = i; |
3609 | if (!share_ant) |
3610 | ans += 100; |
3611 | break; |
3612 | } |
3613 | } |
3614 | |
3615 | return ans; |
3616 | } |
3617 | |
3618 | static u8 rtw_coex_get_tdma_index(struct rtw_dev *rtwdev, u8 *tdma_para) |
3619 | { |
3620 | const struct rtw_chip_info *chip = rtwdev->chip; |
3621 | struct rtw_efuse *efuse = &rtwdev->efuse; |
3622 | u8 ans = 0xFF; |
3623 | u8 n, i, j; |
3624 | u8 load_cur_tab_val; |
3625 | bool valid = false; |
3626 | bool share_ant = efuse->share_ant; |
3627 | |
3628 | if (share_ant) |
3629 | n = chip->tdma_sant_num; |
3630 | else |
3631 | n = chip->tdma_nsant_num; |
3632 | |
3633 | for (i = 0; i < n; i++) { |
3634 | valid = false; |
3635 | for (j = 0; j < 5; j++) { |
3636 | if (share_ant) |
3637 | load_cur_tab_val = chip->tdma_sant[i].para[j]; |
3638 | else |
3639 | load_cur_tab_val = chip->tdma_nsant[i].para[j]; |
3640 | |
3641 | if (*(tdma_para + j) != load_cur_tab_val) |
3642 | break; |
3643 | |
3644 | if (j == 4) |
3645 | valid = true; |
3646 | } |
3647 | if (valid) { |
3648 | ans = i; |
3649 | break; |
3650 | } |
3651 | } |
3652 | |
3653 | return ans; |
3654 | } |
3655 | |
3656 | static int rtw_coex_addr_info(struct rtw_dev *rtwdev, |
3657 | const struct rtw_reg_domain *reg, |
3658 | char addr_info[], int n) |
3659 | { |
3660 | const char *rf_prefix = "" ; |
3661 | const char *sep = n == 0 ? "" : "/ " ; |
3662 | int ffs, fls; |
3663 | int max_fls; |
3664 | |
3665 | if (INFO_SIZE - n <= 0) |
3666 | return 0; |
3667 | |
3668 | switch (reg->domain) { |
3669 | case RTW_REG_DOMAIN_MAC32: |
3670 | max_fls = 31; |
3671 | break; |
3672 | case RTW_REG_DOMAIN_MAC16: |
3673 | max_fls = 15; |
3674 | break; |
3675 | case RTW_REG_DOMAIN_MAC8: |
3676 | max_fls = 7; |
3677 | break; |
3678 | case RTW_REG_DOMAIN_RF_A: |
3679 | case RTW_REG_DOMAIN_RF_B: |
3680 | rf_prefix = "RF_" ; |
3681 | max_fls = 19; |
3682 | break; |
3683 | default: |
3684 | return 0; |
3685 | } |
3686 | |
3687 | ffs = __ffs(reg->mask); |
3688 | fls = __fls(word: reg->mask); |
3689 | |
3690 | if (ffs == 0 && fls == max_fls) |
3691 | return scnprintf(buf: addr_info + n, INFO_SIZE - n, fmt: "%s%s%x" , |
3692 | sep, rf_prefix, reg->addr); |
3693 | else if (ffs == fls) |
3694 | return scnprintf(buf: addr_info + n, INFO_SIZE - n, fmt: "%s%s%x[%d]" , |
3695 | sep, rf_prefix, reg->addr, ffs); |
3696 | else |
3697 | return scnprintf(buf: addr_info + n, INFO_SIZE - n, fmt: "%s%s%x[%d:%d]" , |
3698 | sep, rf_prefix, reg->addr, fls, ffs); |
3699 | } |
3700 | |
3701 | static int rtw_coex_val_info(struct rtw_dev *rtwdev, |
3702 | const struct rtw_reg_domain *reg, |
3703 | char val_info[], int n) |
3704 | { |
3705 | const char *sep = n == 0 ? "" : "/ " ; |
3706 | u8 rf_path; |
3707 | |
3708 | if (INFO_SIZE - n <= 0) |
3709 | return 0; |
3710 | |
3711 | switch (reg->domain) { |
3712 | case RTW_REG_DOMAIN_MAC32: |
3713 | return scnprintf(buf: val_info + n, INFO_SIZE - n, fmt: "%s0x%x" , sep, |
3714 | rtw_read32_mask(rtwdev, addr: reg->addr, mask: reg->mask)); |
3715 | case RTW_REG_DOMAIN_MAC16: |
3716 | return scnprintf(buf: val_info + n, INFO_SIZE - n, fmt: "%s0x%x" , sep, |
3717 | rtw_read16_mask(rtwdev, addr: reg->addr, mask: reg->mask)); |
3718 | case RTW_REG_DOMAIN_MAC8: |
3719 | return scnprintf(buf: val_info + n, INFO_SIZE - n, fmt: "%s0x%x" , sep, |
3720 | rtw_read8_mask(rtwdev, addr: reg->addr, mask: reg->mask)); |
3721 | case RTW_REG_DOMAIN_RF_A: |
3722 | rf_path = RF_PATH_A; |
3723 | break; |
3724 | case RTW_REG_DOMAIN_RF_B: |
3725 | rf_path = RF_PATH_B; |
3726 | break; |
3727 | default: |
3728 | return 0; |
3729 | } |
3730 | |
3731 | /* only RF go through here */ |
3732 | return scnprintf(buf: val_info + n, INFO_SIZE - n, fmt: "%s0x%x" , sep, |
3733 | rtw_read_rf(rtwdev, rf_path, addr: reg->addr, mask: reg->mask)); |
3734 | } |
3735 | |
3736 | static void rtw_coex_set_coexinfo_hw(struct rtw_dev *rtwdev, struct seq_file *m) |
3737 | { |
3738 | const struct rtw_chip_info *chip = rtwdev->chip; |
3739 | const struct rtw_reg_domain *reg; |
3740 | char addr_info[INFO_SIZE]; |
3741 | int n_addr = 0; |
3742 | char val_info[INFO_SIZE]; |
3743 | int n_val = 0; |
3744 | int i; |
3745 | |
3746 | for (i = 0; i < chip->coex_info_hw_regs_num; i++) { |
3747 | reg = &chip->coex_info_hw_regs[i]; |
3748 | |
3749 | n_addr += rtw_coex_addr_info(rtwdev, reg, addr_info, n: n_addr); |
3750 | n_val += rtw_coex_val_info(rtwdev, reg, val_info, n: n_val); |
3751 | |
3752 | if (reg->domain == RTW_REG_DOMAIN_NL) { |
3753 | seq_printf(m, fmt: "%-40s = %s\n" , addr_info, val_info); |
3754 | n_addr = 0; |
3755 | n_val = 0; |
3756 | } |
3757 | } |
3758 | |
3759 | if (n_addr != 0 && n_val != 0) |
3760 | seq_printf(m, fmt: "%-40s = %s\n" , addr_info, val_info); |
3761 | } |
3762 | |
3763 | static bool rtw_coex_get_bt_reg(struct rtw_dev *rtwdev, |
3764 | u8 type, u16 addr, u16 *val) |
3765 | { |
3766 | struct rtw_coex_info_req req = {0}; |
3767 | struct sk_buff *skb; |
3768 | __le16 le_addr; |
3769 | u8 *payload; |
3770 | |
3771 | le_addr = cpu_to_le16(addr); |
3772 | req.op_code = BT_MP_INFO_OP_READ_REG; |
3773 | req.para1 = type; |
3774 | req.para2 = le16_get_bits(v: le_addr, GENMASK(7, 0)); |
3775 | req.para3 = le16_get_bits(v: le_addr, GENMASK(15, 8)); |
3776 | skb = rtw_coex_info_request(rtwdev, req: &req); |
3777 | if (!skb) { |
3778 | *val = 0xeaea; |
3779 | return false; |
3780 | } |
3781 | |
3782 | payload = get_payload_from_coex_resp(resp: skb); |
3783 | *val = GET_COEX_RESP_BT_REG_VAL(payload); |
3784 | dev_kfree_skb_any(skb); |
3785 | |
3786 | return true; |
3787 | } |
3788 | |
3789 | static bool rtw_coex_get_bt_patch_version(struct rtw_dev *rtwdev, |
3790 | u32 *patch_version) |
3791 | { |
3792 | struct rtw_coex_info_req req = {0}; |
3793 | struct sk_buff *skb; |
3794 | u8 *payload; |
3795 | |
3796 | req.op_code = BT_MP_INFO_OP_PATCH_VER; |
3797 | skb = rtw_coex_info_request(rtwdev, req: &req); |
3798 | if (!skb) |
3799 | return false; |
3800 | |
3801 | payload = get_payload_from_coex_resp(resp: skb); |
3802 | *patch_version = GET_COEX_RESP_BT_PATCH_VER(payload); |
3803 | dev_kfree_skb_any(skb); |
3804 | |
3805 | return true; |
3806 | } |
3807 | |
3808 | static bool rtw_coex_get_bt_supported_version(struct rtw_dev *rtwdev, |
3809 | u32 *supported_version) |
3810 | { |
3811 | struct rtw_coex_info_req req = {0}; |
3812 | struct sk_buff *skb; |
3813 | u8 *payload; |
3814 | |
3815 | req.op_code = BT_MP_INFO_OP_SUPP_VER; |
3816 | skb = rtw_coex_info_request(rtwdev, req: &req); |
3817 | if (!skb) |
3818 | return false; |
3819 | |
3820 | payload = get_payload_from_coex_resp(resp: skb); |
3821 | *supported_version = GET_COEX_RESP_BT_SUPP_VER(payload); |
3822 | dev_kfree_skb_any(skb); |
3823 | |
3824 | return true; |
3825 | } |
3826 | |
3827 | static bool rtw_coex_get_bt_supported_feature(struct rtw_dev *rtwdev, |
3828 | u32 *supported_feature) |
3829 | { |
3830 | struct rtw_coex_info_req req = {0}; |
3831 | struct sk_buff *skb; |
3832 | u8 *payload; |
3833 | |
3834 | req.op_code = BT_MP_INFO_OP_SUPP_FEAT; |
3835 | skb = rtw_coex_info_request(rtwdev, req: &req); |
3836 | if (!skb) |
3837 | return false; |
3838 | |
3839 | payload = get_payload_from_coex_resp(resp: skb); |
3840 | *supported_feature = GET_COEX_RESP_BT_SUPP_FEAT(payload); |
3841 | dev_kfree_skb_any(skb); |
3842 | |
3843 | return true; |
3844 | } |
3845 | |
3846 | struct rtw_coex_sta_stat_iter_data { |
3847 | struct rtw_vif *rtwvif; |
3848 | struct seq_file *file; |
3849 | }; |
3850 | |
3851 | static void rtw_coex_sta_stat_iter(void *data, struct ieee80211_sta *sta) |
3852 | { |
3853 | struct rtw_coex_sta_stat_iter_data *sta_iter_data = data; |
3854 | struct rtw_vif *rtwvif = sta_iter_data->rtwvif; |
3855 | struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; |
3856 | struct seq_file *m = sta_iter_data->file; |
3857 | struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); |
3858 | u8 ; |
3859 | |
3860 | if (si->vif != vif) |
3861 | return; |
3862 | |
3863 | rssi = ewma_rssi_read(e: &si->avg_rssi); |
3864 | seq_printf(m, fmt: "\tPeer %3d\n" , si->mac_id); |
3865 | seq_printf(m, fmt: "\t\t%-24s = %d\n" , "RSSI" , rssi); |
3866 | seq_printf(m, fmt: "\t\t%-24s = %d\n" , "BW mode" , si->bw_mode); |
3867 | } |
3868 | |
3869 | struct rtw_coex_vif_stat_iter_data { |
3870 | struct rtw_dev *rtwdev; |
3871 | struct seq_file *file; |
3872 | }; |
3873 | |
3874 | static void rtw_coex_vif_stat_iter(void *data, u8 *mac, |
3875 | struct ieee80211_vif *vif) |
3876 | { |
3877 | struct rtw_coex_vif_stat_iter_data *vif_iter_data = data; |
3878 | struct rtw_coex_sta_stat_iter_data sta_iter_data; |
3879 | struct rtw_dev *rtwdev = vif_iter_data->rtwdev; |
3880 | struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; |
3881 | struct seq_file *m = vif_iter_data->file; |
3882 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; |
3883 | |
3884 | seq_printf(m, fmt: "Iface on Port (%d)\n" , rtwvif->port); |
3885 | seq_printf(m, fmt: "\t%-32s = %d\n" , |
3886 | "Beacon interval" , bss_conf->beacon_int); |
3887 | seq_printf(m, fmt: "\t%-32s = %d\n" , |
3888 | "Network Type" , rtwvif->net_type); |
3889 | |
3890 | sta_iter_data.rtwvif = rtwvif; |
3891 | sta_iter_data.file = m; |
3892 | rtw_iterate_stas_atomic(rtwdev, rtw_coex_sta_stat_iter, |
3893 | &sta_iter_data); |
3894 | } |
3895 | |
3896 | #define case_WLINK(src) \ |
3897 | case COEX_WLINK_##src: return #src |
3898 | |
3899 | static const char *rtw_coex_get_wl_coex_mode(u8 coex_wl_link_mode) |
3900 | { |
3901 | switch (coex_wl_link_mode) { |
3902 | case_WLINK(2G1PORT); |
3903 | case_WLINK(5G); |
3904 | case_WLINK(2GFREE); |
3905 | default: |
3906 | return "Unknown" ; |
3907 | } |
3908 | } |
3909 | |
3910 | void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m) |
3911 | { |
3912 | const struct rtw_chip_info *chip = rtwdev->chip; |
3913 | struct rtw_dm_info *dm_info = &rtwdev->dm_info; |
3914 | struct rtw_coex *coex = &rtwdev->coex; |
3915 | struct rtw_coex_stat *coex_stat = &coex->stat; |
3916 | struct rtw_coex_dm *coex_dm = &coex->dm; |
3917 | struct rtw_hal *hal = &rtwdev->hal; |
3918 | struct rtw_efuse *efuse = &rtwdev->efuse; |
3919 | struct rtw_fw_state *fw = &rtwdev->fw; |
3920 | struct rtw_coex_vif_stat_iter_data vif_iter_data; |
3921 | u8 reason = coex_dm->reason; |
3922 | u8 sys_lte; |
3923 | u16 score_board_WB, score_board_BW; |
3924 | u32 wl_reg_6c0, wl_reg_6c4, wl_reg_6c8, wl_reg_778, wl_reg_6cc; |
3925 | u32 lte_coex, bt_coex; |
3926 | int i; |
3927 | |
3928 | score_board_BW = rtw_coex_read_scbd(rtwdev); |
3929 | score_board_WB = coex_stat->score_board; |
3930 | wl_reg_6c0 = rtw_read32(rtwdev, REG_BT_COEX_TABLE0); |
3931 | wl_reg_6c4 = rtw_read32(rtwdev, REG_BT_COEX_TABLE1); |
3932 | wl_reg_6c8 = rtw_read32(rtwdev, REG_BT_COEX_BRK_TABLE); |
3933 | wl_reg_6cc = rtw_read32(rtwdev, REG_BT_COEX_TABLE_H); |
3934 | wl_reg_778 = rtw_read8(rtwdev, REG_BT_STAT_CTRL); |
3935 | |
3936 | sys_lte = rtw_read8(rtwdev, addr: 0x73); |
3937 | lte_coex = rtw_coex_read_indirect_reg(rtwdev, 0x38); |
3938 | bt_coex = rtw_coex_read_indirect_reg(rtwdev, 0x54); |
3939 | |
3940 | if (!coex_stat->bt_disabled && !coex_stat->bt_mailbox_reply) { |
3941 | rtw_coex_get_bt_supported_version(rtwdev, |
3942 | supported_version: &coex_stat->bt_supported_version); |
3943 | rtw_coex_get_bt_patch_version(rtwdev, patch_version: &coex_stat->patch_ver); |
3944 | rtw_coex_get_bt_supported_feature(rtwdev, |
3945 | supported_feature: &coex_stat->bt_supported_feature); |
3946 | rtw_coex_get_bt_reg(rtwdev, type: 3, addr: 0xae, val: &coex_stat->bt_reg_vendor_ae); |
3947 | rtw_coex_get_bt_reg(rtwdev, type: 3, addr: 0xac, val: &coex_stat->bt_reg_vendor_ac); |
3948 | |
3949 | if (coex_stat->patch_ver != 0) |
3950 | coex_stat->bt_mailbox_reply = true; |
3951 | } |
3952 | |
3953 | rtw_dbg(rtwdev, mask: RTW_DBG_COEX, fmt: "[BTCoex], %s()\n" , __func__); |
3954 | seq_printf(m, fmt: "**********************************************\n" ); |
3955 | seq_printf(m, fmt: "\t\tBT Coexist info %x\n" , chip->id); |
3956 | seq_printf(m, fmt: "**********************************************\n" ); |
3957 | |
3958 | if (coex->manual_control) { |
3959 | seq_puts(m, s: "============[Under Manual Control]============\n" ); |
3960 | seq_puts(m, s: "==========================================\n" ); |
3961 | |
3962 | } else if (coex->stop_dm) { |
3963 | seq_puts(m, s: "============[Coex is STOPPED]============\n" ); |
3964 | seq_puts(m, s: "==========================================\n" ); |
3965 | |
3966 | } else if (coex->freeze) { |
3967 | seq_puts(m, s: "============[coex_freeze]============\n" ); |
3968 | seq_puts(m, s: "==========================================\n" ); |
3969 | } |
3970 | |
3971 | seq_printf(m, fmt: "%-40s = %s/ %d\n" , |
3972 | "Mech/ RFE" , |
3973 | efuse->share_ant ? "Shared" : "Non-Shared" , |
3974 | efuse->rfe_option); |
3975 | seq_printf(m, fmt: "%-40s = %08x/ 0x%02x/ 0x%08x %s\n" , |
3976 | "Coex Ver/ BT Dez/ BT Rpt" , |
3977 | chip->coex_para_ver, chip->bt_desired_ver, |
3978 | coex_stat->bt_supported_version, |
3979 | coex_stat->bt_disabled ? "(BT disabled)" : |
3980 | coex_stat->bt_supported_version >= chip->bt_desired_ver ? |
3981 | "(Match)" : "(Mismatch)" ); |
3982 | seq_printf(m, fmt: "%-40s = %s/ %u/ %d\n" , |
3983 | "Role/ RoleSwCnt/ IgnWL/ Feature" , |
3984 | coex_stat->bt_slave ? "Slave" : "Master" , |
3985 | coex_stat->cnt_bt[COEX_CNT_BT_ROLESWITCH], |
3986 | coex_dm->ignore_wl_act); |
3987 | seq_printf(m, fmt: "%-40s = %u.%u/ 0x%x/ 0x%x/ %c\n" , |
3988 | "WL FW/ BT FW/ BT FW Desired/ KT" , |
3989 | fw->version, fw->sub_version, |
3990 | coex_stat->patch_ver, |
3991 | chip->wl_fw_desired_ver, coex_stat->kt_ver + 65); |
3992 | seq_printf(m, fmt: "%-40s = %u/ %u/ %u/ ch-(%u)\n" , |
3993 | "AFH Map" , |
3994 | coex_dm->wl_ch_info[0], coex_dm->wl_ch_info[1], |
3995 | coex_dm->wl_ch_info[2], hal->current_channel); |
3996 | |
3997 | rtw_debugfs_get_simple_phy_info(m); |
3998 | seq_printf(m, fmt: "**********************************************\n" ); |
3999 | seq_printf(m, fmt: "\t\tBT Status\n" ); |
4000 | seq_printf(m, fmt: "**********************************************\n" ); |
4001 | seq_printf(m, fmt: "%-40s = %s/ %ddBm/ %u/ %u\n" , |
4002 | "BT status/ rssi/ retry/ pop" , |
4003 | coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE ? "non-conn" : |
4004 | coex_dm->bt_status == COEX_BTSTATUS_CON_IDLE ? "conn-idle" : "busy" , |
4005 | coex_stat->bt_rssi - 100, |
4006 | coex_stat->cnt_bt[COEX_CNT_BT_RETRY], |
4007 | coex_stat->cnt_bt[COEX_CNT_BT_POPEVENT]); |
4008 | seq_printf(m, fmt: "%-40s = %s%s%s%s%s (multi-link %d)\n" , |
4009 | "Profiles" , |
4010 | coex_stat->bt_a2dp_exist ? (coex_stat->bt_a2dp_sink ? |
4011 | "A2DP sink," : "A2DP," ) : "" , |
4012 | coex_stat->bt_hfp_exist ? "HFP," : "" , |
4013 | coex_stat->bt_hid_exist ? |
4014 | (coex_stat->bt_ble_exist ? "HID(RCU)," : |
4015 | coex_stat->bt_hid_slot >= 2 ? "HID(4/18)" : |
4016 | coex_stat->bt_ble_hid_exist ? "HID(BLE)" : |
4017 | "HID(2/18)," ) : "" , |
4018 | coex_stat->bt_pan_exist ? coex_stat->bt_opp_exist ? |
4019 | "OPP," : "PAN," : "" , |
4020 | coex_stat->bt_ble_voice ? "Voice," : "" , |
4021 | coex_stat->bt_multi_link); |
4022 | seq_printf(m, fmt: "%-40s = %u/ %u/ %u/ 0x%08x\n" , |
4023 | "Reinit/ Relink/ IgnWl/ Feature" , |
4024 | coex_stat->cnt_bt[COEX_CNT_BT_REINIT], |
4025 | coex_stat->cnt_bt[COEX_CNT_BT_SETUPLINK], |
4026 | coex_stat->cnt_bt[COEX_CNT_BT_IGNWLANACT], |
4027 | coex_stat->bt_supported_feature); |
4028 | seq_printf(m, fmt: "%-40s = %u/ %u/ %u/ %u\n" , |
4029 | "Page/ Inq/ iqk/ iqk fail" , |
4030 | coex_stat->cnt_bt[COEX_CNT_BT_PAGE], |
4031 | coex_stat->cnt_bt[COEX_CNT_BT_INQ], |
4032 | coex_stat->cnt_bt[COEX_CNT_BT_IQK], |
4033 | coex_stat->cnt_bt[COEX_CNT_BT_IQKFAIL]); |
4034 | seq_printf(m, fmt: "%-40s = 0x%04x/ 0x%04x/ 0x%04x/ 0x%04x\n" , |
4035 | "0xae/ 0xac/ score board (W->B)/ (B->W)" , |
4036 | coex_stat->bt_reg_vendor_ae, |
4037 | coex_stat->bt_reg_vendor_ac, |
4038 | score_board_WB, score_board_BW); |
4039 | seq_printf(m, fmt: "%-40s = %u/%u, %u/%u\n" , |
4040 | "Hi-Pri TX/RX, Lo-Pri TX/RX" , |
4041 | coex_stat->hi_pri_tx, coex_stat->hi_pri_rx, |
4042 | coex_stat->lo_pri_tx, coex_stat->lo_pri_rx); |
4043 | for (i = 0; i < COEX_BTINFO_SRC_BT_IQK; i++) |
4044 | seq_printf(m, fmt: "%-40s = %7ph\n" , |
4045 | rtw_coex_get_bt_info_src_string(bt_info_src: i), |
4046 | coex_stat->bt_info_c2h[i]); |
4047 | |
4048 | seq_printf(m, fmt: "**********************************************\n" ); |
4049 | seq_printf(m, fmt: "\t\tWiFi Status\n" ); |
4050 | seq_printf(m, fmt: "**********************************************\n" ); |
4051 | seq_printf(m, fmt: "%-40s = %d\n" , |
4052 | "Scanning" , test_bit(RTW_FLAG_SCANNING, rtwdev->flags)); |
4053 | seq_printf(m, fmt: "%-40s = %u/ TX %d Mbps/ RX %d Mbps\n" , |
4054 | "G_busy/ TX/ RX" , |
4055 | coex_stat->wl_gl_busy, |
4056 | rtwdev->stats.tx_throughput, rtwdev->stats.rx_throughput); |
4057 | seq_printf(m, fmt: "%-40s = %u/ %u/ %u\n" , |
4058 | "IPS/ Low Power/ PS mode" , |
4059 | !test_bit(RTW_FLAG_POWERON, rtwdev->flags), |
4060 | test_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags), |
4061 | rtwdev->lps_conf.mode); |
4062 | |
4063 | vif_iter_data.rtwdev = rtwdev; |
4064 | vif_iter_data.file = m; |
4065 | rtw_iterate_vifs_atomic(rtwdev, rtw_coex_vif_stat_iter, &vif_iter_data); |
4066 | |
4067 | if (coex->manual_control) { |
4068 | seq_printf(m, fmt: "**********************************************\n" ); |
4069 | seq_printf(m, fmt: "\t\tMechanism (Under Manual)\n" ); |
4070 | seq_printf(m, fmt: "**********************************************\n" ); |
4071 | seq_printf(m, fmt: "%-40s = %5ph (%d)\n" , |
4072 | "TDMA Now" , |
4073 | coex_dm->fw_tdma_para, |
4074 | rtw_coex_get_tdma_index(rtwdev, |
4075 | tdma_para: &coex_dm->fw_tdma_para[0])); |
4076 | } else { |
4077 | seq_printf(m, fmt: "**********************************************\n" ); |
4078 | seq_printf(m, fmt: "\t\tMechanism\n" ); |
4079 | seq_printf(m, fmt: "**********************************************\n" ); |
4080 | seq_printf(m, fmt: "%-40s = %5ph (case-%d)\n" , |
4081 | "TDMA" , |
4082 | coex_dm->ps_tdma_para, coex_dm->cur_ps_tdma); |
4083 | } |
4084 | seq_printf(m, fmt: "%-40s = %s/ %s/ %d\n" , |
4085 | "Coex Mode/Free Run/Timer base" , |
4086 | rtw_coex_get_wl_coex_mode(coex_wl_link_mode: coex_stat->wl_coex_mode), |
4087 | coex->freerun ? "Yes" : "No" , |
4088 | coex_stat->tdma_timer_base); |
4089 | seq_printf(m, fmt: "%-40s = %d(%d)/ 0x%08x/ 0x%08x/ 0x%08x\n" , |
4090 | "Table/ 0x6c0/ 0x6c4/ 0x6c8" , |
4091 | coex_dm->cur_table, |
4092 | rtw_coex_get_table_index(rtwdev, wl_reg_6c0, wl_reg_6c4), |
4093 | wl_reg_6c0, wl_reg_6c4, wl_reg_6c8); |
4094 | seq_printf(m, fmt: "%-40s = 0x%08x/ 0x%08x/ %d/ reason (%s)\n" , |
4095 | "0x778/ 0x6cc/ Run Count/ Reason" , |
4096 | wl_reg_778, wl_reg_6cc, |
4097 | coex_stat->cnt_wl[COEX_CNT_WL_COEXRUN], |
4098 | rtw_coex_get_reason_string(reason)); |
4099 | seq_printf(m, fmt: "%-40s = %3ph\n" , |
4100 | "AFH Map to BT" , |
4101 | coex_dm->wl_ch_info); |
4102 | seq_printf(m, fmt: "%-40s = %s/ %d\n" , |
4103 | "AntDiv/ BtCtrlLPS/ g_busy" , |
4104 | coex_stat->wl_force_lps_ctrl ? "On" : "Off" , |
4105 | coex_stat->wl_gl_busy); |
4106 | seq_printf(m, fmt: "%-40s = %u/ %u/ %u/ %u/ %u\n" , |
4107 | "Null All/ Retry/ Ack/ BT Empty/ BT Late" , |
4108 | coex_stat->wl_fw_dbg_info[1], coex_stat->wl_fw_dbg_info[2], |
4109 | coex_stat->wl_fw_dbg_info[3], coex_stat->wl_fw_dbg_info[4], |
4110 | coex_stat->wl_fw_dbg_info[5]); |
4111 | seq_printf(m, fmt: "%-40s = %u/ %u/ %s/ %u\n" , |
4112 | "Cnt TDMA Toggle/ Lk 5ms/ Lk 5ms on/ FW" , |
4113 | coex_stat->wl_fw_dbg_info[6], |
4114 | coex_stat->wl_fw_dbg_info[7], |
4115 | coex_stat->wl_slot_extend ? "Yes" : "No" , |
4116 | coex_stat->cnt_wl[COEX_CNT_WL_FW_NOTIFY]); |
4117 | seq_printf(m, fmt: "%-40s = %d/ %d/ %s/ %d\n" , |
4118 | "WL_TxPw/ BT_TxPw/ WL_Rx/ BT_LNA_Lvl" , |
4119 | coex_dm->cur_wl_pwr_lvl, |
4120 | coex_dm->cur_bt_pwr_lvl, |
4121 | coex_dm->cur_wl_rx_low_gain_en ? "On" : "Off" , |
4122 | coex_dm->cur_bt_lna_lvl); |
4123 | |
4124 | seq_printf(m, fmt: "**********************************************\n" ); |
4125 | seq_printf(m, fmt: "\t\tHW setting\n" ); |
4126 | seq_printf(m, fmt: "**********************************************\n" ); |
4127 | seq_printf(m, fmt: "%-40s = %s/ %s\n" , |
4128 | "LTE Coex/ Path Owner" , |
4129 | lte_coex & BIT(7) ? "ON" : "OFF" , |
4130 | sys_lte & BIT(2) ? "WL" : "BT" ); |
4131 | seq_printf(m, fmt: "%-40s = RF:%s_BB:%s/ RF:%s_BB:%s/ %s\n" , |
4132 | "GNT_WL_CTRL/ GNT_BT_CTRL/ Dbg" , |
4133 | lte_coex & BIT(12) ? "SW" : "HW" , |
4134 | lte_coex & BIT(8) ? "SW" : "HW" , |
4135 | lte_coex & BIT(14) ? "SW" : "HW" , |
4136 | lte_coex & BIT(10) ? "SW" : "HW" , |
4137 | sys_lte & BIT(3) ? "On" : "Off" ); |
4138 | seq_printf(m, fmt: "%-40s = %lu/ %lu\n" , |
4139 | "GNT_WL/ GNT_BT" , |
4140 | (bt_coex & BIT(2)) >> 2, (bt_coex & BIT(3)) >> 3); |
4141 | seq_printf(m, fmt: "%-40s = %u/ %u/ %u/ %u\n" , |
4142 | "CRC OK CCK/ OFDM/ HT/ VHT" , |
4143 | dm_info->cck_ok_cnt, dm_info->ofdm_ok_cnt, |
4144 | dm_info->ht_ok_cnt, dm_info->vht_ok_cnt); |
4145 | seq_printf(m, fmt: "%-40s = %u/ %u/ %u/ %u\n" , |
4146 | "CRC ERR CCK/ OFDM/ HT/ VHT" , |
4147 | dm_info->cck_err_cnt, dm_info->ofdm_err_cnt, |
4148 | dm_info->ht_err_cnt, dm_info->vht_err_cnt); |
4149 | seq_printf(m, fmt: "%-40s = %s/ %s/ %s/ %u\n" , |
4150 | "HiPr/ Locking/ Locked/ Noisy" , |
4151 | coex_stat->wl_hi_pri_task1 ? "Y" : "N" , |
4152 | coex_stat->wl_cck_lock ? "Y" : "N" , |
4153 | coex_stat->wl_cck_lock_ever ? "Y" : "N" , |
4154 | coex_stat->wl_noisy_level); |
4155 | |
4156 | rtw_coex_set_coexinfo_hw(rtwdev, m); |
4157 | seq_printf(m, fmt: "%-40s = %d/ %d/ %d/ %d\n" , |
4158 | "EVM A/ EVM B/ SNR A/ SNR B" , |
4159 | -dm_info->rx_evm_dbm[RF_PATH_A], |
4160 | -dm_info->rx_evm_dbm[RF_PATH_B], |
4161 | -dm_info->rx_snr[RF_PATH_A], |
4162 | -dm_info->rx_snr[RF_PATH_B]); |
4163 | seq_printf(m, fmt: "%-40s = %d/ %d/ %d/ %d\n" , |
4164 | "CCK-CCA/CCK-FA/OFDM-CCA/OFDM-FA" , |
4165 | dm_info->cck_cca_cnt, dm_info->cck_fa_cnt, |
4166 | dm_info->ofdm_cca_cnt, dm_info->ofdm_fa_cnt); |
4167 | seq_printf(m, fmt: "%-40s = %d/ %d/ %d/ %d\n" , "CRC OK CCK/11g/11n/11ac" , |
4168 | dm_info->cck_ok_cnt, dm_info->ofdm_ok_cnt, |
4169 | dm_info->ht_ok_cnt, dm_info->vht_ok_cnt); |
4170 | seq_printf(m, fmt: "%-40s = %d/ %d/ %d/ %d\n" , "CRC Err CCK/11g/11n/11ac" , |
4171 | dm_info->cck_err_cnt, dm_info->ofdm_err_cnt, |
4172 | dm_info->ht_err_cnt, dm_info->vht_err_cnt); |
4173 | |
4174 | } |
4175 | #endif /* CONFIG_RTW88_DEBUGFS */ |
4176 | |