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
13static u8 rtw_coex_next_rssi_state(struct rtw_dev *rtwdev, u8 pre_state,
14 u8 rssi, u8 rssi_thresh)
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
36static 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
97static 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
112static 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 bt_rssi;
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
148static 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: &para[1]);
164}
165
166static 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
206static 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
258static 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
308static 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: &para[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
355static 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
366void 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}
399EXPORT_SYMBOL(rtw_coex_write_scbd);
400
401static 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
411static 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
449static 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
462static void rtw_coex_gnt_workaround(struct rtw_dev *rtwdev, bool force, u8 mode)
463{
464 rtw_coex_set_gnt_fix(rtwdev);
465}
466
467static 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
490static 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
525static 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 rssi_state;
537 u8 rssi_step;
538 u8 rssi;
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
605static 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
616void 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
630static 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
652out:
653 return skb_resp;
654}
655
656static 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
673static 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
692static 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
706static 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 rssi_state;
714 u8 rssi_step;
715 u8 rssi;
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
806static 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
856static 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
869static 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
890static 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
906u32 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}
917EXPORT_SYMBOL(rtw_coex_read_indirect_reg);
918
919void 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}
931EXPORT_SYMBOL(rtw_coex_write_indirect_reg);
932
933static 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
951static 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
957static 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
963static 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
980static 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
1015static 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
1043static 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
1065static 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
1093static 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
1103static 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
1134static 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
1193static 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
1259static 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
1415static 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
1435static 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
1459static 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
1526static 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
1549static 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
1594static 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
1619static 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
1644static 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
1684static 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
1748exit:
1749 rtw_coex_table(rtwdev, force: false, type: table_case);
1750 rtw_coex_tdma(rtwdev, force: false, tcase: tdma_case);
1751}
1752
1753static 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
1853static 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
1901static 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
1932static 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
2015static 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
2057static 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
2096static 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
2133static 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
2190static 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
2247static 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
2282static 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
2316static 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
2348static 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
2372static 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
2411static 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
2451static 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
2475static 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
2528static 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
2644exit:
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
2661static 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
2688static 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
2743void 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
2769void rtw_coex_power_off_setting(struct rtw_dev *rtwdev)
2770{
2771 rtw_write16(rtwdev, REG_WIFI_BT_INFO, BIT_BT_INT_EN);
2772}
2773
2774void rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only)
2775{
2776 __rtw_coex_init_hw_config(rtwdev, wifi_only);
2777}
2778
2779void 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
2808void 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
2846void 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
2884void 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
2910void 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
2964void 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
3002void 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
3267static const u8 coex_bt_hidinfo_ps[] = {0x57, 0x69, 0x72};
3268static const u8 coex_bt_hidinfo_xb[] = {0x58, 0x62, 0x6f};
3269
3270void 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
3360void 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
3395void 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
3426void 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
3431void 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
3442void 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
3454void 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
3465void 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
3479void 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
3491void 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
3503void 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
3516void 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
3527void 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
3544static 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
3558static 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
3581static 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
3618static 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
3656static 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
3701static 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
3736static 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
3763static 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
3789static 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
3808static 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
3827static 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
3846struct rtw_coex_sta_stat_iter_data {
3847 struct rtw_vif *rtwvif;
3848 struct seq_file *file;
3849};
3850
3851static 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 rssi;
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
3869struct rtw_coex_vif_stat_iter_data {
3870 struct rtw_dev *rtwdev;
3871 struct seq_file *file;
3872};
3873
3874static 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
3899static 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
3910void 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

source code of linux/drivers/net/wireless/realtek/rtw88/coex.c