Commit | Line | Data |
---|---|---|
4136214f YHC |
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 | ||
12 | static u8 rtw_coex_next_rssi_state(struct rtw_dev *rtwdev, u8 pre_state, | |
13 | u8 rssi, u8 rssi_thresh) | |
14 | { | |
15 | struct rtw_chip_info *chip = rtwdev->chip; | |
16 | u8 tol = chip->rssi_tolerance; | |
17 | u8 next_state; | |
18 | ||
19 | if (pre_state == COEX_RSSI_STATE_LOW || | |
20 | pre_state == COEX_RSSI_STATE_STAY_LOW) { | |
21 | if (rssi >= (rssi_thresh + tol)) | |
22 | next_state = COEX_RSSI_STATE_HIGH; | |
23 | else | |
24 | next_state = COEX_RSSI_STATE_STAY_LOW; | |
25 | } else { | |
26 | if (rssi < rssi_thresh) | |
27 | next_state = COEX_RSSI_STATE_LOW; | |
28 | else | |
29 | next_state = COEX_RSSI_STATE_STAY_HIGH; | |
30 | } | |
31 | ||
32 | return next_state; | |
33 | } | |
34 | ||
35 | static void rtw_coex_limited_tx(struct rtw_dev *rtwdev, | |
36 | bool tx_limit_en, bool ampdu_limit_en) | |
37 | { | |
38 | struct rtw_chip_info *chip = rtwdev->chip; | |
39 | struct rtw_coex *coex = &rtwdev->coex; | |
40 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
41 | bool wifi_under_b_mode = false; | |
42 | ||
43 | if (!chip->scbd_support) | |
44 | return; | |
45 | ||
46 | /* force max tx retry limit = 8 */ | |
47 | if (coex_stat->wl_tx_limit_en == tx_limit_en && | |
48 | coex_stat->wl_ampdu_limit_en == ampdu_limit_en) | |
49 | return; | |
50 | ||
51 | if (!coex_stat->wl_tx_limit_en) { | |
52 | coex_stat->darfrc = rtw_read32(rtwdev, REG_DARFRC); | |
53 | coex_stat->darfrch = rtw_read32(rtwdev, REG_DARFRCH); | |
54 | coex_stat->retry_limit = rtw_read16(rtwdev, REG_RETRY_LIMIT); | |
55 | } | |
56 | ||
57 | if (!coex_stat->wl_ampdu_limit_en) | |
58 | coex_stat->ampdu_max_time = | |
59 | rtw_read8(rtwdev, REG_AMPDU_MAX_TIME_V1); | |
60 | ||
61 | coex_stat->wl_tx_limit_en = tx_limit_en; | |
62 | coex_stat->wl_ampdu_limit_en = ampdu_limit_en; | |
63 | ||
64 | if (tx_limit_en) { | |
65 | /* set BT polluted packet on for tx rate adaptive, | |
66 | * not including tx retry broken by PTA | |
67 | */ | |
68 | rtw_write8_set(rtwdev, REG_TX_HANG_CTRL, BIT_EN_GNT_BT_AWAKE); | |
69 | ||
70 | /* set queue life time to avoid can't reach tx retry limit | |
71 | * if tx is always broken by GNT_BT | |
72 | */ | |
73 | rtw_write8_set(rtwdev, REG_LIFETIME_EN, 0xf); | |
74 | rtw_write16(rtwdev, REG_RETRY_LIMIT, 0x0808); | |
75 | ||
76 | /* auto rate fallback step within 8 retries */ | |
77 | if (wifi_under_b_mode) { | |
78 | rtw_write32(rtwdev, REG_DARFRC, 0x1000000); | |
79 | rtw_write32(rtwdev, REG_DARFRCH, 0x1010101); | |
80 | } else { | |
81 | rtw_write32(rtwdev, REG_DARFRC, 0x1000000); | |
82 | rtw_write32(rtwdev, REG_DARFRCH, 0x4030201); | |
83 | } | |
84 | } else { | |
85 | rtw_write8_clr(rtwdev, REG_TX_HANG_CTRL, BIT_EN_GNT_BT_AWAKE); | |
86 | rtw_write8_clr(rtwdev, REG_LIFETIME_EN, 0xf); | |
87 | ||
88 | rtw_write16(rtwdev, REG_RETRY_LIMIT, coex_stat->retry_limit); | |
89 | rtw_write32(rtwdev, REG_DARFRC, coex_stat->darfrc); | |
90 | rtw_write32(rtwdev, REG_DARFRCH, coex_stat->darfrch); | |
91 | } | |
92 | ||
93 | if (ampdu_limit_en) | |
94 | rtw_write8(rtwdev, REG_AMPDU_MAX_TIME_V1, 0x20); | |
95 | else | |
96 | rtw_write8(rtwdev, REG_AMPDU_MAX_TIME_V1, | |
97 | coex_stat->ampdu_max_time); | |
98 | } | |
99 | ||
100 | static void rtw_coex_limited_wl(struct rtw_dev *rtwdev) | |
101 | { | |
102 | struct rtw_coex *coex = &rtwdev->coex; | |
103 | struct rtw_coex_dm *coex_dm = &coex->dm; | |
104 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
105 | bool tx_limit = false; | |
106 | bool tx_agg_ctrl = false; | |
107 | ||
108 | if (coex->under_5g || | |
109 | coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) { | |
110 | /* no need to limit tx */ | |
111 | } else { | |
112 | tx_limit = true; | |
113 | if (coex_stat->bt_hid_exist || coex_stat->bt_hfp_exist || | |
114 | coex_stat->bt_hid_pair_num > 0) | |
115 | tx_agg_ctrl = true; | |
116 | } | |
117 | ||
118 | rtw_coex_limited_tx(rtwdev, tx_limit, tx_agg_ctrl); | |
119 | } | |
120 | ||
121 | static void rtw_coex_wl_ccklock_action(struct rtw_dev *rtwdev) | |
122 | { | |
123 | struct rtw_coex *coex = &rtwdev->coex; | |
124 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
125 | u8 para[6] = {0}; | |
126 | ||
127 | if (coex->stop_dm) | |
128 | return; | |
129 | ||
130 | para[0] = COEX_H2C69_WL_LEAKAP; | |
131 | ||
132 | if (coex_stat->tdma_timer_base == 3 && coex_stat->wl_slot_extend) { | |
133 | para[1] = PARA1_H2C69_DIS_5MS; /* disable 5ms extend */ | |
134 | rtw_fw_bt_wifi_control(rtwdev, para[0], ¶[1]); | |
135 | coex_stat->wl_slot_extend = false; | |
136 | coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] = 0; | |
137 | return; | |
138 | } | |
139 | ||
140 | if (coex_stat->wl_slot_extend && coex_stat->wl_force_lps_ctrl && | |
141 | !coex_stat->wl_cck_lock_ever) { | |
142 | if (coex_stat->wl_fw_dbg_info[7] <= 5) | |
143 | coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND]++; | |
144 | else | |
145 | coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] = 0; | |
146 | ||
147 | if (coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] == 7) { | |
148 | para[1] = 0x1; /* disable 5ms extend */ | |
149 | rtw_fw_bt_wifi_control(rtwdev, para[0], ¶[1]); | |
150 | coex_stat->wl_slot_extend = false; | |
151 | coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] = 0; | |
152 | } | |
153 | } else if (!coex_stat->wl_slot_extend && coex_stat->wl_cck_lock) { | |
154 | para[1] = 0x0; /* enable 5ms extend */ | |
155 | rtw_fw_bt_wifi_control(rtwdev, para[0], ¶[1]); | |
156 | coex_stat->wl_slot_extend = true; | |
157 | } | |
158 | } | |
159 | ||
160 | static void rtw_coex_wl_ccklock_detect(struct rtw_dev *rtwdev) | |
161 | { | |
162 | struct rtw_coex *coex = &rtwdev->coex; | |
163 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
164 | ||
165 | /* TODO: wait for rx_rate_change_notify implement */ | |
166 | coex_stat->wl_cck_lock = false; | |
167 | coex_stat->wl_cck_lock_pre = false; | |
168 | coex_stat->wl_cck_lock_ever = false; | |
169 | } | |
170 | ||
171 | static void rtw_coex_wl_noisy_detect(struct rtw_dev *rtwdev) | |
172 | { | |
173 | struct rtw_coex *coex = &rtwdev->coex; | |
174 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
175 | struct rtw_dm_info *dm_info = &rtwdev->dm_info; | |
176 | u32 cnt_cck; | |
177 | ||
178 | /* wifi noisy environment identification */ | |
179 | cnt_cck = dm_info->cck_ok_cnt + dm_info->cck_err_cnt; | |
180 | ||
181 | if (!coex_stat->wl_gl_busy) { | |
182 | if (cnt_cck > 250) { | |
183 | if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] < 5) | |
184 | coex_stat->cnt_wl[COEX_CNT_WL_NOISY2]++; | |
185 | ||
186 | if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] == 5) { | |
187 | coex_stat->cnt_wl[COEX_CNT_WL_NOISY0] = 0; | |
188 | coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] = 0; | |
189 | } | |
190 | } else if (cnt_cck < 100) { | |
191 | if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY0] < 5) | |
192 | coex_stat->cnt_wl[COEX_CNT_WL_NOISY0]++; | |
193 | ||
194 | if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY0] == 5) { | |
195 | coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] = 0; | |
196 | coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] = 0; | |
197 | } | |
198 | } else { | |
199 | if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] < 5) | |
200 | coex_stat->cnt_wl[COEX_CNT_WL_NOISY1]++; | |
201 | ||
202 | if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] == 5) { | |
203 | coex_stat->cnt_wl[COEX_CNT_WL_NOISY0] = 0; | |
204 | coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] = 0; | |
205 | } | |
206 | } | |
207 | ||
208 | if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] == 5) | |
209 | coex_stat->wl_noisy_level = 2; | |
210 | else if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] == 5) | |
211 | coex_stat->wl_noisy_level = 1; | |
212 | else | |
213 | coex_stat->wl_noisy_level = 0; | |
214 | } | |
215 | } | |
216 | ||
217 | static void rtw_coex_tdma_timer_base(struct rtw_dev *rtwdev, u8 type) | |
218 | { | |
219 | struct rtw_coex *coex = &rtwdev->coex; | |
220 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
221 | u8 para[2] = {0}; | |
222 | ||
223 | if (coex_stat->tdma_timer_base == type) | |
224 | return; | |
225 | ||
226 | coex_stat->tdma_timer_base = type; | |
227 | ||
228 | para[0] = COEX_H2C69_TDMA_SLOT; | |
229 | ||
230 | if (type == 3) /* 4-slot */ | |
231 | para[1] = PARA1_H2C69_TDMA_4SLOT; /* 4-slot */ | |
232 | else /* 2-slot */ | |
233 | para[1] = PARA1_H2C69_TDMA_2SLOT; | |
234 | ||
235 | rtw_fw_bt_wifi_control(rtwdev, para[0], ¶[1]); | |
236 | ||
237 | /* no 5ms_wl_slot_extend for 4-slot mode */ | |
238 | if (coex_stat->tdma_timer_base == 3) | |
239 | rtw_coex_wl_ccklock_action(rtwdev); | |
240 | } | |
241 | ||
242 | static void rtw_coex_set_wl_pri_mask(struct rtw_dev *rtwdev, u8 bitmap, | |
243 | u8 data) | |
244 | { | |
245 | u32 addr; | |
246 | ||
247 | addr = REG_BT_COEX_TABLE_H + (bitmap / 8); | |
248 | bitmap = bitmap % 8; | |
249 | ||
250 | rtw_write8_mask(rtwdev, addr, BIT(bitmap), data); | |
251 | } | |
252 | ||
253 | void rtw_coex_write_scbd(struct rtw_dev *rtwdev, u16 bitpos, bool set) | |
254 | { | |
255 | struct rtw_chip_info *chip = rtwdev->chip; | |
256 | struct rtw_coex *coex = &rtwdev->coex; | |
257 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
258 | u16 val = 0x2; | |
259 | ||
260 | if (!chip->scbd_support) | |
261 | return; | |
262 | ||
263 | val |= coex_stat->score_board; | |
264 | ||
265 | /* for 8822b, scbd[10] is CQDDR on | |
266 | * for 8822c, scbd[10] is no fix 2M | |
267 | */ | |
268 | if (!chip->new_scbd10_def && (bitpos & COEX_SCBD_FIX2M)) { | |
269 | if (set) | |
270 | val &= ~COEX_SCBD_FIX2M; | |
271 | else | |
272 | val |= COEX_SCBD_FIX2M; | |
273 | } else { | |
274 | if (set) | |
275 | val |= bitpos; | |
276 | else | |
277 | val &= ~bitpos; | |
278 | } | |
279 | ||
280 | if (val != coex_stat->score_board) { | |
281 | coex_stat->score_board = val; | |
282 | val |= BIT_BT_INT_EN; | |
283 | rtw_write16(rtwdev, REG_WIFI_BT_INFO, val); | |
284 | } | |
285 | } | |
286 | ||
287 | static u16 rtw_coex_read_scbd(struct rtw_dev *rtwdev) | |
288 | { | |
289 | struct rtw_chip_info *chip = rtwdev->chip; | |
290 | ||
291 | if (!chip->scbd_support) | |
292 | return 0; | |
293 | ||
294 | return (rtw_read16(rtwdev, REG_WIFI_BT_INFO)) & ~(BIT_BT_INT_EN); | |
295 | } | |
296 | ||
297 | static void rtw_coex_check_rfk(struct rtw_dev *rtwdev) | |
298 | { | |
299 | struct rtw_chip_info *chip = rtwdev->chip; | |
300 | struct rtw_coex *coex = &rtwdev->coex; | |
301 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
302 | struct rtw_coex_rfe *coex_rfe = &coex->rfe; | |
303 | u8 cnt = 0; | |
304 | u32 wait_cnt; | |
305 | bool btk, wlk; | |
306 | ||
307 | if (coex_rfe->wlg_at_btg && chip->scbd_support && | |
308 | coex_stat->bt_iqk_state != 0xff) { | |
309 | wait_cnt = COEX_RFK_TIMEOUT / COEX_MIN_DELAY; | |
310 | do { | |
311 | /* BT RFK */ | |
312 | btk = !!(rtw_coex_read_scbd(rtwdev) & COEX_SCBD_BT_RFK); | |
313 | ||
314 | /* WL RFK */ | |
315 | wlk = !!(rtw_read8(rtwdev, REG_ARFR4) & BIT_WL_RFK); | |
316 | ||
317 | if (!btk && !wlk) | |
318 | break; | |
319 | ||
320 | mdelay(COEX_MIN_DELAY); | |
321 | } while (++cnt < wait_cnt); | |
322 | ||
323 | if (cnt >= wait_cnt) | |
324 | coex_stat->bt_iqk_state = 0xff; | |
325 | } | |
326 | } | |
327 | ||
328 | static void rtw_coex_query_bt_info(struct rtw_dev *rtwdev) | |
329 | { | |
330 | struct rtw_coex *coex = &rtwdev->coex; | |
331 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
332 | ||
333 | if (coex_stat->bt_disabled) | |
334 | return; | |
335 | ||
336 | rtw_fw_query_bt_info(rtwdev); | |
337 | } | |
338 | ||
339 | static void rtw_coex_monitor_bt_enable(struct rtw_dev *rtwdev) | |
340 | { | |
341 | struct rtw_chip_info *chip = rtwdev->chip; | |
342 | struct rtw_coex *coex = &rtwdev->coex; | |
343 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
344 | struct rtw_coex_dm *coex_dm = &coex->dm; | |
345 | bool bt_disabled = false; | |
346 | u16 score_board; | |
347 | ||
348 | if (chip->scbd_support) { | |
349 | score_board = rtw_coex_read_scbd(rtwdev); | |
350 | bt_disabled = !(score_board & COEX_SCBD_ONOFF); | |
351 | } | |
352 | ||
353 | if (coex_stat->bt_disabled != bt_disabled) { | |
354 | rtw_dbg(rtwdev, RTW_DBG_COEX, "coex: BT state changed (%d) -> (%d)\n", | |
355 | coex_stat->bt_disabled, bt_disabled); | |
356 | ||
357 | coex_stat->bt_disabled = bt_disabled; | |
358 | coex_stat->bt_ble_scan_type = 0; | |
359 | coex_dm->cur_bt_lna_lvl = 0; | |
360 | } | |
361 | ||
362 | if (!coex_stat->bt_disabled) { | |
363 | coex_stat->bt_reenable = true; | |
364 | ieee80211_queue_delayed_work(rtwdev->hw, | |
365 | &coex->bt_reenable_work, 15 * HZ); | |
366 | } else { | |
367 | coex_stat->bt_mailbox_reply = false; | |
368 | coex_stat->bt_reenable = false; | |
369 | } | |
370 | } | |
371 | ||
372 | static void rtw_coex_update_wl_link_info(struct rtw_dev *rtwdev, u8 reason) | |
373 | { | |
374 | struct rtw_coex *coex = &rtwdev->coex; | |
375 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
376 | struct rtw_coex_dm *coex_dm = &coex->dm; | |
377 | struct rtw_chip_info *chip = rtwdev->chip; | |
378 | struct rtw_traffic_stats *stats = &rtwdev->stats; | |
379 | bool is_5G = false; | |
380 | bool scan = false, link = false; | |
381 | int i; | |
382 | u8 rssi_state; | |
383 | u8 rssi_step; | |
384 | u8 rssi; | |
385 | ||
3c519605 | 386 | scan = test_bit(RTW_FLAG_SCANNING, rtwdev->flags); |
4136214f | 387 | coex_stat->wl_connected = !!rtwdev->sta_cnt; |
3c519605 | 388 | coex_stat->wl_gl_busy = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); |
4136214f YHC |
389 | |
390 | if (stats->tx_throughput > stats->rx_throughput) | |
391 | coex_stat->wl_tput_dir = COEX_WL_TPUT_TX; | |
392 | else | |
393 | coex_stat->wl_tput_dir = COEX_WL_TPUT_RX; | |
394 | ||
395 | if (scan || link || reason == COEX_RSN_2GCONSTART || | |
396 | reason == COEX_RSN_2GSCANSTART || reason == COEX_RSN_2GSWITCHBAND) | |
397 | coex_stat->wl_linkscan_proc = true; | |
398 | else | |
399 | coex_stat->wl_linkscan_proc = false; | |
400 | ||
401 | rtw_coex_wl_noisy_detect(rtwdev); | |
402 | ||
403 | for (i = 0; i < 4; i++) { | |
404 | rssi_state = coex_dm->wl_rssi_state[i]; | |
405 | rssi_step = chip->wl_rssi_step[i]; | |
406 | rssi = rtwdev->dm_info.min_rssi; | |
407 | rssi_state = rtw_coex_next_rssi_state(rtwdev, rssi_state, | |
408 | rssi, rssi_step); | |
409 | coex_dm->wl_rssi_state[i] = rssi_state; | |
410 | } | |
411 | ||
412 | switch (reason) { | |
413 | case COEX_RSN_5GSCANSTART: | |
414 | case COEX_RSN_5GSWITCHBAND: | |
415 | case COEX_RSN_5GCONSTART: | |
416 | ||
417 | is_5G = true; | |
418 | break; | |
419 | case COEX_RSN_2GSCANSTART: | |
420 | case COEX_RSN_2GSWITCHBAND: | |
421 | case COEX_RSN_2GCONSTART: | |
422 | ||
423 | is_5G = false; | |
424 | break; | |
425 | default: | |
426 | if (rtwdev->hal.current_band_type == RTW_BAND_5G) | |
427 | is_5G = true; | |
428 | else | |
429 | is_5G = false; | |
430 | break; | |
431 | } | |
432 | ||
433 | coex->under_5g = is_5G; | |
434 | } | |
435 | ||
436 | static inline u8 *get_payload_from_coex_resp(struct sk_buff *resp) | |
437 | { | |
438 | struct rtw_c2h_cmd *c2h; | |
439 | u32 pkt_offset; | |
440 | ||
441 | pkt_offset = *((u32 *)resp->cb); | |
442 | c2h = (struct rtw_c2h_cmd *)(resp->data + pkt_offset); | |
443 | ||
444 | return c2h->payload; | |
445 | } | |
446 | ||
447 | void rtw_coex_info_response(struct rtw_dev *rtwdev, struct sk_buff *skb) | |
448 | { | |
449 | struct rtw_coex *coex = &rtwdev->coex; | |
450 | u8 *payload = get_payload_from_coex_resp(skb); | |
451 | ||
452 | if (payload[0] != COEX_RESP_ACK_BY_WL_FW) | |
453 | return; | |
454 | ||
455 | skb_queue_tail(&coex->queue, skb); | |
456 | wake_up(&coex->wait); | |
457 | } | |
458 | ||
459 | static struct sk_buff *rtw_coex_info_request(struct rtw_dev *rtwdev, | |
460 | struct rtw_coex_info_req *req) | |
461 | { | |
462 | struct rtw_coex *coex = &rtwdev->coex; | |
463 | struct sk_buff *skb_resp = NULL; | |
464 | ||
465 | mutex_lock(&coex->mutex); | |
466 | ||
467 | rtw_fw_query_bt_mp_info(rtwdev, req); | |
468 | ||
469 | if (!wait_event_timeout(coex->wait, !skb_queue_empty(&coex->queue), | |
470 | COEX_REQUEST_TIMEOUT)) { | |
471 | rtw_err(rtwdev, "coex request time out\n"); | |
472 | goto out; | |
473 | } | |
474 | ||
475 | skb_resp = skb_dequeue(&coex->queue); | |
476 | if (!skb_resp) { | |
477 | rtw_err(rtwdev, "failed to get coex info response\n"); | |
478 | goto out; | |
479 | } | |
480 | ||
481 | out: | |
482 | mutex_unlock(&coex->mutex); | |
483 | return skb_resp; | |
484 | } | |
485 | ||
486 | static bool rtw_coex_get_bt_scan_type(struct rtw_dev *rtwdev, u8 *scan_type) | |
487 | { | |
488 | struct rtw_coex_info_req req = {0}; | |
489 | struct sk_buff *skb; | |
490 | u8 *payload; | |
491 | bool ret = false; | |
492 | ||
493 | req.op_code = BT_MP_INFO_OP_SCAN_TYPE; | |
494 | skb = rtw_coex_info_request(rtwdev, &req); | |
495 | if (!skb) | |
496 | goto out; | |
497 | ||
498 | payload = get_payload_from_coex_resp(skb); | |
499 | *scan_type = GET_COEX_RESP_BT_SCAN_TYPE(payload); | |
500 | dev_kfree_skb_any(skb); | |
501 | ret = true; | |
502 | ||
503 | out: | |
504 | return ret; | |
505 | } | |
506 | ||
507 | static bool rtw_coex_set_lna_constrain_level(struct rtw_dev *rtwdev, | |
508 | u8 lna_constrain_level) | |
509 | { | |
510 | struct rtw_coex_info_req req = {0}; | |
511 | struct sk_buff *skb; | |
512 | bool ret = false; | |
513 | ||
514 | req.op_code = BT_MP_INFO_OP_LNA_CONSTRAINT; | |
515 | req.para1 = lna_constrain_level; | |
516 | skb = rtw_coex_info_request(rtwdev, &req); | |
517 | if (!skb) | |
518 | goto out; | |
519 | ||
520 | dev_kfree_skb_any(skb); | |
521 | ret = true; | |
522 | ||
523 | out: | |
524 | return ret; | |
525 | } | |
526 | ||
527 | static void rtw_coex_update_bt_link_info(struct rtw_dev *rtwdev) | |
528 | { | |
529 | struct rtw_coex *coex = &rtwdev->coex; | |
530 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
531 | struct rtw_coex_dm *coex_dm = &coex->dm; | |
532 | struct rtw_chip_info *chip = rtwdev->chip; | |
533 | u8 i; | |
534 | u8 rssi_state; | |
535 | u8 rssi_step; | |
536 | u8 rssi; | |
537 | ||
538 | /* update wl/bt rssi by btinfo */ | |
539 | for (i = 0; i < COEX_RSSI_STEP; i++) { | |
540 | rssi_state = coex_dm->bt_rssi_state[i]; | |
541 | rssi_step = chip->bt_rssi_step[i]; | |
542 | rssi = coex_stat->bt_rssi; | |
543 | rssi_state = rtw_coex_next_rssi_state(rtwdev, rssi_state, | |
544 | rssi, rssi_step); | |
545 | coex_dm->bt_rssi_state[i] = rssi_state; | |
546 | } | |
547 | ||
548 | for (i = 0; i < COEX_RSSI_STEP; i++) { | |
549 | rssi_state = coex_dm->wl_rssi_state[i]; | |
550 | rssi_step = chip->wl_rssi_step[i]; | |
551 | rssi = rtwdev->dm_info.min_rssi; | |
552 | rssi_state = rtw_coex_next_rssi_state(rtwdev, rssi_state, | |
553 | rssi, rssi_step); | |
554 | coex_dm->wl_rssi_state[i] = rssi_state; | |
555 | } | |
556 | ||
557 | if (coex_stat->bt_ble_scan_en && | |
558 | coex_stat->cnt_bt[COEX_CNT_BT_INFOUPDATE] % 3 == 0) { | |
559 | u8 scan_type; | |
560 | ||
561 | if (rtw_coex_get_bt_scan_type(rtwdev, &scan_type)) { | |
562 | coex_stat->bt_ble_scan_type = scan_type; | |
563 | if ((coex_stat->bt_ble_scan_type & 0x1) == 0x1) | |
564 | coex_stat->bt_init_scan = true; | |
565 | else | |
566 | coex_stat->bt_init_scan = false; | |
567 | } | |
568 | } | |
569 | ||
570 | coex_stat->bt_profile_num = 0; | |
571 | ||
572 | /* set link exist status */ | |
573 | if (!(coex_stat->bt_info_lb2 & COEX_INFO_CONNECTION)) { | |
574 | coex_stat->bt_link_exist = false; | |
575 | coex_stat->bt_pan_exist = false; | |
576 | coex_stat->bt_a2dp_exist = false; | |
577 | coex_stat->bt_hid_exist = false; | |
578 | coex_stat->bt_hfp_exist = false; | |
579 | } else { | |
580 | /* connection exists */ | |
581 | coex_stat->bt_link_exist = true; | |
582 | if (coex_stat->bt_info_lb2 & COEX_INFO_FTP) { | |
583 | coex_stat->bt_pan_exist = true; | |
584 | coex_stat->bt_profile_num++; | |
585 | } else { | |
586 | coex_stat->bt_pan_exist = false; | |
587 | } | |
588 | ||
589 | if (coex_stat->bt_info_lb2 & COEX_INFO_A2DP) { | |
590 | coex_stat->bt_a2dp_exist = true; | |
591 | coex_stat->bt_profile_num++; | |
592 | } else { | |
593 | coex_stat->bt_a2dp_exist = false; | |
594 | } | |
595 | ||
596 | if (coex_stat->bt_info_lb2 & COEX_INFO_HID) { | |
597 | coex_stat->bt_hid_exist = true; | |
598 | coex_stat->bt_profile_num++; | |
599 | } else { | |
600 | coex_stat->bt_hid_exist = false; | |
601 | } | |
602 | ||
603 | if (coex_stat->bt_info_lb2 & COEX_INFO_SCO_ESCO) { | |
604 | coex_stat->bt_hfp_exist = true; | |
605 | coex_stat->bt_profile_num++; | |
606 | } else { | |
607 | coex_stat->bt_hfp_exist = false; | |
608 | } | |
609 | } | |
610 | ||
611 | if (coex_stat->bt_info_lb2 & COEX_INFO_INQ_PAGE) { | |
612 | coex_dm->bt_status = COEX_BTSTATUS_INQ_PAGE; | |
613 | } else if (!(coex_stat->bt_info_lb2 & COEX_INFO_CONNECTION)) { | |
614 | coex_dm->bt_status = COEX_BTSTATUS_NCON_IDLE; | |
615 | } else if (coex_stat->bt_info_lb2 == COEX_INFO_CONNECTION) { | |
616 | coex_dm->bt_status = COEX_BTSTATUS_CON_IDLE; | |
617 | } else if ((coex_stat->bt_info_lb2 & COEX_INFO_SCO_ESCO) || | |
618 | (coex_stat->bt_info_lb2 & COEX_INFO_SCO_BUSY)) { | |
619 | if (coex_stat->bt_info_lb2 & COEX_INFO_ACL_BUSY) | |
620 | coex_dm->bt_status = COEX_BTSTATUS_ACL_SCO_BUSY; | |
621 | else | |
622 | coex_dm->bt_status = COEX_BTSTATUS_SCO_BUSY; | |
623 | } else if (coex_stat->bt_info_lb2 & COEX_INFO_ACL_BUSY) { | |
624 | coex_dm->bt_status = COEX_BTSTATUS_ACL_BUSY; | |
625 | } else { | |
626 | coex_dm->bt_status = COEX_BTSTATUS_MAX; | |
627 | } | |
628 | ||
629 | coex_stat->cnt_bt[COEX_CNT_BT_INFOUPDATE]++; | |
630 | ||
631 | rtw_dbg(rtwdev, RTW_DBG_COEX, "coex: bt status(%d)\n", coex_dm->bt_status); | |
632 | } | |
633 | ||
634 | static void rtw_coex_update_wl_ch_info(struct rtw_dev *rtwdev, u8 type) | |
635 | { | |
636 | struct rtw_chip_info *chip = rtwdev->chip; | |
637 | struct rtw_coex_dm *coex_dm = &rtwdev->coex.dm; | |
638 | struct rtw_efuse *efuse = &rtwdev->efuse; | |
639 | u8 link = 0; | |
640 | u8 center_chan = 0; | |
641 | u8 bw; | |
642 | int i; | |
643 | ||
644 | bw = rtwdev->hal.current_band_width; | |
645 | ||
646 | if (type != COEX_MEDIA_DISCONNECT) | |
647 | center_chan = rtwdev->hal.current_channel; | |
648 | ||
649 | if (center_chan == 0 || (efuse->share_ant && center_chan <= 14)) { | |
650 | link = 0; | |
651 | } else if (center_chan <= 14) { | |
652 | link = 0x1; | |
653 | ||
654 | if (bw == RTW_CHANNEL_WIDTH_40) | |
655 | bw = chip->bt_afh_span_bw40; | |
656 | else | |
657 | bw = chip->bt_afh_span_bw20; | |
658 | } else if (chip->afh_5g_num > 1) { | |
659 | for (i = 0; i < chip->afh_5g_num; i++) { | |
660 | if (center_chan == chip->afh_5g[i].wl_5g_ch) { | |
661 | link = 0x3; | |
662 | center_chan = chip->afh_5g[i].bt_skip_ch; | |
663 | bw = chip->afh_5g[i].bt_skip_span; | |
664 | break; | |
665 | } | |
666 | } | |
667 | } | |
668 | ||
669 | coex_dm->wl_ch_info[0] = link; | |
670 | coex_dm->wl_ch_info[1] = center_chan; | |
671 | coex_dm->wl_ch_info[2] = bw; | |
672 | ||
673 | rtw_fw_wl_ch_info(rtwdev, link, center_chan, bw); | |
674 | } | |
675 | ||
676 | static void rtw_coex_set_bt_tx_power(struct rtw_dev *rtwdev, u8 bt_pwr_dec_lvl) | |
677 | { | |
678 | struct rtw_coex *coex = &rtwdev->coex; | |
679 | struct rtw_coex_dm *coex_dm = &coex->dm; | |
680 | ||
681 | if (bt_pwr_dec_lvl == coex_dm->cur_bt_pwr_lvl) | |
682 | return; | |
683 | ||
684 | coex_dm->cur_bt_pwr_lvl = bt_pwr_dec_lvl; | |
685 | ||
686 | rtw_fw_force_bt_tx_power(rtwdev, bt_pwr_dec_lvl); | |
687 | } | |
688 | ||
689 | static void rtw_coex_set_bt_rx_gain(struct rtw_dev *rtwdev, u8 bt_lna_lvl) | |
690 | { | |
691 | struct rtw_coex *coex = &rtwdev->coex; | |
692 | struct rtw_coex_dm *coex_dm = &coex->dm; | |
693 | ||
694 | if (bt_lna_lvl == coex_dm->cur_bt_lna_lvl) | |
695 | return; | |
696 | ||
697 | coex_dm->cur_bt_lna_lvl = bt_lna_lvl; | |
698 | ||
699 | /* notify BT rx gain table changed */ | |
700 | if (bt_lna_lvl < 7) { | |
701 | rtw_coex_set_lna_constrain_level(rtwdev, bt_lna_lvl); | |
702 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_RXGAIN, true); | |
703 | } else { | |
704 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_RXGAIN, false); | |
705 | } | |
706 | } | |
707 | ||
708 | static void rtw_coex_set_rf_para(struct rtw_dev *rtwdev, | |
709 | struct coex_rf_para para) | |
710 | { | |
711 | struct rtw_coex *coex = &rtwdev->coex; | |
712 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
713 | u8 offset = 0; | |
714 | ||
715 | if (coex->freerun && coex_stat->wl_noisy_level <= 1) | |
716 | offset = 3; | |
717 | ||
718 | rtw_coex_set_wl_tx_power(rtwdev, para.wl_pwr_dec_lvl); | |
719 | rtw_coex_set_bt_tx_power(rtwdev, para.bt_pwr_dec_lvl + offset); | |
720 | rtw_coex_set_wl_rx_gain(rtwdev, para.wl_low_gain_en); | |
721 | rtw_coex_set_bt_rx_gain(rtwdev, para.bt_lna_lvl); | |
722 | } | |
723 | ||
5227c2ee | 724 | u32 rtw_coex_read_indirect_reg(struct rtw_dev *rtwdev, u16 addr) |
4136214f YHC |
725 | { |
726 | u32 val; | |
727 | ||
728 | if (!ltecoex_read_reg(rtwdev, addr, &val)) { | |
729 | rtw_err(rtwdev, "failed to read indirect register\n"); | |
730 | return 0; | |
731 | } | |
732 | ||
733 | return val; | |
734 | } | |
735 | ||
736 | void rtw_coex_write_indirect_reg(struct rtw_dev *rtwdev, u16 addr, | |
737 | u32 mask, u32 val) | |
738 | { | |
739 | u32 shift = __ffs(mask); | |
740 | u32 tmp; | |
741 | ||
742 | tmp = rtw_coex_read_indirect_reg(rtwdev, addr); | |
743 | tmp = (tmp & (~mask)) | ((val << shift) & mask); | |
744 | ||
745 | if (!ltecoex_reg_write(rtwdev, addr, tmp)) | |
746 | rtw_err(rtwdev, "failed to write indirect register\n"); | |
747 | } | |
748 | ||
749 | static void rtw_coex_coex_ctrl_owner(struct rtw_dev *rtwdev, bool wifi_control) | |
750 | { | |
751 | if (wifi_control) | |
752 | rtw_write32_set(rtwdev, REG_SYS_SDIO_CTRL, BIT_LTE_MUX_CTRL_PATH); | |
753 | else | |
754 | rtw_write32_clr(rtwdev, REG_SYS_SDIO_CTRL, BIT_LTE_MUX_CTRL_PATH); | |
755 | } | |
756 | ||
757 | static void rtw_coex_set_gnt_bt(struct rtw_dev *rtwdev, u8 state) | |
758 | { | |
759 | rtw_coex_write_indirect_reg(rtwdev, 0x38, 0xc000, state); | |
760 | rtw_coex_write_indirect_reg(rtwdev, 0x38, 0x0c00, state); | |
761 | } | |
762 | ||
763 | static void rtw_coex_set_gnt_wl(struct rtw_dev *rtwdev, u8 state) | |
764 | { | |
765 | rtw_coex_write_indirect_reg(rtwdev, 0x38, 0x3000, state); | |
766 | rtw_coex_write_indirect_reg(rtwdev, 0x38, 0x0300, state); | |
767 | } | |
768 | ||
769 | static void rtw_coex_set_table(struct rtw_dev *rtwdev, u32 table0, u32 table1) | |
770 | { | |
771 | #define DEF_BRK_TABLE_VAL 0xf0ffffff | |
772 | rtw_write32(rtwdev, REG_BT_COEX_TABLE0, table0); | |
773 | rtw_write32(rtwdev, REG_BT_COEX_TABLE1, table1); | |
774 | rtw_write32(rtwdev, REG_BT_COEX_BRK_TABLE, DEF_BRK_TABLE_VAL); | |
775 | } | |
776 | ||
777 | static void rtw_coex_table(struct rtw_dev *rtwdev, u8 type) | |
778 | { | |
779 | struct rtw_coex *coex = &rtwdev->coex; | |
780 | struct rtw_coex_dm *coex_dm = &coex->dm; | |
781 | struct rtw_chip_info *chip = rtwdev->chip; | |
782 | struct rtw_efuse *efuse = &rtwdev->efuse; | |
783 | ||
784 | coex_dm->cur_table = type; | |
785 | ||
786 | if (efuse->share_ant) { | |
787 | if (type < chip->table_sant_num) | |
788 | rtw_coex_set_table(rtwdev, | |
789 | chip->table_sant[type].bt, | |
790 | chip->table_sant[type].wl); | |
791 | } else { | |
792 | type = type - 100; | |
793 | if (type < chip->table_nsant_num) | |
794 | rtw_coex_set_table(rtwdev, | |
795 | chip->table_nsant[type].bt, | |
796 | chip->table_nsant[type].wl); | |
797 | } | |
798 | } | |
799 | ||
800 | static void rtw_coex_ignore_wlan_act(struct rtw_dev *rtwdev, bool enable) | |
801 | { | |
802 | struct rtw_coex *coex = &rtwdev->coex; | |
803 | ||
804 | if (coex->stop_dm) | |
805 | return; | |
806 | ||
807 | rtw_fw_bt_ignore_wlan_action(rtwdev, enable); | |
808 | } | |
809 | ||
810 | static void rtw_coex_power_save_state(struct rtw_dev *rtwdev, u8 ps_type, | |
811 | u8 lps_val, u8 rpwm_val) | |
812 | { | |
4136214f YHC |
813 | struct rtw_coex *coex = &rtwdev->coex; |
814 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
815 | u8 lps_mode = 0x0; | |
816 | ||
817 | lps_mode = rtwdev->lps_conf.mode; | |
818 | ||
819 | switch (ps_type) { | |
820 | case COEX_PS_WIFI_NATIVE: | |
821 | /* recover to original 32k low power setting */ | |
822 | coex_stat->wl_force_lps_ctrl = false; | |
823 | ||
3d391c06 | 824 | rtw_leave_lps(rtwdev); |
4136214f YHC |
825 | break; |
826 | case COEX_PS_LPS_OFF: | |
827 | coex_stat->wl_force_lps_ctrl = true; | |
828 | if (lps_mode) | |
829 | rtw_fw_coex_tdma_type(rtwdev, 0x8, 0, 0, 0, 0); | |
830 | ||
3d391c06 | 831 | rtw_leave_lps(rtwdev); |
4136214f YHC |
832 | break; |
833 | default: | |
834 | break; | |
835 | } | |
836 | } | |
837 | ||
838 | static void rtw_coex_set_tdma(struct rtw_dev *rtwdev, u8 byte1, u8 byte2, | |
839 | u8 byte3, u8 byte4, u8 byte5) | |
840 | { | |
841 | struct rtw_coex *coex = &rtwdev->coex; | |
842 | struct rtw_coex_dm *coex_dm = &coex->dm; | |
843 | struct rtw_chip_info *chip = rtwdev->chip; | |
844 | u8 ps_type = COEX_PS_WIFI_NATIVE; | |
845 | bool ap_enable = false; | |
846 | ||
847 | if (ap_enable && (byte1 & BIT(4) && !(byte1 & BIT(5)))) { | |
848 | byte1 &= ~BIT(4); | |
849 | byte1 |= BIT(5); | |
850 | ||
851 | byte5 |= BIT(5); | |
852 | byte5 &= ~BIT(6); | |
853 | ||
854 | ps_type = COEX_PS_WIFI_NATIVE; | |
855 | rtw_coex_power_save_state(rtwdev, ps_type, 0x0, 0x0); | |
856 | } else if (byte1 & BIT(4) && !(byte1 & BIT(5))) { | |
857 | if (chip->pstdma_type == COEX_PSTDMA_FORCE_LPSOFF) | |
858 | ps_type = COEX_PS_LPS_OFF; | |
859 | else | |
860 | ps_type = COEX_PS_LPS_ON; | |
861 | rtw_coex_power_save_state(rtwdev, ps_type, 0x50, 0x4); | |
862 | } else { | |
863 | ps_type = COEX_PS_WIFI_NATIVE; | |
864 | rtw_coex_power_save_state(rtwdev, ps_type, 0x0, 0x0); | |
865 | } | |
866 | ||
867 | coex_dm->ps_tdma_para[0] = byte1; | |
868 | coex_dm->ps_tdma_para[1] = byte2; | |
869 | coex_dm->ps_tdma_para[2] = byte3; | |
870 | coex_dm->ps_tdma_para[3] = byte4; | |
871 | coex_dm->ps_tdma_para[4] = byte5; | |
872 | ||
873 | rtw_fw_coex_tdma_type(rtwdev, byte1, byte2, byte3, byte4, byte5); | |
874 | } | |
875 | ||
876 | static void rtw_coex_tdma(struct rtw_dev *rtwdev, bool force, u32 tcase) | |
877 | { | |
878 | struct rtw_coex *coex = &rtwdev->coex; | |
879 | struct rtw_coex_dm *coex_dm = &coex->dm; | |
880 | struct rtw_chip_info *chip = rtwdev->chip; | |
881 | struct rtw_efuse *efuse = &rtwdev->efuse; | |
882 | u8 n, type; | |
883 | bool turn_on; | |
884 | ||
885 | if (tcase & TDMA_4SLOT)/* 4-slot (50ms) mode */ | |
886 | rtw_coex_tdma_timer_base(rtwdev, 3); | |
887 | else | |
888 | rtw_coex_tdma_timer_base(rtwdev, 0); | |
889 | ||
890 | type = (u8)(tcase & 0xff); | |
891 | ||
892 | turn_on = (type == 0 || type == 100) ? false : true; | |
893 | ||
894 | if (!force) { | |
895 | if (turn_on == coex_dm->cur_ps_tdma_on && | |
896 | type == coex_dm->cur_ps_tdma) { | |
897 | return; | |
898 | } | |
899 | } | |
900 | ||
901 | if (turn_on) { | |
902 | /* enable TBTT interrupt */ | |
903 | rtw_write8_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION); | |
904 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_TDMA, true); | |
905 | } else { | |
906 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_TDMA, false); | |
907 | } | |
908 | ||
909 | if (efuse->share_ant) { | |
910 | if (type < chip->tdma_sant_num) | |
911 | rtw_coex_set_tdma(rtwdev, | |
912 | chip->tdma_sant[type].para[0], | |
913 | chip->tdma_sant[type].para[1], | |
914 | chip->tdma_sant[type].para[2], | |
915 | chip->tdma_sant[type].para[3], | |
916 | chip->tdma_sant[type].para[4]); | |
917 | } else { | |
918 | n = type - 100; | |
919 | if (n < chip->tdma_nsant_num) | |
920 | rtw_coex_set_tdma(rtwdev, | |
921 | chip->tdma_nsant[n].para[0], | |
922 | chip->tdma_nsant[n].para[1], | |
923 | chip->tdma_nsant[n].para[2], | |
924 | chip->tdma_nsant[n].para[3], | |
925 | chip->tdma_nsant[n].para[4]); | |
926 | } | |
927 | ||
928 | /* update pre state */ | |
929 | coex_dm->cur_ps_tdma_on = turn_on; | |
930 | coex_dm->cur_ps_tdma = type; | |
931 | ||
932 | rtw_dbg(rtwdev, RTW_DBG_COEX, "coex: coex tdma type (%d)\n", type); | |
933 | } | |
934 | ||
935 | static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase) | |
936 | { | |
937 | struct rtw_coex *coex = &rtwdev->coex; | |
938 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
939 | struct rtw_coex_dm *coex_dm = &coex->dm; | |
940 | u8 ctrl_type = COEX_SWITCH_CTRL_MAX; | |
941 | u8 pos_type = COEX_SWITCH_TO_MAX; | |
942 | ||
943 | if (!force && coex_dm->cur_ant_pos_type == phase) | |
944 | return; | |
945 | ||
946 | coex_dm->cur_ant_pos_type = phase; | |
947 | ||
948 | /* avoid switch coex_ctrl_owner during BT IQK */ | |
949 | rtw_coex_check_rfk(rtwdev); | |
950 | ||
951 | switch (phase) { | |
952 | case COEX_SET_ANT_POWERON: | |
953 | /* set path control owner to BT at power-on */ | |
954 | if (coex_stat->bt_disabled) | |
955 | rtw_coex_coex_ctrl_owner(rtwdev, true); | |
956 | else | |
957 | rtw_coex_coex_ctrl_owner(rtwdev, false); | |
958 | ||
959 | ctrl_type = COEX_SWITCH_CTRL_BY_BBSW; | |
960 | pos_type = COEX_SWITCH_TO_BT; | |
961 | break; | |
962 | case COEX_SET_ANT_INIT: | |
963 | if (coex_stat->bt_disabled) { | |
964 | /* set GNT_BT to SW low */ | |
965 | rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_LOW); | |
966 | ||
967 | /* set GNT_WL to SW high */ | |
968 | rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_HIGH); | |
969 | } else { | |
970 | /* set GNT_BT to SW high */ | |
971 | rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_HIGH); | |
972 | ||
973 | /* set GNT_WL to SW low */ | |
974 | rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_LOW); | |
975 | } | |
976 | ||
977 | /* set path control owner to wl at initial step */ | |
978 | rtw_coex_coex_ctrl_owner(rtwdev, true); | |
979 | ||
980 | ctrl_type = COEX_SWITCH_CTRL_BY_BBSW; | |
981 | pos_type = COEX_SWITCH_TO_BT; | |
982 | break; | |
983 | case COEX_SET_ANT_WONLY: | |
984 | /* set GNT_BT to SW Low */ | |
985 | rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_LOW); | |
986 | ||
987 | /* Set GNT_WL to SW high */ | |
988 | rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_HIGH); | |
989 | ||
990 | /* set path control owner to wl at initial step */ | |
991 | rtw_coex_coex_ctrl_owner(rtwdev, true); | |
992 | ||
993 | ctrl_type = COEX_SWITCH_CTRL_BY_BBSW; | |
994 | pos_type = COEX_SWITCH_TO_WLG; | |
995 | break; | |
996 | case COEX_SET_ANT_WOFF: | |
997 | /* set path control owner to BT */ | |
998 | rtw_coex_coex_ctrl_owner(rtwdev, false); | |
999 | ||
1000 | ctrl_type = COEX_SWITCH_CTRL_BY_BT; | |
1001 | pos_type = COEX_SWITCH_TO_NOCARE; | |
1002 | break; | |
1003 | case COEX_SET_ANT_2G: | |
1004 | /* set GNT_BT to PTA */ | |
1005 | rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_HW_PTA); | |
1006 | ||
1007 | /* set GNT_WL to PTA */ | |
1008 | rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_HW_PTA); | |
1009 | ||
1010 | /* set path control owner to wl at runtime step */ | |
1011 | rtw_coex_coex_ctrl_owner(rtwdev, true); | |
1012 | ||
1013 | ctrl_type = COEX_SWITCH_CTRL_BY_PTA; | |
1014 | pos_type = COEX_SWITCH_TO_NOCARE; | |
1015 | break; | |
1016 | case COEX_SET_ANT_5G: | |
1017 | /* set GNT_BT to PTA */ | |
1018 | rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_HIGH); | |
1019 | ||
1020 | /* set GNT_WL to SW high */ | |
1021 | rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_HIGH); | |
1022 | ||
1023 | /* set path control owner to wl at runtime step */ | |
1024 | rtw_coex_coex_ctrl_owner(rtwdev, true); | |
1025 | ||
1026 | ctrl_type = COEX_SWITCH_CTRL_BY_BBSW; | |
1027 | pos_type = COEX_SWITCH_TO_WLA; | |
1028 | break; | |
1029 | case COEX_SET_ANT_2G_FREERUN: | |
1030 | /* set GNT_BT to SW high */ | |
1031 | rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_HIGH); | |
1032 | ||
1033 | /* Set GNT_WL to SW high */ | |
1034 | rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_HIGH); | |
1035 | ||
1036 | /* set path control owner to wl at runtime step */ | |
1037 | rtw_coex_coex_ctrl_owner(rtwdev, true); | |
1038 | ||
1039 | ctrl_type = COEX_SWITCH_CTRL_BY_BBSW; | |
1040 | pos_type = COEX_SWITCH_TO_WLG_BT; | |
1041 | break; | |
1042 | case COEX_SET_ANT_2G_WLBT: | |
1043 | /* set GNT_BT to SW high */ | |
1044 | rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_HW_PTA); | |
1045 | ||
1046 | /* Set GNT_WL to SW high */ | |
1047 | rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_HW_PTA); | |
1048 | ||
1049 | /* set path control owner to wl at runtime step */ | |
1050 | rtw_coex_coex_ctrl_owner(rtwdev, true); | |
1051 | ||
1052 | ctrl_type = COEX_SWITCH_CTRL_BY_BBSW; | |
1053 | pos_type = COEX_SWITCH_TO_WLG_BT; | |
1054 | break; | |
1055 | default: | |
52929cad | 1056 | WARN(1, "unknown phase when setting antenna path\n"); |
4136214f YHC |
1057 | return; |
1058 | } | |
1059 | ||
1060 | if (ctrl_type < COEX_SWITCH_CTRL_MAX && pos_type < COEX_SWITCH_TO_MAX) | |
1061 | rtw_coex_set_ant_switch(rtwdev, ctrl_type, pos_type); | |
1062 | } | |
1063 | ||
1064 | static u8 rtw_coex_algorithm(struct rtw_dev *rtwdev) | |
1065 | { | |
1066 | struct rtw_coex *coex = &rtwdev->coex; | |
1067 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
1068 | u8 algorithm = COEX_ALGO_NOPROFILE; | |
1069 | u8 profile_map = 0; | |
1070 | ||
1071 | if (coex_stat->bt_hfp_exist) | |
1072 | profile_map |= BPM_HFP; | |
1073 | if (coex_stat->bt_hid_exist) | |
1074 | profile_map |= BPM_HID; | |
1075 | if (coex_stat->bt_a2dp_exist) | |
1076 | profile_map |= BPM_A2DP; | |
1077 | if (coex_stat->bt_pan_exist) | |
1078 | profile_map |= BPM_PAN; | |
1079 | ||
1080 | switch (profile_map) { | |
1081 | case BPM_HFP: | |
1082 | algorithm = COEX_ALGO_HFP; | |
1083 | break; | |
1084 | case BPM_HID: | |
1085 | case BPM_HFP + BPM_HID: | |
1086 | algorithm = COEX_ALGO_HID; | |
1087 | break; | |
1088 | case BPM_HFP + BPM_A2DP: | |
1089 | case BPM_HID + BPM_A2DP: | |
1090 | case BPM_HFP + BPM_HID + BPM_A2DP: | |
1091 | algorithm = COEX_ALGO_A2DP_HID; | |
1092 | break; | |
1093 | case BPM_HFP + BPM_PAN: | |
1094 | case BPM_HID + BPM_PAN: | |
1095 | case BPM_HFP + BPM_HID + BPM_PAN: | |
1096 | algorithm = COEX_ALGO_PAN_HID; | |
1097 | break; | |
1098 | case BPM_HFP + BPM_A2DP + BPM_PAN: | |
1099 | case BPM_HID + BPM_A2DP + BPM_PAN: | |
1100 | case BPM_HFP + BPM_HID + BPM_A2DP + BPM_PAN: | |
1101 | algorithm = COEX_ALGO_A2DP_PAN_HID; | |
1102 | break; | |
1103 | case BPM_PAN: | |
1104 | algorithm = COEX_ALGO_PAN; | |
1105 | break; | |
1106 | case BPM_A2DP + BPM_PAN: | |
1107 | algorithm = COEX_ALGO_A2DP_PAN; | |
1108 | break; | |
1109 | case BPM_A2DP: | |
1110 | if (coex_stat->bt_multi_link) { | |
1111 | if (coex_stat->bt_hid_pair_num > 0) | |
1112 | algorithm = COEX_ALGO_A2DP_HID; | |
1113 | else | |
1114 | algorithm = COEX_ALGO_A2DP_PAN; | |
1115 | } else { | |
1116 | algorithm = COEX_ALGO_A2DP; | |
1117 | } | |
1118 | break; | |
1119 | default: | |
1120 | algorithm = COEX_ALGO_NOPROFILE; | |
1121 | break; | |
1122 | } | |
1123 | ||
1124 | return algorithm; | |
1125 | } | |
1126 | ||
1127 | static void rtw_coex_action_coex_all_off(struct rtw_dev *rtwdev) | |
1128 | { | |
1129 | struct rtw_efuse *efuse = &rtwdev->efuse; | |
1130 | struct rtw_chip_info *chip = rtwdev->chip; | |
1131 | u8 table_case, tdma_case; | |
1132 | ||
1133 | if (efuse->share_ant) { | |
1134 | /* Shared-Ant */ | |
1135 | table_case = 2; | |
1136 | tdma_case = 0; | |
1137 | } else { | |
1138 | /* Non-Shared-Ant */ | |
1139 | table_case = 100; | |
1140 | tdma_case = 100; | |
1141 | } | |
1142 | ||
1143 | rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]); | |
1144 | rtw_coex_table(rtwdev, table_case); | |
1145 | rtw_coex_tdma(rtwdev, false, tdma_case); | |
1146 | } | |
1147 | ||
1148 | static void rtw_coex_action_freerun(struct rtw_dev *rtwdev) | |
1149 | { | |
1150 | struct rtw_coex *coex = &rtwdev->coex; | |
1151 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
1152 | struct rtw_coex_dm *coex_dm = &coex->dm; | |
1153 | struct rtw_efuse *efuse = &rtwdev->efuse; | |
1154 | struct rtw_chip_info *chip = rtwdev->chip; | |
1155 | u8 level = 0; | |
1156 | ||
1157 | if (efuse->share_ant) | |
1158 | return; | |
1159 | ||
1160 | coex->freerun = true; | |
1161 | ||
1162 | if (coex_stat->wl_connected) | |
1163 | rtw_coex_update_wl_ch_info(rtwdev, COEX_MEDIA_CONNECT); | |
1164 | ||
1165 | rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G_FREERUN); | |
1166 | ||
1167 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_FIX2M, false); | |
1168 | ||
1169 | if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[0])) | |
1170 | level = 2; | |
1171 | else if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1])) | |
1172 | level = 3; | |
1173 | else if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[2])) | |
1174 | level = 4; | |
1175 | else | |
1176 | level = 5; | |
1177 | ||
1178 | if (level > chip->wl_rf_para_num - 1) | |
1179 | level = chip->wl_rf_para_num - 1; | |
1180 | ||
1181 | if (coex_stat->wl_tput_dir == COEX_WL_TPUT_TX) | |
1182 | rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_tx[level]); | |
1183 | else | |
1184 | rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[level]); | |
1185 | ||
1186 | rtw_coex_table(rtwdev, 100); | |
1187 | rtw_coex_tdma(rtwdev, false, 100); | |
1188 | } | |
1189 | ||
1190 | static void rtw_coex_action_bt_whql_test(struct rtw_dev *rtwdev) | |
1191 | { | |
1192 | struct rtw_efuse *efuse = &rtwdev->efuse; | |
1193 | struct rtw_chip_info *chip = rtwdev->chip; | |
1194 | u8 table_case, tdma_case; | |
1195 | ||
1196 | if (efuse->share_ant) { | |
1197 | /* Shared-Ant */ | |
1198 | table_case = 2; | |
1199 | tdma_case = 0; | |
1200 | } else { | |
1201 | /* Non-Shared-Ant */ | |
1202 | table_case = 100; | |
1203 | tdma_case = 100; | |
1204 | } | |
1205 | ||
1206 | rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G); | |
1207 | rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]); | |
1208 | rtw_coex_table(rtwdev, table_case); | |
1209 | rtw_coex_tdma(rtwdev, false, tdma_case); | |
1210 | } | |
1211 | ||
1212 | static void rtw_coex_action_bt_relink(struct rtw_dev *rtwdev) | |
1213 | { | |
1214 | struct rtw_efuse *efuse = &rtwdev->efuse; | |
1215 | struct rtw_chip_info *chip = rtwdev->chip; | |
1216 | u8 table_case, tdma_case; | |
1217 | ||
1218 | if (efuse->share_ant) { | |
1219 | /* Shared-Ant */ | |
1220 | table_case = 1; | |
1221 | tdma_case = 0; | |
1222 | } else { | |
1223 | /* Non-Shared-Ant */ | |
1224 | table_case = 100; | |
1225 | tdma_case = 100; | |
1226 | } | |
1227 | ||
1228 | rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G); | |
1229 | rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]); | |
1230 | rtw_coex_table(rtwdev, table_case); | |
1231 | rtw_coex_tdma(rtwdev, false, tdma_case); | |
1232 | } | |
1233 | ||
1234 | static void rtw_coex_action_bt_idle(struct rtw_dev *rtwdev) | |
1235 | { | |
1236 | struct rtw_coex *coex = &rtwdev->coex; | |
1237 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
1238 | struct rtw_coex_dm *coex_dm = &coex->dm; | |
1239 | struct rtw_efuse *efuse = &rtwdev->efuse; | |
1240 | struct rtw_chip_info *chip = rtwdev->chip; | |
1241 | struct rtw_coex_rfe *coex_rfe = &coex->rfe; | |
1242 | u8 table_case = 0xff, tdma_case = 0xff; | |
1243 | ||
1244 | if (coex_rfe->ant_switch_with_bt && | |
1245 | coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) { | |
1246 | if (efuse->share_ant && | |
1247 | COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1])) { | |
1248 | table_case = 0; | |
1249 | tdma_case = 0; | |
1250 | } else if (!efuse->share_ant) { | |
1251 | table_case = 100; | |
1252 | tdma_case = 100; | |
1253 | } | |
1254 | } | |
1255 | ||
1256 | if (table_case != 0xff && tdma_case != 0xff) { | |
1257 | rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G_FREERUN); | |
1258 | rtw_coex_table(rtwdev, table_case); | |
1259 | rtw_coex_tdma(rtwdev, false, tdma_case); | |
1260 | return; | |
1261 | } | |
1262 | ||
1263 | rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G); | |
1264 | ||
1265 | if (efuse->share_ant) { | |
1266 | /* Shared-Ant */ | |
1267 | if (!coex_stat->wl_gl_busy) { | |
1268 | table_case = 10; | |
1269 | tdma_case = 3; | |
1270 | } else if (coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) { | |
1271 | table_case = 6; | |
1272 | tdma_case = 7; | |
1273 | } else { | |
1274 | table_case = 12; | |
1275 | tdma_case = 7; | |
1276 | } | |
1277 | } else { | |
1278 | /* Non-Shared-Ant */ | |
1279 | if (!coex_stat->wl_gl_busy) { | |
1280 | table_case = 112; | |
1281 | tdma_case = 104; | |
1282 | } else if ((coex_stat->bt_ble_scan_type & 0x2) && | |
1283 | coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) { | |
1284 | table_case = 114; | |
1285 | tdma_case = 103; | |
1286 | } else { | |
1287 | table_case = 112; | |
1288 | tdma_case = 103; | |
1289 | } | |
1290 | } | |
1291 | ||
1292 | rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]); | |
1293 | rtw_coex_table(rtwdev, table_case); | |
1294 | rtw_coex_tdma(rtwdev, false, tdma_case); | |
1295 | } | |
1296 | ||
1297 | static void rtw_coex_action_bt_inquiry(struct rtw_dev *rtwdev) | |
1298 | { | |
1299 | struct rtw_coex *coex = &rtwdev->coex; | |
1300 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
1301 | struct rtw_efuse *efuse = &rtwdev->efuse; | |
1302 | struct rtw_chip_info *chip = rtwdev->chip; | |
1303 | bool wl_hi_pri = false; | |
1304 | u8 table_case, tdma_case; | |
12078aae | 1305 | u32 slot_type = 0; |
4136214f YHC |
1306 | |
1307 | if (coex_stat->wl_linkscan_proc || coex_stat->wl_hi_pri_task1 || | |
1308 | coex_stat->wl_hi_pri_task2) | |
1309 | wl_hi_pri = true; | |
1310 | ||
1311 | if (efuse->share_ant) { | |
1312 | /* Shared-Ant */ | |
1313 | if (wl_hi_pri) { | |
1314 | table_case = 15; | |
1315 | if (coex_stat->bt_a2dp_exist && | |
12078aae PKS |
1316 | !coex_stat->bt_pan_exist) { |
1317 | slot_type = TDMA_4SLOT; | |
4136214f | 1318 | tdma_case = 11; |
12078aae | 1319 | } else if (coex_stat->wl_hi_pri_task1) { |
4136214f | 1320 | tdma_case = 6; |
12078aae | 1321 | } else if (!coex_stat->bt_page) { |
4136214f | 1322 | tdma_case = 8; |
12078aae | 1323 | } else { |
4136214f | 1324 | tdma_case = 9; |
12078aae | 1325 | } |
4136214f YHC |
1326 | } else if (coex_stat->wl_connected) { |
1327 | table_case = 10; | |
1328 | tdma_case = 10; | |
1329 | } else { | |
1330 | table_case = 1; | |
1331 | tdma_case = 0; | |
1332 | } | |
1333 | } else { | |
1334 | /* Non_Shared-Ant */ | |
1335 | if (wl_hi_pri) { | |
1336 | table_case = 113; | |
1337 | if (coex_stat->bt_a2dp_exist && | |
1338 | !coex_stat->bt_pan_exist) | |
1339 | tdma_case = 111; | |
1340 | else if (coex_stat->wl_hi_pri_task1) | |
1341 | tdma_case = 106; | |
1342 | else if (!coex_stat->bt_page) | |
1343 | tdma_case = 108; | |
1344 | else | |
1345 | tdma_case = 109; | |
1346 | } else if (coex_stat->wl_connected) { | |
1347 | table_case = 101; | |
1348 | tdma_case = 110; | |
1349 | } else { | |
1350 | table_case = 100; | |
1351 | tdma_case = 100; | |
1352 | } | |
1353 | } | |
1354 | ||
1355 | rtw_dbg(rtwdev, RTW_DBG_COEX, "coex: wifi hi(%d), bt page(%d)\n", | |
1356 | wl_hi_pri, coex_stat->bt_page); | |
1357 | ||
1358 | rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G); | |
1359 | rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]); | |
1360 | rtw_coex_table(rtwdev, table_case); | |
12078aae | 1361 | rtw_coex_tdma(rtwdev, false, tdma_case | slot_type); |
4136214f YHC |
1362 | } |
1363 | ||
1364 | static void rtw_coex_action_bt_hfp(struct rtw_dev *rtwdev) | |
1365 | { | |
1366 | struct rtw_coex *coex = &rtwdev->coex; | |
1367 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
1368 | struct rtw_efuse *efuse = &rtwdev->efuse; | |
1369 | struct rtw_chip_info *chip = rtwdev->chip; | |
1370 | u8 table_case, tdma_case; | |
1371 | ||
1372 | if (efuse->share_ant) { | |
1373 | /* Shared-Ant */ | |
1374 | if (coex_stat->bt_multi_link) { | |
1375 | table_case = 10; | |
1376 | tdma_case = 17; | |
1377 | } else { | |
1378 | table_case = 10; | |
1379 | tdma_case = 5; | |
1380 | } | |
1381 | } else { | |
1382 | /* Non-Shared-Ant */ | |
1383 | if (coex_stat->bt_multi_link) { | |
1384 | table_case = 112; | |
1385 | tdma_case = 117; | |
1386 | } else { | |
1387 | table_case = 105; | |
1388 | tdma_case = 100; | |
1389 | } | |
1390 | } | |
1391 | ||
1392 | rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G); | |
1393 | rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]); | |
1394 | rtw_coex_table(rtwdev, table_case); | |
1395 | rtw_coex_tdma(rtwdev, false, tdma_case); | |
1396 | } | |
1397 | ||
1398 | static void rtw_coex_action_bt_hid(struct rtw_dev *rtwdev) | |
1399 | { | |
1400 | struct rtw_coex *coex = &rtwdev->coex; | |
1401 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
1402 | struct rtw_efuse *efuse = &rtwdev->efuse; | |
1403 | struct rtw_chip_info *chip = rtwdev->chip; | |
1404 | u8 table_case, tdma_case; | |
1405 | u32 wl_bw; | |
1406 | ||
1407 | wl_bw = rtwdev->hal.current_band_width; | |
1408 | ||
1409 | if (efuse->share_ant) { | |
1410 | /* Shared-Ant */ | |
1411 | if (coex_stat->bt_ble_exist) { | |
1412 | /* RCU */ | |
1413 | if (!coex_stat->wl_gl_busy) | |
1414 | table_case = 14; | |
1415 | else | |
1416 | table_case = 15; | |
1417 | ||
1418 | if (coex_stat->bt_a2dp_active || wl_bw == 0) | |
1419 | tdma_case = 18; | |
1420 | else if (coex_stat->wl_gl_busy) | |
1421 | tdma_case = 8; | |
1422 | else | |
1423 | tdma_case = 4; | |
1424 | } else { | |
1425 | if (coex_stat->bt_a2dp_active || wl_bw == 0) { | |
1426 | table_case = 8; | |
1427 | tdma_case = 4; | |
1428 | } else { | |
1429 | /* for 4/18 HID */ | |
1430 | if (coex_stat->bt_418_hid_exist && | |
1431 | coex_stat->wl_gl_busy) | |
1432 | table_case = 12; | |
1433 | else | |
1434 | table_case = 10; | |
1435 | tdma_case = 4; | |
1436 | } | |
1437 | } | |
1438 | } else { | |
1439 | /* Non-Shared-Ant */ | |
1440 | if (coex_stat->bt_a2dp_active) { | |
1441 | table_case = 113; | |
1442 | tdma_case = 118; | |
1443 | } else if (coex_stat->bt_ble_exist) { | |
1444 | /* BLE */ | |
1445 | table_case = 113; | |
1446 | ||
1447 | if (coex_stat->wl_gl_busy) | |
1448 | tdma_case = 106; | |
1449 | else | |
1450 | tdma_case = 104; | |
1451 | } else { | |
1452 | table_case = 113; | |
1453 | tdma_case = 104; | |
1454 | } | |
1455 | } | |
1456 | ||
1457 | rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G); | |
1458 | rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]); | |
1459 | rtw_coex_table(rtwdev, table_case); | |
1460 | rtw_coex_tdma(rtwdev, false, tdma_case); | |
1461 | } | |
1462 | ||
1463 | static void rtw_coex_action_bt_a2dp(struct rtw_dev *rtwdev) | |
1464 | { | |
1465 | struct rtw_coex *coex = &rtwdev->coex; | |
1466 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
1467 | struct rtw_coex_dm *coex_dm = &coex->dm; | |
1468 | struct rtw_efuse *efuse = &rtwdev->efuse; | |
1469 | struct rtw_chip_info *chip = rtwdev->chip; | |
1470 | u8 table_case, tdma_case; | |
1471 | u32 slot_type = 0; | |
1472 | ||
1473 | if (efuse->share_ant) { | |
1474 | /* Shared-Ant */ | |
12078aae PKS |
1475 | slot_type = TDMA_4SLOT; |
1476 | ||
4136214f YHC |
1477 | if (coex_stat->wl_gl_busy && coex_stat->wl_noisy_level == 0) |
1478 | table_case = 10; | |
1479 | else | |
1480 | table_case = 9; | |
1481 | ||
4136214f YHC |
1482 | if (coex_stat->wl_gl_busy) |
1483 | tdma_case = 13; | |
1484 | else | |
1485 | tdma_case = 14; | |
1486 | } else { | |
1487 | /* Non-Shared-Ant */ | |
1488 | table_case = 112; | |
1489 | ||
1490 | if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1])) | |
1491 | tdma_case = 112; | |
1492 | else | |
1493 | tdma_case = 113; | |
1494 | } | |
1495 | ||
1496 | rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G); | |
1497 | rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]); | |
1498 | rtw_coex_table(rtwdev, table_case); | |
1499 | rtw_coex_tdma(rtwdev, false, tdma_case | slot_type); | |
1500 | } | |
1501 | ||
1502 | static void rtw_coex_action_bt_a2dpsink(struct rtw_dev *rtwdev) | |
1503 | { | |
1504 | struct rtw_coex *coex = &rtwdev->coex; | |
1505 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
1506 | struct rtw_efuse *efuse = &rtwdev->efuse; | |
1507 | struct rtw_chip_info *chip = rtwdev->chip; | |
1508 | u8 table_case, tdma_case; | |
1509 | bool ap_enable = false; | |
1510 | ||
1511 | if (efuse->share_ant) { /* Shared-Ant */ | |
1512 | if (ap_enable) { | |
1513 | table_case = 2; | |
1514 | tdma_case = 0; | |
1515 | } else if (coex_stat->wl_gl_busy) { | |
1516 | table_case = 28; | |
1517 | tdma_case = 20; | |
1518 | } else { | |
1519 | table_case = 28; | |
1520 | tdma_case = 26; | |
1521 | } | |
1522 | } else { /* Non-Shared-Ant */ | |
1523 | if (ap_enable) { | |
1524 | table_case = 100; | |
1525 | tdma_case = 100; | |
1526 | } else { | |
1527 | table_case = 119; | |
1528 | tdma_case = 120; | |
1529 | } | |
1530 | } | |
1531 | ||
1532 | rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G); | |
1533 | rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]); | |
1534 | rtw_coex_table(rtwdev, table_case); | |
1535 | rtw_coex_tdma(rtwdev, false, tdma_case); | |
1536 | } | |
1537 | ||
1538 | static void rtw_coex_action_bt_pan(struct rtw_dev *rtwdev) | |
1539 | { | |
1540 | struct rtw_coex *coex = &rtwdev->coex; | |
1541 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
1542 | struct rtw_efuse *efuse = &rtwdev->efuse; | |
1543 | struct rtw_chip_info *chip = rtwdev->chip; | |
1544 | u8 table_case, tdma_case; | |
1545 | ||
1546 | if (efuse->share_ant) { | |
1547 | /* Shared-Ant */ | |
1548 | if (coex_stat->wl_gl_busy && coex_stat->wl_noisy_level == 0) | |
1549 | table_case = 14; | |
1550 | else | |
1551 | table_case = 10; | |
1552 | ||
1553 | if (coex_stat->wl_gl_busy) | |
1554 | tdma_case = 17; | |
1555 | else | |
1556 | tdma_case = 19; | |
1557 | } else { | |
1558 | /* Non-Shared-Ant */ | |
1559 | table_case = 112; | |
1560 | ||
1561 | if (coex_stat->wl_gl_busy) | |
1562 | tdma_case = 117; | |
1563 | else | |
1564 | tdma_case = 119; | |
1565 | } | |
1566 | ||
1567 | rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G); | |
1568 | rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]); | |
1569 | rtw_coex_table(rtwdev, table_case); | |
1570 | rtw_coex_tdma(rtwdev, false, tdma_case); | |
1571 | } | |
1572 | ||
1573 | static void rtw_coex_action_bt_a2dp_hid(struct rtw_dev *rtwdev) | |
1574 | { | |
1575 | struct rtw_coex *coex = &rtwdev->coex; | |
1576 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
1577 | struct rtw_coex_dm *coex_dm = &coex->dm; | |
1578 | struct rtw_efuse *efuse = &rtwdev->efuse; | |
1579 | struct rtw_chip_info *chip = rtwdev->chip; | |
1580 | u8 table_case, tdma_case; | |
1581 | u32 slot_type = 0; | |
1582 | ||
1583 | if (efuse->share_ant) { | |
1584 | /* Shared-Ant */ | |
12078aae PKS |
1585 | slot_type = TDMA_4SLOT; |
1586 | ||
4136214f YHC |
1587 | if (coex_stat->bt_ble_exist) |
1588 | table_case = 26; | |
1589 | else | |
1590 | table_case = 9; | |
1591 | ||
1592 | if (coex_stat->wl_gl_busy) { | |
4136214f YHC |
1593 | tdma_case = 13; |
1594 | } else { | |
1595 | tdma_case = 14; | |
1596 | } | |
1597 | } else { | |
1598 | /* Non-Shared-Ant */ | |
1599 | if (coex_stat->bt_ble_exist) | |
1600 | table_case = 121; | |
1601 | else | |
1602 | table_case = 113; | |
1603 | ||
1604 | if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1])) | |
1605 | tdma_case = 112; | |
1606 | else | |
1607 | tdma_case = 113; | |
1608 | } | |
1609 | ||
1610 | rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G); | |
1611 | rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]); | |
1612 | rtw_coex_table(rtwdev, table_case); | |
1613 | rtw_coex_tdma(rtwdev, false, tdma_case | slot_type); | |
1614 | } | |
1615 | ||
1616 | static void rtw_coex_action_bt_a2dp_pan(struct rtw_dev *rtwdev) | |
1617 | { | |
1618 | struct rtw_coex *coex = &rtwdev->coex; | |
1619 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
1620 | struct rtw_efuse *efuse = &rtwdev->efuse; | |
1621 | struct rtw_chip_info *chip = rtwdev->chip; | |
1622 | u8 table_case, tdma_case; | |
1623 | ||
1624 | if (efuse->share_ant) { | |
1625 | /* Shared-Ant */ | |
1626 | if (coex_stat->wl_gl_busy && | |
1627 | coex_stat->wl_noisy_level == 0) | |
1628 | table_case = 14; | |
1629 | else | |
1630 | table_case = 10; | |
1631 | ||
1632 | if (coex_stat->wl_gl_busy) | |
1633 | tdma_case = 15; | |
1634 | else | |
1635 | tdma_case = 20; | |
1636 | } else { | |
1637 | /* Non-Shared-Ant */ | |
1638 | table_case = 112; | |
1639 | ||
1640 | if (coex_stat->wl_gl_busy) | |
1641 | tdma_case = 115; | |
1642 | else | |
1643 | tdma_case = 120; | |
1644 | } | |
1645 | ||
1646 | rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G); | |
1647 | rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]); | |
1648 | rtw_coex_table(rtwdev, table_case); | |
1649 | rtw_coex_tdma(rtwdev, false, tdma_case); | |
1650 | } | |
1651 | ||
1652 | static void rtw_coex_action_bt_pan_hid(struct rtw_dev *rtwdev) | |
1653 | { | |
1654 | struct rtw_coex *coex = &rtwdev->coex; | |
1655 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
1656 | struct rtw_efuse *efuse = &rtwdev->efuse; | |
1657 | struct rtw_chip_info *chip = rtwdev->chip; | |
1658 | u8 table_case, tdma_case; | |
1659 | ||
1660 | if (efuse->share_ant) { | |
1661 | /* Shared-Ant */ | |
1662 | table_case = 9; | |
1663 | ||
1664 | if (coex_stat->wl_gl_busy) | |
1665 | tdma_case = 18; | |
1666 | else | |
1667 | tdma_case = 19; | |
1668 | } else { | |
1669 | /* Non-Shared-Ant */ | |
1670 | table_case = 113; | |
1671 | ||
1672 | if (coex_stat->wl_gl_busy) | |
1673 | tdma_case = 117; | |
1674 | else | |
1675 | tdma_case = 119; | |
1676 | } | |
1677 | ||
1678 | rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G); | |
1679 | rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]); | |
1680 | rtw_coex_table(rtwdev, table_case); | |
1681 | rtw_coex_tdma(rtwdev, false, tdma_case); | |
1682 | } | |
1683 | ||
1684 | static void rtw_coex_action_bt_a2dp_pan_hid(struct rtw_dev *rtwdev) | |
1685 | { | |
1686 | struct rtw_coex *coex = &rtwdev->coex; | |
1687 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
1688 | struct rtw_efuse *efuse = &rtwdev->efuse; | |
1689 | struct rtw_chip_info *chip = rtwdev->chip; | |
1690 | u8 table_case, tdma_case; | |
1691 | ||
1692 | if (efuse->share_ant) { | |
1693 | /* Shared-Ant */ | |
1694 | table_case = 10; | |
1695 | ||
1696 | if (coex_stat->wl_gl_busy) | |
1697 | tdma_case = 15; | |
1698 | else | |
1699 | tdma_case = 20; | |
1700 | } else { | |
1701 | /* Non-Shared-Ant */ | |
1702 | table_case = 113; | |
1703 | ||
1704 | if (coex_stat->wl_gl_busy) | |
1705 | tdma_case = 115; | |
1706 | else | |
1707 | tdma_case = 120; | |
1708 | } | |
1709 | ||
1710 | rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G); | |
1711 | rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]); | |
1712 | rtw_coex_table(rtwdev, table_case); | |
1713 | rtw_coex_tdma(rtwdev, false, tdma_case); | |
1714 | } | |
1715 | ||
1716 | static void rtw_coex_action_wl_under5g(struct rtw_dev *rtwdev) | |
1717 | { | |
1718 | struct rtw_efuse *efuse = &rtwdev->efuse; | |
1719 | struct rtw_chip_info *chip = rtwdev->chip; | |
1720 | u8 table_case, tdma_case; | |
1721 | ||
1722 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_FIX2M, false); | |
1723 | ||
1724 | if (efuse->share_ant) { | |
1725 | /* Shared-Ant */ | |
1726 | table_case = 0; | |
1727 | tdma_case = 0; | |
1728 | } else { | |
1729 | /* Non-Shared-Ant */ | |
1730 | table_case = 100; | |
1731 | tdma_case = 100; | |
1732 | } | |
1733 | ||
1734 | rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G); | |
1735 | rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]); | |
1736 | rtw_coex_table(rtwdev, table_case); | |
1737 | rtw_coex_tdma(rtwdev, false, tdma_case); | |
1738 | } | |
1739 | ||
1740 | static void rtw_coex_action_wl_only(struct rtw_dev *rtwdev) | |
1741 | { | |
1742 | struct rtw_efuse *efuse = &rtwdev->efuse; | |
1743 | struct rtw_chip_info *chip = rtwdev->chip; | |
1744 | u8 table_case, tdma_case; | |
1745 | ||
1746 | if (efuse->share_ant) { | |
1747 | /* Shared-Ant */ | |
1748 | table_case = 2; | |
1749 | tdma_case = 0; | |
1750 | } else { | |
1751 | /* Non-Shared-Ant */ | |
1752 | table_case = 100; | |
1753 | tdma_case = 100; | |
1754 | } | |
1755 | ||
1756 | rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G); | |
1757 | rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]); | |
1758 | rtw_coex_table(rtwdev, table_case); | |
1759 | rtw_coex_tdma(rtwdev, false, tdma_case); | |
1760 | } | |
1761 | ||
1762 | static void rtw_coex_action_wl_native_lps(struct rtw_dev *rtwdev) | |
1763 | { | |
1764 | struct rtw_coex *coex = &rtwdev->coex; | |
1765 | struct rtw_efuse *efuse = &rtwdev->efuse; | |
1766 | struct rtw_chip_info *chip = rtwdev->chip; | |
1767 | u8 table_case, tdma_case; | |
1768 | ||
1769 | if (coex->under_5g) | |
1770 | return; | |
1771 | ||
1772 | if (efuse->share_ant) { | |
1773 | /* Shared-Ant */ | |
1774 | table_case = 28; | |
1775 | tdma_case = 0; | |
1776 | } else { | |
1777 | /* Non-Shared-Ant */ | |
1778 | table_case = 100; | |
1779 | tdma_case = 100; | |
1780 | } | |
1781 | ||
1782 | rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G); | |
1783 | rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]); | |
1784 | rtw_coex_table(rtwdev, table_case); | |
1785 | rtw_coex_tdma(rtwdev, false, tdma_case); | |
1786 | } | |
1787 | ||
1788 | static void rtw_coex_action_wl_linkscan(struct rtw_dev *rtwdev) | |
1789 | { | |
1790 | struct rtw_coex *coex = &rtwdev->coex; | |
1791 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
1792 | struct rtw_efuse *efuse = &rtwdev->efuse; | |
1793 | struct rtw_chip_info *chip = rtwdev->chip; | |
1794 | u8 table_case, tdma_case; | |
12078aae | 1795 | u32 slot_type = 0; |
4136214f YHC |
1796 | |
1797 | if (efuse->share_ant) { | |
1798 | /* Shared-Ant */ | |
1799 | if (coex_stat->bt_a2dp_exist) { | |
12078aae | 1800 | slot_type = TDMA_4SLOT; |
4136214f YHC |
1801 | table_case = 9; |
1802 | tdma_case = 11; | |
1803 | } else { | |
1804 | table_case = 9; | |
1805 | tdma_case = 7; | |
1806 | } | |
1807 | } else { | |
1808 | /* Non-Shared-Ant */ | |
1809 | if (coex_stat->bt_a2dp_exist) { | |
1810 | table_case = 112; | |
1811 | tdma_case = 111; | |
1812 | } else { | |
1813 | table_case = 112; | |
1814 | tdma_case = 107; | |
1815 | } | |
1816 | } | |
1817 | ||
1818 | rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G); | |
1819 | rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]); | |
1820 | rtw_coex_table(rtwdev, table_case); | |
12078aae | 1821 | rtw_coex_tdma(rtwdev, false, tdma_case | slot_type); |
4136214f YHC |
1822 | } |
1823 | ||
1824 | static void rtw_coex_action_wl_not_connected(struct rtw_dev *rtwdev) | |
1825 | { | |
1826 | struct rtw_efuse *efuse = &rtwdev->efuse; | |
1827 | struct rtw_chip_info *chip = rtwdev->chip; | |
1828 | u8 table_case, tdma_case; | |
1829 | ||
1830 | if (efuse->share_ant) { | |
1831 | /* Shared-Ant */ | |
1832 | table_case = 1; | |
1833 | tdma_case = 0; | |
1834 | } else { | |
1835 | /* Non-Shared-Ant */ | |
1836 | table_case = 100; | |
1837 | tdma_case = 100; | |
1838 | } | |
1839 | ||
1840 | rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G); | |
1841 | rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]); | |
1842 | rtw_coex_table(rtwdev, table_case); | |
1843 | rtw_coex_tdma(rtwdev, false, tdma_case); | |
1844 | } | |
1845 | ||
1846 | static void rtw_coex_action_wl_connected(struct rtw_dev *rtwdev) | |
1847 | { | |
1848 | struct rtw_coex *coex = &rtwdev->coex; | |
1849 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
1850 | struct rtw_coex_dm *coex_dm = &coex->dm; | |
1851 | struct rtw_efuse *efuse = &rtwdev->efuse; | |
1852 | u8 algorithm; | |
1853 | ||
1854 | /* Non-Shared-Ant */ | |
1855 | if (!efuse->share_ant && coex_stat->wl_gl_busy && | |
1856 | COEX_RSSI_HIGH(coex_dm->wl_rssi_state[3]) && | |
1857 | COEX_RSSI_HIGH(coex_dm->bt_rssi_state[0])) { | |
1858 | rtw_coex_action_freerun(rtwdev); | |
1859 | return; | |
1860 | } | |
1861 | ||
1862 | algorithm = rtw_coex_algorithm(rtwdev); | |
1863 | ||
1864 | switch (algorithm) { | |
1865 | case COEX_ALGO_HFP: | |
1866 | rtw_coex_action_bt_hfp(rtwdev); | |
1867 | break; | |
1868 | case COEX_ALGO_HID: | |
1869 | rtw_coex_action_bt_hid(rtwdev); | |
1870 | break; | |
1871 | case COEX_ALGO_A2DP: | |
1872 | if (coex_stat->bt_a2dp_sink) | |
1873 | rtw_coex_action_bt_a2dpsink(rtwdev); | |
1874 | else | |
1875 | rtw_coex_action_bt_a2dp(rtwdev); | |
1876 | break; | |
1877 | case COEX_ALGO_PAN: | |
1878 | rtw_coex_action_bt_pan(rtwdev); | |
1879 | break; | |
1880 | case COEX_ALGO_A2DP_HID: | |
1881 | rtw_coex_action_bt_a2dp_hid(rtwdev); | |
1882 | break; | |
1883 | case COEX_ALGO_A2DP_PAN: | |
1884 | rtw_coex_action_bt_a2dp_pan(rtwdev); | |
1885 | break; | |
1886 | case COEX_ALGO_PAN_HID: | |
1887 | rtw_coex_action_bt_pan_hid(rtwdev); | |
1888 | break; | |
1889 | case COEX_ALGO_A2DP_PAN_HID: | |
1890 | rtw_coex_action_bt_a2dp_pan_hid(rtwdev); | |
1891 | break; | |
1892 | default: | |
1893 | case COEX_ALGO_NOPROFILE: | |
1894 | rtw_coex_action_bt_idle(rtwdev); | |
1895 | break; | |
1896 | } | |
1897 | } | |
1898 | ||
1899 | static void rtw_coex_run_coex(struct rtw_dev *rtwdev, u8 reason) | |
1900 | { | |
1901 | struct rtw_coex *coex = &rtwdev->coex; | |
1902 | struct rtw_coex_dm *coex_dm = &coex->dm; | |
1903 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
1904 | ||
1905 | lockdep_assert_held(&rtwdev->mutex); | |
1906 | ||
1907 | coex_dm->reason = reason; | |
1908 | ||
1909 | /* update wifi_link_info_ext variable */ | |
1910 | rtw_coex_update_wl_link_info(rtwdev, reason); | |
1911 | ||
1912 | rtw_coex_monitor_bt_enable(rtwdev); | |
1913 | ||
1914 | if (coex->stop_dm) | |
1915 | return; | |
1916 | ||
1917 | if (coex_stat->wl_under_ips) | |
1918 | return; | |
1919 | ||
1920 | if (coex->freeze && !coex_stat->bt_setup_link) | |
1921 | return; | |
1922 | ||
1923 | coex_stat->cnt_wl[COEX_CNT_WL_COEXRUN]++; | |
1924 | coex->freerun = false; | |
1925 | ||
1926 | /* Pure-5G Coex Process */ | |
1927 | if (coex->under_5g) { | |
1928 | coex_stat->wl_coex_mode = COEX_WLINK_5G; | |
1929 | rtw_coex_action_wl_under5g(rtwdev); | |
1930 | goto exit; | |
1931 | } | |
1932 | ||
1933 | coex_stat->wl_coex_mode = COEX_WLINK_2G1PORT; | |
1934 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_FIX2M, false); | |
1935 | if (coex_stat->bt_disabled) { | |
1936 | rtw_coex_action_wl_only(rtwdev); | |
1937 | goto exit; | |
1938 | } | |
1939 | ||
1940 | if (coex_stat->wl_under_lps && !coex_stat->wl_force_lps_ctrl) { | |
1941 | rtw_coex_action_wl_native_lps(rtwdev); | |
1942 | goto exit; | |
1943 | } | |
1944 | ||
1945 | if (coex_stat->bt_whck_test) { | |
1946 | rtw_coex_action_bt_whql_test(rtwdev); | |
1947 | goto exit; | |
1948 | } | |
1949 | ||
1950 | if (coex_stat->bt_setup_link) { | |
1951 | rtw_coex_action_bt_relink(rtwdev); | |
1952 | goto exit; | |
1953 | } | |
1954 | ||
1955 | if (coex_stat->bt_inq_page) { | |
1956 | rtw_coex_action_bt_inquiry(rtwdev); | |
1957 | goto exit; | |
1958 | } | |
1959 | ||
1960 | if ((coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE || | |
1961 | coex_dm->bt_status == COEX_BTSTATUS_CON_IDLE) && | |
1962 | coex_stat->wl_connected) { | |
1963 | rtw_coex_action_bt_idle(rtwdev); | |
1964 | goto exit; | |
1965 | } | |
1966 | ||
1967 | if (coex_stat->wl_linkscan_proc) { | |
1968 | rtw_coex_action_wl_linkscan(rtwdev); | |
1969 | goto exit; | |
1970 | } | |
1971 | ||
1972 | if (coex_stat->wl_connected) | |
1973 | rtw_coex_action_wl_connected(rtwdev); | |
1974 | else | |
1975 | rtw_coex_action_wl_not_connected(rtwdev); | |
1976 | ||
1977 | exit: | |
1978 | rtw_coex_set_gnt_fix(rtwdev); | |
1979 | rtw_coex_limited_wl(rtwdev); | |
1980 | } | |
1981 | ||
1982 | static void rtw_coex_init_coex_var(struct rtw_dev *rtwdev) | |
1983 | { | |
1984 | struct rtw_coex *coex = &rtwdev->coex; | |
1985 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
1986 | struct rtw_coex_dm *coex_dm = &coex->dm; | |
1987 | u8 i; | |
1988 | ||
1989 | memset(coex_dm, 0, sizeof(*coex_dm)); | |
1990 | memset(coex_stat, 0, sizeof(*coex_stat)); | |
1991 | ||
1992 | for (i = 0; i < COEX_CNT_WL_MAX; i++) | |
1993 | coex_stat->cnt_wl[i] = 0; | |
1994 | ||
1995 | for (i = 0; i < COEX_CNT_BT_MAX; i++) | |
1996 | coex_stat->cnt_bt[i] = 0; | |
1997 | ||
1998 | for (i = 0; i < ARRAY_SIZE(coex_dm->bt_rssi_state); i++) | |
1999 | coex_dm->bt_rssi_state[i] = COEX_RSSI_STATE_LOW; | |
2000 | ||
2001 | for (i = 0; i < ARRAY_SIZE(coex_dm->wl_rssi_state); i++) | |
2002 | coex_dm->wl_rssi_state[i] = COEX_RSSI_STATE_LOW; | |
2003 | ||
2004 | coex_stat->wl_coex_mode = COEX_WLINK_MAX; | |
2005 | } | |
2006 | ||
2007 | static void __rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only) | |
2008 | { | |
2009 | struct rtw_coex *coex = &rtwdev->coex; | |
2010 | ||
2011 | rtw_coex_init_coex_var(rtwdev); | |
2012 | rtw_coex_monitor_bt_enable(rtwdev); | |
2013 | rtw_coex_set_rfe_type(rtwdev); | |
2014 | rtw_coex_set_init(rtwdev); | |
2015 | ||
2016 | /* set Tx response = Hi-Pri (ex: Transmitting ACK,BA,CTS) */ | |
2017 | rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_TX_RSP, 1); | |
2018 | ||
2019 | /* set Tx beacon = Hi-Pri */ | |
2020 | rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_TX_BEACON, 1); | |
2021 | ||
2022 | /* set Tx beacon queue = Hi-Pri */ | |
2023 | rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_TX_BEACONQ, 1); | |
2024 | ||
2025 | /* antenna config */ | |
2026 | if (coex->wl_rf_off) { | |
2027 | rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_WOFF); | |
2028 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ALL, false); | |
2029 | coex->stop_dm = true; | |
2030 | } else if (wifi_only) { | |
2031 | rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_WONLY); | |
2032 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_SCAN, | |
2033 | true); | |
2034 | coex->stop_dm = true; | |
2035 | } else { | |
2036 | rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_INIT); | |
2037 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_SCAN, | |
2038 | true); | |
2039 | coex->stop_dm = false; | |
2040 | coex->freeze = true; | |
2041 | } | |
2042 | ||
2043 | /* PTA parameter */ | |
2044 | rtw_coex_table(rtwdev, 0); | |
2045 | rtw_coex_tdma(rtwdev, true, 0); | |
2046 | rtw_coex_query_bt_info(rtwdev); | |
2047 | } | |
2048 | ||
2049 | void rtw_coex_power_on_setting(struct rtw_dev *rtwdev) | |
2050 | { | |
2051 | struct rtw_coex *coex = &rtwdev->coex; | |
2052 | ||
2053 | coex->stop_dm = true; | |
2054 | coex->wl_rf_off = false; | |
2055 | ||
2056 | /* enable BB, we can write 0x948 */ | |
2057 | rtw_write8_set(rtwdev, REG_SYS_FUNC_EN, BIT(0) | BIT(1)); | |
2058 | ||
2059 | rtw_coex_monitor_bt_enable(rtwdev); | |
2060 | rtw_coex_set_rfe_type(rtwdev); | |
2061 | ||
2062 | /* set antenna path to BT */ | |
2063 | rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_POWERON); | |
2064 | ||
2065 | /* red x issue */ | |
2066 | rtw_write8(rtwdev, 0xff1a, 0x0); | |
2067 | } | |
2068 | ||
2069 | void rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only) | |
2070 | { | |
2071 | __rtw_coex_init_hw_config(rtwdev, wifi_only); | |
2072 | } | |
2073 | ||
2074 | void rtw_coex_ips_notify(struct rtw_dev *rtwdev, u8 type) | |
2075 | { | |
2076 | struct rtw_coex *coex = &rtwdev->coex; | |
2077 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
2078 | ||
2079 | if (coex->stop_dm) | |
2080 | return; | |
2081 | ||
2082 | if (type == COEX_IPS_ENTER) { | |
2083 | coex_stat->wl_under_ips = true; | |
2084 | ||
2085 | /* for lps off */ | |
2086 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ALL, false); | |
2087 | ||
2088 | rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_WOFF); | |
2089 | rtw_coex_action_coex_all_off(rtwdev); | |
2090 | } else if (type == COEX_IPS_LEAVE) { | |
2091 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF, true); | |
2092 | ||
2093 | /* run init hw config (exclude wifi only) */ | |
2094 | __rtw_coex_init_hw_config(rtwdev, false); | |
2095 | /* sw all off */ | |
2096 | ||
2097 | coex_stat->wl_under_ips = false; | |
2098 | } | |
2099 | } | |
2100 | ||
2101 | void rtw_coex_lps_notify(struct rtw_dev *rtwdev, u8 type) | |
2102 | { | |
2103 | struct rtw_coex *coex = &rtwdev->coex; | |
2104 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
2105 | ||
2106 | if (coex->stop_dm) | |
2107 | return; | |
2108 | ||
2109 | if (type == COEX_LPS_ENABLE) { | |
2110 | coex_stat->wl_under_lps = true; | |
2111 | ||
2112 | if (coex_stat->wl_force_lps_ctrl) { | |
2113 | /* for ps-tdma */ | |
2114 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true); | |
2115 | } else { | |
2116 | /* for native ps */ | |
2117 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, false); | |
2118 | ||
2119 | rtw_coex_run_coex(rtwdev, COEX_RSN_LPS); | |
2120 | } | |
2121 | } else if (type == COEX_LPS_DISABLE) { | |
2122 | coex_stat->wl_under_lps = false; | |
2123 | ||
2124 | /* for lps off */ | |
2125 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true); | |
2126 | ||
2127 | if (!coex_stat->wl_force_lps_ctrl) | |
2128 | rtw_coex_query_bt_info(rtwdev); | |
2129 | } | |
2130 | } | |
2131 | ||
2132 | void rtw_coex_scan_notify(struct rtw_dev *rtwdev, u8 type) | |
2133 | { | |
2134 | struct rtw_coex *coex = &rtwdev->coex; | |
2135 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
2136 | ||
2137 | if (coex->stop_dm) | |
2138 | return; | |
2139 | ||
2140 | coex->freeze = false; | |
2141 | ||
2142 | if (type != COEX_SCAN_FINISH) | |
2143 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_SCAN | | |
2144 | COEX_SCBD_ONOFF, true); | |
2145 | ||
2146 | if (type == COEX_SCAN_START_5G) { | |
2147 | rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G); | |
2148 | rtw_coex_run_coex(rtwdev, COEX_RSN_5GSCANSTART); | |
2149 | } else if ((type == COEX_SCAN_START_2G) || (type == COEX_SCAN_START)) { | |
2150 | coex_stat->wl_hi_pri_task2 = true; | |
2151 | ||
2152 | /* Force antenna setup for no scan result issue */ | |
2153 | rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G); | |
2154 | rtw_coex_run_coex(rtwdev, COEX_RSN_2GSCANSTART); | |
2155 | } else { | |
2156 | coex_stat->wl_hi_pri_task2 = false; | |
2157 | rtw_coex_run_coex(rtwdev, COEX_RSN_SCANFINISH); | |
2158 | } | |
2159 | } | |
2160 | ||
2161 | void rtw_coex_switchband_notify(struct rtw_dev *rtwdev, u8 type) | |
2162 | { | |
2163 | struct rtw_coex *coex = &rtwdev->coex; | |
2164 | ||
2165 | if (coex->stop_dm) | |
2166 | return; | |
2167 | ||
2168 | if (type == COEX_SWITCH_TO_5G) | |
2169 | rtw_coex_run_coex(rtwdev, COEX_RSN_5GSWITCHBAND); | |
2170 | else if (type == COEX_SWITCH_TO_24G_NOFORSCAN) | |
2171 | rtw_coex_run_coex(rtwdev, COEX_RSN_2GSWITCHBAND); | |
2172 | else | |
2173 | rtw_coex_scan_notify(rtwdev, COEX_SCAN_START_2G); | |
2174 | } | |
2175 | ||
2176 | void rtw_coex_connect_notify(struct rtw_dev *rtwdev, u8 type) | |
2177 | { | |
2178 | struct rtw_coex *coex = &rtwdev->coex; | |
2179 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
2180 | ||
2181 | if (coex->stop_dm) | |
2182 | return; | |
2183 | ||
2184 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_SCAN | | |
2185 | COEX_SCBD_ONOFF, true); | |
2186 | ||
2187 | if (type == COEX_ASSOCIATE_5G_START) { | |
2188 | rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G); | |
2189 | rtw_coex_run_coex(rtwdev, COEX_RSN_5GCONSTART); | |
2190 | } else if (type == COEX_ASSOCIATE_5G_FINISH) { | |
2191 | rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G); | |
2192 | rtw_coex_run_coex(rtwdev, COEX_RSN_5GCONFINISH); | |
2193 | } else if (type == COEX_ASSOCIATE_START) { | |
2194 | coex_stat->wl_hi_pri_task1 = true; | |
2195 | coex_stat->cnt_wl[COEX_CNT_WL_CONNPKT] = 2; | |
2196 | ||
2197 | /* Force antenna setup for no scan result issue */ | |
2198 | rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G); | |
2199 | ||
2200 | rtw_coex_run_coex(rtwdev, COEX_RSN_2GCONSTART); | |
2201 | ||
2202 | /* To keep TDMA case during connect process, | |
2203 | * to avoid changed by Btinfo and runcoexmechanism | |
2204 | */ | |
2205 | coex->freeze = true; | |
2206 | ieee80211_queue_delayed_work(rtwdev->hw, &coex->defreeze_work, | |
2207 | 5 * HZ); | |
2208 | } else { | |
2209 | coex_stat->wl_hi_pri_task1 = false; | |
2210 | coex->freeze = false; | |
2211 | ||
2212 | rtw_coex_run_coex(rtwdev, COEX_RSN_2GCONFINISH); | |
2213 | } | |
2214 | } | |
2215 | ||
2216 | void rtw_coex_media_status_notify(struct rtw_dev *rtwdev, u8 type) | |
2217 | { | |
2218 | struct rtw_coex *coex = &rtwdev->coex; | |
2219 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
2220 | u8 para[6] = {0}; | |
2221 | ||
2222 | if (coex->stop_dm) | |
2223 | return; | |
2224 | ||
2225 | if (type == COEX_MEDIA_CONNECT_5G) { | |
2226 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true); | |
2227 | ||
2228 | rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G); | |
2229 | rtw_coex_run_coex(rtwdev, COEX_RSN_5GMEDIA); | |
2230 | } else if (type == COEX_MEDIA_CONNECT) { | |
2231 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true); | |
2232 | ||
2233 | /* Force antenna setup for no scan result issue */ | |
2234 | rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G); | |
2235 | ||
2236 | /* Set CCK Rx high Pri */ | |
2237 | rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_RX_CCK, 1); | |
2238 | ||
2239 | /* always enable 5ms extend if connect */ | |
2240 | para[0] = COEX_H2C69_WL_LEAKAP; | |
2241 | para[1] = PARA1_H2C69_EN_5MS; /* enable 5ms extend */ | |
2242 | rtw_fw_bt_wifi_control(rtwdev, para[0], ¶[1]); | |
2243 | coex_stat->wl_slot_extend = true; | |
2244 | rtw_coex_run_coex(rtwdev, COEX_RSN_2GMEDIA); | |
2245 | } else { | |
2246 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, false); | |
2247 | ||
2248 | rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_RX_CCK, 0); | |
2249 | ||
2250 | rtw_coex_run_coex(rtwdev, COEX_RSN_MEDIADISCON); | |
2251 | } | |
2252 | ||
2253 | rtw_coex_update_wl_ch_info(rtwdev, type); | |
2254 | } | |
2255 | ||
2256 | void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length) | |
2257 | { | |
2258 | struct rtw_coex *coex = &rtwdev->coex; | |
2259 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
2260 | struct rtw_chip_info *chip = rtwdev->chip; | |
2261 | unsigned long bt_relink_time; | |
2262 | u8 i, rsp_source = 0, type; | |
2263 | ||
2264 | rsp_source = buf[0] & 0xf; | |
2265 | if (rsp_source >= COEX_BTINFO_SRC_MAX) | |
2266 | rsp_source = COEX_BTINFO_SRC_WL_FW; | |
2267 | ||
2268 | if (rsp_source == COEX_BTINFO_SRC_BT_IQK) { | |
2269 | coex_stat->bt_iqk_state = buf[1]; | |
2270 | if (coex_stat->bt_iqk_state == 1) | |
2271 | coex_stat->cnt_bt[COEX_CNT_BT_IQK]++; | |
2272 | else if (coex_stat->bt_iqk_state == 2) | |
2273 | coex_stat->cnt_bt[COEX_CNT_BT_IQKFAIL]++; | |
2274 | ||
2275 | return; | |
2276 | } | |
2277 | ||
2278 | if (rsp_source == COEX_BTINFO_SRC_BT_SCBD) { | |
2279 | rtw_coex_monitor_bt_enable(rtwdev); | |
2280 | if (coex_stat->bt_disabled != coex_stat->bt_disabled_pre) { | |
2281 | coex_stat->bt_disabled_pre = coex_stat->bt_disabled; | |
2282 | rtw_coex_run_coex(rtwdev, COEX_RSN_BTINFO); | |
2283 | } | |
2284 | return; | |
2285 | } | |
2286 | ||
2287 | if (rsp_source == COEX_BTINFO_SRC_BT_RSP || | |
2288 | rsp_source == COEX_BTINFO_SRC_BT_ACT) { | |
2289 | if (coex_stat->bt_disabled) { | |
2290 | coex_stat->bt_disabled = false; | |
2291 | coex_stat->bt_reenable = true; | |
2292 | ieee80211_queue_delayed_work(rtwdev->hw, | |
2293 | &coex->bt_reenable_work, | |
2294 | 15 * HZ); | |
2295 | } | |
2296 | } | |
2297 | ||
2298 | for (i = 0; i < length; i++) { | |
2299 | if (i < COEX_BTINFO_LENGTH_MAX) | |
2300 | coex_stat->bt_info_c2h[rsp_source][i] = buf[i]; | |
2301 | else | |
2302 | break; | |
2303 | } | |
2304 | ||
2305 | if (rsp_source == COEX_BTINFO_SRC_WL_FW) { | |
2306 | rtw_coex_update_bt_link_info(rtwdev); | |
2307 | rtw_coex_run_coex(rtwdev, COEX_RSN_BTINFO); | |
2308 | return; | |
2309 | } | |
2310 | ||
2311 | /* get the same info from bt, skip it */ | |
2312 | if (coex_stat->bt_info_c2h[rsp_source][1] == coex_stat->bt_info_lb2 && | |
2313 | coex_stat->bt_info_c2h[rsp_source][2] == coex_stat->bt_info_lb3 && | |
2314 | coex_stat->bt_info_c2h[rsp_source][3] == coex_stat->bt_info_hb0 && | |
2315 | coex_stat->bt_info_c2h[rsp_source][4] == coex_stat->bt_info_hb1 && | |
2316 | coex_stat->bt_info_c2h[rsp_source][5] == coex_stat->bt_info_hb2 && | |
2317 | coex_stat->bt_info_c2h[rsp_source][6] == coex_stat->bt_info_hb3) | |
2318 | return; | |
2319 | ||
2320 | coex_stat->bt_info_lb2 = coex_stat->bt_info_c2h[rsp_source][1]; | |
2321 | coex_stat->bt_info_lb3 = coex_stat->bt_info_c2h[rsp_source][2]; | |
2322 | coex_stat->bt_info_hb0 = coex_stat->bt_info_c2h[rsp_source][3]; | |
2323 | coex_stat->bt_info_hb1 = coex_stat->bt_info_c2h[rsp_source][4]; | |
2324 | coex_stat->bt_info_hb2 = coex_stat->bt_info_c2h[rsp_source][5]; | |
2325 | coex_stat->bt_info_hb3 = coex_stat->bt_info_c2h[rsp_source][6]; | |
2326 | ||
2327 | /* 0xff means BT is under WHCK test */ | |
2328 | coex_stat->bt_whck_test = (coex_stat->bt_info_lb2 == 0xff); | |
2329 | coex_stat->bt_inq_page = ((coex_stat->bt_info_lb2 & BIT(2)) == BIT(2)); | |
2330 | coex_stat->bt_acl_busy = ((coex_stat->bt_info_lb2 & BIT(3)) == BIT(3)); | |
2331 | coex_stat->cnt_bt[COEX_CNT_BT_RETRY] = coex_stat->bt_info_lb3 & 0xf; | |
2332 | if (coex_stat->cnt_bt[COEX_CNT_BT_RETRY] >= 1) | |
2333 | coex_stat->cnt_bt[COEX_CNT_BT_POPEVENT]++; | |
2334 | ||
2335 | coex_stat->bt_fix_2M = ((coex_stat->bt_info_lb3 & BIT(4)) == BIT(4)); | |
2336 | coex_stat->bt_inq = ((coex_stat->bt_info_lb3 & BIT(5)) == BIT(5)); | |
2337 | if (coex_stat->bt_inq) | |
2338 | coex_stat->cnt_bt[COEX_CNT_BT_INQ]++; | |
2339 | ||
2340 | coex_stat->bt_page = ((coex_stat->bt_info_lb3 & BIT(7)) == BIT(7)); | |
2341 | if (coex_stat->bt_page) { | |
2342 | coex_stat->cnt_bt[COEX_CNT_BT_PAGE]++; | |
2343 | if (coex_stat->wl_linkscan_proc || | |
2344 | coex_stat->wl_hi_pri_task1 || | |
2345 | coex_stat->wl_hi_pri_task2 || coex_stat->wl_gl_busy) | |
2346 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_SCAN, true); | |
2347 | else | |
2348 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_SCAN, false); | |
2349 | } else { | |
2350 | rtw_coex_write_scbd(rtwdev, COEX_SCBD_SCAN, false); | |
2351 | } | |
2352 | ||
2353 | /* unit: % (value-100 to translate to unit: dBm in coex info) */ | |
2354 | if (chip->bt_rssi_type == COEX_BTRSSI_RATIO) { | |
2355 | coex_stat->bt_rssi = coex_stat->bt_info_hb0 * 2 + 10; | |
2356 | } else { /* original unit: dbm -> unit: % -> value-100 in coex info */ | |
2357 | if (coex_stat->bt_info_hb0 <= 127) | |
2358 | coex_stat->bt_rssi = 100; | |
2359 | else if (256 - coex_stat->bt_info_hb0 <= 100) | |
2360 | coex_stat->bt_rssi = 100 - (256 - coex_stat->bt_info_hb0); | |
2361 | else | |
2362 | coex_stat->bt_rssi = 0; | |
2363 | } | |
2364 | ||
2365 | coex_stat->bt_ble_exist = ((coex_stat->bt_info_hb1 & BIT(0)) == BIT(0)); | |
2366 | if (coex_stat->bt_info_hb1 & BIT(1)) | |
2367 | coex_stat->cnt_bt[COEX_CNT_BT_REINIT]++; | |
2368 | ||
2369 | if (coex_stat->bt_info_hb1 & BIT(2)) { | |
2370 | coex_stat->cnt_bt[COEX_CNT_BT_SETUPLINK]++; | |
2371 | coex_stat->bt_setup_link = true; | |
2372 | if (coex_stat->bt_reenable) | |
2373 | bt_relink_time = 6 * HZ; | |
2374 | else | |
2375 | bt_relink_time = 2 * HZ; | |
2376 | ||
2377 | ieee80211_queue_delayed_work(rtwdev->hw, | |
2378 | &coex->bt_relink_work, | |
2379 | bt_relink_time); | |
2380 | } | |
2381 | ||
2382 | if (coex_stat->bt_info_hb1 & BIT(3)) | |
2383 | coex_stat->cnt_bt[COEX_CNT_BT_IGNWLANACT]++; | |
2384 | ||
2385 | coex_stat->bt_ble_voice = ((coex_stat->bt_info_hb1 & BIT(4)) == BIT(4)); | |
2386 | coex_stat->bt_ble_scan_en = ((coex_stat->bt_info_hb1 & BIT(5)) == BIT(5)); | |
2387 | if (coex_stat->bt_info_hb1 & BIT(6)) | |
2388 | coex_stat->cnt_bt[COEX_CNT_BT_ROLESWITCH]++; | |
2389 | ||
2390 | coex_stat->bt_multi_link = ((coex_stat->bt_info_hb1 & BIT(7)) == BIT(7)); | |
2391 | /* resend wifi info to bt, it is reset and lost the info */ | |
2392 | if ((coex_stat->bt_info_hb1 & BIT(1))) { | |
2393 | if (coex_stat->wl_connected) | |
2394 | type = COEX_MEDIA_CONNECT; | |
2395 | else | |
2396 | type = COEX_MEDIA_DISCONNECT; | |
2397 | rtw_coex_update_wl_ch_info(rtwdev, type); | |
2398 | } | |
2399 | ||
2400 | /* if ignore_wlan_act && not set_up_link */ | |
2401 | if ((coex_stat->bt_info_hb1 & BIT(3)) && | |
2402 | (!(coex_stat->bt_info_hb1 & BIT(2)))) | |
2403 | rtw_coex_ignore_wlan_act(rtwdev, false); | |
2404 | ||
2405 | coex_stat->bt_opp_exist = ((coex_stat->bt_info_hb2 & BIT(0)) == BIT(0)); | |
2406 | if (coex_stat->bt_info_hb2 & BIT(1)) | |
2407 | coex_stat->cnt_bt[COEX_CNT_BT_AFHUPDATE]++; | |
2408 | ||
2409 | coex_stat->bt_a2dp_active = (coex_stat->bt_info_hb2 & BIT(2)) == BIT(2); | |
2410 | coex_stat->bt_slave = ((coex_stat->bt_info_hb2 & BIT(3)) == BIT(3)); | |
2411 | coex_stat->bt_hid_slot = (coex_stat->bt_info_hb2 & 0x30) >> 4; | |
2412 | coex_stat->bt_hid_pair_num = (coex_stat->bt_info_hb2 & 0xc0) >> 6; | |
2413 | if (coex_stat->bt_hid_pair_num > 0 && coex_stat->bt_hid_slot >= 2) | |
2414 | coex_stat->bt_418_hid_exist = true; | |
2415 | else if (coex_stat->bt_hid_pair_num == 0) | |
2416 | coex_stat->bt_418_hid_exist = false; | |
2417 | ||
2418 | if ((coex_stat->bt_info_lb2 & 0x49) == 0x49) | |
2419 | coex_stat->bt_a2dp_bitpool = (coex_stat->bt_info_hb3 & 0x7f); | |
2420 | else | |
2421 | coex_stat->bt_a2dp_bitpool = 0; | |
2422 | ||
2423 | coex_stat->bt_a2dp_sink = ((coex_stat->bt_info_hb3 & BIT(7)) == BIT(7)); | |
2424 | ||
2425 | rtw_coex_update_bt_link_info(rtwdev); | |
2426 | rtw_coex_run_coex(rtwdev, COEX_RSN_BTINFO); | |
2427 | } | |
2428 | ||
2429 | void rtw_coex_wl_fwdbginfo_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length) | |
2430 | { | |
2431 | struct rtw_coex *coex = &rtwdev->coex; | |
2432 | struct rtw_coex_stat *coex_stat = &coex->stat; | |
2433 | u8 val; | |
2434 | int i; | |
2435 | ||
2436 | if (WARN(length < 8, "invalid wl info c2h length\n")) | |
2437 | return; | |
2438 | ||
2439 | if (buf[0] != 0x08) | |
2440 | return; | |
2441 | ||
2442 | for (i = 1; i < 8; i++) { | |
2443 | val = coex_stat->wl_fw_dbg_info_pre[i]; | |
2444 | if (buf[i] >= val) | |
2445 | coex_stat->wl_fw_dbg_info[i] = buf[i] - val; | |
2446 | else | |
2447 | coex_stat->wl_fw_dbg_info[i] = val - buf[i]; | |
2448 | ||
2449 | coex_stat->wl_fw_dbg_info_pre[i] = buf[i]; | |
2450 | } | |
2451 | ||
2452 | coex_stat->cnt_wl[COEX_CNT_WL_FW_NOTIFY]++; | |
2453 | rtw_coex_wl_ccklock_action(rtwdev); | |
2454 | rtw_coex_wl_ccklock_detect(rtwdev); | |
2455 | } | |
2456 | ||
4136214f YHC |
2457 | void rtw_coex_wl_status_change_notify(struct rtw_dev *rtwdev) |
2458 | { | |
2459 | struct rtw_coex *coex = &rtwdev->coex; | |
2460 | ||
2461 | if (coex->stop_dm) | |
2462 | return; | |
2463 | ||
2464 | rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS); | |
2465 | } | |
2466 | ||
2467 | void rtw_coex_bt_relink_work(struct work_struct *work) | |
2468 | { | |
2469 | struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, | |
2470 | coex.bt_relink_work.work); | |
2471 | struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat; | |
2472 | ||
2473 | mutex_lock(&rtwdev->mutex); | |
2474 | coex_stat->bt_setup_link = false; | |
2475 | rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS); | |
2476 | mutex_unlock(&rtwdev->mutex); | |
2477 | } | |
2478 | ||
2479 | void rtw_coex_bt_reenable_work(struct work_struct *work) | |
2480 | { | |
2481 | struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, | |
2482 | coex.bt_reenable_work.work); | |
2483 | struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat; | |
2484 | ||
2485 | mutex_lock(&rtwdev->mutex); | |
2486 | coex_stat->bt_reenable = false; | |
2487 | mutex_unlock(&rtwdev->mutex); | |
2488 | } | |
2489 | ||
2490 | void rtw_coex_defreeze_work(struct work_struct *work) | |
2491 | { | |
2492 | struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, | |
2493 | coex.defreeze_work.work); | |
2494 | struct rtw_coex *coex = &rtwdev->coex; | |
2495 | struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat; | |
2496 | ||
2497 | mutex_lock(&rtwdev->mutex); | |
2498 | coex->freeze = false; | |
2499 | coex_stat->wl_hi_pri_task1 = false; | |
2500 | rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS); | |
2501 | mutex_unlock(&rtwdev->mutex); | |
2502 | } |