1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /* Copyright(c) 2019-2020  Realtek Corporation
3  */
4 
5 #include "coex.h"
6 #include "debug.h"
7 #include "fw.h"
8 #include "mac.h"
9 #include "ps.h"
10 #include "reg.h"
11 
12 #define FCXDEF_STEP 50 /* MUST <= FCXMAX_STEP and match with wl fw*/
13 
14 enum btc_fbtc_tdma_template {
15 	CXTD_OFF = 0x0,
16 	CXTD_OFF_B2,
17 	CXTD_OFF_EXT,
18 	CXTD_FIX,
19 	CXTD_PFIX,
20 	CXTD_AUTO,
21 	CXTD_PAUTO,
22 	CXTD_AUTO2,
23 	CXTD_PAUTO2,
24 	CXTD_MAX,
25 };
26 
27 enum btc_fbtc_tdma_type {
28 	CXTDMA_OFF = 0x0,
29 	CXTDMA_FIX = 0x1,
30 	CXTDMA_AUTO = 0x2,
31 	CXTDMA_AUTO2 = 0x3,
32 	CXTDMA_MAX
33 };
34 
35 enum btc_fbtc_tdma_rx_flow_ctrl {
36 	CXFLC_OFF = 0x0,
37 	CXFLC_NULLP = 0x1,
38 	CXFLC_QOSNULL = 0x2,
39 	CXFLC_CTS = 0x3,
40 	CXFLC_MAX
41 };
42 
43 enum btc_fbtc_tdma_wlan_tx_pause {
44 	CXTPS_OFF = 0x0,  /* no wl tx pause*/
45 	CXTPS_ON = 0x1,
46 	CXTPS_MAX
47 };
48 
49 enum btc_mlme_state {
50 	MLME_NO_LINK,
51 	MLME_LINKING,
52 	MLME_LINKED,
53 };
54 
55 #define FCXONESLOT_VER 1
56 struct btc_fbtc_1slot {
57 	u8 fver;
58 	u8 sid; /* slot id */
59 	struct rtw89_btc_fbtc_slot slot;
60 } __packed;
61 
62 static const struct rtw89_btc_fbtc_tdma t_def[] = {
63 	[CXTD_OFF]	= { CXTDMA_OFF,    CXFLC_OFF, CXTPS_OFF, 0, 0, 0, 0, 0},
64 	[CXTD_OFF_B2]	= { CXTDMA_OFF,    CXFLC_OFF, CXTPS_OFF, 0, 0, 1, 0, 0},
65 	[CXTD_OFF_EXT]	= { CXTDMA_OFF,    CXFLC_OFF, CXTPS_OFF, 0, 0, 3, 0, 0},
66 	[CXTD_FIX]	= { CXTDMA_FIX,    CXFLC_OFF, CXTPS_OFF, 0, 0, 0, 0, 0},
67 	[CXTD_PFIX]	= { CXTDMA_FIX,  CXFLC_NULLP,  CXTPS_ON, 0, 5, 0, 0, 0},
68 	[CXTD_AUTO]	= { CXTDMA_AUTO,   CXFLC_OFF, CXTPS_OFF, 0, 0, 0, 0, 0},
69 	[CXTD_PAUTO]	= { CXTDMA_AUTO, CXFLC_NULLP,  CXTPS_ON, 0, 5, 0, 0, 0},
70 	[CXTD_AUTO2]	= {CXTDMA_AUTO2,   CXFLC_OFF, CXTPS_OFF, 0, 0, 0, 0, 0},
71 	[CXTD_PAUTO2]	= {CXTDMA_AUTO2, CXFLC_NULLP,  CXTPS_ON, 0, 5, 0, 0, 0}
72 };
73 
74 #define __DEF_FBTC_SLOT(__dur, __cxtbl, __cxtype) \
75 	{ .dur = cpu_to_le16(__dur), .cxtbl = cpu_to_le32(__cxtbl), \
76 	  .cxtype = cpu_to_le16(__cxtype),}
77 
78 static const struct rtw89_btc_fbtc_slot s_def[] = {
79 	[CXST_OFF]	= __DEF_FBTC_SLOT(100, 0x55555555, SLOT_MIX),
80 	[CXST_B2W]	= __DEF_FBTC_SLOT(5,   0x5a5a5a5a, SLOT_ISO),
81 	[CXST_W1]	= __DEF_FBTC_SLOT(70,  0x5a5a5a5a, SLOT_ISO),
82 	[CXST_W2]	= __DEF_FBTC_SLOT(70,  0x5a5a5aaa, SLOT_ISO),
83 	[CXST_W2B]	= __DEF_FBTC_SLOT(15,  0x5a5a5a5a, SLOT_ISO),
84 	[CXST_B1]	= __DEF_FBTC_SLOT(100, 0x55555555, SLOT_MIX),
85 	[CXST_B2]	= __DEF_FBTC_SLOT(7,   0x6a5a5a5a, SLOT_MIX),
86 	[CXST_B3]	= __DEF_FBTC_SLOT(5,   0x55555555, SLOT_MIX),
87 	[CXST_B4]	= __DEF_FBTC_SLOT(50,  0x55555555, SLOT_MIX),
88 	[CXST_LK]	= __DEF_FBTC_SLOT(20,  0x5a5a5a5a, SLOT_ISO),
89 	[CXST_BLK]	= __DEF_FBTC_SLOT(250, 0x55555555, SLOT_MIX),
90 	[CXST_E2G]	= __DEF_FBTC_SLOT(20,  0x6a5a5a5a, SLOT_MIX),
91 	[CXST_E5G]	= __DEF_FBTC_SLOT(20,  0xffffffff, SLOT_MIX),
92 	[CXST_EBT]	= __DEF_FBTC_SLOT(20,  0x55555555, SLOT_MIX),
93 	[CXST_ENULL]	= __DEF_FBTC_SLOT(7,   0xaaaaaaaa, SLOT_ISO),
94 	[CXST_WLK]	= __DEF_FBTC_SLOT(250, 0x6a5a6a5a, SLOT_MIX),
95 	[CXST_W1FDD]	= __DEF_FBTC_SLOT(35,  0xfafafafa, SLOT_ISO),
96 	[CXST_B1FDD]	= __DEF_FBTC_SLOT(100, 0xffffffff, SLOT_MIX),
97 };
98 
99 static const u32 cxtbl[] = {
100 	0xffffffff, /* 0 */
101 	0xaaaaaaaa, /* 1 */
102 	0x55555555, /* 2 */
103 	0x66555555, /* 3 */
104 	0x66556655, /* 4 */
105 	0x5a5a5a5a, /* 5 */
106 	0x5a5a5aaa, /* 6 */
107 	0xaa5a5a5a, /* 7 */
108 	0x6a5a5a5a, /* 8 */
109 	0x6a5a5aaa, /* 9 */
110 	0x6a5a6a5a, /* 10 */
111 	0x6a5a6aaa, /* 11 */
112 	0x6afa5afa, /* 12 */
113 	0xaaaa5aaa, /* 13 */
114 	0xaaffffaa, /* 14 */
115 	0xaa5555aa, /* 15 */
116 	0xfafafafa, /* 16 */
117 	0xffffddff, /* 17 */
118 	0xdaffdaff, /* 18 */
119 	0xfafadafa  /* 19 */
120 };
121 
122 struct rtw89_btc_btf_tlv {
123 	u8 type;
124 	u8 len;
125 	u8 val[1];
126 } __packed;
127 
128 enum btc_btf_set_report_en {
129 	RPT_EN_TDMA = BIT(0),
130 	RPT_EN_CYCLE = BIT(1),
131 	RPT_EN_MREG = BIT(2),
132 	RPT_EN_BT_VER_INFO = BIT(3),
133 	RPT_EN_BT_SCAN_INFO = BIT(4),
134 	RPT_EN_BT_AFH_MAP = BIT(5),
135 	RPT_EN_BT_DEVICE_INFO = BIT(6),
136 	RPT_EN_WL_ALL = GENMASK(2, 0),
137 	RPT_EN_BT_ALL = GENMASK(6, 3),
138 	RPT_EN_ALL = GENMASK(6, 0),
139 };
140 
141 #define BTF_SET_REPORT_VER 1
142 struct rtw89_btc_btf_set_report {
143 	u8 fver;
144 	__le32 enable;
145 	__le32 para;
146 } __packed;
147 
148 #define BTF_SET_SLOT_TABLE_VER 1
149 struct rtw89_btc_btf_set_slot_table {
150 	u8 fver;
151 	u8 tbl_num;
152 	u8 buf[];
153 } __packed;
154 
155 #define BTF_SET_MON_REG_VER 1
156 struct rtw89_btc_btf_set_mon_reg {
157 	u8 fver;
158 	u8 reg_num;
159 	u8 buf[];
160 } __packed;
161 
162 enum btc_btf_set_cx_policy {
163 	CXPOLICY_TDMA = 0x0,
164 	CXPOLICY_SLOT = 0x1,
165 	CXPOLICY_TYPE = 0x2,
166 	CXPOLICY_MAX,
167 };
168 
169 enum btc_b2w_scoreboard {
170 	BTC_BSCB_ACT = BIT(0),
171 	BTC_BSCB_ON = BIT(1),
172 	BTC_BSCB_WHQL = BIT(2),
173 	BTC_BSCB_BT_S1 = BIT(3),
174 	BTC_BSCB_A2DP_ACT = BIT(4),
175 	BTC_BSCB_RFK_RUN = BIT(5),
176 	BTC_BSCB_RFK_REQ = BIT(6),
177 	BTC_BSCB_LPS = BIT(7),
178 	BTC_BSCB_WLRFK = BIT(11),
179 	BTC_BSCB_BT_HILNA = BIT(13),
180 	BTC_BSCB_BT_CONNECT = BIT(16),
181 	BTC_BSCB_PATCH_CODE = BIT(30),
182 	BTC_BSCB_ALL = GENMASK(30, 0),
183 };
184 
185 enum btc_phymap {
186 	BTC_PHY_0 = BIT(0),
187 	BTC_PHY_1 = BIT(1),
188 	BTC_PHY_ALL = BIT(0) | BIT(1),
189 };
190 
191 enum btc_cx_state_map {
192 	BTC_WIDLE = 0,
193 	BTC_WBUSY_BNOSCAN,
194 	BTC_WBUSY_BSCAN,
195 	BTC_WSCAN_BNOSCAN,
196 	BTC_WSCAN_BSCAN,
197 	BTC_WLINKING
198 };
199 
200 enum btc_ant_phase {
201 	BTC_ANT_WPOWERON = 0,
202 	BTC_ANT_WINIT,
203 	BTC_ANT_WONLY,
204 	BTC_ANT_WOFF,
205 	BTC_ANT_W2G,
206 	BTC_ANT_W5G,
207 	BTC_ANT_W25G,
208 	BTC_ANT_FREERUN,
209 	BTC_ANT_WRFK,
210 	BTC_ANT_BRFK,
211 	BTC_ANT_MAX
212 };
213 
214 enum btc_plt {
215 	BTC_PLT_NONE = 0,
216 	BTC_PLT_LTE_RX = BIT(0),
217 	BTC_PLT_GNT_BT_TX = BIT(1),
218 	BTC_PLT_GNT_BT_RX = BIT(2),
219 	BTC_PLT_GNT_WL = BIT(3),
220 	BTC_PLT_BT = BIT(1) | BIT(2),
221 	BTC_PLT_ALL = 0xf
222 };
223 
224 enum btc_cx_poicy_main_type {
225 	BTC_CXP_OFF = 0,
226 	BTC_CXP_OFFB,
227 	BTC_CXP_OFFE,
228 	BTC_CXP_FIX,
229 	BTC_CXP_PFIX,
230 	BTC_CXP_AUTO,
231 	BTC_CXP_PAUTO,
232 	BTC_CXP_AUTO2,
233 	BTC_CXP_PAUTO2,
234 	BTC_CXP_MANUAL,
235 	BTC_CXP_USERDEF0,
236 	BTC_CXP_MAIN_MAX
237 };
238 
239 enum btc_cx_poicy_type {
240 	/* TDMA off + pri: BT > WL */
241 	BTC_CXP_OFF_BT = (BTC_CXP_OFF << 8) | 0,
242 
243 	/* TDMA off + pri: WL > BT */
244 	BTC_CXP_OFF_WL = (BTC_CXP_OFF << 8) | 1,
245 
246 	/* TDMA off + pri: BT = WL */
247 	BTC_CXP_OFF_EQ0 = (BTC_CXP_OFF << 8) | 2,
248 
249 	/* TDMA off + pri: BT = WL > BT_Lo */
250 	BTC_CXP_OFF_EQ1 = (BTC_CXP_OFF << 8) | 3,
251 
252 	/* TDMA off + pri: WL = BT, BT_Rx > WL_Lo_Tx */
253 	BTC_CXP_OFF_EQ2 = (BTC_CXP_OFF << 8) | 4,
254 
255 	/* TDMA off + pri: WL_Rx = BT, BT_HI > WL_Tx > BT_Lo */
256 	BTC_CXP_OFF_EQ3 = (BTC_CXP_OFF << 8) | 5,
257 
258 	/* TDMA off + pri: BT_Hi > WL > BT_Lo */
259 	BTC_CXP_OFF_BWB0 = (BTC_CXP_OFF << 8) | 6,
260 
261 	/* TDMA off + pri: WL_Hi-Tx > BT_Hi_Rx, BT_Hi > WL > BT_Lo */
262 	BTC_CXP_OFF_BWB1 = (BTC_CXP_OFF << 8) | 7,
263 
264 	/* TDMA off+Bcn-Protect + pri: WL_Hi-Tx > BT_Hi_Rx, BT_Hi > WL > BT_Lo*/
265 	BTC_CXP_OFFB_BWB0 = (BTC_CXP_OFFB << 8) | 0,
266 
267 	/* TDMA off + Ext-Ctrl + pri: default */
268 	BTC_CXP_OFFE_DEF = (BTC_CXP_OFFE << 8) | 0,
269 
270 	/* TDMA off + Ext-Ctrl + pri: E2G-slot block all BT */
271 	BTC_CXP_OFFE_DEF2 = (BTC_CXP_OFFE << 8) | 1,
272 
273 	/* TDMA Fix slot-0: W1:B1 = 30:30 */
274 	BTC_CXP_FIX_TD3030 = (BTC_CXP_FIX << 8) | 0,
275 
276 	/* TDMA Fix slot-1: W1:B1 = 50:50 */
277 	BTC_CXP_FIX_TD5050 = (BTC_CXP_FIX << 8) | 1,
278 
279 	/* TDMA Fix slot-2: W1:B1 = 20:30 */
280 	BTC_CXP_FIX_TD2030 = (BTC_CXP_FIX << 8) | 2,
281 
282 	/* TDMA Fix slot-3: W1:B1 = 40:10 */
283 	BTC_CXP_FIX_TD4010 = (BTC_CXP_FIX << 8) | 3,
284 
285 	/* TDMA Fix slot-4: W1:B1 = 70:10 */
286 	BTC_CXP_FIX_TD7010 = (BTC_CXP_FIX << 8) | 4,
287 
288 	/* TDMA Fix slot-5: W1:B1 = 20:60 */
289 	BTC_CXP_FIX_TD2060 = (BTC_CXP_FIX << 8) | 5,
290 
291 	/* TDMA Fix slot-6: W1:B1 = 30:60 */
292 	BTC_CXP_FIX_TD3060 = (BTC_CXP_FIX << 8) | 6,
293 
294 	/* TDMA Fix slot-7: W1:B1 = 20:80 */
295 	BTC_CXP_FIX_TD2080 = (BTC_CXP_FIX << 8) | 7,
296 
297 	/* TDMA Fix slot-8: W1:B1 = user-define */
298 	BTC_CXP_FIX_TDW1B1 = (BTC_CXP_FIX << 8) | 8,
299 
300 	/* TDMA Fix slot-9: W1:B1 = 40:20 */
301 	BTC_CXP_FIX_TD4020 = (BTC_CXP_FIX << 8) | 9,
302 
303 	/* PS-TDMA Fix slot-0: W1:B1 = 30:30 */
304 	BTC_CXP_PFIX_TD3030 = (BTC_CXP_PFIX << 8) | 0,
305 
306 	/* PS-TDMA Fix slot-1: W1:B1 = 50:50 */
307 	BTC_CXP_PFIX_TD5050 = (BTC_CXP_PFIX << 8) | 1,
308 
309 	/* PS-TDMA Fix slot-2: W1:B1 = 20:30 */
310 	BTC_CXP_PFIX_TD2030 = (BTC_CXP_PFIX << 8) | 2,
311 
312 	/* PS-TDMA Fix slot-3: W1:B1 = 20:60 */
313 	BTC_CXP_PFIX_TD2060 = (BTC_CXP_PFIX << 8) | 3,
314 
315 	/* PS-TDMA Fix slot-4: W1:B1 = 30:70 */
316 	BTC_CXP_PFIX_TD3070 = (BTC_CXP_PFIX << 8) | 4,
317 
318 	/* PS-TDMA Fix slot-5: W1:B1 = 20:80 */
319 	BTC_CXP_PFIX_TD2080 = (BTC_CXP_PFIX << 8) | 5,
320 
321 	/* PS-TDMA Fix slot-6: W1:B1 = user-define */
322 	BTC_CXP_PFIX_TDW1B1 = (BTC_CXP_PFIX << 8) | 6,
323 
324 	/* TDMA Auto slot-0: W1:B1 = 50:200 */
325 	BTC_CXP_AUTO_TD50200 = (BTC_CXP_AUTO << 8) | 0,
326 
327 	/* TDMA Auto slot-1: W1:B1 = 60:200 */
328 	BTC_CXP_AUTO_TD60200 = (BTC_CXP_AUTO << 8) | 1,
329 
330 	/* TDMA Auto slot-2: W1:B1 = 20:200 */
331 	BTC_CXP_AUTO_TD20200 = (BTC_CXP_AUTO << 8) | 2,
332 
333 	/* TDMA Auto slot-3: W1:B1 = user-define */
334 	BTC_CXP_AUTO_TDW1B1 = (BTC_CXP_AUTO << 8) | 3,
335 
336 	/* PS-TDMA Auto slot-0: W1:B1 = 50:200 */
337 	BTC_CXP_PAUTO_TD50200 = (BTC_CXP_PAUTO << 8) | 0,
338 
339 	/* PS-TDMA Auto slot-1: W1:B1 = 60:200 */
340 	BTC_CXP_PAUTO_TD60200 = (BTC_CXP_PAUTO << 8) | 1,
341 
342 	/* PS-TDMA Auto slot-2: W1:B1 = 20:200 */
343 	BTC_CXP_PAUTO_TD20200 = (BTC_CXP_PAUTO << 8) | 2,
344 
345 	/* PS-TDMA Auto slot-3: W1:B1 = user-define */
346 	BTC_CXP_PAUTO_TDW1B1 = (BTC_CXP_PAUTO << 8) | 3,
347 
348 	/* TDMA Auto slot2-0: W1:B4 = 30:50 */
349 	BTC_CXP_AUTO2_TD3050 = (BTC_CXP_AUTO2 << 8) | 0,
350 
351 	/* TDMA Auto slot2-1: W1:B4 = 30:70 */
352 	BTC_CXP_AUTO2_TD3070 = (BTC_CXP_AUTO2 << 8) | 1,
353 
354 	/* TDMA Auto slot2-2: W1:B4 = 50:50 */
355 	BTC_CXP_AUTO2_TD5050 = (BTC_CXP_AUTO2 << 8) | 2,
356 
357 	/* TDMA Auto slot2-3: W1:B4 = 60:60 */
358 	BTC_CXP_AUTO2_TD6060 = (BTC_CXP_AUTO2 << 8) | 3,
359 
360 	/* TDMA Auto slot2-4: W1:B4 = 20:80 */
361 	BTC_CXP_AUTO2_TD2080 = (BTC_CXP_AUTO2 << 8) | 4,
362 
363 	/* TDMA Auto slot2-5: W1:B4 = user-define */
364 	BTC_CXP_AUTO2_TDW1B4 = (BTC_CXP_AUTO2 << 8) | 5,
365 
366 	/* PS-TDMA Auto slot2-0: W1:B4 = 30:50 */
367 	BTC_CXP_PAUTO2_TD3050 = (BTC_CXP_PAUTO2 << 8) | 0,
368 
369 	/* PS-TDMA Auto slot2-1: W1:B4 = 30:70 */
370 	BTC_CXP_PAUTO2_TD3070 = (BTC_CXP_PAUTO2 << 8) | 1,
371 
372 	/* PS-TDMA Auto slot2-2: W1:B4 = 50:50 */
373 	BTC_CXP_PAUTO2_TD5050 = (BTC_CXP_PAUTO2 << 8) | 2,
374 
375 	/* PS-TDMA Auto slot2-3: W1:B4 = 60:60 */
376 	BTC_CXP_PAUTO2_TD6060 = (BTC_CXP_PAUTO2 << 8) | 3,
377 
378 	/* PS-TDMA Auto slot2-4: W1:B4 = 20:80 */
379 	BTC_CXP_PAUTO2_TD2080 = (BTC_CXP_PAUTO2 << 8) | 4,
380 
381 	/* PS-TDMA Auto slot2-5: W1:B4 = user-define */
382 	BTC_CXP_PAUTO2_TDW1B4 = (BTC_CXP_PAUTO2 << 8) | 5,
383 
384 	BTC_CXP_MAX = 0xffff
385 };
386 
387 enum btc_wl_rfk_result {
388 	BTC_WRFK_REJECT = 0,
389 	BTC_WRFK_ALLOW = 1,
390 };
391 
392 enum btc_coex_info_map_en {
393 	BTC_COEX_INFO_CX = BIT(0),
394 	BTC_COEX_INFO_WL = BIT(1),
395 	BTC_COEX_INFO_BT = BIT(2),
396 	BTC_COEX_INFO_DM = BIT(3),
397 	BTC_COEX_INFO_MREG = BIT(4),
398 	BTC_COEX_INFO_SUMMARY = BIT(5),
399 	BTC_COEX_INFO_ALL = GENMASK(7, 0),
400 };
401 
402 #define BTC_CXP_MASK GENMASK(15, 8)
403 
404 enum btc_w2b_scoreboard {
405 	BTC_WSCB_ACTIVE = BIT(0),
406 	BTC_WSCB_ON = BIT(1),
407 	BTC_WSCB_SCAN = BIT(2),
408 	BTC_WSCB_UNDERTEST = BIT(3),
409 	BTC_WSCB_RXGAIN = BIT(4),
410 	BTC_WSCB_WLBUSY = BIT(7),
411 	BTC_WSCB_EXTFEM = BIT(8),
412 	BTC_WSCB_TDMA = BIT(9),
413 	BTC_WSCB_FIX2M = BIT(10),
414 	BTC_WSCB_WLRFK = BIT(11),
415 	BTC_WSCB_BTRFK_GNT = BIT(12), /* not used, use mailbox to inform BT */
416 	BTC_WSCB_BT_HILNA = BIT(13),
417 	BTC_WSCB_BTLOG = BIT(14),
418 	BTC_WSCB_ALL = GENMASK(23, 0),
419 };
420 
421 enum btc_wl_link_mode {
422 	BTC_WLINK_NOLINK = 0x0,
423 	BTC_WLINK_2G_STA,
424 	BTC_WLINK_2G_AP,
425 	BTC_WLINK_2G_GO,
426 	BTC_WLINK_2G_GC,
427 	BTC_WLINK_2G_SCC,
428 	BTC_WLINK_2G_MCC,
429 	BTC_WLINK_25G_MCC,
430 	BTC_WLINK_25G_DBCC,
431 	BTC_WLINK_5G,
432 	BTC_WLINK_2G_NAN,
433 	BTC_WLINK_OTHER,
434 	BTC_WLINK_MAX
435 };
436 
437 enum btc_bt_hid_type {
438 	BTC_HID_218 = BIT(0),
439 	BTC_HID_418 = BIT(1),
440 	BTC_HID_BLE = BIT(2),
441 	BTC_HID_RCU = BIT(3),
442 	BTC_HID_RCU_VOICE = BIT(4),
443 	BTC_HID_OTHER_LEGACY = BIT(5)
444 };
445 
446 enum btc_reset_module {
447 	BTC_RESET_CX = BIT(0),
448 	BTC_RESET_DM = BIT(1),
449 	BTC_RESET_CTRL = BIT(2),
450 	BTC_RESET_CXDM = BIT(0) | BIT(1),
451 	BTC_RESET_BTINFO = BIT(3),
452 	BTC_RESET_MDINFO = BIT(4),
453 	BTC_RESET_ALL =  GENMASK(7, 0),
454 };
455 
456 enum btc_gnt_state {
457 	BTC_GNT_HW	= 0,
458 	BTC_GNT_SW_LO,
459 	BTC_GNT_SW_HI,
460 	BTC_GNT_MAX
461 };
462 
463 enum btc_wl_max_tx_time {
464 	BTC_MAX_TX_TIME_L1 = 500,
465 	BTC_MAX_TX_TIME_L2 = 1000,
466 	BTC_MAX_TX_TIME_L3 = 2000,
467 	BTC_MAX_TX_TIME_DEF = 5280
468 };
469 
470 enum btc_wl_max_tx_retry {
471 	BTC_MAX_TX_RETRY_L1 = 7,
472 	BTC_MAX_TX_RETRY_L2 = 15,
473 	BTC_MAX_TX_RETRY_DEF = 31,
474 };
475 
476 enum btc_reason_and_action {
477 	BTC_RSN_NONE,
478 	BTC_RSN_NTFY_INIT,
479 	BTC_RSN_NTFY_SWBAND,
480 	BTC_RSN_NTFY_WL_STA,
481 	BTC_RSN_NTFY_RADIO_STATE,
482 	BTC_RSN_UPDATE_BT_SCBD,
483 	BTC_RSN_NTFY_WL_RFK,
484 	BTC_RSN_UPDATE_BT_INFO,
485 	BTC_RSN_NTFY_SCAN_START,
486 	BTC_RSN_NTFY_SCAN_FINISH,
487 	BTC_RSN_NTFY_SPECIFIC_PACKET,
488 	BTC_RSN_NTFY_POWEROFF,
489 	BTC_RSN_NTFY_ROLE_INFO,
490 	BTC_RSN_CMD_SET_COEX,
491 	BTC_RSN_ACT1_WORK,
492 	BTC_RSN_BT_DEVINFO_WORK,
493 	BTC_RSN_RFK_CHK_WORK,
494 	BTC_RSN_NUM,
495 	BTC_ACT_NONE = 100,
496 	BTC_ACT_WL_ONLY,
497 	BTC_ACT_WL_5G,
498 	BTC_ACT_WL_OTHER,
499 	BTC_ACT_WL_IDLE,
500 	BTC_ACT_WL_NC,
501 	BTC_ACT_WL_RFK,
502 	BTC_ACT_WL_INIT,
503 	BTC_ACT_WL_OFF,
504 	BTC_ACT_FREERUN,
505 	BTC_ACT_BT_WHQL,
506 	BTC_ACT_BT_RFK,
507 	BTC_ACT_BT_OFF,
508 	BTC_ACT_BT_IDLE,
509 	BTC_ACT_BT_HFP,
510 	BTC_ACT_BT_HID,
511 	BTC_ACT_BT_A2DP,
512 	BTC_ACT_BT_A2DPSINK,
513 	BTC_ACT_BT_PAN,
514 	BTC_ACT_BT_A2DP_HID,
515 	BTC_ACT_BT_A2DP_PAN,
516 	BTC_ACT_BT_PAN_HID,
517 	BTC_ACT_BT_A2DP_PAN_HID,
518 	BTC_ACT_WL_25G_MCC,
519 	BTC_ACT_WL_2G_MCC,
520 	BTC_ACT_WL_2G_SCC,
521 	BTC_ACT_WL_2G_AP,
522 	BTC_ACT_WL_2G_GO,
523 	BTC_ACT_WL_2G_GC,
524 	BTC_ACT_WL_2G_NAN,
525 	BTC_ACT_LAST,
526 	BTC_ACT_NUM = BTC_ACT_LAST - BTC_ACT_NONE,
527 	BTC_ACT_EXT_BIT = BIT(14),
528 	BTC_POLICY_EXT_BIT = BIT(15),
529 };
530 
531 #define BTC_FREERUN_ANTISO_MIN 30
532 #define BTC_TDMA_BTHID_MAX 2
533 #define BTC_BLINK_NOCONNECT 0
534 
535 static void _run_coex(struct rtw89_dev *rtwdev,
536 		      enum btc_reason_and_action reason);
537 static void _write_scbd(struct rtw89_dev *rtwdev, u32 val, bool state);
538 static void _update_bt_scbd(struct rtw89_dev *rtwdev, bool only_update);
539 
540 static void _send_fw_cmd(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func,
541 			 void *param, u16 len)
542 {
543 	rtw89_fw_h2c_raw_with_hdr(rtwdev, h2c_class, h2c_func, param, len,
544 				  false, true);
545 }
546 
547 static void _reset_btc_var(struct rtw89_dev *rtwdev, u8 type)
548 {
549 	struct rtw89_btc *btc = &rtwdev->btc;
550 	struct rtw89_btc_cx *cx = &btc->cx;
551 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
552 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
553 	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
554 	struct rtw89_btc_wl_link_info *wl_linfo = wl->link_info;
555 	u8 i;
556 
557 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s\n", __func__);
558 
559 	if (type & BTC_RESET_CX)
560 		memset(cx, 0, sizeof(*cx));
561 	else if (type & BTC_RESET_BTINFO) /* only for BT enable */
562 		memset(bt, 0, sizeof(*bt));
563 
564 	if (type & BTC_RESET_CTRL) {
565 		memset(&btc->ctrl, 0, sizeof(btc->ctrl));
566 		btc->ctrl.trace_step = FCXDEF_STEP;
567 	}
568 
569 	/* Init Coex variables that are not zero */
570 	if (type & BTC_RESET_DM) {
571 		memset(&btc->dm, 0, sizeof(btc->dm));
572 		memset(bt_linfo->rssi_state, 0, sizeof(bt_linfo->rssi_state));
573 
574 		for (i = 0; i < RTW89_MAX_HW_PORT_NUM; i++)
575 			memset(wl_linfo[i].rssi_state, 0,
576 			       sizeof(wl_linfo[i].rssi_state));
577 
578 		/* set the slot_now table to original */
579 		btc->dm.tdma_now = t_def[CXTD_OFF];
580 		btc->dm.tdma = t_def[CXTD_OFF];
581 		memcpy(&btc->dm.slot_now, s_def, sizeof(btc->dm.slot_now));
582 		memcpy(&btc->dm.slot, s_def, sizeof(btc->dm.slot));
583 
584 		btc->policy_len = 0;
585 		btc->bt_req_len = 0;
586 
587 		btc->dm.coex_info_map = BTC_COEX_INFO_ALL;
588 		btc->dm.wl_tx_limit.tx_time = BTC_MAX_TX_TIME_DEF;
589 		btc->dm.wl_tx_limit.tx_retry = BTC_MAX_TX_RETRY_DEF;
590 	}
591 
592 	if (type & BTC_RESET_MDINFO)
593 		memset(&btc->mdinfo, 0, sizeof(btc->mdinfo));
594 }
595 
596 #define BTC_FWINFO_BUF 1024
597 
598 #define BTC_RPT_HDR_SIZE 3
599 #define BTC_CHK_WLSLOT_DRIFT_MAX 15
600 #define BTC_CHK_HANG_MAX 3
601 
602 static void _chk_btc_err(struct rtw89_dev *rtwdev, u8 type, u32 cnt)
603 {
604 	struct rtw89_btc *btc = &rtwdev->btc;
605 	struct rtw89_btc_cx *cx = &btc->cx;
606 	struct rtw89_btc_dm *dm = &btc->dm;
607 	struct rtw89_btc_bt_info *bt = &cx->bt;
608 
609 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
610 		    "[BTC], %s(): type:%d cnt:%d\n",
611 		    __func__, type, cnt);
612 
613 	switch (type) {
614 	case BTC_DCNT_RPT_FREEZE:
615 		if (dm->cnt_dm[BTC_DCNT_RPT] == cnt && btc->fwinfo.rpt_en_map)
616 			dm->cnt_dm[BTC_DCNT_RPT_FREEZE]++;
617 		else
618 			dm->cnt_dm[BTC_DCNT_RPT_FREEZE] = 0;
619 
620 		if (dm->cnt_dm[BTC_DCNT_RPT_FREEZE] >= BTC_CHK_HANG_MAX)
621 			dm->error.map.wl_fw_hang = true;
622 		else
623 			dm->error.map.wl_fw_hang = false;
624 
625 		dm->cnt_dm[BTC_DCNT_RPT] = cnt;
626 		break;
627 	case BTC_DCNT_CYCLE_FREEZE:
628 		if (dm->cnt_dm[BTC_DCNT_CYCLE] == cnt &&
629 		    (dm->tdma_now.type != CXTDMA_OFF ||
630 		     dm->tdma_now.ext_ctrl == CXECTL_EXT))
631 			dm->cnt_dm[BTC_DCNT_CYCLE_FREEZE]++;
632 		else
633 			dm->cnt_dm[BTC_DCNT_CYCLE_FREEZE] = 0;
634 
635 		if (dm->cnt_dm[BTC_DCNT_CYCLE_FREEZE] >= BTC_CHK_HANG_MAX)
636 			dm->error.map.cycle_hang = true;
637 		else
638 			dm->error.map.cycle_hang = false;
639 
640 		dm->cnt_dm[BTC_DCNT_CYCLE] = cnt;
641 		break;
642 	case BTC_DCNT_W1_FREEZE:
643 		if (dm->cnt_dm[BTC_DCNT_W1] == cnt &&
644 		    dm->tdma_now.type != CXTDMA_OFF)
645 			dm->cnt_dm[BTC_DCNT_W1_FREEZE]++;
646 		else
647 			dm->cnt_dm[BTC_DCNT_W1_FREEZE] = 0;
648 
649 		if (dm->cnt_dm[BTC_DCNT_W1_FREEZE] >= BTC_CHK_HANG_MAX)
650 			dm->error.map.w1_hang = true;
651 		else
652 			dm->error.map.w1_hang = false;
653 
654 		dm->cnt_dm[BTC_DCNT_W1] = cnt;
655 		break;
656 	case BTC_DCNT_B1_FREEZE:
657 		if (dm->cnt_dm[BTC_DCNT_B1] == cnt &&
658 		    dm->tdma_now.type != CXTDMA_OFF)
659 			dm->cnt_dm[BTC_DCNT_B1_FREEZE]++;
660 		else
661 			dm->cnt_dm[BTC_DCNT_B1_FREEZE] = 0;
662 
663 		if (dm->cnt_dm[BTC_DCNT_B1_FREEZE] >= BTC_CHK_HANG_MAX)
664 			dm->error.map.b1_hang = true;
665 		else
666 			dm->error.map.b1_hang = false;
667 
668 		dm->cnt_dm[BTC_DCNT_B1] = cnt;
669 		break;
670 	case BTC_DCNT_TDMA_NONSYNC:
671 		if (cnt != 0) /* if tdma not sync between drv/fw  */
672 			dm->cnt_dm[BTC_DCNT_TDMA_NONSYNC]++;
673 		else
674 			dm->cnt_dm[BTC_DCNT_TDMA_NONSYNC] = 0;
675 
676 		if (dm->cnt_dm[BTC_DCNT_TDMA_NONSYNC] >= BTC_CHK_HANG_MAX)
677 			dm->error.map.tdma_no_sync = true;
678 		else
679 			dm->error.map.tdma_no_sync = false;
680 		break;
681 	case BTC_DCNT_SLOT_NONSYNC:
682 		if (cnt != 0) /* if slot not sync between drv/fw  */
683 			dm->cnt_dm[BTC_DCNT_SLOT_NONSYNC]++;
684 		else
685 			dm->cnt_dm[BTC_DCNT_SLOT_NONSYNC] = 0;
686 
687 		if (dm->cnt_dm[BTC_DCNT_SLOT_NONSYNC] >= BTC_CHK_HANG_MAX)
688 			dm->error.map.tdma_no_sync = true;
689 		else
690 			dm->error.map.tdma_no_sync = false;
691 		break;
692 	case BTC_DCNT_BTCNT_FREEZE:
693 		cnt = cx->cnt_bt[BTC_BCNT_HIPRI_RX] +
694 		      cx->cnt_bt[BTC_BCNT_HIPRI_TX] +
695 		      cx->cnt_bt[BTC_BCNT_LOPRI_RX] +
696 		      cx->cnt_bt[BTC_BCNT_LOPRI_TX];
697 
698 		if (cnt == 0)
699 			dm->cnt_dm[BTC_DCNT_BTCNT_FREEZE]++;
700 		else
701 			dm->cnt_dm[BTC_DCNT_BTCNT_FREEZE] = 0;
702 
703 		if ((dm->cnt_dm[BTC_DCNT_BTCNT_FREEZE] >= BTC_CHK_HANG_MAX &&
704 		     bt->enable.now) || (!dm->cnt_dm[BTC_DCNT_BTCNT_FREEZE] &&
705 		     !bt->enable.now))
706 			_update_bt_scbd(rtwdev, false);
707 		break;
708 	case BTC_DCNT_WL_SLOT_DRIFT:
709 		if (cnt >= BTC_CHK_WLSLOT_DRIFT_MAX)
710 			dm->cnt_dm[BTC_DCNT_WL_SLOT_DRIFT]++;
711 		else
712 			dm->cnt_dm[BTC_DCNT_WL_SLOT_DRIFT] = 0;
713 
714 		if (dm->cnt_dm[BTC_DCNT_WL_SLOT_DRIFT] >= BTC_CHK_HANG_MAX)
715 			dm->error.map.wl_slot_drift = true;
716 		else
717 			dm->error.map.wl_slot_drift = false;
718 		break;
719 	}
720 }
721 
722 static void _update_bt_report(struct rtw89_dev *rtwdev, u8 rpt_type, u8 *pfinfo)
723 {
724 	struct rtw89_btc *btc = &rtwdev->btc;
725 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
726 	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
727 	struct rtw89_btc_bt_a2dp_desc *a2dp = &bt_linfo->a2dp_desc;
728 	struct rtw89_btc_fbtc_btver *pver = NULL;
729 	struct rtw89_btc_fbtc_btscan *pscan = NULL;
730 	struct rtw89_btc_fbtc_btafh *pafh = NULL;
731 	struct rtw89_btc_fbtc_btdevinfo *pdev = NULL;
732 
733 	pver = (struct rtw89_btc_fbtc_btver *)pfinfo;
734 	pscan = (struct rtw89_btc_fbtc_btscan *)pfinfo;
735 	pafh = (struct rtw89_btc_fbtc_btafh *)pfinfo;
736 	pdev = (struct rtw89_btc_fbtc_btdevinfo *)pfinfo;
737 
738 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
739 		    "[BTC], %s(): rpt_type:%d\n",
740 		    __func__, rpt_type);
741 
742 	switch (rpt_type) {
743 	case BTC_RPT_TYPE_BT_VER:
744 		bt->ver_info.fw = le32_to_cpu(pver->fw_ver);
745 		bt->ver_info.fw_coex = le32_get_bits(pver->coex_ver, GENMASK(7, 0));
746 		bt->feature = le32_to_cpu(pver->feature);
747 		break;
748 	case BTC_RPT_TYPE_BT_SCAN:
749 		memcpy(bt->scan_info, pscan->scan, BTC_SCAN_MAX1);
750 		break;
751 	case BTC_RPT_TYPE_BT_AFH:
752 		memcpy(&bt_linfo->afh_map[0], pafh->afh_l, 4);
753 		memcpy(&bt_linfo->afh_map[4], pafh->afh_m, 4);
754 		memcpy(&bt_linfo->afh_map[8], pafh->afh_h, 2);
755 		break;
756 	case BTC_RPT_TYPE_BT_DEVICE:
757 		a2dp->device_name = le32_to_cpu(pdev->dev_name);
758 		a2dp->vendor_id = le16_to_cpu(pdev->vendor_id);
759 		a2dp->flush_time = le32_to_cpu(pdev->flush_time);
760 		break;
761 	default:
762 		break;
763 	}
764 }
765 
766 struct rtw89_btc_fbtc_cysta_cpu {
767 	u8 fver;
768 	u8 rsvd;
769 	u16 cycles;
770 	u16 cycles_a2dp[CXT_FLCTRL_MAX];
771 	u16 a2dpept;
772 	u16 a2dpeptto;
773 	u16 tavg_cycle[CXT_MAX];
774 	u16 tmax_cycle[CXT_MAX];
775 	u16 tmaxdiff_cycle[CXT_MAX];
776 	u16 tavg_a2dp[CXT_FLCTRL_MAX];
777 	u16 tmax_a2dp[CXT_FLCTRL_MAX];
778 	u16 tavg_a2dpept;
779 	u16 tmax_a2dpept;
780 	u16 tavg_lk;
781 	u16 tmax_lk;
782 	u32 slot_cnt[CXST_MAX];
783 	u32 bcn_cnt[CXBCN_MAX];
784 	u32 leakrx_cnt;
785 	u32 collision_cnt;
786 	u32 skip_cnt;
787 	u32 exception;
788 	u32 except_cnt;
789 	u16 tslot_cycle[BTC_CYCLE_SLOT_MAX];
790 };
791 
792 static void rtw89_btc_fbtc_cysta_to_cpu(const struct rtw89_btc_fbtc_cysta *src,
793 					struct rtw89_btc_fbtc_cysta_cpu *dst)
794 {
795 	static_assert(sizeof(*src) == sizeof(*dst));
796 
797 #define __CPY_U8(_x)	({dst->_x = src->_x; })
798 #define __CPY_LE16(_x)	({dst->_x = le16_to_cpu(src->_x); })
799 #define __CPY_LE16S(_x)	({int _i; for (_i = 0; _i < ARRAY_SIZE(dst->_x); _i++) \
800 				   dst->_x[_i] = le16_to_cpu(src->_x[_i]); })
801 #define __CPY_LE32(_x)	({dst->_x = le32_to_cpu(src->_x); })
802 #define __CPY_LE32S(_x)	({int _i; for (_i = 0; _i < ARRAY_SIZE(dst->_x); _i++) \
803 				   dst->_x[_i] = le32_to_cpu(src->_x[_i]); })
804 
805 	__CPY_U8(fver);
806 	__CPY_U8(rsvd);
807 	__CPY_LE16(cycles);
808 	__CPY_LE16S(cycles_a2dp);
809 	__CPY_LE16(a2dpept);
810 	__CPY_LE16(a2dpeptto);
811 	__CPY_LE16S(tavg_cycle);
812 	__CPY_LE16S(tmax_cycle);
813 	__CPY_LE16S(tmaxdiff_cycle);
814 	__CPY_LE16S(tavg_a2dp);
815 	__CPY_LE16S(tmax_a2dp);
816 	__CPY_LE16(tavg_a2dpept);
817 	__CPY_LE16(tmax_a2dpept);
818 	__CPY_LE16(tavg_lk);
819 	__CPY_LE16(tmax_lk);
820 	__CPY_LE32S(slot_cnt);
821 	__CPY_LE32S(bcn_cnt);
822 	__CPY_LE32(leakrx_cnt);
823 	__CPY_LE32(collision_cnt);
824 	__CPY_LE32(skip_cnt);
825 	__CPY_LE32(exception);
826 	__CPY_LE32(except_cnt);
827 	__CPY_LE16S(tslot_cycle);
828 
829 #undef __CPY_U8
830 #undef __CPY_LE16
831 #undef __CPY_LE16S
832 #undef __CPY_LE32
833 #undef __CPY_LE32S
834 }
835 
836 #define BTC_LEAK_AP_TH 10
837 #define BTC_CYSTA_CHK_PERIOD 100
838 
839 struct rtw89_btc_prpt {
840 	u8 type;
841 	__le16 len;
842 	u8 content[];
843 } __packed;
844 
845 static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
846 			   struct rtw89_btc_btf_fwinfo *pfwinfo,
847 			   u8 *prptbuf, u32 index)
848 {
849 	struct rtw89_btc *btc = &rtwdev->btc;
850 	struct rtw89_btc_dm *dm = &btc->dm;
851 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
852 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
853 	struct rtw89_btc_fbtc_rpt_ctrl *prpt = NULL;
854 	struct rtw89_btc_fbtc_cysta *pcysta_le32 = NULL;
855 	struct rtw89_btc_fbtc_cysta_cpu pcysta[1];
856 	struct rtw89_btc_prpt *btc_prpt = NULL;
857 	struct rtw89_btc_fbtc_slot *rtp_slot = NULL;
858 	u8 rpt_type = 0, *rpt_content = NULL, *pfinfo = NULL;
859 	u16 wl_slot_set = 0;
860 	u32 trace_step = btc->ctrl.trace_step, rpt_len = 0, diff_t;
861 	u8 i;
862 
863 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
864 		    "[BTC], %s(): index:%d\n",
865 		    __func__, index);
866 
867 	if (!prptbuf) {
868 		pfwinfo->err[BTFRE_INVALID_INPUT]++;
869 		return 0;
870 	}
871 
872 	btc_prpt = (struct rtw89_btc_prpt *)&prptbuf[index];
873 	rpt_type = btc_prpt->type;
874 	rpt_len = le16_to_cpu(btc_prpt->len);
875 	rpt_content = btc_prpt->content;
876 
877 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
878 		    "[BTC], %s(): rpt_type:%d\n",
879 		    __func__, rpt_type);
880 
881 	switch (rpt_type) {
882 	case BTC_RPT_TYPE_CTRL:
883 		pcinfo = &pfwinfo->rpt_ctrl.cinfo;
884 		pfinfo = (u8 *)(&pfwinfo->rpt_ctrl.finfo);
885 		pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo);
886 		pcinfo->req_fver = BTCRPT_VER;
887 		pcinfo->rx_len = rpt_len;
888 		pcinfo->rx_cnt++;
889 		break;
890 	case BTC_RPT_TYPE_TDMA:
891 		pcinfo = &pfwinfo->rpt_fbtc_tdma.cinfo;
892 		pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_tdma.finfo);
893 		pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo);
894 		pcinfo->req_fver = FCXTDMA_VER;
895 		pcinfo->rx_len = rpt_len;
896 		pcinfo->rx_cnt++;
897 		break;
898 	case BTC_RPT_TYPE_SLOT:
899 		pcinfo = &pfwinfo->rpt_fbtc_slots.cinfo;
900 		pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_slots.finfo);
901 		pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_slots.finfo);
902 		pcinfo->req_fver = FCXSLOTS_VER;
903 		pcinfo->rx_len = rpt_len;
904 		pcinfo->rx_cnt++;
905 		break;
906 	case BTC_RPT_TYPE_CYSTA:
907 		pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
908 		pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_cysta.finfo);
909 		pcysta_le32 = &pfwinfo->rpt_fbtc_cysta.finfo;
910 		rtw89_btc_fbtc_cysta_to_cpu(pcysta_le32, pcysta);
911 		pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo);
912 		pcinfo->req_fver = FCXCYSTA_VER;
913 		pcinfo->rx_len = rpt_len;
914 		pcinfo->rx_cnt++;
915 		break;
916 	case BTC_RPT_TYPE_STEP:
917 		pcinfo = &pfwinfo->rpt_fbtc_step.cinfo;
918 		pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_step.finfo);
919 		pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_step.finfo.step[0]) *
920 				  trace_step + 8;
921 		pcinfo->req_fver = FCXSTEP_VER;
922 		pcinfo->rx_len = rpt_len;
923 		pcinfo->rx_cnt++;
924 		break;
925 	case BTC_RPT_TYPE_NULLSTA:
926 		pcinfo = &pfwinfo->rpt_fbtc_nullsta.cinfo;
927 		pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_nullsta.finfo);
928 		pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo);
929 		pcinfo->req_fver = FCXNULLSTA_VER;
930 		pcinfo->rx_len = rpt_len;
931 		pcinfo->rx_cnt++;
932 		break;
933 	case BTC_RPT_TYPE_MREG:
934 		pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo;
935 		pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_mregval.finfo);
936 		pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_mregval.finfo);
937 		pcinfo->req_fver = FCXMREG_VER;
938 		pcinfo->rx_len = rpt_len;
939 		pcinfo->rx_cnt++;
940 		break;
941 	case BTC_RPT_TYPE_GPIO_DBG:
942 		pcinfo = &pfwinfo->rpt_fbtc_gpio_dbg.cinfo;
943 		pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_gpio_dbg.finfo);
944 		pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_gpio_dbg.finfo);
945 		pcinfo->req_fver = FCXGPIODBG_VER;
946 		pcinfo->rx_len = rpt_len;
947 		pcinfo->rx_cnt++;
948 		break;
949 	case BTC_RPT_TYPE_BT_VER:
950 		pcinfo = &pfwinfo->rpt_fbtc_btver.cinfo;
951 		pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_btver.finfo);
952 		pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btver.finfo);
953 		pcinfo->req_fver = FCX_BTVER_VER;
954 		pcinfo->rx_len = rpt_len;
955 		pcinfo->rx_cnt++;
956 		break;
957 	case BTC_RPT_TYPE_BT_SCAN:
958 		pcinfo = &pfwinfo->rpt_fbtc_btscan.cinfo;
959 		pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_btscan.finfo);
960 		pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btscan.finfo);
961 		pcinfo->req_fver = FCX_BTSCAN_VER;
962 		pcinfo->rx_len = rpt_len;
963 		pcinfo->rx_cnt++;
964 		break;
965 	case BTC_RPT_TYPE_BT_AFH:
966 		pcinfo = &pfwinfo->rpt_fbtc_btafh.cinfo;
967 		pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_btafh.finfo);
968 		pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo);
969 		pcinfo->req_fver = FCX_BTAFH_VER;
970 		pcinfo->rx_len = rpt_len;
971 		pcinfo->rx_cnt++;
972 		break;
973 	case BTC_RPT_TYPE_BT_DEVICE:
974 		pcinfo = &pfwinfo->rpt_fbtc_btdev.cinfo;
975 		pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_btdev.finfo);
976 		pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btdev.finfo);
977 		pcinfo->req_fver = FCX_BTDEVINFO_VER;
978 		pcinfo->rx_len = rpt_len;
979 		pcinfo->rx_cnt++;
980 		break;
981 	default:
982 		pfwinfo->err[BTFRE_UNDEF_TYPE]++;
983 		return 0;
984 	}
985 
986 	if (rpt_len != pcinfo->req_len) {
987 		if (rpt_type < BTC_RPT_TYPE_MAX)
988 			pfwinfo->len_mismch |= (0x1 << rpt_type);
989 		else
990 			pfwinfo->len_mismch |= BIT(31);
991 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
992 			    "[BTC], %s(): %d rpt_len:%d!=req_len:%d\n",
993 			    __func__, rpt_type, rpt_len, pcinfo->req_len);
994 
995 		pcinfo->valid = 0;
996 		return 0;
997 	} else if (!pfinfo || !rpt_content || !pcinfo->req_len) {
998 		pfwinfo->err[BTFRE_EXCEPTION]++;
999 		pcinfo->valid = 0;
1000 		return 0;
1001 	}
1002 
1003 	memcpy(pfinfo, rpt_content, pcinfo->req_len);
1004 	pcinfo->valid = 1;
1005 
1006 	if (rpt_type == BTC_RPT_TYPE_TDMA) {
1007 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
1008 			    "[BTC], %s(): check %d %zu\n", __func__,
1009 			    BTC_DCNT_TDMA_NONSYNC, sizeof(dm->tdma_now));
1010 
1011 		if (memcmp(&dm->tdma_now, &pfwinfo->rpt_fbtc_tdma.finfo,
1012 			   sizeof(dm->tdma_now)) != 0) {
1013 			rtw89_debug(rtwdev, RTW89_DBG_BTC,
1014 				    "[BTC], %s(): %d tdma_now %x %x %x %x %x %x %x %x\n",
1015 				    __func__, BTC_DCNT_TDMA_NONSYNC,
1016 				    dm->tdma_now.type, dm->tdma_now.rxflctrl,
1017 				    dm->tdma_now.txpause, dm->tdma_now.wtgle_n,
1018 				    dm->tdma_now.leak_n, dm->tdma_now.ext_ctrl,
1019 				    dm->tdma_now.rsvd0, dm->tdma_now.rsvd1);
1020 
1021 			rtw89_debug(rtwdev, RTW89_DBG_BTC,
1022 				    "[BTC], %s(): %d rpt_fbtc_tdma %x %x %x %x %x %x %x %x\n",
1023 				    __func__, BTC_DCNT_TDMA_NONSYNC,
1024 				    pfwinfo->rpt_fbtc_tdma.finfo.type,
1025 				    pfwinfo->rpt_fbtc_tdma.finfo.rxflctrl,
1026 				    pfwinfo->rpt_fbtc_tdma.finfo.txpause,
1027 				    pfwinfo->rpt_fbtc_tdma.finfo.wtgle_n,
1028 				    pfwinfo->rpt_fbtc_tdma.finfo.leak_n,
1029 				    pfwinfo->rpt_fbtc_tdma.finfo.ext_ctrl,
1030 				    pfwinfo->rpt_fbtc_tdma.finfo.rsvd0,
1031 				    pfwinfo->rpt_fbtc_tdma.finfo.rsvd1);
1032 		}
1033 
1034 		_chk_btc_err(rtwdev, BTC_DCNT_TDMA_NONSYNC,
1035 			     memcmp(&dm->tdma_now,
1036 				    &pfwinfo->rpt_fbtc_tdma.finfo,
1037 				    sizeof(dm->tdma_now)));
1038 	}
1039 
1040 	if (rpt_type == BTC_RPT_TYPE_SLOT) {
1041 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
1042 			    "[BTC], %s(): check %d %zu\n",
1043 			    __func__, BTC_DCNT_SLOT_NONSYNC,
1044 			    sizeof(dm->slot_now));
1045 
1046 		if (memcmp(dm->slot_now, pfwinfo->rpt_fbtc_slots.finfo.slot,
1047 			   sizeof(dm->slot_now)) != 0) {
1048 			for (i = 0; i < CXST_MAX; i++) {
1049 				rtp_slot =
1050 				&pfwinfo->rpt_fbtc_slots.finfo.slot[i];
1051 				if (memcmp(&dm->slot_now[i], rtp_slot,
1052 					   sizeof(dm->slot_now[i])) != 0) {
1053 					rtw89_debug(rtwdev, RTW89_DBG_BTC,
1054 						    "[BTC], %s(): %d slot_now[%d] dur=0x%04x tbl=%08x type=0x%04x\n",
1055 						    __func__,
1056 						    BTC_DCNT_SLOT_NONSYNC, i,
1057 						    dm->slot_now[i].dur,
1058 						    dm->slot_now[i].cxtbl,
1059 						    dm->slot_now[i].cxtype);
1060 
1061 					rtw89_debug(rtwdev, RTW89_DBG_BTC,
1062 						    "[BTC], %s(): %d rpt_fbtc_slots[%d] dur=0x%04x tbl=%08x type=0x%04x\n",
1063 						    __func__,
1064 						    BTC_DCNT_SLOT_NONSYNC, i,
1065 						    rtp_slot->dur,
1066 						    rtp_slot->cxtbl,
1067 						    rtp_slot->cxtype);
1068 				}
1069 			}
1070 		}
1071 		_chk_btc_err(rtwdev, BTC_DCNT_SLOT_NONSYNC,
1072 			     memcmp(dm->slot_now,
1073 				    pfwinfo->rpt_fbtc_slots.finfo.slot,
1074 				    sizeof(dm->slot_now)));
1075 	}
1076 
1077 	if (rpt_type == BTC_RPT_TYPE_CYSTA &&
1078 	    pcysta->cycles >= BTC_CYSTA_CHK_PERIOD) {
1079 		/* Check Leak-AP */
1080 		if (pcysta->slot_cnt[CXST_LK] != 0 &&
1081 		    pcysta->leakrx_cnt != 0 && dm->tdma_now.rxflctrl) {
1082 			if (pcysta->slot_cnt[CXST_LK] <
1083 			    BTC_LEAK_AP_TH * pcysta->leakrx_cnt)
1084 				dm->leak_ap = 1;
1085 		}
1086 
1087 		/* Check diff time between WL slot and W1/E2G slot */
1088 		if (dm->tdma_now.type == CXTDMA_OFF &&
1089 		    dm->tdma_now.ext_ctrl == CXECTL_EXT)
1090 			wl_slot_set = le16_to_cpu(dm->slot_now[CXST_E2G].dur);
1091 		else
1092 			wl_slot_set = le16_to_cpu(dm->slot_now[CXST_W1].dur);
1093 
1094 		if (pcysta->tavg_cycle[CXT_WL] > wl_slot_set) {
1095 			diff_t = pcysta->tavg_cycle[CXT_WL] - wl_slot_set;
1096 			_chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, diff_t);
1097 		}
1098 	}
1099 
1100 	if (rpt_type == BTC_RPT_TYPE_CTRL) {
1101 		prpt = &pfwinfo->rpt_ctrl.finfo;
1102 		btc->fwinfo.rpt_en_map = prpt->rpt_enable;
1103 		wl->ver_info.fw_coex = prpt->wl_fw_coex_ver;
1104 		wl->ver_info.fw = prpt->wl_fw_ver;
1105 		dm->wl_fw_cx_offload = !!(prpt->wl_fw_cx_offload);
1106 	}
1107 
1108 	if (rpt_type >= BTC_RPT_TYPE_BT_VER &&
1109 	    rpt_type <= BTC_RPT_TYPE_BT_DEVICE)
1110 		_update_bt_report(rtwdev, rpt_type, pfinfo);
1111 
1112 	return (rpt_len + BTC_RPT_HDR_SIZE);
1113 }
1114 
1115 static void _parse_btc_report(struct rtw89_dev *rtwdev,
1116 			      struct rtw89_btc_btf_fwinfo *pfwinfo,
1117 			      u8 *pbuf, u32 buf_len)
1118 {
1119 	struct rtw89_btc_prpt *btc_prpt = NULL;
1120 	u32 index = 0, rpt_len = 0;
1121 
1122 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
1123 		    "[BTC], %s(): buf_len:%d\n",
1124 		    __func__, buf_len);
1125 
1126 	while (pbuf) {
1127 		btc_prpt = (struct rtw89_btc_prpt *)&pbuf[index];
1128 		if (index + 2 >= BTC_FWINFO_BUF)
1129 			break;
1130 		/* At least 3 bytes: type(1) & len(2) */
1131 		rpt_len = le16_to_cpu(btc_prpt->len);
1132 		if ((index + rpt_len + BTC_RPT_HDR_SIZE) > buf_len)
1133 			break;
1134 
1135 		rpt_len = _chk_btc_report(rtwdev, pfwinfo, pbuf, index);
1136 		if (!rpt_len)
1137 			break;
1138 		index += rpt_len;
1139 	}
1140 }
1141 
1142 #define BTC_TLV_HDR_LEN 2
1143 
1144 static void _append_tdma(struct rtw89_dev *rtwdev)
1145 {
1146 	struct rtw89_btc *btc = &rtwdev->btc;
1147 	struct rtw89_btc_dm *dm = &btc->dm;
1148 	struct rtw89_btc_btf_tlv *tlv = NULL;
1149 	struct rtw89_btc_fbtc_tdma *v = NULL;
1150 	u16 len = btc->policy_len;
1151 
1152 	if (!btc->update_policy_force &&
1153 	    !memcmp(&dm->tdma, &dm->tdma_now, sizeof(dm->tdma))) {
1154 		rtw89_debug(rtwdev,
1155 			    RTW89_DBG_BTC, "[BTC], %s(): tdma no change!\n",
1156 			    __func__);
1157 		return;
1158 	}
1159 
1160 	tlv = (struct rtw89_btc_btf_tlv *)&btc->policy[len];
1161 	v = (struct rtw89_btc_fbtc_tdma *)&tlv->val[0];
1162 	tlv->type = CXPOLICY_TDMA;
1163 	tlv->len = sizeof(*v);
1164 
1165 	memcpy(v, &dm->tdma, sizeof(*v));
1166 	btc->policy_len += BTC_TLV_HDR_LEN  + sizeof(*v);
1167 
1168 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
1169 		    "[BTC], %s(): type:%d, rxflctrl=%d, txpause=%d, wtgle_n=%d, leak_n=%d, ext_ctrl=%d\n",
1170 		    __func__, dm->tdma.type, dm->tdma.rxflctrl,
1171 		    dm->tdma.txpause, dm->tdma.wtgle_n, dm->tdma.leak_n,
1172 		    dm->tdma.ext_ctrl);
1173 }
1174 
1175 static void _append_slot(struct rtw89_dev *rtwdev)
1176 {
1177 	struct rtw89_btc *btc = &rtwdev->btc;
1178 	struct rtw89_btc_dm *dm = &btc->dm;
1179 	struct rtw89_btc_btf_tlv *tlv = NULL;
1180 	struct btc_fbtc_1slot *v = NULL;
1181 	u16 len = 0;
1182 	u8 i, cnt = 0;
1183 
1184 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
1185 		    "[BTC], %s(): A:btc->policy_len = %d\n",
1186 		    __func__, btc->policy_len);
1187 
1188 	for (i = 0; i < CXST_MAX; i++) {
1189 		if (!btc->update_policy_force &&
1190 		    !memcmp(&dm->slot[i], &dm->slot_now[i],
1191 			    sizeof(dm->slot[i])))
1192 			continue;
1193 
1194 		len = btc->policy_len;
1195 
1196 		tlv = (struct rtw89_btc_btf_tlv *)&btc->policy[len];
1197 		v = (struct btc_fbtc_1slot *)&tlv->val[0];
1198 		tlv->type = CXPOLICY_SLOT;
1199 		tlv->len = sizeof(*v);
1200 
1201 		v->fver = FCXONESLOT_VER;
1202 		v->sid = i;
1203 		v->slot = dm->slot[i];
1204 
1205 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
1206 			    "[BTC], %s(): slot-%d: dur=%d, table=0x%08x, type=%d\n",
1207 			    __func__, i, dm->slot[i].dur, dm->slot[i].cxtbl,
1208 			    dm->slot[i].cxtype);
1209 		cnt++;
1210 
1211 		btc->policy_len += BTC_TLV_HDR_LEN  + sizeof(*v);
1212 	}
1213 
1214 	if (cnt > 0)
1215 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
1216 			    "[BTC], %s(): slot update (cnt=%d)!!\n",
1217 			    __func__, cnt);
1218 }
1219 
1220 static void rtw89_btc_fw_en_rpt(struct rtw89_dev *rtwdev,
1221 				u32 rpt_map, bool rpt_state)
1222 {
1223 	struct rtw89_btc *btc = &rtwdev->btc;
1224 	struct rtw89_btc_btf_fwinfo *fwinfo = &btc->fwinfo;
1225 	struct rtw89_btc_btf_set_report r = {0};
1226 	u32 val = 0;
1227 
1228 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
1229 		    "[BTC], %s(): rpt_map=%x, rpt_state=%x\n",
1230 		    __func__, rpt_map, rpt_state);
1231 
1232 	if (rpt_state)
1233 		val = fwinfo->rpt_en_map | rpt_map;
1234 	else
1235 		val = fwinfo->rpt_en_map & ~rpt_map;
1236 
1237 	if (val == fwinfo->rpt_en_map)
1238 		return;
1239 
1240 	fwinfo->rpt_en_map = val;
1241 
1242 	r.fver = BTF_SET_REPORT_VER;
1243 	r.enable = cpu_to_le32(val);
1244 	r.para = cpu_to_le32(rpt_state);
1245 
1246 	_send_fw_cmd(rtwdev, BTFC_SET, SET_REPORT_EN, &r, sizeof(r));
1247 }
1248 
1249 static void rtw89_btc_fw_set_slots(struct rtw89_dev *rtwdev, u8 num,
1250 				   struct rtw89_btc_fbtc_slot *s)
1251 {
1252 	struct rtw89_btc_btf_set_slot_table *tbl = NULL;
1253 	u8 *ptr = NULL;
1254 	u16 n = 0;
1255 
1256 	n = sizeof(*s) * num + sizeof(*tbl);
1257 	tbl = kmalloc(n, GFP_KERNEL);
1258 	if (!tbl)
1259 		return;
1260 
1261 	tbl->fver = BTF_SET_SLOT_TABLE_VER;
1262 	tbl->tbl_num = num;
1263 	ptr = &tbl->buf[0];
1264 	memcpy(ptr, s, num * sizeof(*s));
1265 
1266 	_send_fw_cmd(rtwdev, BTFC_SET, SET_SLOT_TABLE, tbl, n);
1267 
1268 	kfree(tbl);
1269 }
1270 
1271 static void btc_fw_set_monreg(struct rtw89_dev *rtwdev)
1272 {
1273 	const struct rtw89_chip_info *chip = rtwdev->chip;
1274 	struct rtw89_btc_btf_set_mon_reg *monreg = NULL;
1275 	u8 n, *ptr = NULL, ulen;
1276 	u16 sz = 0;
1277 
1278 	n = chip->mon_reg_num;
1279 
1280 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
1281 		    "[BTC], %s(): mon_reg_num=%d\n", __func__, n);
1282 	if (n > CXMREG_MAX) {
1283 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
1284 			    "[BTC], %s(): mon reg count %d > %d\n",
1285 			    __func__, n, CXMREG_MAX);
1286 		return;
1287 	}
1288 
1289 	ulen = sizeof(struct rtw89_btc_fbtc_mreg);
1290 	sz = (ulen * n) + sizeof(*monreg);
1291 	monreg = kmalloc(sz, GFP_KERNEL);
1292 	if (!monreg)
1293 		return;
1294 
1295 	monreg->fver = BTF_SET_MON_REG_VER;
1296 	monreg->reg_num = n;
1297 	ptr = &monreg->buf[0];
1298 	memcpy(ptr, chip->mon_reg, n * ulen);
1299 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
1300 		    "[BTC], %s(): sz=%d ulen=%d n=%d\n",
1301 		    __func__, sz, ulen, n);
1302 
1303 	_send_fw_cmd(rtwdev, BTFC_SET, SET_MREG_TABLE, (u8 *)monreg, sz);
1304 	kfree(monreg);
1305 	rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_MREG, 1);
1306 }
1307 
1308 static void _update_dm_step(struct rtw89_dev *rtwdev,
1309 			    enum btc_reason_and_action reason_or_action)
1310 {
1311 	struct rtw89_btc *btc = &rtwdev->btc;
1312 	struct rtw89_btc_dm *dm = &btc->dm;
1313 
1314 	/* use ring-structure to store dm step */
1315 	dm->dm_step.step[dm->dm_step.step_pos] = reason_or_action;
1316 	dm->dm_step.step_pos++;
1317 
1318 	if (dm->dm_step.step_pos >= ARRAY_SIZE(dm->dm_step.step)) {
1319 		dm->dm_step.step_pos = 0;
1320 		dm->dm_step.step_ov = true;
1321 	}
1322 }
1323 
1324 static void _fw_set_policy(struct rtw89_dev *rtwdev, u16 policy_type,
1325 			   enum btc_reason_and_action action)
1326 {
1327 	struct rtw89_btc *btc = &rtwdev->btc;
1328 	struct rtw89_btc_dm *dm = &btc->dm;
1329 
1330 	dm->run_action = action;
1331 
1332 	_update_dm_step(rtwdev, action | BTC_ACT_EXT_BIT);
1333 	_update_dm_step(rtwdev, policy_type | BTC_POLICY_EXT_BIT);
1334 
1335 	btc->policy_len = 0;
1336 	btc->policy_type = policy_type;
1337 
1338 	_append_tdma(rtwdev);
1339 	_append_slot(rtwdev);
1340 
1341 	if (btc->policy_len == 0 || btc->policy_len > RTW89_BTC_POLICY_MAXLEN)
1342 		return;
1343 
1344 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
1345 		    "[BTC], %s(): action = %d -> policy type/len: 0x%04x/%d\n",
1346 		    __func__, action, policy_type, btc->policy_len);
1347 
1348 	if (dm->tdma.rxflctrl == CXFLC_NULLP ||
1349 	    dm->tdma.rxflctrl == CXFLC_QOSNULL)
1350 		btc->lps = 1;
1351 	else
1352 		btc->lps = 0;
1353 
1354 	if (btc->lps == 1)
1355 		rtw89_set_coex_ctrl_lps(rtwdev, btc->lps);
1356 
1357 	_send_fw_cmd(rtwdev, BTFC_SET, SET_CX_POLICY,
1358 		     btc->policy, btc->policy_len);
1359 
1360 	memcpy(&dm->tdma_now, &dm->tdma, sizeof(dm->tdma_now));
1361 	memcpy(&dm->slot_now, &dm->slot, sizeof(dm->slot_now));
1362 
1363 	if (btc->update_policy_force)
1364 		btc->update_policy_force = false;
1365 
1366 	if (btc->lps == 0)
1367 		rtw89_set_coex_ctrl_lps(rtwdev, btc->lps);
1368 }
1369 
1370 static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 type)
1371 {
1372 	switch (type) {
1373 	case CXDRVINFO_INIT:
1374 		rtw89_fw_h2c_cxdrv_init(rtwdev);
1375 		break;
1376 	case CXDRVINFO_ROLE:
1377 		rtw89_fw_h2c_cxdrv_role(rtwdev);
1378 		break;
1379 	case CXDRVINFO_CTRL:
1380 		rtw89_fw_h2c_cxdrv_ctrl(rtwdev);
1381 		break;
1382 	case CXDRVINFO_RFK:
1383 		rtw89_fw_h2c_cxdrv_rfk(rtwdev);
1384 		break;
1385 	default:
1386 		break;
1387 	}
1388 }
1389 
1390 static
1391 void btc_fw_event(struct rtw89_dev *rtwdev, u8 evt_id, void *data, u32 len)
1392 {
1393 	struct rtw89_btc *btc = &rtwdev->btc;
1394 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
1395 
1396 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
1397 		    "[BTC], %s(): evt_id:%d len:%d\n",
1398 		    __func__, evt_id, len);
1399 
1400 	if (!len || !data)
1401 		return;
1402 
1403 	switch (evt_id) {
1404 	case BTF_EVNT_RPT:
1405 		_parse_btc_report(rtwdev, pfwinfo, data, len);
1406 		break;
1407 	default:
1408 		break;
1409 	}
1410 }
1411 
1412 static void _set_gnt_wl(struct rtw89_dev *rtwdev, u8 phy_map, u8 state)
1413 {
1414 	struct rtw89_btc *btc = &rtwdev->btc;
1415 	struct rtw89_btc_dm *dm = &btc->dm;
1416 	struct rtw89_mac_ax_gnt *g = dm->gnt.band;
1417 	u8 i;
1418 
1419 	if (phy_map > BTC_PHY_ALL)
1420 		return;
1421 
1422 	for (i = 0; i < RTW89_PHY_MAX; i++) {
1423 		if (!(phy_map & BIT(i)))
1424 			continue;
1425 
1426 		switch (state) {
1427 		case BTC_GNT_HW:
1428 			g[i].gnt_wl_sw_en = 0;
1429 			g[i].gnt_wl = 0;
1430 			break;
1431 		case BTC_GNT_SW_LO:
1432 			g[i].gnt_wl_sw_en = 1;
1433 			g[i].gnt_wl = 0;
1434 			break;
1435 		case BTC_GNT_SW_HI:
1436 			g[i].gnt_wl_sw_en = 1;
1437 			g[i].gnt_wl = 1;
1438 			break;
1439 		}
1440 	}
1441 
1442 	rtw89_mac_cfg_gnt(rtwdev, &dm->gnt);
1443 }
1444 
1445 #define BTC_TDMA_WLROLE_MAX 2
1446 
1447 static void _set_bt_ignore_wlan_act(struct rtw89_dev *rtwdev, u8 enable)
1448 {
1449 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
1450 		    "[BTC], %s(): set bt %s wlan_act\n", __func__,
1451 		    enable ? "ignore" : "do not ignore");
1452 
1453 	_send_fw_cmd(rtwdev, BTFC_SET, SET_BT_IGNORE_WLAN_ACT, &enable, 1);
1454 }
1455 
1456 #define WL_TX_POWER_NO_BTC_CTRL	GENMASK(31, 0)
1457 #define WL_TX_POWER_ALL_TIME GENMASK(15, 0)
1458 #define WL_TX_POWER_WITH_BT GENMASK(31, 16)
1459 #define WL_TX_POWER_INT_PART GENMASK(8, 2)
1460 #define WL_TX_POWER_FRA_PART GENMASK(1, 0)
1461 #define B_BTC_WL_TX_POWER_SIGN BIT(7)
1462 #define B_TSSI_WL_TX_POWER_SIGN BIT(8)
1463 
1464 static void _set_wl_tx_power(struct rtw89_dev *rtwdev, u32 level)
1465 {
1466 	const struct rtw89_chip_info *chip = rtwdev->chip;
1467 	struct rtw89_btc *btc = &rtwdev->btc;
1468 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
1469 	u32 pwr_val;
1470 
1471 	if (wl->rf_para.tx_pwr_freerun == level)
1472 		return;
1473 
1474 	wl->rf_para.tx_pwr_freerun = level;
1475 	btc->dm.rf_trx_para.wl_tx_power = level;
1476 
1477 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
1478 		    "[BTC], %s(): level = %d\n",
1479 		    __func__, level);
1480 
1481 	if (level == RTW89_BTC_WL_DEF_TX_PWR) {
1482 		pwr_val = WL_TX_POWER_NO_BTC_CTRL;
1483 	} else { /* only apply "force tx power" */
1484 		pwr_val = FIELD_PREP(WL_TX_POWER_INT_PART, level);
1485 		if (pwr_val > RTW89_BTC_WL_DEF_TX_PWR)
1486 			pwr_val = RTW89_BTC_WL_DEF_TX_PWR;
1487 
1488 		if (level & B_BTC_WL_TX_POWER_SIGN)
1489 			pwr_val |= B_TSSI_WL_TX_POWER_SIGN;
1490 		pwr_val |= WL_TX_POWER_WITH_BT;
1491 	}
1492 
1493 	chip->ops->btc_set_wl_txpwr_ctrl(rtwdev, pwr_val);
1494 }
1495 
1496 static void _set_wl_rx_gain(struct rtw89_dev *rtwdev, u32 level)
1497 {
1498 	struct rtw89_btc *btc = &rtwdev->btc;
1499 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
1500 
1501 	if (wl->rf_para.rx_gain_freerun == level)
1502 		return;
1503 
1504 	wl->rf_para.rx_gain_freerun = level;
1505 	btc->dm.rf_trx_para.wl_rx_gain = level;
1506 
1507 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
1508 		    "[BTC], %s(): level = %d\n",
1509 		    __func__, level);
1510 }
1511 
1512 static void _set_bt_tx_power(struct rtw89_dev *rtwdev, u8 level)
1513 {
1514 	struct rtw89_btc *btc = &rtwdev->btc;
1515 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
1516 	u8 buf;
1517 
1518 	if (bt->rf_para.tx_pwr_freerun == level)
1519 		return;
1520 
1521 	bt->rf_para.tx_pwr_freerun = level;
1522 	btc->dm.rf_trx_para.bt_tx_power = level;
1523 
1524 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
1525 		    "[BTC], %s(): level = %d\n",
1526 		    __func__, level);
1527 
1528 	buf = (s8)(-level);
1529 	_send_fw_cmd(rtwdev, BTFC_SET, SET_BT_TX_PWR, &buf, 1);
1530 }
1531 
1532 #define BTC_BT_RX_NORMAL_LVL 7
1533 
1534 static void _set_bt_rx_gain(struct rtw89_dev *rtwdev, u8 level)
1535 {
1536 	struct rtw89_btc *btc = &rtwdev->btc;
1537 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
1538 
1539 	if (bt->rf_para.rx_gain_freerun == level ||
1540 	    level > BTC_BT_RX_NORMAL_LVL)
1541 		return;
1542 
1543 	bt->rf_para.rx_gain_freerun = level;
1544 	btc->dm.rf_trx_para.bt_rx_gain = level;
1545 
1546 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
1547 		    "[BTC], %s(): level = %d\n",
1548 		    __func__, level);
1549 
1550 	if (level == BTC_BT_RX_NORMAL_LVL)
1551 		_write_scbd(rtwdev, BTC_WSCB_RXGAIN, false);
1552 	else
1553 		_write_scbd(rtwdev, BTC_WSCB_RXGAIN, true);
1554 
1555 	_send_fw_cmd(rtwdev, BTFC_SET, SET_BT_LNA_CONSTRAIN, &level, 1);
1556 }
1557 
1558 static void _set_rf_trx_para(struct rtw89_dev *rtwdev)
1559 {
1560 	const struct rtw89_chip_info *chip = rtwdev->chip;
1561 	struct rtw89_btc *btc = &rtwdev->btc;
1562 	struct rtw89_btc_dm *dm = &btc->dm;
1563 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
1564 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
1565 	struct rtw89_btc_rf_trx_para para;
1566 	u32 wl_stb_chg = 0;
1567 	u8 level_id = 0;
1568 
1569 	if (!dm->freerun) {
1570 		dm->trx_para_level = 0;
1571 		chip->ops->btc_bt_aci_imp(rtwdev);
1572 	}
1573 
1574 	level_id = (u8)dm->trx_para_level;
1575 
1576 	if (level_id >= chip->rf_para_dlink_num ||
1577 	    level_id >= chip->rf_para_ulink_num) {
1578 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
1579 			    "[BTC], %s(): invalid level_id: %d\n",
1580 			    __func__, level_id);
1581 		return;
1582 	}
1583 
1584 	if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL))
1585 		para = chip->rf_para_ulink[level_id];
1586 	else
1587 		para = chip->rf_para_dlink[level_id];
1588 
1589 	if (para.wl_tx_power != RTW89_BTC_WL_DEF_TX_PWR)
1590 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
1591 			    "[BTC], %s(): wl_tx_power=%d\n",
1592 			    __func__, para.wl_tx_power);
1593 	_set_wl_tx_power(rtwdev, para.wl_tx_power);
1594 	_set_wl_rx_gain(rtwdev, para.wl_rx_gain);
1595 	_set_bt_tx_power(rtwdev, para.bt_tx_power);
1596 	_set_bt_rx_gain(rtwdev, para.bt_rx_gain);
1597 
1598 	if (bt->enable.now == 0 || wl->status.map.rf_off == 1 ||
1599 	    wl->status.map.lps == 1)
1600 		wl_stb_chg = 0;
1601 	else
1602 		wl_stb_chg = 1;
1603 
1604 	if (wl_stb_chg != dm->wl_stb_chg) {
1605 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
1606 			    "[BTC], %s(): wl_stb_chg=%d\n",
1607 			    __func__, wl_stb_chg);
1608 		dm->wl_stb_chg = wl_stb_chg;
1609 		chip->ops->btc_wl_s1_standby(rtwdev, dm->wl_stb_chg);
1610 	}
1611 }
1612 
1613 static void _update_btc_state_map(struct rtw89_dev *rtwdev)
1614 {
1615 	struct rtw89_btc *btc = &rtwdev->btc;
1616 	struct rtw89_btc_cx *cx = &btc->cx;
1617 	struct rtw89_btc_wl_info *wl = &cx->wl;
1618 	struct rtw89_btc_bt_info *bt = &cx->bt;
1619 	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
1620 
1621 	if (wl->status.map.connecting || wl->status.map._4way ||
1622 	    wl->status.map.roaming) {
1623 		cx->state_map = BTC_WLINKING;
1624 	} else if (wl->status.map.scan) { /* wl scan */
1625 		if (bt_linfo->status.map.inq_pag)
1626 			cx->state_map = BTC_WSCAN_BSCAN;
1627 		else
1628 			cx->state_map = BTC_WSCAN_BNOSCAN;
1629 	} else if (wl->status.map.busy) { /* only busy */
1630 		if (bt_linfo->status.map.inq_pag)
1631 			cx->state_map = BTC_WBUSY_BSCAN;
1632 		else
1633 			cx->state_map = BTC_WBUSY_BNOSCAN;
1634 	} else { /* wl idle */
1635 		cx->state_map = BTC_WIDLE;
1636 	}
1637 }
1638 
1639 static void _set_bt_afh_info(struct rtw89_dev *rtwdev)
1640 {
1641 	const struct rtw89_chip_info *chip = rtwdev->chip;
1642 	struct rtw89_btc *btc = &rtwdev->btc;
1643 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
1644 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
1645 	struct rtw89_btc_bt_link_info *b = &bt->link_info;
1646 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
1647 	u8 en = 0, i, ch = 0, bw = 0;
1648 
1649 	if (btc->ctrl.manual || wl->status.map.scan)
1650 		return;
1651 
1652 	/* TODO if include module->ant.type == BTC_ANT_SHARED */
1653 	if (wl->status.map.rf_off || bt->whql_test ||
1654 	    wl_rinfo->link_mode == BTC_WLINK_NOLINK ||
1655 	    wl_rinfo->link_mode == BTC_WLINK_5G ||
1656 	    wl_rinfo->connect_cnt > BTC_TDMA_WLROLE_MAX) {
1657 		en = false;
1658 	} else if (wl_rinfo->link_mode == BTC_WLINK_2G_MCC ||
1659 		   wl_rinfo->link_mode == BTC_WLINK_2G_SCC) {
1660 		en = true;
1661 		/* get p2p channel */
1662 		for (i = 0; i < RTW89_MAX_HW_PORT_NUM; i++) {
1663 			if (wl_rinfo->active_role[i].role ==
1664 			    RTW89_WIFI_ROLE_P2P_GO ||
1665 			    wl_rinfo->active_role[i].role ==
1666 			    RTW89_WIFI_ROLE_P2P_CLIENT) {
1667 				ch = wl_rinfo->active_role[i].ch;
1668 				bw = wl_rinfo->active_role[i].bw;
1669 				break;
1670 			}
1671 		}
1672 	} else {
1673 		en = true;
1674 		/* get 2g channel  */
1675 		for (i = 0; i < RTW89_MAX_HW_PORT_NUM; i++) {
1676 			if (wl_rinfo->active_role[i].connected &&
1677 			    wl_rinfo->active_role[i].band == RTW89_BAND_2G) {
1678 				ch = wl_rinfo->active_role[i].ch;
1679 				bw = wl_rinfo->active_role[i].bw;
1680 				break;
1681 			}
1682 		}
1683 	}
1684 
1685 	switch (bw) {
1686 	case RTW89_CHANNEL_WIDTH_20:
1687 		bw = 20 + chip->afh_guard_ch * 2;
1688 		break;
1689 	case RTW89_CHANNEL_WIDTH_40:
1690 		bw = 40 + chip->afh_guard_ch * 2;
1691 		break;
1692 	case RTW89_CHANNEL_WIDTH_5:
1693 		bw = 5 + chip->afh_guard_ch * 2;
1694 		break;
1695 	case RTW89_CHANNEL_WIDTH_10:
1696 		bw = 10 + chip->afh_guard_ch * 2;
1697 		break;
1698 	default:
1699 		bw = 0;
1700 		en = false; /* turn off AFH info if BW > 40 */
1701 		break;
1702 	}
1703 
1704 	if (wl->afh_info.en == en &&
1705 	    wl->afh_info.ch == ch &&
1706 	    wl->afh_info.bw == bw &&
1707 	    b->profile_cnt.last == b->profile_cnt.now) {
1708 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
1709 			    "[BTC], %s(): return because no change!\n",
1710 			    __func__);
1711 		return;
1712 	}
1713 
1714 	wl->afh_info.en = en;
1715 	wl->afh_info.ch = ch;
1716 	wl->afh_info.bw = bw;
1717 
1718 	_send_fw_cmd(rtwdev, BTFC_SET, SET_BT_WL_CH_INFO, &wl->afh_info, 3);
1719 
1720 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
1721 		    "[BTC], %s(): en=%d, ch=%d, bw=%d\n",
1722 		    __func__, en, ch, bw);
1723 	btc->cx.cnt_wl[BTC_WCNT_CH_UPDATE]++;
1724 }
1725 
1726 static bool _check_freerun(struct rtw89_dev *rtwdev)
1727 {
1728 	struct rtw89_btc *btc = &rtwdev->btc;
1729 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
1730 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
1731 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
1732 	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
1733 	struct rtw89_btc_bt_hid_desc *hid = &bt_linfo->hid_desc;
1734 
1735 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) {
1736 		btc->dm.trx_para_level = 0;
1737 		return false;
1738 	}
1739 
1740 	/* The below is dedicated antenna case */
1741 	if (wl_rinfo->connect_cnt > BTC_TDMA_WLROLE_MAX) {
1742 		btc->dm.trx_para_level = 5;
1743 		return true;
1744 	}
1745 
1746 	if (bt_linfo->profile_cnt.now == 0) {
1747 		btc->dm.trx_para_level = 5;
1748 		return true;
1749 	}
1750 
1751 	if (hid->pair_cnt > BTC_TDMA_BTHID_MAX) {
1752 		btc->dm.trx_para_level = 5;
1753 		return true;
1754 	}
1755 
1756 	/* TODO get isolation by BT psd */
1757 	if (btc->mdinfo.ant.isolation >= BTC_FREERUN_ANTISO_MIN) {
1758 		btc->dm.trx_para_level = 5;
1759 		return true;
1760 	}
1761 
1762 	if (!wl->status.map.busy) {/* wl idle -> freerun */
1763 		btc->dm.trx_para_level = 5;
1764 		return true;
1765 	} else if (wl->rssi_level > 1) {/* WL rssi < 50% (-60dBm) */
1766 		btc->dm.trx_para_level = 0;
1767 		return false;
1768 	} else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) {
1769 		if (wl->rssi_level == 0 && bt_linfo->rssi > 31) {
1770 			btc->dm.trx_para_level = 6;
1771 			return true;
1772 		} else if (wl->rssi_level == 1 && bt_linfo->rssi > 36) {
1773 			btc->dm.trx_para_level = 7;
1774 			return true;
1775 		}
1776 		btc->dm.trx_para_level = 0;
1777 		return false;
1778 	} else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_DL)) {
1779 		if (bt_linfo->rssi > 28) {
1780 			btc->dm.trx_para_level = 6;
1781 			return true;
1782 		}
1783 	}
1784 
1785 	btc->dm.trx_para_level = 0;
1786 	return false;
1787 }
1788 
1789 #define _tdma_set_flctrl(btc, flc) ({(btc)->dm.tdma.rxflctrl = flc; })
1790 #define _tdma_set_tog(btc, wtg) ({(btc)->dm.tdma.wtgle_n = wtg; })
1791 #define _tdma_set_lek(btc, lek) ({(btc)->dm.tdma.leak_n = lek; })
1792 
1793 #define _slot_set(btc, sid, dura, tbl, type) \
1794 	do { \
1795 		typeof(sid) _sid = (sid); \
1796 		typeof(btc) _btc = (btc); \
1797 		_btc->dm.slot[_sid].dur = cpu_to_le16(dura);\
1798 		_btc->dm.slot[_sid].cxtbl = cpu_to_le32(tbl); \
1799 		_btc->dm.slot[_sid].cxtype = cpu_to_le16(type); \
1800 	} while (0)
1801 
1802 #define _slot_set_dur(btc, sid, dura) (btc)->dm.slot[sid].dur = cpu_to_le16(dura)
1803 #define _slot_set_tbl(btc, sid, tbl) (btc)->dm.slot[sid].cxtbl = cpu_to_le32(tbl)
1804 #define _slot_set_type(btc, sid, type) (btc)->dm.slot[sid].cxtype = cpu_to_le16(type)
1805 
1806 struct btc_btinfo_lb2 {
1807 	u8 connect: 1;
1808 	u8 sco_busy: 1;
1809 	u8 inq_pag: 1;
1810 	u8 acl_busy: 1;
1811 	u8 hfp: 1;
1812 	u8 hid: 1;
1813 	u8 a2dp: 1;
1814 	u8 pan: 1;
1815 };
1816 
1817 struct btc_btinfo_lb3 {
1818 	u8 retry: 4;
1819 	u8 cqddr: 1;
1820 	u8 inq: 1;
1821 	u8 mesh_busy: 1;
1822 	u8 pag: 1;
1823 };
1824 
1825 struct btc_btinfo_hb0 {
1826 	s8 rssi;
1827 };
1828 
1829 struct btc_btinfo_hb1 {
1830 	u8 ble_connect: 1;
1831 	u8 reinit: 1;
1832 	u8 relink: 1;
1833 	u8 igno_wl: 1;
1834 	u8 voice: 1;
1835 	u8 ble_scan: 1;
1836 	u8 role_sw: 1;
1837 	u8 multi_link: 1;
1838 };
1839 
1840 struct btc_btinfo_hb2 {
1841 	u8 pan_active: 1;
1842 	u8 afh_update: 1;
1843 	u8 a2dp_active: 1;
1844 	u8 slave: 1;
1845 	u8 hid_slot: 2;
1846 	u8 hid_cnt: 2;
1847 };
1848 
1849 struct btc_btinfo_hb3 {
1850 	u8 a2dp_bitpool: 6;
1851 	u8 tx_3m: 1;
1852 	u8 a2dp_sink: 1;
1853 };
1854 
1855 union btc_btinfo {
1856 	u8 val;
1857 	struct btc_btinfo_lb2 lb2;
1858 	struct btc_btinfo_lb3 lb3;
1859 	struct btc_btinfo_hb0 hb0;
1860 	struct btc_btinfo_hb1 hb1;
1861 	struct btc_btinfo_hb2 hb2;
1862 	struct btc_btinfo_hb3 hb3;
1863 };
1864 
1865 static void _set_policy(struct rtw89_dev *rtwdev, u16 policy_type,
1866 			enum btc_reason_and_action action)
1867 {
1868 	struct rtw89_btc *btc = &rtwdev->btc;
1869 	struct rtw89_btc_dm *dm = &btc->dm;
1870 	struct rtw89_btc_fbtc_tdma *t = &dm->tdma;
1871 	struct rtw89_btc_fbtc_slot *s = dm->slot;
1872 	u8 type;
1873 	u32 tbl_w1, tbl_b1, tbl_b4;
1874 
1875 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) {
1876 		if (btc->cx.wl.status.map._4way)
1877 			tbl_w1 = cxtbl[1];
1878 		else
1879 			tbl_w1 = cxtbl[8];
1880 		tbl_b1 = cxtbl[3];
1881 		tbl_b4 = cxtbl[3];
1882 	} else {
1883 		tbl_w1 = cxtbl[16];
1884 		tbl_b1 = cxtbl[17];
1885 		tbl_b4 = cxtbl[17];
1886 	}
1887 
1888 	type = (u8)((policy_type & BTC_CXP_MASK) >> 8);
1889 	btc->bt_req_en = false;
1890 
1891 	switch (type) {
1892 	case BTC_CXP_USERDEF0:
1893 		*t = t_def[CXTD_OFF];
1894 		s[CXST_OFF] = s_def[CXST_OFF];
1895 		_slot_set_tbl(btc, CXST_OFF, cxtbl[2]);
1896 		btc->update_policy_force = true;
1897 		break;
1898 	case BTC_CXP_OFF: /* TDMA off */
1899 		_write_scbd(rtwdev, BTC_WSCB_TDMA, false);
1900 		*t = t_def[CXTD_OFF];
1901 		s[CXST_OFF] = s_def[CXST_OFF];
1902 
1903 		switch (policy_type) {
1904 		case BTC_CXP_OFF_BT:
1905 			_slot_set_tbl(btc, CXST_OFF, cxtbl[2]);
1906 			break;
1907 		case BTC_CXP_OFF_WL:
1908 			_slot_set_tbl(btc, CXST_OFF, cxtbl[1]);
1909 			break;
1910 		case BTC_CXP_OFF_EQ0:
1911 			_slot_set_tbl(btc, CXST_OFF, cxtbl[0]);
1912 			break;
1913 		case BTC_CXP_OFF_EQ1:
1914 			_slot_set_tbl(btc, CXST_OFF, cxtbl[16]);
1915 			break;
1916 		case BTC_CXP_OFF_EQ2:
1917 			_slot_set_tbl(btc, CXST_OFF, cxtbl[17]);
1918 			break;
1919 		case BTC_CXP_OFF_EQ3:
1920 			_slot_set_tbl(btc, CXST_OFF, cxtbl[18]);
1921 			break;
1922 		case BTC_CXP_OFF_BWB0:
1923 			_slot_set_tbl(btc, CXST_OFF, cxtbl[5]);
1924 			break;
1925 		case BTC_CXP_OFF_BWB1:
1926 			_slot_set_tbl(btc, CXST_OFF, cxtbl[8]);
1927 			break;
1928 		}
1929 		break;
1930 	case BTC_CXP_OFFB: /* TDMA off + beacon protect */
1931 		_write_scbd(rtwdev, BTC_WSCB_TDMA, false);
1932 		*t = t_def[CXTD_OFF_B2];
1933 		s[CXST_OFF] = s_def[CXST_OFF];
1934 		switch (policy_type) {
1935 		case BTC_CXP_OFFB_BWB0:
1936 			_slot_set_tbl(btc, CXST_OFF, cxtbl[8]);
1937 			break;
1938 		}
1939 		break;
1940 	case BTC_CXP_OFFE: /* TDMA off + beacon protect + Ext_control */
1941 		btc->bt_req_en = true;
1942 		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
1943 		*t = t_def[CXTD_OFF_EXT];
1944 		switch (policy_type) {
1945 		case BTC_CXP_OFFE_DEF:
1946 			s[CXST_E2G] = s_def[CXST_E2G];
1947 			s[CXST_E5G] = s_def[CXST_E5G];
1948 			s[CXST_EBT] = s_def[CXST_EBT];
1949 			s[CXST_ENULL] = s_def[CXST_ENULL];
1950 			break;
1951 		case BTC_CXP_OFFE_DEF2:
1952 			_slot_set(btc, CXST_E2G, 20, cxtbl[1], SLOT_ISO);
1953 			s[CXST_E5G] = s_def[CXST_E5G];
1954 			s[CXST_EBT] = s_def[CXST_EBT];
1955 			s[CXST_ENULL] = s_def[CXST_ENULL];
1956 			break;
1957 		}
1958 		break;
1959 	case BTC_CXP_FIX: /* TDMA Fix-Slot */
1960 		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
1961 		*t = t_def[CXTD_FIX];
1962 		switch (policy_type) {
1963 		case BTC_CXP_FIX_TD3030:
1964 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
1965 			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
1966 			break;
1967 		case BTC_CXP_FIX_TD5050:
1968 			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
1969 			_slot_set(btc, CXST_B1, 50, tbl_b1, SLOT_MIX);
1970 			break;
1971 		case BTC_CXP_FIX_TD2030:
1972 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
1973 			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
1974 			break;
1975 		case BTC_CXP_FIX_TD4010:
1976 			_slot_set(btc, CXST_W1, 40, tbl_w1, SLOT_ISO);
1977 			_slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
1978 			break;
1979 		case BTC_CXP_FIX_TD4020:
1980 			_slot_set(btc, CXST_W1, 40, cxtbl[1], SLOT_MIX);
1981 			_slot_set(btc, CXST_B1, 20, tbl_b1, SLOT_MIX);
1982 			break;
1983 		case BTC_CXP_FIX_TD7010:
1984 			_slot_set(btc, CXST_W1, 70, tbl_w1, SLOT_ISO);
1985 			_slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
1986 			break;
1987 		case BTC_CXP_FIX_TD2060:
1988 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
1989 			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
1990 			break;
1991 		case BTC_CXP_FIX_TD3060:
1992 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
1993 			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
1994 			break;
1995 		case BTC_CXP_FIX_TD2080:
1996 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
1997 			_slot_set(btc, CXST_B1, 80, tbl_b1, SLOT_MIX);
1998 			break;
1999 		case BTC_CXP_FIX_TDW1B1: /* W1:B1 = user-define */
2000 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
2001 				  tbl_w1, SLOT_ISO);
2002 			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
2003 				  tbl_b1, SLOT_MIX);
2004 			break;
2005 		}
2006 		break;
2007 	case BTC_CXP_PFIX: /* PS-TDMA Fix-Slot */
2008 		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
2009 		*t = t_def[CXTD_PFIX];
2010 		if (btc->cx.wl.role_info.role_map.role.ap)
2011 			_tdma_set_flctrl(btc, CXFLC_QOSNULL);
2012 
2013 		switch (policy_type) {
2014 		case BTC_CXP_PFIX_TD3030:
2015 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
2016 			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
2017 			break;
2018 		case BTC_CXP_PFIX_TD5050:
2019 			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
2020 			_slot_set(btc, CXST_B1, 50, tbl_b1, SLOT_MIX);
2021 			break;
2022 		case BTC_CXP_PFIX_TD2030:
2023 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
2024 			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
2025 			break;
2026 		case BTC_CXP_PFIX_TD2060:
2027 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
2028 			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
2029 			break;
2030 		case BTC_CXP_PFIX_TD3070:
2031 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
2032 			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
2033 			break;
2034 		case BTC_CXP_PFIX_TD2080:
2035 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
2036 			_slot_set(btc, CXST_B1, 80, tbl_b1, SLOT_MIX);
2037 			break;
2038 		}
2039 		break;
2040 	case BTC_CXP_AUTO: /* TDMA Auto-Slot */
2041 		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
2042 		*t = t_def[CXTD_AUTO];
2043 		switch (policy_type) {
2044 		case BTC_CXP_AUTO_TD50200:
2045 			_slot_set(btc, CXST_W1,  50, tbl_w1, SLOT_ISO);
2046 			_slot_set(btc, CXST_B1, 200, tbl_b1, SLOT_MIX);
2047 			break;
2048 		case BTC_CXP_AUTO_TD60200:
2049 			_slot_set(btc, CXST_W1,  60, tbl_w1, SLOT_ISO);
2050 			_slot_set(btc, CXST_B1, 200, tbl_b1, SLOT_MIX);
2051 			break;
2052 		case BTC_CXP_AUTO_TD20200:
2053 			_slot_set(btc, CXST_W1,  20, tbl_w1, SLOT_ISO);
2054 			_slot_set(btc, CXST_B1, 200, tbl_b1, SLOT_MIX);
2055 			break;
2056 		case BTC_CXP_AUTO_TDW1B1: /* W1:B1 = user-define */
2057 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
2058 				  tbl_w1, SLOT_ISO);
2059 			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
2060 				  tbl_b1, SLOT_MIX);
2061 			break;
2062 		}
2063 		break;
2064 	case BTC_CXP_PAUTO: /* PS-TDMA Auto-Slot */
2065 		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
2066 		*t = t_def[CXTD_PAUTO];
2067 		switch (policy_type) {
2068 		case BTC_CXP_PAUTO_TD50200:
2069 			_slot_set(btc, CXST_W1,  50, tbl_w1, SLOT_ISO);
2070 			_slot_set(btc, CXST_B1, 200, tbl_b1, SLOT_MIX);
2071 			break;
2072 		case BTC_CXP_PAUTO_TD60200:
2073 			_slot_set(btc, CXST_W1,  60, tbl_w1, SLOT_ISO);
2074 			_slot_set(btc, CXST_B1, 200, tbl_b1, SLOT_MIX);
2075 			break;
2076 		case BTC_CXP_PAUTO_TD20200:
2077 			_slot_set(btc, CXST_W1,  20, tbl_w1, SLOT_ISO);
2078 			_slot_set(btc, CXST_B1, 200, tbl_b1, SLOT_MIX);
2079 			break;
2080 		case BTC_CXP_PAUTO_TDW1B1:
2081 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
2082 				  tbl_w1, SLOT_ISO);
2083 			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
2084 				  tbl_b1, SLOT_MIX);
2085 			break;
2086 		}
2087 		break;
2088 	case BTC_CXP_AUTO2: /* TDMA Auto-Slot2 */
2089 		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
2090 		*t = t_def[CXTD_AUTO2];
2091 		switch (policy_type) {
2092 		case BTC_CXP_AUTO2_TD3050:
2093 			_slot_set(btc, CXST_W1,  30, tbl_w1, SLOT_ISO);
2094 			_slot_set(btc, CXST_B1, 200, tbl_b1, SLOT_MIX);
2095 			_slot_set(btc, CXST_B4,  50, tbl_b4, SLOT_MIX);
2096 			break;
2097 		case BTC_CXP_AUTO2_TD3070:
2098 			_slot_set(btc, CXST_W1,  30, tbl_w1, SLOT_ISO);
2099 			_slot_set(btc, CXST_B1, 200, tbl_b1, SLOT_MIX);
2100 			_slot_set(btc, CXST_B4,  70, tbl_b4, SLOT_MIX);
2101 			break;
2102 		case BTC_CXP_AUTO2_TD5050:
2103 			_slot_set(btc, CXST_W1,  50, tbl_w1, SLOT_ISO);
2104 			_slot_set(btc, CXST_B1, 200, tbl_b1, SLOT_MIX);
2105 			_slot_set(btc, CXST_B4,  50, tbl_b4, SLOT_MIX);
2106 			break;
2107 		case BTC_CXP_AUTO2_TD6060:
2108 			_slot_set(btc, CXST_W1,  60, tbl_w1, SLOT_ISO);
2109 			_slot_set(btc, CXST_B1, 200, tbl_b1, SLOT_MIX);
2110 			_slot_set(btc, CXST_B4,  60, tbl_b4, SLOT_MIX);
2111 			break;
2112 		case BTC_CXP_AUTO2_TD2080:
2113 			_slot_set(btc, CXST_W1,  20, tbl_w1, SLOT_ISO);
2114 			_slot_set(btc, CXST_B1, 200, tbl_b1, SLOT_MIX);
2115 			_slot_set(btc, CXST_B4,  80, tbl_b4, SLOT_MIX);
2116 			break;
2117 		case BTC_CXP_AUTO2_TDW1B4: /* W1:B1 = user-define */
2118 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
2119 				  tbl_w1, SLOT_ISO);
2120 			_slot_set(btc, CXST_B4, dm->slot_dur[CXST_B4],
2121 				  tbl_b4, SLOT_MIX);
2122 			break;
2123 		}
2124 		break;
2125 	case BTC_CXP_PAUTO2: /* PS-TDMA Auto-Slot2 */
2126 		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
2127 		*t = t_def[CXTD_PAUTO2];
2128 		switch (policy_type) {
2129 		case BTC_CXP_PAUTO2_TD3050:
2130 			_slot_set(btc, CXST_W1,  30, tbl_w1, SLOT_ISO);
2131 			_slot_set(btc, CXST_B1, 200, tbl_b1, SLOT_MIX);
2132 			_slot_set(btc, CXST_B4,  50, tbl_b4, SLOT_MIX);
2133 			break;
2134 		case BTC_CXP_PAUTO2_TD3070:
2135 			_slot_set(btc, CXST_W1,  30, tbl_w1, SLOT_ISO);
2136 			_slot_set(btc, CXST_B1, 200, tbl_b1, SLOT_MIX);
2137 			_slot_set(btc, CXST_B4,  70, tbl_b4, SLOT_MIX);
2138 			break;
2139 		case BTC_CXP_PAUTO2_TD5050:
2140 			_slot_set(btc, CXST_W1,  50, tbl_w1, SLOT_ISO);
2141 			_slot_set(btc, CXST_B1, 200, tbl_b1, SLOT_MIX);
2142 			_slot_set(btc, CXST_B4,  50, tbl_b4, SLOT_MIX);
2143 			break;
2144 		case BTC_CXP_PAUTO2_TD6060:
2145 			_slot_set(btc, CXST_W1,  60, tbl_w1, SLOT_ISO);
2146 			_slot_set(btc, CXST_B1, 200, tbl_b1, SLOT_MIX);
2147 			_slot_set(btc, CXST_B4,  60, tbl_b4, SLOT_MIX);
2148 			break;
2149 		case BTC_CXP_PAUTO2_TD2080:
2150 			_slot_set(btc, CXST_W1,  20, tbl_w1, SLOT_ISO);
2151 			_slot_set(btc, CXST_B1, 200, tbl_b1, SLOT_MIX);
2152 			_slot_set(btc, CXST_B4,  80, tbl_b4, SLOT_MIX);
2153 			break;
2154 		case BTC_CXP_PAUTO2_TDW1B4: /* W1:B1 = user-define */
2155 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
2156 				  tbl_w1, SLOT_ISO);
2157 			_slot_set(btc, CXST_B4, dm->slot_dur[CXST_B4],
2158 				  tbl_b4, SLOT_MIX);
2159 			break;
2160 		}
2161 		break;
2162 	}
2163 
2164 	_fw_set_policy(rtwdev, policy_type, action);
2165 }
2166 
2167 static void _set_gnt_bt(struct rtw89_dev *rtwdev, u8 phy_map, u8 state)
2168 {
2169 	struct rtw89_btc *btc = &rtwdev->btc;
2170 	struct rtw89_btc_dm *dm = &btc->dm;
2171 	struct rtw89_mac_ax_gnt *g = dm->gnt.band;
2172 	u8 i;
2173 
2174 	if (phy_map > BTC_PHY_ALL)
2175 		return;
2176 
2177 	for (i = 0; i < RTW89_PHY_MAX; i++) {
2178 		if (!(phy_map & BIT(i)))
2179 			continue;
2180 
2181 		switch (state) {
2182 		case BTC_GNT_HW:
2183 			g[i].gnt_bt_sw_en = 0;
2184 			g[i].gnt_bt = 0;
2185 			break;
2186 		case BTC_GNT_SW_LO:
2187 			g[i].gnt_bt_sw_en = 1;
2188 			g[i].gnt_bt = 0;
2189 			break;
2190 		case BTC_GNT_SW_HI:
2191 			g[i].gnt_bt_sw_en = 1;
2192 			g[i].gnt_bt = 1;
2193 			break;
2194 		}
2195 	}
2196 
2197 	rtw89_mac_cfg_gnt(rtwdev, &dm->gnt);
2198 }
2199 
2200 static void _set_bt_plut(struct rtw89_dev *rtwdev, u8 phy_map,
2201 			 u8 tx_val, u8 rx_val)
2202 {
2203 	struct rtw89_mac_ax_plt plt;
2204 
2205 	plt.band = RTW89_MAC_0;
2206 	plt.tx = tx_val;
2207 	plt.rx = rx_val;
2208 
2209 	if (phy_map & BTC_PHY_0)
2210 		rtw89_mac_cfg_plt(rtwdev, &plt);
2211 
2212 	if (!rtwdev->dbcc_en)
2213 		return;
2214 
2215 	plt.band = RTW89_MAC_1;
2216 	if (phy_map & BTC_PHY_1)
2217 		rtw89_mac_cfg_plt(rtwdev, &plt);
2218 }
2219 
2220 static void _set_ant(struct rtw89_dev *rtwdev, bool force_exec,
2221 		     u8 phy_map, u8 type)
2222 {
2223 	struct rtw89_btc *btc = &rtwdev->btc;
2224 	struct rtw89_btc_dm *dm = &btc->dm;
2225 	struct rtw89_btc_cx *cx = &btc->cx;
2226 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
2227 	struct rtw89_btc_bt_info *bt = &cx->bt;
2228 	struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
2229 	u8 gnt_wl_ctrl, gnt_bt_ctrl, plt_ctrl, i, b2g = 0;
2230 	u32 ant_path_type;
2231 
2232 	ant_path_type = ((phy_map << 8) + type);
2233 
2234 	if (btc->dm.run_reason == BTC_RSN_NTFY_POWEROFF ||
2235 	    btc->dm.run_reason == BTC_RSN_NTFY_RADIO_STATE ||
2236 	    btc->dm.run_reason == BTC_RSN_CMD_SET_COEX)
2237 		force_exec = FC_EXEC;
2238 
2239 	if (!force_exec && ant_path_type == dm->set_ant_path) {
2240 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
2241 			    "[BTC], %s(): return by no change!!\n",
2242 			     __func__);
2243 		return;
2244 	} else if (bt->rfk_info.map.run) {
2245 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
2246 			    "[BTC], %s(): return by bt rfk!!\n", __func__);
2247 		return;
2248 	} else if (btc->dm.run_reason != BTC_RSN_NTFY_WL_RFK &&
2249 		   wl->rfk_info.state != BTC_WRFK_STOP) {
2250 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
2251 			    "[BTC], %s(): return by wl rfk!!\n", __func__);
2252 		return;
2253 	}
2254 
2255 	dm->set_ant_path = ant_path_type;
2256 
2257 	rtw89_debug(rtwdev,
2258 		    RTW89_DBG_BTC,
2259 		    "[BTC], %s(): path=0x%x, set_type=0x%x\n",
2260 		    __func__, phy_map, dm->set_ant_path & 0xff);
2261 
2262 	switch (type) {
2263 	case BTC_ANT_WPOWERON:
2264 		rtw89_mac_cfg_ctrl_path(rtwdev, false);
2265 		break;
2266 	case BTC_ANT_WINIT:
2267 		if (bt->enable.now) {
2268 			_set_gnt_wl(rtwdev, phy_map, BTC_GNT_SW_LO);
2269 			_set_gnt_bt(rtwdev, phy_map, BTC_GNT_SW_HI);
2270 		} else {
2271 			_set_gnt_wl(rtwdev, phy_map, BTC_GNT_SW_HI);
2272 			_set_gnt_bt(rtwdev, phy_map, BTC_GNT_SW_LO);
2273 		}
2274 		rtw89_mac_cfg_ctrl_path(rtwdev, true);
2275 		_set_bt_plut(rtwdev, BTC_PHY_ALL, BTC_PLT_BT, BTC_PLT_BT);
2276 		break;
2277 	case BTC_ANT_WONLY:
2278 		_set_gnt_wl(rtwdev, phy_map, BTC_GNT_SW_HI);
2279 		_set_gnt_bt(rtwdev, phy_map, BTC_GNT_SW_LO);
2280 		rtw89_mac_cfg_ctrl_path(rtwdev, true);
2281 		_set_bt_plut(rtwdev, BTC_PHY_ALL, BTC_PLT_NONE, BTC_PLT_NONE);
2282 		break;
2283 	case BTC_ANT_WOFF:
2284 		rtw89_mac_cfg_ctrl_path(rtwdev, false);
2285 		_set_bt_plut(rtwdev, BTC_PHY_ALL, BTC_PLT_NONE, BTC_PLT_NONE);
2286 		break;
2287 	case BTC_ANT_W2G:
2288 		rtw89_mac_cfg_ctrl_path(rtwdev, true);
2289 		if (rtwdev->dbcc_en) {
2290 			for (i = 0; i < RTW89_PHY_MAX; i++) {
2291 				b2g = (wl_dinfo->real_band[i] == RTW89_BAND_2G);
2292 
2293 				gnt_wl_ctrl = b2g ? BTC_GNT_HW : BTC_GNT_SW_HI;
2294 				_set_gnt_wl(rtwdev, BIT(i), gnt_wl_ctrl);
2295 
2296 				gnt_bt_ctrl = b2g ? BTC_GNT_HW : BTC_GNT_SW_HI;
2297 				/* BT should control by GNT_BT if WL_2G at S0 */
2298 				if (i == 1 &&
2299 				    wl_dinfo->real_band[0] == RTW89_BAND_2G &&
2300 				    wl_dinfo->real_band[1] == RTW89_BAND_5G)
2301 					gnt_bt_ctrl = BTC_GNT_HW;
2302 				_set_gnt_bt(rtwdev, BIT(i), gnt_bt_ctrl);
2303 
2304 				plt_ctrl = b2g ? BTC_PLT_BT : BTC_PLT_NONE;
2305 				_set_bt_plut(rtwdev, BIT(i),
2306 					     plt_ctrl, plt_ctrl);
2307 			}
2308 		} else {
2309 			_set_gnt_wl(rtwdev, phy_map, BTC_GNT_HW);
2310 			_set_gnt_bt(rtwdev, phy_map, BTC_GNT_HW);
2311 			_set_bt_plut(rtwdev, BTC_PHY_ALL,
2312 				     BTC_PLT_BT, BTC_PLT_BT);
2313 		}
2314 		break;
2315 	case BTC_ANT_W5G:
2316 		rtw89_mac_cfg_ctrl_path(rtwdev, true);
2317 		_set_gnt_wl(rtwdev, phy_map, BTC_GNT_SW_HI);
2318 		_set_gnt_bt(rtwdev, phy_map, BTC_GNT_HW);
2319 		_set_bt_plut(rtwdev, BTC_PHY_ALL, BTC_PLT_NONE, BTC_PLT_NONE);
2320 		break;
2321 	case BTC_ANT_W25G:
2322 		rtw89_mac_cfg_ctrl_path(rtwdev, true);
2323 		_set_gnt_wl(rtwdev, phy_map, BTC_GNT_HW);
2324 		_set_gnt_bt(rtwdev, phy_map, BTC_GNT_HW);
2325 		_set_bt_plut(rtwdev, BTC_PHY_ALL,
2326 			     BTC_PLT_GNT_WL, BTC_PLT_GNT_WL);
2327 		break;
2328 	case BTC_ANT_FREERUN:
2329 		rtw89_mac_cfg_ctrl_path(rtwdev, true);
2330 		_set_gnt_wl(rtwdev, phy_map, BTC_GNT_SW_HI);
2331 		_set_gnt_bt(rtwdev, phy_map, BTC_GNT_SW_HI);
2332 		_set_bt_plut(rtwdev, BTC_PHY_ALL, BTC_PLT_NONE, BTC_PLT_NONE);
2333 		break;
2334 	case BTC_ANT_WRFK:
2335 		rtw89_mac_cfg_ctrl_path(rtwdev, true);
2336 		_set_gnt_wl(rtwdev, phy_map, BTC_GNT_SW_HI);
2337 		_set_gnt_bt(rtwdev, phy_map, BTC_GNT_SW_LO);
2338 		_set_bt_plut(rtwdev, phy_map, BTC_PLT_NONE, BTC_PLT_NONE);
2339 		break;
2340 	case BTC_ANT_BRFK:
2341 		rtw89_mac_cfg_ctrl_path(rtwdev, false);
2342 		_set_gnt_wl(rtwdev, phy_map, BTC_GNT_SW_LO);
2343 		_set_gnt_bt(rtwdev, phy_map, BTC_GNT_SW_HI);
2344 		_set_bt_plut(rtwdev, phy_map, BTC_PLT_NONE, BTC_PLT_NONE);
2345 		break;
2346 	default:
2347 		break;
2348 	}
2349 }
2350 
2351 static void _action_wl_only(struct rtw89_dev *rtwdev)
2352 {
2353 	_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WONLY);
2354 	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_ONLY);
2355 }
2356 
2357 static void _action_wl_init(struct rtw89_dev *rtwdev)
2358 {
2359 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
2360 
2361 	_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WINIT);
2362 	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_INIT);
2363 }
2364 
2365 static void _action_wl_off(struct rtw89_dev *rtwdev)
2366 {
2367 	struct rtw89_btc *btc = &rtwdev->btc;
2368 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
2369 
2370 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
2371 
2372 	if (wl->status.map.rf_off || btc->dm.bt_only)
2373 		_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_WOFF);
2374 
2375 	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_OFF);
2376 }
2377 
2378 static void _action_freerun(struct rtw89_dev *rtwdev)
2379 {
2380 	struct rtw89_btc *btc = &rtwdev->btc;
2381 
2382 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
2383 
2384 	_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_FREERUN);
2385 	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_FREERUN);
2386 
2387 	btc->dm.freerun = true;
2388 }
2389 
2390 static void _action_bt_whql(struct rtw89_dev *rtwdev)
2391 {
2392 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
2393 
2394 	_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
2395 	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_BT_WHQL);
2396 }
2397 
2398 static void _action_bt_off(struct rtw89_dev *rtwdev)
2399 {
2400 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
2401 
2402 	_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WONLY);
2403 	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_BT_OFF);
2404 }
2405 
2406 static void _action_bt_idle(struct rtw89_dev *rtwdev)
2407 {
2408 	struct rtw89_btc *btc = &rtwdev->btc;
2409 	struct rtw89_btc_bt_link_info *b = &btc->cx.bt.link_info;
2410 
2411 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
2412 
2413 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */
2414 		switch (btc->cx.state_map) {
2415 		case BTC_WBUSY_BNOSCAN: /*wl-busy + bt idle*/
2416 			if (b->profile_cnt.now > 0)
2417 				_set_policy(rtwdev, BTC_CXP_FIX_TD4010,
2418 					    BTC_ACT_BT_IDLE);
2419 			else
2420 				_set_policy(rtwdev, BTC_CXP_FIX_TD4020,
2421 					    BTC_ACT_BT_IDLE);
2422 			break;
2423 		case BTC_WBUSY_BSCAN: /*wl-busy + bt-inq */
2424 			_set_policy(rtwdev, BTC_CXP_PFIX_TD5050,
2425 				    BTC_ACT_BT_IDLE);
2426 			break;
2427 		case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-idle */
2428 			if (b->profile_cnt.now > 0)
2429 				_set_policy(rtwdev, BTC_CXP_FIX_TD4010,
2430 					    BTC_ACT_BT_IDLE);
2431 			else
2432 				_set_policy(rtwdev, BTC_CXP_FIX_TD4020,
2433 					    BTC_ACT_BT_IDLE);
2434 			break;
2435 		case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq */
2436 			_set_policy(rtwdev, BTC_CXP_FIX_TD5050,
2437 				    BTC_ACT_BT_IDLE);
2438 			break;
2439 		case BTC_WLINKING: /* wl-connecting + bt-inq or bt-idle */
2440 			_set_policy(rtwdev, BTC_CXP_FIX_TD7010,
2441 				    BTC_ACT_BT_IDLE);
2442 			break;
2443 		case BTC_WIDLE:  /* wl-idle + bt-idle */
2444 			_set_policy(rtwdev, BTC_CXP_OFF_BWB1, BTC_ACT_BT_IDLE);
2445 			break;
2446 		}
2447 	} else { /* dedicated-antenna */
2448 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_BT_IDLE);
2449 	}
2450 }
2451 
2452 static void _action_bt_hfp(struct rtw89_dev *rtwdev)
2453 {
2454 	struct rtw89_btc *btc = &rtwdev->btc;
2455 
2456 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
2457 
2458 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) {
2459 		if (btc->cx.wl.status.map._4way)
2460 			_set_policy(rtwdev, BTC_CXP_OFF_WL, BTC_ACT_BT_HFP);
2461 		else
2462 			_set_policy(rtwdev, BTC_CXP_OFF_BWB0, BTC_ACT_BT_HFP);
2463 	} else {
2464 		_set_policy(rtwdev, BTC_CXP_OFF_EQ2, BTC_ACT_BT_HFP);
2465 	}
2466 }
2467 
2468 static void _action_bt_hid(struct rtw89_dev *rtwdev)
2469 {
2470 	struct rtw89_btc *btc = &rtwdev->btc;
2471 
2472 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
2473 
2474 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) /* shared-antenna */
2475 		if (btc->cx.wl.status.map._4way)
2476 			_set_policy(rtwdev, BTC_CXP_OFF_WL, BTC_ACT_BT_HID);
2477 		else
2478 			_set_policy(rtwdev, BTC_CXP_OFF_BWB0, BTC_ACT_BT_HID);
2479 	else /* dedicated-antenna */
2480 		_set_policy(rtwdev, BTC_CXP_OFF_EQ3, BTC_ACT_BT_HID);
2481 }
2482 
2483 static void _action_bt_a2dp(struct rtw89_dev *rtwdev)
2484 {
2485 	struct rtw89_btc *btc = &rtwdev->btc;
2486 	struct rtw89_btc_bt_link_info *bt_linfo = &btc->cx.bt.link_info;
2487 	struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc;
2488 	struct rtw89_btc_dm *dm = &btc->dm;
2489 
2490 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
2491 
2492 	switch (btc->cx.state_map) {
2493 	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-A2DP */
2494 		if (a2dp.vendor_id == 0x4c || dm->leak_ap) {
2495 			dm->slot_dur[CXST_W1] = 40;
2496 			dm->slot_dur[CXST_B1] = 200;
2497 			_set_policy(rtwdev,
2498 				    BTC_CXP_PAUTO_TDW1B1, BTC_ACT_BT_A2DP);
2499 		} else {
2500 			_set_policy(rtwdev,
2501 				    BTC_CXP_PAUTO_TD50200, BTC_ACT_BT_A2DP);
2502 		}
2503 		break;
2504 	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-A2DP */
2505 		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD3050, BTC_ACT_BT_A2DP);
2506 		break;
2507 	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-A2DP */
2508 		_set_policy(rtwdev, BTC_CXP_AUTO2_TD3050, BTC_ACT_BT_A2DP);
2509 		break;
2510 	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-A2DP */
2511 	case BTC_WLINKING: /* wl-connecting + bt-A2DP */
2512 		if (a2dp.vendor_id == 0x4c || dm->leak_ap) {
2513 			dm->slot_dur[CXST_W1] = 40;
2514 			dm->slot_dur[CXST_B1] = 200;
2515 			_set_policy(rtwdev, BTC_CXP_AUTO_TDW1B1,
2516 				    BTC_ACT_BT_A2DP);
2517 		} else {
2518 			_set_policy(rtwdev, BTC_CXP_AUTO_TD50200,
2519 				    BTC_ACT_BT_A2DP);
2520 		}
2521 		break;
2522 	case BTC_WIDLE:  /* wl-idle + bt-A2DP */
2523 		_set_policy(rtwdev, BTC_CXP_AUTO_TD20200, BTC_ACT_BT_A2DP);
2524 		break;
2525 	}
2526 }
2527 
2528 static void _action_bt_a2dpsink(struct rtw89_dev *rtwdev)
2529 {
2530 	struct rtw89_btc *btc = &rtwdev->btc;
2531 
2532 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
2533 
2534 	switch (btc->cx.state_map) {
2535 	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-A2dp_Sink */
2536 		_set_policy(rtwdev, BTC_CXP_PFIX_TD2030, BTC_ACT_BT_A2DPSINK);
2537 		break;
2538 	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-A2dp_Sink */
2539 		_set_policy(rtwdev, BTC_CXP_PFIX_TD2060, BTC_ACT_BT_A2DPSINK);
2540 		break;
2541 	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-A2dp_Sink */
2542 		_set_policy(rtwdev, BTC_CXP_FIX_TD2030, BTC_ACT_BT_A2DPSINK);
2543 		break;
2544 	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-A2dp_Sink */
2545 		_set_policy(rtwdev, BTC_CXP_FIX_TD2060, BTC_ACT_BT_A2DPSINK);
2546 		break;
2547 	case BTC_WLINKING: /* wl-connecting + bt-A2dp_Sink */
2548 		_set_policy(rtwdev, BTC_CXP_FIX_TD3030, BTC_ACT_BT_A2DPSINK);
2549 		break;
2550 	case BTC_WIDLE: /* wl-idle + bt-A2dp_Sink */
2551 		_set_policy(rtwdev, BTC_CXP_FIX_TD2080, BTC_ACT_BT_A2DPSINK);
2552 		break;
2553 	}
2554 }
2555 
2556 static void _action_bt_pan(struct rtw89_dev *rtwdev)
2557 {
2558 	struct rtw89_btc *btc = &rtwdev->btc;
2559 
2560 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
2561 
2562 	switch (btc->cx.state_map) {
2563 	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-PAN */
2564 		_set_policy(rtwdev, BTC_CXP_PFIX_TD5050, BTC_ACT_BT_PAN);
2565 		break;
2566 	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-PAN */
2567 		_set_policy(rtwdev, BTC_CXP_PFIX_TD3070, BTC_ACT_BT_PAN);
2568 		break;
2569 	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-PAN */
2570 		_set_policy(rtwdev, BTC_CXP_FIX_TD3030, BTC_ACT_BT_PAN);
2571 		break;
2572 	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-PAN */
2573 		_set_policy(rtwdev, BTC_CXP_FIX_TD3060, BTC_ACT_BT_PAN);
2574 		break;
2575 	case BTC_WLINKING: /* wl-connecting + bt-PAN */
2576 		_set_policy(rtwdev, BTC_CXP_FIX_TD4020, BTC_ACT_BT_PAN);
2577 		break;
2578 	case BTC_WIDLE: /* wl-idle + bt-pan */
2579 		_set_policy(rtwdev, BTC_CXP_PFIX_TD2080, BTC_ACT_BT_PAN);
2580 		break;
2581 	}
2582 }
2583 
2584 static void _action_bt_a2dp_hid(struct rtw89_dev *rtwdev)
2585 {
2586 	struct rtw89_btc *btc = &rtwdev->btc;
2587 	struct rtw89_btc_bt_link_info *bt_linfo = &btc->cx.bt.link_info;
2588 	struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc;
2589 	struct rtw89_btc_dm *dm = &btc->dm;
2590 
2591 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
2592 
2593 	switch (btc->cx.state_map) {
2594 	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-A2DP+HID */
2595 	case BTC_WIDLE:  /* wl-idle + bt-A2DP */
2596 		if (a2dp.vendor_id == 0x4c || dm->leak_ap) {
2597 			dm->slot_dur[CXST_W1] = 40;
2598 			dm->slot_dur[CXST_B1] = 200;
2599 			_set_policy(rtwdev,
2600 				    BTC_CXP_PAUTO_TDW1B1, BTC_ACT_BT_A2DP_HID);
2601 		} else {
2602 			_set_policy(rtwdev,
2603 				    BTC_CXP_PAUTO_TD50200, BTC_ACT_BT_A2DP_HID);
2604 		}
2605 		break;
2606 	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-A2DP+HID */
2607 		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD3050, BTC_ACT_BT_A2DP_HID);
2608 		break;
2609 
2610 	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-A2DP+HID */
2611 		_set_policy(rtwdev, BTC_CXP_AUTO2_TD3050, BTC_ACT_BT_A2DP_HID);
2612 		break;
2613 	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-A2DP+HID */
2614 	case BTC_WLINKING: /* wl-connecting + bt-A2DP+HID */
2615 		if (a2dp.vendor_id == 0x4c || dm->leak_ap) {
2616 			dm->slot_dur[CXST_W1] = 40;
2617 			dm->slot_dur[CXST_B1] = 200;
2618 			_set_policy(rtwdev, BTC_CXP_AUTO_TDW1B1,
2619 				    BTC_ACT_BT_A2DP_HID);
2620 		} else {
2621 			_set_policy(rtwdev, BTC_CXP_AUTO_TD50200,
2622 				    BTC_ACT_BT_A2DP_HID);
2623 		}
2624 		break;
2625 	}
2626 }
2627 
2628 static void _action_bt_a2dp_pan(struct rtw89_dev *rtwdev)
2629 {
2630 	struct rtw89_btc *btc = &rtwdev->btc;
2631 
2632 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
2633 
2634 	switch (btc->cx.state_map) {
2635 	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-A2DP+PAN */
2636 		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD3070, BTC_ACT_BT_A2DP_PAN);
2637 		break;
2638 	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-A2DP+PAN */
2639 		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD3070, BTC_ACT_BT_A2DP_PAN);
2640 		break;
2641 	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-A2DP+PAN */
2642 		_set_policy(rtwdev, BTC_CXP_AUTO2_TD5050, BTC_ACT_BT_A2DP_PAN);
2643 		break;
2644 	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-A2DP+PAN */
2645 		_set_policy(rtwdev, BTC_CXP_AUTO2_TD3070, BTC_ACT_BT_A2DP_PAN);
2646 		break;
2647 	case BTC_WLINKING: /* wl-connecting + bt-A2DP+PAN */
2648 		_set_policy(rtwdev, BTC_CXP_AUTO2_TD3050, BTC_ACT_BT_A2DP_PAN);
2649 		break;
2650 	case BTC_WIDLE:  /* wl-idle + bt-A2DP+PAN */
2651 		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD2080, BTC_ACT_BT_A2DP_PAN);
2652 		break;
2653 	}
2654 }
2655 
2656 static void _action_bt_pan_hid(struct rtw89_dev *rtwdev)
2657 {
2658 	struct rtw89_btc *btc = &rtwdev->btc;
2659 
2660 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
2661 
2662 	switch (btc->cx.state_map) {
2663 	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-PAN+HID */
2664 		_set_policy(rtwdev, BTC_CXP_PFIX_TD3030, BTC_ACT_BT_PAN_HID);
2665 		break;
2666 	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-PAN+HID */
2667 		_set_policy(rtwdev, BTC_CXP_PFIX_TD3070, BTC_ACT_BT_PAN_HID);
2668 		break;
2669 	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-PAN+HID */
2670 		_set_policy(rtwdev, BTC_CXP_FIX_TD3030, BTC_ACT_BT_PAN_HID);
2671 		break;
2672 	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-PAN+HID */
2673 		_set_policy(rtwdev, BTC_CXP_FIX_TD3060, BTC_ACT_BT_PAN_HID);
2674 		break;
2675 	case BTC_WLINKING: /* wl-connecting + bt-PAN+HID */
2676 		_set_policy(rtwdev, BTC_CXP_FIX_TD4010, BTC_ACT_BT_PAN_HID);
2677 		break;
2678 	case BTC_WIDLE: /* wl-idle + bt-PAN+HID */
2679 		_set_policy(rtwdev, BTC_CXP_PFIX_TD2080, BTC_ACT_BT_PAN_HID);
2680 		break;
2681 	}
2682 }
2683 
2684 static void _action_bt_a2dp_pan_hid(struct rtw89_dev *rtwdev)
2685 {
2686 	struct rtw89_btc *btc = &rtwdev->btc;
2687 
2688 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
2689 
2690 	switch (btc->cx.state_map) {
2691 	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-A2DP+PAN+HID */
2692 		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD3070,
2693 			    BTC_ACT_BT_A2DP_PAN_HID);
2694 		break;
2695 	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-A2DP+PAN+HID */
2696 		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD3070,
2697 			    BTC_ACT_BT_A2DP_PAN_HID);
2698 		break;
2699 	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-A2DP+PAN+HID */
2700 		_set_policy(rtwdev, BTC_CXP_AUTO2_TD3070,
2701 			    BTC_ACT_BT_A2DP_PAN_HID);
2702 		break;
2703 	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-A2DP+PAN+HID */
2704 	case BTC_WLINKING: /* wl-connecting + bt-A2DP+PAN+HID */
2705 		_set_policy(rtwdev, BTC_CXP_AUTO2_TD3050,
2706 			    BTC_ACT_BT_A2DP_PAN_HID);
2707 		break;
2708 	case BTC_WIDLE:  /* wl-idle + bt-A2DP+PAN+HID */
2709 		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD2080,
2710 			    BTC_ACT_BT_A2DP_PAN_HID);
2711 		break;
2712 	}
2713 }
2714 
2715 static void _action_wl_5g(struct rtw89_dev *rtwdev)
2716 {
2717 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W5G);
2718 	_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_5G);
2719 }
2720 
2721 static void _action_wl_other(struct rtw89_dev *rtwdev)
2722 {
2723 	struct rtw89_btc *btc = &rtwdev->btc;
2724 
2725 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
2726 
2727 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED)
2728 		_set_policy(rtwdev, BTC_CXP_OFFB_BWB0, BTC_ACT_WL_OTHER);
2729 	else
2730 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_OTHER);
2731 }
2732 
2733 static void _action_wl_nc(struct rtw89_dev *rtwdev)
2734 {
2735 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
2736 	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_NC);
2737 }
2738 
2739 static void _action_wl_rfk(struct rtw89_dev *rtwdev)
2740 {
2741 	struct rtw89_btc *btc = &rtwdev->btc;
2742 	struct rtw89_btc_wl_rfk_info rfk = btc->cx.wl.rfk_info;
2743 
2744 	if (rfk.state != BTC_WRFK_START)
2745 		return;
2746 
2747 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): band = %d\n",
2748 		    __func__, rfk.band);
2749 
2750 	_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WRFK);
2751 	_set_policy(rtwdev, BTC_CXP_OFF_WL, BTC_ACT_WL_RFK);
2752 }
2753 
2754 static void _set_btg_ctrl(struct rtw89_dev *rtwdev)
2755 {
2756 	struct rtw89_btc *btc = &rtwdev->btc;
2757 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
2758 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
2759 	struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
2760 	bool is_btg = false;
2761 
2762 	if (btc->ctrl.manual)
2763 		return;
2764 
2765 	/* notify halbb ignore GNT_BT or not for WL BB Rx-AGC control */
2766 	if (wl_rinfo->link_mode == BTC_WLINK_5G) /* always 0 if 5G */
2767 		is_btg = false;
2768 	else if (wl_rinfo->link_mode == BTC_WLINK_25G_DBCC &&
2769 		 wl_dinfo->real_band[RTW89_PHY_1] != RTW89_BAND_2G)
2770 		is_btg = false;
2771 	else
2772 		is_btg = true;
2773 
2774 	if (btc->dm.run_reason != BTC_RSN_NTFY_INIT &&
2775 	    is_btg == btc->dm.wl_btg_rx)
2776 		return;
2777 
2778 	btc->dm.wl_btg_rx = is_btg;
2779 
2780 	if (wl_rinfo->link_mode == BTC_WLINK_25G_MCC)
2781 		return;
2782 
2783 	rtw89_ctrl_btg(rtwdev, is_btg);
2784 }
2785 
2786 struct rtw89_txtime_data {
2787 	struct rtw89_dev *rtwdev;
2788 	int type;
2789 	u32 tx_time;
2790 	u8 tx_retry;
2791 	u16 enable;
2792 	bool reenable;
2793 };
2794 
2795 static void rtw89_tx_time_iter(void *data, struct ieee80211_sta *sta)
2796 {
2797 	struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
2798 	struct rtw89_txtime_data *iter_data =
2799 				(struct rtw89_txtime_data *)data;
2800 	struct rtw89_dev *rtwdev = iter_data->rtwdev;
2801 	struct rtw89_vif *rtwvif = rtwsta->rtwvif;
2802 	struct rtw89_btc *btc = &rtwdev->btc;
2803 	struct rtw89_btc_cx *cx = &btc->cx;
2804 	struct rtw89_btc_wl_info *wl = &cx->wl;
2805 	struct rtw89_btc_wl_link_info *plink = NULL;
2806 	u8 port = rtwvif->port;
2807 	u32 tx_time = iter_data->tx_time;
2808 	u8 tx_retry = iter_data->tx_retry;
2809 	u16 enable = iter_data->enable;
2810 	bool reenable = iter_data->reenable;
2811 
2812 	plink = &wl->link_info[port];
2813 
2814 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
2815 		    "[BTC], %s(): port = %d\n", __func__, port);
2816 
2817 	if (!plink->connected) {
2818 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
2819 			    "[BTC], %s(): connected = %d\n",
2820 			    __func__, plink->connected);
2821 		return;
2822 	}
2823 
2824 	/* backup the original tx time before tx-limit on */
2825 	if (reenable) {
2826 		rtw89_mac_get_tx_time(rtwdev, rtwsta, &plink->tx_time);
2827 		rtw89_mac_get_tx_retry_limit(rtwdev, rtwsta, &plink->tx_retry);
2828 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
2829 			    "[BTC], %s(): reenable, tx_time=%d tx_retry= %d\n",
2830 			    __func__, plink->tx_time, plink->tx_retry);
2831 	}
2832 
2833 	/* restore the original tx time if no tx-limit */
2834 	if (!enable) {
2835 		rtw89_mac_set_tx_time(rtwdev, rtwsta, true, plink->tx_time);
2836 		rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta, true,
2837 					     plink->tx_retry);
2838 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
2839 			    "[BTC], %s(): restore, tx_time=%d tx_retry= %d\n",
2840 			    __func__, plink->tx_time, plink->tx_retry);
2841 
2842 	} else {
2843 		rtw89_mac_set_tx_time(rtwdev, rtwsta, false, tx_time);
2844 		rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta, false, tx_retry);
2845 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
2846 			    "[BTC], %s(): set, tx_time=%d tx_retry= %d\n",
2847 			    __func__, tx_time, tx_retry);
2848 	}
2849 }
2850 
2851 static void _set_wl_tx_limit(struct rtw89_dev *rtwdev)
2852 {
2853 	struct rtw89_btc *btc = &rtwdev->btc;
2854 	struct rtw89_btc_cx *cx = &btc->cx;
2855 	struct rtw89_btc_dm *dm = &btc->dm;
2856 	struct rtw89_btc_wl_info *wl = &cx->wl;
2857 	struct rtw89_btc_bt_info *bt = &cx->bt;
2858 	struct rtw89_btc_bt_link_info *b = &bt->link_info;
2859 	struct rtw89_btc_bt_hfp_desc *hfp = &b->hfp_desc;
2860 	struct rtw89_btc_bt_hid_desc *hid = &b->hid_desc;
2861 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
2862 	struct rtw89_txtime_data data = {.rtwdev = rtwdev};
2863 	u8 mode = wl_rinfo->link_mode;
2864 	u8 tx_retry = 0;
2865 	u32 tx_time = 0;
2866 	u16 enable = 0;
2867 	bool reenable = false;
2868 
2869 	if (btc->ctrl.manual)
2870 		return;
2871 
2872 	if (btc->dm.freerun || btc->ctrl.igno_bt || b->profile_cnt.now == 0 ||
2873 	    mode == BTC_WLINK_5G || mode == BTC_WLINK_NOLINK) {
2874 		enable = 0;
2875 		tx_time = BTC_MAX_TX_TIME_DEF;
2876 		tx_retry = BTC_MAX_TX_RETRY_DEF;
2877 	} else if ((hfp->exist && hid->exist) || hid->pair_cnt > 1) {
2878 		enable = 1;
2879 		tx_time = BTC_MAX_TX_TIME_L2;
2880 		tx_retry = BTC_MAX_TX_RETRY_L1;
2881 	} else if (hfp->exist || hid->exist) {
2882 		enable = 1;
2883 		tx_time = BTC_MAX_TX_TIME_L3;
2884 		tx_retry = BTC_MAX_TX_RETRY_L1;
2885 	} else {
2886 		enable = 0;
2887 		tx_time = BTC_MAX_TX_TIME_DEF;
2888 		tx_retry = BTC_MAX_TX_RETRY_DEF;
2889 	}
2890 
2891 	if (dm->wl_tx_limit.enable == enable &&
2892 	    dm->wl_tx_limit.tx_time == tx_time &&
2893 	    dm->wl_tx_limit.tx_retry == tx_retry)
2894 		return;
2895 
2896 	if (!dm->wl_tx_limit.enable && enable)
2897 		reenable = true;
2898 
2899 	dm->wl_tx_limit.enable = enable;
2900 	dm->wl_tx_limit.tx_time = tx_time;
2901 	dm->wl_tx_limit.tx_retry = tx_retry;
2902 
2903 	data.enable = enable;
2904 	data.tx_time = tx_time;
2905 	data.tx_retry = tx_retry;
2906 	data.reenable = reenable;
2907 
2908 	ieee80211_iterate_stations_atomic(rtwdev->hw,
2909 					  rtw89_tx_time_iter,
2910 					  &data);
2911 }
2912 
2913 static void _set_bt_rx_agc(struct rtw89_dev *rtwdev)
2914 {
2915 	struct rtw89_btc *btc = &rtwdev->btc;
2916 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
2917 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
2918 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
2919 	bool bt_hi_lna_rx = false;
2920 
2921 	if (wl_rinfo->link_mode != BTC_WLINK_NOLINK && btc->dm.wl_btg_rx)
2922 		bt_hi_lna_rx = true;
2923 
2924 	if (bt_hi_lna_rx == bt->hi_lna_rx)
2925 		return;
2926 
2927 	_write_scbd(rtwdev, BTC_WSCB_BT_HILNA, bt_hi_lna_rx);
2928 }
2929 
2930 /* TODO add these functions */
2931 static void _action_common(struct rtw89_dev *rtwdev)
2932 {
2933 	_set_btg_ctrl(rtwdev);
2934 	_set_wl_tx_limit(rtwdev);
2935 	_set_bt_afh_info(rtwdev);
2936 	_set_bt_rx_agc(rtwdev);
2937 	_set_rf_trx_para(rtwdev);
2938 }
2939 
2940 static void _action_by_bt(struct rtw89_dev *rtwdev)
2941 {
2942 	struct rtw89_btc *btc = &rtwdev->btc;
2943 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
2944 	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
2945 	struct rtw89_btc_bt_hid_desc hid = bt_linfo->hid_desc;
2946 	struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc;
2947 	struct rtw89_btc_bt_pan_desc pan = bt_linfo->pan_desc;
2948 	u8 profile_map = 0;
2949 
2950 	if (bt_linfo->hfp_desc.exist)
2951 		profile_map |= BTC_BT_HFP;
2952 
2953 	if (bt_linfo->hid_desc.exist)
2954 		profile_map |= BTC_BT_HID;
2955 
2956 	if (bt_linfo->a2dp_desc.exist)
2957 		profile_map |= BTC_BT_A2DP;
2958 
2959 	if (bt_linfo->pan_desc.exist)
2960 		profile_map |= BTC_BT_PAN;
2961 
2962 	switch (profile_map) {
2963 	case BTC_BT_NOPROFILE:
2964 		if (_check_freerun(rtwdev))
2965 			_action_freerun(rtwdev);
2966 		else if (a2dp.active || pan.active)
2967 			_action_bt_pan(rtwdev);
2968 		else
2969 			_action_bt_idle(rtwdev);
2970 		break;
2971 	case BTC_BT_HFP:
2972 		if (_check_freerun(rtwdev))
2973 			_action_freerun(rtwdev);
2974 		else
2975 			_action_bt_hfp(rtwdev);
2976 		break;
2977 	case BTC_BT_HFP | BTC_BT_HID:
2978 	case BTC_BT_HID:
2979 		if (_check_freerun(rtwdev))
2980 			_action_freerun(rtwdev);
2981 		else
2982 			_action_bt_hid(rtwdev);
2983 		break;
2984 	case BTC_BT_A2DP:
2985 		if (_check_freerun(rtwdev))
2986 			_action_freerun(rtwdev);
2987 		else if (a2dp.sink)
2988 			_action_bt_a2dpsink(rtwdev);
2989 		else if (bt_linfo->multi_link.now && !hid.pair_cnt)
2990 			_action_bt_a2dp_pan(rtwdev);
2991 		else
2992 			_action_bt_a2dp(rtwdev);
2993 		break;
2994 	case BTC_BT_PAN:
2995 		_action_bt_pan(rtwdev);
2996 		break;
2997 	case BTC_BT_A2DP | BTC_BT_HFP:
2998 	case BTC_BT_A2DP | BTC_BT_HID:
2999 	case BTC_BT_A2DP | BTC_BT_HFP | BTC_BT_HID:
3000 		if (_check_freerun(rtwdev))
3001 			_action_freerun(rtwdev);
3002 		else
3003 			_action_bt_a2dp_hid(rtwdev);
3004 		break;
3005 	case BTC_BT_A2DP | BTC_BT_PAN:
3006 		_action_bt_a2dp_pan(rtwdev);
3007 		break;
3008 	case BTC_BT_PAN | BTC_BT_HFP:
3009 	case BTC_BT_PAN | BTC_BT_HID:
3010 	case BTC_BT_PAN | BTC_BT_HFP | BTC_BT_HID:
3011 		_action_bt_pan_hid(rtwdev);
3012 		break;
3013 	case BTC_BT_A2DP | BTC_BT_PAN | BTC_BT_HID:
3014 	case BTC_BT_A2DP | BTC_BT_PAN | BTC_BT_HFP:
3015 	default:
3016 		_action_bt_a2dp_pan_hid(rtwdev);
3017 		break;
3018 	}
3019 }
3020 
3021 static void _action_wl_2g_sta(struct rtw89_dev *rtwdev)
3022 {
3023 	_action_by_bt(rtwdev);
3024 }
3025 
3026 static void _action_wl_scan(struct rtw89_dev *rtwdev)
3027 {
3028 	struct rtw89_btc *btc = &rtwdev->btc;
3029 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
3030 	struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
3031 
3032 	if (rtwdev->dbcc_en) {
3033 		if (wl_dinfo->real_band[RTW89_PHY_0] != RTW89_BAND_2G &&
3034 		    wl_dinfo->real_band[RTW89_PHY_1] != RTW89_BAND_2G)
3035 			_action_wl_5g(rtwdev);
3036 		else
3037 			_action_by_bt(rtwdev);
3038 	} else {
3039 		if (wl->scan_info.band[RTW89_PHY_0] != RTW89_BAND_2G)
3040 			_action_wl_5g(rtwdev);
3041 		else
3042 			_action_by_bt(rtwdev);
3043 	}
3044 }
3045 
3046 static void _action_wl_25g_mcc(struct rtw89_dev *rtwdev)
3047 {
3048 	struct rtw89_btc *btc = &rtwdev->btc;
3049 
3050 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W25G);
3051 
3052 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) {
3053 		if (btc->cx.bt.link_info.profile_cnt.now == 0)
3054 			_set_policy(rtwdev, BTC_CXP_OFFE_DEF2,
3055 				    BTC_ACT_WL_25G_MCC);
3056 		else
3057 			_set_policy(rtwdev, BTC_CXP_OFFE_DEF,
3058 				    BTC_ACT_WL_25G_MCC);
3059 	} else { /* dedicated-antenna */
3060 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_25G_MCC);
3061 	}
3062 }
3063 
3064 static void _action_wl_2g_mcc(struct rtw89_dev *rtwdev)
3065 {	struct rtw89_btc *btc = &rtwdev->btc;
3066 
3067 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3068 
3069 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */
3070 		if (btc->cx.bt.link_info.profile_cnt.now == 0)
3071 			_set_policy(rtwdev, BTC_CXP_OFFE_DEF2,
3072 				    BTC_ACT_WL_2G_MCC);
3073 		else
3074 			_set_policy(rtwdev, BTC_CXP_OFFE_DEF,
3075 				    BTC_ACT_WL_2G_MCC);
3076 	} else { /* dedicated-antenna */
3077 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_MCC);
3078 	}
3079 }
3080 
3081 static void _action_wl_2g_scc(struct rtw89_dev *rtwdev)
3082 {
3083 	struct rtw89_btc *btc = &rtwdev->btc;
3084 
3085 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3086 
3087 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */
3088 		if (btc->cx.bt.link_info.profile_cnt.now == 0)
3089 			_set_policy(rtwdev,
3090 				    BTC_CXP_OFFE_DEF2, BTC_ACT_WL_2G_SCC);
3091 		else
3092 			_set_policy(rtwdev,
3093 				    BTC_CXP_OFFE_DEF, BTC_ACT_WL_2G_SCC);
3094 	} else { /* dedicated-antenna */
3095 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_SCC);
3096 	}
3097 }
3098 
3099 static void _action_wl_2g_ap(struct rtw89_dev *rtwdev)
3100 {
3101 	struct rtw89_btc *btc = &rtwdev->btc;
3102 
3103 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3104 
3105 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) {
3106 		if (btc->cx.bt.link_info.profile_cnt.now == 0)
3107 			_set_policy(rtwdev, BTC_CXP_OFFE_DEF2,
3108 				    BTC_ACT_WL_2G_AP);
3109 		else
3110 			_set_policy(rtwdev, BTC_CXP_OFFE_DEF, BTC_ACT_WL_2G_AP);
3111 	} else {/* dedicated-antenna */
3112 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_AP);
3113 	}
3114 }
3115 
3116 static void _action_wl_2g_go(struct rtw89_dev *rtwdev)
3117 {
3118 	struct rtw89_btc *btc = &rtwdev->btc;
3119 
3120 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3121 
3122 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */
3123 		if (btc->cx.bt.link_info.profile_cnt.now == 0)
3124 			_set_policy(rtwdev,
3125 				    BTC_CXP_OFFE_DEF2, BTC_ACT_WL_2G_GO);
3126 		else
3127 			_set_policy(rtwdev,
3128 				    BTC_CXP_OFFE_DEF, BTC_ACT_WL_2G_GO);
3129 	} else { /* dedicated-antenna */
3130 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_GO);
3131 	}
3132 }
3133 
3134 static void _action_wl_2g_gc(struct rtw89_dev *rtwdev)
3135 {
3136 	struct rtw89_btc *btc = &rtwdev->btc;
3137 
3138 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3139 
3140 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */
3141 		_action_by_bt(rtwdev);
3142 	} else {/* dedicated-antenna */
3143 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_GC);
3144 	}
3145 }
3146 
3147 static void _action_wl_2g_nan(struct rtw89_dev *rtwdev)
3148 {
3149 	struct rtw89_btc *btc = &rtwdev->btc;
3150 
3151 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3152 
3153 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */
3154 		if (btc->cx.bt.link_info.profile_cnt.now == 0)
3155 			_set_policy(rtwdev,
3156 				    BTC_CXP_OFFE_DEF2, BTC_ACT_WL_2G_NAN);
3157 		else
3158 			_set_policy(rtwdev,
3159 				    BTC_CXP_OFFE_DEF, BTC_ACT_WL_2G_NAN);
3160 	} else { /* dedicated-antenna */
3161 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_NAN);
3162 	}
3163 }
3164 
3165 static u32 _read_scbd(struct rtw89_dev *rtwdev)
3166 {
3167 	const struct rtw89_chip_info *chip = rtwdev->chip;
3168 	struct rtw89_btc *btc = &rtwdev->btc;
3169 	u32 scbd_val = 0;
3170 
3171 	if (!chip->scbd)
3172 		return 0;
3173 
3174 	scbd_val = rtw89_mac_get_sb(rtwdev);
3175 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], read scbd: 0x%08x\n",
3176 		    scbd_val);
3177 
3178 	btc->cx.cnt_bt[BTC_BCNT_SCBDREAD]++;
3179 	return scbd_val;
3180 }
3181 
3182 static void _write_scbd(struct rtw89_dev *rtwdev, u32 val, bool state)
3183 {
3184 	const struct rtw89_chip_info *chip = rtwdev->chip;
3185 	struct rtw89_btc *btc = &rtwdev->btc;
3186 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
3187 	u32 scbd_val = 0;
3188 
3189 	if (!chip->scbd)
3190 		return;
3191 
3192 	scbd_val = state ? wl->scbd | val : wl->scbd & ~val;
3193 
3194 	if (scbd_val == wl->scbd)
3195 		return;
3196 	rtw89_mac_cfg_sb(rtwdev, scbd_val);
3197 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], write scbd: 0x%08x\n",
3198 		    scbd_val);
3199 	wl->scbd = scbd_val;
3200 
3201 	btc->cx.cnt_wl[BTC_WCNT_SCBDUPDATE]++;
3202 }
3203 
3204 static u8
3205 _update_rssi_state(struct rtw89_dev *rtwdev, u8 pre_state, u8 rssi, u8 thresh)
3206 {
3207 	const struct rtw89_chip_info *chip = rtwdev->chip;
3208 	u8 next_state, tol = chip->rssi_tol;
3209 
3210 	if (pre_state == BTC_RSSI_ST_LOW ||
3211 	    pre_state == BTC_RSSI_ST_STAY_LOW) {
3212 		if (rssi >= (thresh + tol))
3213 			next_state = BTC_RSSI_ST_HIGH;
3214 		else
3215 			next_state = BTC_RSSI_ST_STAY_LOW;
3216 	} else {
3217 		if (rssi < thresh)
3218 			next_state = BTC_RSSI_ST_LOW;
3219 		else
3220 			next_state = BTC_RSSI_ST_STAY_HIGH;
3221 	}
3222 
3223 	return next_state;
3224 }
3225 
3226 static
3227 void _update_dbcc_band(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
3228 {
3229 	struct rtw89_btc *btc = &rtwdev->btc;
3230 
3231 	btc->cx.wl.dbcc_info.real_band[phy_idx] =
3232 		btc->cx.wl.scan_info.phy_map & BIT(phy_idx) ?
3233 		btc->cx.wl.dbcc_info.scan_band[phy_idx] :
3234 		btc->cx.wl.dbcc_info.op_band[phy_idx];
3235 }
3236 
3237 static void _update_wl_info(struct rtw89_dev *rtwdev)
3238 {
3239 	struct rtw89_btc *btc = &rtwdev->btc;
3240 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
3241 	struct rtw89_btc_wl_link_info *wl_linfo = wl->link_info;
3242 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
3243 	struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
3244 	u8 i, cnt_connect = 0, cnt_connecting = 0, cnt_active = 0;
3245 	u8 cnt_2g = 0, cnt_5g = 0, phy;
3246 	u32 wl_2g_ch[2] = {0}, wl_5g_ch[2] = {0};
3247 	bool b2g = false, b5g = false, client_joined = false;
3248 
3249 	memset(wl_rinfo, 0, sizeof(*wl_rinfo));
3250 
3251 	for (i = 0; i < RTW89_MAX_HW_PORT_NUM; i++) {
3252 		/* check if role active? */
3253 		if (!wl_linfo[i].active)
3254 			continue;
3255 
3256 		cnt_active++;
3257 		wl_rinfo->active_role[cnt_active - 1].role = wl_linfo[i].role;
3258 		wl_rinfo->active_role[cnt_active - 1].pid = wl_linfo[i].pid;
3259 		wl_rinfo->active_role[cnt_active - 1].phy = wl_linfo[i].phy;
3260 		wl_rinfo->active_role[cnt_active - 1].band = wl_linfo[i].band;
3261 		wl_rinfo->active_role[cnt_active - 1].noa = (u8)wl_linfo[i].noa;
3262 		wl_rinfo->active_role[cnt_active - 1].connected = 0;
3263 
3264 		wl->port_id[wl_linfo[i].role] = wl_linfo[i].pid;
3265 
3266 		phy = wl_linfo[i].phy;
3267 
3268 		/* check dbcc role */
3269 		if (rtwdev->dbcc_en && phy < RTW89_PHY_MAX) {
3270 			wl_dinfo->role[phy] = wl_linfo[i].role;
3271 			wl_dinfo->op_band[phy] = wl_linfo[i].band;
3272 			_update_dbcc_band(rtwdev, phy);
3273 			_fw_set_drv_info(rtwdev, CXDRVINFO_DBCC);
3274 		}
3275 
3276 		if (wl_linfo[i].connected == MLME_NO_LINK) {
3277 			continue;
3278 		} else if (wl_linfo[i].connected == MLME_LINKING) {
3279 			cnt_connecting++;
3280 		} else {
3281 			cnt_connect++;
3282 			if ((wl_linfo[i].role == RTW89_WIFI_ROLE_P2P_GO ||
3283 			     wl_linfo[i].role == RTW89_WIFI_ROLE_AP) &&
3284 			     wl_linfo[i].client_cnt > 1)
3285 				client_joined = true;
3286 		}
3287 
3288 		wl_rinfo->role_map.val |= BIT(wl_linfo[i].role);
3289 		wl_rinfo->active_role[cnt_active - 1].ch = wl_linfo[i].ch;
3290 		wl_rinfo->active_role[cnt_active - 1].bw = wl_linfo[i].bw;
3291 		wl_rinfo->active_role[cnt_active - 1].connected = 1;
3292 
3293 		/* only care 2 roles + BT coex */
3294 		if (wl_linfo[i].band != RTW89_BAND_2G) {
3295 			if (cnt_5g <= ARRAY_SIZE(wl_5g_ch) - 1)
3296 				wl_5g_ch[cnt_5g] = wl_linfo[i].ch;
3297 			cnt_5g++;
3298 			b5g = true;
3299 		} else {
3300 			if (cnt_2g <= ARRAY_SIZE(wl_2g_ch) - 1)
3301 				wl_2g_ch[cnt_2g] = wl_linfo[i].ch;
3302 			cnt_2g++;
3303 			b2g = true;
3304 		}
3305 	}
3306 
3307 	wl_rinfo->connect_cnt = cnt_connect;
3308 
3309 	/* Be careful to change the following sequence!! */
3310 	if (cnt_connect == 0) {
3311 		wl_rinfo->link_mode = BTC_WLINK_NOLINK;
3312 		wl_rinfo->role_map.role.none = 1;
3313 	} else if (!b2g && b5g) {
3314 		wl_rinfo->link_mode = BTC_WLINK_5G;
3315 	} else if (wl_rinfo->role_map.role.nan) {
3316 		wl_rinfo->link_mode = BTC_WLINK_2G_NAN;
3317 	} else if (cnt_connect > BTC_TDMA_WLROLE_MAX) {
3318 		wl_rinfo->link_mode = BTC_WLINK_OTHER;
3319 	} else  if (b2g && b5g && cnt_connect == 2) {
3320 		if (rtwdev->dbcc_en) {
3321 			switch (wl_dinfo->role[RTW89_PHY_0]) {
3322 			case RTW89_WIFI_ROLE_STATION:
3323 				wl_rinfo->link_mode = BTC_WLINK_2G_STA;
3324 				break;
3325 			case RTW89_WIFI_ROLE_P2P_GO:
3326 				wl_rinfo->link_mode = BTC_WLINK_2G_GO;
3327 				break;
3328 			case RTW89_WIFI_ROLE_P2P_CLIENT:
3329 				wl_rinfo->link_mode = BTC_WLINK_2G_GC;
3330 				break;
3331 			case RTW89_WIFI_ROLE_AP:
3332 				wl_rinfo->link_mode = BTC_WLINK_2G_AP;
3333 				break;
3334 			default:
3335 				wl_rinfo->link_mode = BTC_WLINK_OTHER;
3336 				break;
3337 			}
3338 		} else {
3339 			wl_rinfo->link_mode = BTC_WLINK_25G_MCC;
3340 		}
3341 	} else if (!b5g && cnt_connect == 2) {
3342 		if (wl_rinfo->role_map.role.station &&
3343 		    (wl_rinfo->role_map.role.p2p_go ||
3344 		    wl_rinfo->role_map.role.p2p_gc ||
3345 		    wl_rinfo->role_map.role.ap)) {
3346 			if (wl_2g_ch[0] == wl_2g_ch[1])
3347 				wl_rinfo->link_mode = BTC_WLINK_2G_SCC;
3348 			else
3349 				wl_rinfo->link_mode = BTC_WLINK_2G_MCC;
3350 		} else {
3351 			wl_rinfo->link_mode = BTC_WLINK_2G_MCC;
3352 		}
3353 	} else if (!b5g && cnt_connect == 1) {
3354 		if (wl_rinfo->role_map.role.station)
3355 			wl_rinfo->link_mode = BTC_WLINK_2G_STA;
3356 		else if (wl_rinfo->role_map.role.ap)
3357 			wl_rinfo->link_mode = BTC_WLINK_2G_AP;
3358 		else if (wl_rinfo->role_map.role.p2p_go)
3359 			wl_rinfo->link_mode = BTC_WLINK_2G_GO;
3360 		else if (wl_rinfo->role_map.role.p2p_gc)
3361 			wl_rinfo->link_mode = BTC_WLINK_2G_GC;
3362 		else
3363 			wl_rinfo->link_mode = BTC_WLINK_OTHER;
3364 	}
3365 
3366 	/* if no client_joined, don't care P2P-GO/AP role */
3367 	if (wl_rinfo->role_map.role.p2p_go || wl_rinfo->role_map.role.ap) {
3368 		if (!client_joined) {
3369 			if (wl_rinfo->link_mode == BTC_WLINK_2G_SCC ||
3370 			    wl_rinfo->link_mode == BTC_WLINK_2G_MCC) {
3371 				wl_rinfo->link_mode = BTC_WLINK_2G_STA;
3372 				wl_rinfo->connect_cnt = 1;
3373 			} else if (wl_rinfo->link_mode == BTC_WLINK_2G_GO ||
3374 				 wl_rinfo->link_mode == BTC_WLINK_2G_AP) {
3375 				wl_rinfo->link_mode = BTC_WLINK_NOLINK;
3376 				wl_rinfo->connect_cnt = 0;
3377 			}
3378 		}
3379 	}
3380 
3381 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
3382 		    "[BTC], cnt_connect = %d, link_mode = %d\n",
3383 		    cnt_connect, wl_rinfo->link_mode);
3384 
3385 	_fw_set_drv_info(rtwdev, CXDRVINFO_ROLE);
3386 }
3387 
3388 #define BTC_CHK_HANG_MAX 3
3389 #define BTC_SCB_INV_VALUE GENMASK(31, 0)
3390 
3391 void rtw89_coex_act1_work(struct work_struct *work)
3392 {
3393 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
3394 						coex_act1_work.work);
3395 	struct rtw89_btc *btc = &rtwdev->btc;
3396 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
3397 	struct rtw89_btc_cx *cx = &btc->cx;
3398 	struct rtw89_btc_wl_info *wl = &cx->wl;
3399 
3400 	mutex_lock(&rtwdev->mutex);
3401 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): enter\n", __func__);
3402 	dm->cnt_notify[BTC_NCNT_TIMER]++;
3403 	if (wl->status.map._4way)
3404 		wl->status.map._4way = false;
3405 	if (wl->status.map.connecting)
3406 		wl->status.map.connecting = false;
3407 
3408 	_run_coex(rtwdev, BTC_RSN_ACT1_WORK);
3409 	mutex_unlock(&rtwdev->mutex);
3410 }
3411 
3412 void rtw89_coex_bt_devinfo_work(struct work_struct *work)
3413 {
3414 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
3415 						coex_bt_devinfo_work.work);
3416 	struct rtw89_btc *btc = &rtwdev->btc;
3417 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
3418 	struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc;
3419 
3420 	mutex_lock(&rtwdev->mutex);
3421 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): enter\n", __func__);
3422 	dm->cnt_notify[BTC_NCNT_TIMER]++;
3423 	a2dp->play_latency = 0;
3424 	_run_coex(rtwdev, BTC_RSN_BT_DEVINFO_WORK);
3425 	mutex_unlock(&rtwdev->mutex);
3426 }
3427 
3428 void rtw89_coex_rfk_chk_work(struct work_struct *work)
3429 {
3430 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
3431 						coex_rfk_chk_work.work);
3432 	struct rtw89_btc *btc = &rtwdev->btc;
3433 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
3434 	struct rtw89_btc_cx *cx = &btc->cx;
3435 	struct rtw89_btc_wl_info *wl = &cx->wl;
3436 
3437 	mutex_lock(&rtwdev->mutex);
3438 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): enter\n", __func__);
3439 	dm->cnt_notify[BTC_NCNT_TIMER]++;
3440 	if (wl->rfk_info.state != BTC_WRFK_STOP) {
3441 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3442 			    "[BTC], %s(): RFK timeout\n", __func__);
3443 		cx->cnt_wl[BTC_WCNT_RFK_TIMEOUT]++;
3444 		dm->error.map.wl_rfk_timeout = true;
3445 		wl->rfk_info.state = BTC_WRFK_STOP;
3446 		_write_scbd(rtwdev, BTC_WSCB_WLRFK, false);
3447 		_run_coex(rtwdev, BTC_RSN_RFK_CHK_WORK);
3448 	}
3449 	mutex_unlock(&rtwdev->mutex);
3450 }
3451 
3452 static void _update_bt_scbd(struct rtw89_dev *rtwdev, bool only_update)
3453 {
3454 	const struct rtw89_chip_info *chip = rtwdev->chip;
3455 	struct rtw89_btc *btc = &rtwdev->btc;
3456 	struct rtw89_btc_cx *cx = &btc->cx;
3457 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
3458 	u32 val;
3459 	bool status_change = false;
3460 
3461 	if (!chip->scbd)
3462 		return;
3463 
3464 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s\n", __func__);
3465 
3466 	val = _read_scbd(rtwdev);
3467 	if (val == BTC_SCB_INV_VALUE) {
3468 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3469 			    "[BTC], %s(): return by invalid scbd value\n",
3470 			    __func__);
3471 		return;
3472 	}
3473 
3474 	if (!(val & BTC_BSCB_ON) ||
3475 	    btc->dm.cnt_dm[BTC_DCNT_BTCNT_FREEZE] >= BTC_CHK_HANG_MAX)
3476 		bt->enable.now = 0;
3477 	else
3478 		bt->enable.now = 1;
3479 
3480 	if (bt->enable.now != bt->enable.last)
3481 		status_change = true;
3482 
3483 	/* reset bt info if bt re-enable */
3484 	if (bt->enable.now && !bt->enable.last) {
3485 		_reset_btc_var(rtwdev, BTC_RESET_BTINFO);
3486 		cx->cnt_bt[BTC_BCNT_REENABLE]++;
3487 		bt->enable.now = 1;
3488 	}
3489 
3490 	bt->enable.last = bt->enable.now;
3491 	bt->scbd = val;
3492 	bt->mbx_avl = !!(val & BTC_BSCB_ACT);
3493 
3494 	if (bt->whql_test != !!(val & BTC_BSCB_WHQL))
3495 		status_change = true;
3496 
3497 	bt->whql_test = !!(val & BTC_BSCB_WHQL);
3498 	bt->btg_type = val & BTC_BSCB_BT_S1 ? BTC_BT_BTG : BTC_BT_ALONE;
3499 	bt->link_info.a2dp_desc.active = !!(val & BTC_BSCB_A2DP_ACT);
3500 
3501 	/* if rfk run 1->0 */
3502 	if (bt->rfk_info.map.run && !(val & BTC_BSCB_RFK_RUN))
3503 		status_change = true;
3504 
3505 	bt->rfk_info.map.run  = !!(val & BTC_BSCB_RFK_RUN);
3506 	bt->rfk_info.map.req = !!(val & BTC_BSCB_RFK_REQ);
3507 	bt->hi_lna_rx = !!(val & BTC_BSCB_BT_HILNA);
3508 	bt->link_info.status.map.connect = !!(val & BTC_BSCB_BT_CONNECT);
3509 	bt->run_patch_code = !!(val & BTC_BSCB_PATCH_CODE);
3510 
3511 	if (!only_update && status_change)
3512 		_run_coex(rtwdev, BTC_RSN_UPDATE_BT_SCBD);
3513 }
3514 
3515 static bool _chk_wl_rfk_request(struct rtw89_dev *rtwdev)
3516 {
3517 	struct rtw89_btc *btc = &rtwdev->btc;
3518 	struct rtw89_btc_cx *cx = &btc->cx;
3519 	struct rtw89_btc_bt_info *bt = &cx->bt;
3520 
3521 	_update_bt_scbd(rtwdev, true);
3522 
3523 	cx->cnt_wl[BTC_WCNT_RFK_REQ]++;
3524 
3525 	if ((bt->rfk_info.map.run || bt->rfk_info.map.req) &&
3526 	    !bt->rfk_info.map.timeout) {
3527 		cx->cnt_wl[BTC_WCNT_RFK_REJECT]++;
3528 	} else {
3529 		cx->cnt_wl[BTC_WCNT_RFK_GO]++;
3530 		return true;
3531 	}
3532 	return false;
3533 }
3534 
3535 static
3536 void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason)
3537 {
3538 	struct rtw89_btc *btc = &rtwdev->btc;
3539 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
3540 	struct rtw89_btc_cx *cx = &btc->cx;
3541 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
3542 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
3543 	u8 mode = wl_rinfo->link_mode;
3544 
3545 	lockdep_assert_held(&rtwdev->mutex);
3546 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): reason=%d, mode=%d\n",
3547 		    __func__, reason, mode);
3548 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): wl_only=%d, bt_only=%d\n",
3549 		    __func__, dm->wl_only, dm->bt_only);
3550 
3551 	dm->run_reason = reason;
3552 	_update_dm_step(rtwdev, reason);
3553 	_update_btc_state_map(rtwdev);
3554 
3555 	/* Be careful to change the following function sequence!! */
3556 	if (btc->ctrl.manual) {
3557 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3558 			    "[BTC], %s(): return for Manual CTRL!!\n",
3559 			    __func__);
3560 		return;
3561 	}
3562 
3563 	if (btc->ctrl.igno_bt &&
3564 	    (reason == BTC_RSN_UPDATE_BT_INFO ||
3565 	     reason == BTC_RSN_UPDATE_BT_SCBD)) {
3566 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3567 			    "[BTC], %s(): return for Stop Coex DM!!\n",
3568 			    __func__);
3569 		return;
3570 	}
3571 
3572 	if (!wl->status.map.init_ok) {
3573 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3574 			    "[BTC], %s(): return for WL init fail!!\n",
3575 			    __func__);
3576 		return;
3577 	}
3578 
3579 	if (wl->status.map.rf_off_pre == wl->status.map.rf_off &&
3580 	    wl->status.map.lps_pre == wl->status.map.lps &&
3581 	    (reason == BTC_RSN_NTFY_POWEROFF ||
3582 	    reason == BTC_RSN_NTFY_RADIO_STATE)) {
3583 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3584 			    "[BTC], %s(): return for WL rf off state no change!!\n",
3585 			    __func__);
3586 		return;
3587 	}
3588 
3589 	dm->cnt_dm[BTC_DCNT_RUN]++;
3590 
3591 	if (btc->ctrl.always_freerun) {
3592 		_action_freerun(rtwdev);
3593 		btc->ctrl.igno_bt = true;
3594 		goto exit;
3595 	}
3596 
3597 	if (dm->wl_only) {
3598 		_action_wl_only(rtwdev);
3599 		btc->ctrl.igno_bt = true;
3600 		goto exit;
3601 	}
3602 
3603 	if (wl->status.map.rf_off || wl->status.map.lps || dm->bt_only) {
3604 		_action_wl_off(rtwdev);
3605 		btc->ctrl.igno_bt = true;
3606 		goto exit;
3607 	}
3608 
3609 	btc->ctrl.igno_bt = false;
3610 	dm->freerun = false;
3611 
3612 	if (reason == BTC_RSN_NTFY_INIT) {
3613 		_action_wl_init(rtwdev);
3614 		goto exit;
3615 	}
3616 
3617 	if (!cx->bt.enable.now && !cx->other.type) {
3618 		_action_bt_off(rtwdev);
3619 		goto exit;
3620 	}
3621 
3622 	if (cx->bt.whql_test) {
3623 		_action_bt_whql(rtwdev);
3624 		goto exit;
3625 	}
3626 
3627 	if (wl->rfk_info.state != BTC_WRFK_STOP) {
3628 		_action_wl_rfk(rtwdev);
3629 		goto exit;
3630 	}
3631 
3632 	if (cx->state_map == BTC_WLINKING) {
3633 		if (mode == BTC_WLINK_NOLINK || mode == BTC_WLINK_2G_STA ||
3634 		    mode == BTC_WLINK_5G) {
3635 			_action_wl_scan(rtwdev);
3636 			goto exit;
3637 		}
3638 	}
3639 
3640 	if (wl->status.map.scan) {
3641 		_action_wl_scan(rtwdev);
3642 		goto exit;
3643 	}
3644 
3645 	switch (mode) {
3646 	case BTC_WLINK_NOLINK:
3647 		_action_wl_nc(rtwdev);
3648 		break;
3649 	case BTC_WLINK_2G_STA:
3650 		_action_wl_2g_sta(rtwdev);
3651 		break;
3652 	case BTC_WLINK_2G_AP:
3653 		_action_wl_2g_ap(rtwdev);
3654 		break;
3655 	case BTC_WLINK_2G_GO:
3656 		_action_wl_2g_go(rtwdev);
3657 		break;
3658 	case BTC_WLINK_2G_GC:
3659 		_action_wl_2g_gc(rtwdev);
3660 		break;
3661 	case BTC_WLINK_2G_SCC:
3662 		_action_wl_2g_scc(rtwdev);
3663 		break;
3664 	case BTC_WLINK_2G_MCC:
3665 		_action_wl_2g_mcc(rtwdev);
3666 		break;
3667 	case BTC_WLINK_25G_MCC:
3668 		_action_wl_25g_mcc(rtwdev);
3669 		break;
3670 	case BTC_WLINK_5G:
3671 		_action_wl_5g(rtwdev);
3672 		break;
3673 	case BTC_WLINK_2G_NAN:
3674 		_action_wl_2g_nan(rtwdev);
3675 		break;
3676 	default:
3677 		_action_wl_other(rtwdev);
3678 		break;
3679 	}
3680 
3681 exit:
3682 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): exit\n", __func__);
3683 	_action_common(rtwdev);
3684 }
3685 
3686 void rtw89_btc_ntfy_poweron(struct rtw89_dev *rtwdev)
3687 {
3688 	struct rtw89_btc *btc = &rtwdev->btc;
3689 
3690 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
3691 	btc->dm.cnt_notify[BTC_NCNT_POWER_ON]++;
3692 }
3693 
3694 void rtw89_btc_ntfy_poweroff(struct rtw89_dev *rtwdev)
3695 {
3696 	struct rtw89_btc *btc = &rtwdev->btc;
3697 
3698 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
3699 	btc->dm.cnt_notify[BTC_NCNT_POWER_OFF]++;
3700 
3701 	btc->cx.wl.status.map.rf_off = 1;
3702 
3703 	_write_scbd(rtwdev, BTC_WSCB_ALL, false);
3704 	_run_coex(rtwdev, BTC_RSN_NTFY_POWEROFF);
3705 
3706 	rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_ALL, 0);
3707 
3708 	btc->cx.wl.status.map.rf_off_pre = btc->cx.wl.status.map.rf_off;
3709 }
3710 
3711 static void _set_init_info(struct rtw89_dev *rtwdev)
3712 {
3713 	const struct rtw89_chip_info *chip = rtwdev->chip;
3714 	struct rtw89_btc *btc = &rtwdev->btc;
3715 	struct rtw89_btc_dm *dm = &btc->dm;
3716 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
3717 
3718 	dm->init_info.wl_only = (u8)dm->wl_only;
3719 	dm->init_info.bt_only = (u8)dm->bt_only;
3720 	dm->init_info.wl_init_ok = (u8)wl->status.map.init_ok;
3721 	dm->init_info.dbcc_en = rtwdev->dbcc_en;
3722 	dm->init_info.cx_other = btc->cx.other.type;
3723 	dm->init_info.wl_guard_ch = chip->afh_guard_ch;
3724 	dm->init_info.module = btc->mdinfo;
3725 }
3726 
3727 void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode)
3728 {
3729 	struct rtw89_btc *btc = &rtwdev->btc;
3730 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
3731 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
3732 	const struct rtw89_chip_info *chip = rtwdev->chip;
3733 
3734 	_reset_btc_var(rtwdev, BTC_RESET_ALL);
3735 	btc->dm.run_reason = BTC_RSN_NONE;
3736 	btc->dm.run_action = BTC_ACT_NONE;
3737 	btc->ctrl.igno_bt = true;
3738 
3739 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
3740 		    "[BTC], %s(): mode=%d\n", __func__, mode);
3741 
3742 	dm->cnt_notify[BTC_NCNT_INIT_COEX]++;
3743 	dm->wl_only = mode == BTC_MODE_WL ? 1 : 0;
3744 	dm->bt_only = mode == BTC_MODE_BT ? 1 : 0;
3745 	wl->status.map.rf_off = mode == BTC_MODE_WLOFF ? 1 : 0;
3746 
3747 	chip->ops->btc_set_rfe(rtwdev);
3748 	chip->ops->btc_init_cfg(rtwdev);
3749 
3750 	if (!wl->status.map.init_ok) {
3751 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3752 			    "[BTC], %s(): return for WL init fail!!\n",
3753 			    __func__);
3754 		dm->error.map.init = true;
3755 		return;
3756 	}
3757 
3758 	_write_scbd(rtwdev,
3759 		    BTC_WSCB_ACTIVE | BTC_WSCB_ON | BTC_WSCB_BTLOG, true);
3760 	_update_bt_scbd(rtwdev, true);
3761 	if (rtw89_mac_get_ctrl_path(rtwdev)) {
3762 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3763 			    "[BTC], %s(): PTA owner warning!!\n",
3764 			    __func__);
3765 		dm->error.map.pta_owner = true;
3766 	}
3767 
3768 	_set_init_info(rtwdev);
3769 	_set_wl_tx_power(rtwdev, RTW89_BTC_WL_DEF_TX_PWR);
3770 	rtw89_btc_fw_set_slots(rtwdev, CXST_MAX, dm->slot);
3771 	btc_fw_set_monreg(rtwdev);
3772 	_fw_set_drv_info(rtwdev, CXDRVINFO_INIT);
3773 	_fw_set_drv_info(rtwdev, CXDRVINFO_CTRL);
3774 
3775 	_run_coex(rtwdev, BTC_RSN_NTFY_INIT);
3776 }
3777 
3778 void rtw89_btc_ntfy_scan_start(struct rtw89_dev *rtwdev, u8 phy_idx, u8 band)
3779 {
3780 	struct rtw89_btc *btc = &rtwdev->btc;
3781 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
3782 
3783 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
3784 		    "[BTC], %s(): phy_idx=%d, band=%d\n",
3785 		    __func__, phy_idx, band);
3786 	btc->dm.cnt_notify[BTC_NCNT_SCAN_START]++;
3787 	wl->status.map.scan = true;
3788 	wl->scan_info.band[phy_idx] = band;
3789 	wl->scan_info.phy_map |= BIT(phy_idx);
3790 	_fw_set_drv_info(rtwdev, CXDRVINFO_SCAN);
3791 
3792 	if (rtwdev->dbcc_en) {
3793 		wl->dbcc_info.scan_band[phy_idx] = band;
3794 		_update_dbcc_band(rtwdev, phy_idx);
3795 		_fw_set_drv_info(rtwdev, CXDRVINFO_DBCC);
3796 	}
3797 
3798 	_run_coex(rtwdev, BTC_RSN_NTFY_SCAN_START);
3799 }
3800 
3801 void rtw89_btc_ntfy_scan_finish(struct rtw89_dev *rtwdev, u8 phy_idx)
3802 {
3803 	struct rtw89_btc *btc = &rtwdev->btc;
3804 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
3805 
3806 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
3807 		    "[BTC], %s(): phy_idx=%d\n", __func__, phy_idx);
3808 	btc->dm.cnt_notify[BTC_NCNT_SCAN_FINISH]++;
3809 
3810 	wl->status.map.scan = false;
3811 	wl->scan_info.phy_map &= ~BIT(phy_idx);
3812 	_fw_set_drv_info(rtwdev, CXDRVINFO_SCAN);
3813 
3814 	if (rtwdev->dbcc_en) {
3815 		_update_dbcc_band(rtwdev, phy_idx);
3816 		_fw_set_drv_info(rtwdev, CXDRVINFO_DBCC);
3817 	}
3818 
3819 	_run_coex(rtwdev, BTC_RSN_NTFY_SCAN_FINISH);
3820 }
3821 
3822 void rtw89_btc_ntfy_switch_band(struct rtw89_dev *rtwdev, u8 phy_idx, u8 band)
3823 {
3824 	struct rtw89_btc *btc = &rtwdev->btc;
3825 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
3826 
3827 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
3828 		    "[BTC], %s(): phy_idx=%d, band=%d\n",
3829 		    __func__, phy_idx, band);
3830 	btc->dm.cnt_notify[BTC_NCNT_SWITCH_BAND]++;
3831 
3832 	wl->scan_info.band[phy_idx] = band;
3833 	wl->scan_info.phy_map |= BIT(phy_idx);
3834 	_fw_set_drv_info(rtwdev, CXDRVINFO_SCAN);
3835 
3836 	if (rtwdev->dbcc_en) {
3837 		wl->dbcc_info.scan_band[phy_idx] = band;
3838 		_update_dbcc_band(rtwdev, phy_idx);
3839 		_fw_set_drv_info(rtwdev, CXDRVINFO_DBCC);
3840 	}
3841 	_run_coex(rtwdev, BTC_RSN_NTFY_SWBAND);
3842 }
3843 
3844 void rtw89_btc_ntfy_specific_packet(struct rtw89_dev *rtwdev,
3845 				    enum btc_pkt_type pkt_type)
3846 {
3847 	struct rtw89_btc *btc = &rtwdev->btc;
3848 	struct rtw89_btc_cx *cx = &btc->cx;
3849 	struct rtw89_btc_wl_info *wl = &cx->wl;
3850 	struct rtw89_btc_bt_link_info *b = &cx->bt.link_info;
3851 	struct rtw89_btc_bt_hfp_desc *hfp = &b->hfp_desc;
3852 	struct rtw89_btc_bt_hid_desc *hid = &b->hid_desc;
3853 	u32 cnt;
3854 	u32 delay = RTW89_COEX_ACT1_WORK_PERIOD;
3855 	bool delay_work = false;
3856 
3857 	switch (pkt_type) {
3858 	case PACKET_DHCP:
3859 		cnt = ++cx->cnt_wl[BTC_WCNT_DHCP];
3860 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3861 			    "[BTC], %s(): DHCP cnt=%d\n", __func__, cnt);
3862 		wl->status.map.connecting = true;
3863 		delay_work = true;
3864 		break;
3865 	case PACKET_EAPOL:
3866 		cnt = ++cx->cnt_wl[BTC_WCNT_EAPOL];
3867 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3868 			    "[BTC], %s(): EAPOL cnt=%d\n", __func__, cnt);
3869 		wl->status.map._4way = true;
3870 		delay_work = true;
3871 		if (hfp->exist || hid->exist)
3872 			delay /= 2;
3873 		break;
3874 	case PACKET_EAPOL_END:
3875 		cnt = ++cx->cnt_wl[BTC_WCNT_EAPOL];
3876 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3877 			    "[BTC], %s(): EAPOL_End cnt=%d\n",
3878 			    __func__, cnt);
3879 		wl->status.map._4way = false;
3880 		cancel_delayed_work(&rtwdev->coex_act1_work);
3881 		break;
3882 	case PACKET_ARP:
3883 		cnt = ++cx->cnt_wl[BTC_WCNT_ARP];
3884 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3885 			    "[BTC], %s(): ARP cnt=%d\n", __func__, cnt);
3886 		return;
3887 	case PACKET_ICMP:
3888 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3889 			    "[BTC], %s(): ICMP pkt\n", __func__);
3890 		return;
3891 	default:
3892 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3893 			    "[BTC], %s(): unknown packet type %d\n",
3894 			    __func__, pkt_type);
3895 		return;
3896 	}
3897 
3898 	if (delay_work) {
3899 		cancel_delayed_work(&rtwdev->coex_act1_work);
3900 		ieee80211_queue_delayed_work(rtwdev->hw,
3901 					     &rtwdev->coex_act1_work, delay);
3902 	}
3903 
3904 	btc->dm.cnt_notify[BTC_NCNT_SPECIAL_PACKET]++;
3905 	_run_coex(rtwdev, BTC_RSN_NTFY_SPECIFIC_PACKET);
3906 }
3907 
3908 void rtw89_btc_ntfy_eapol_packet_work(struct work_struct *work)
3909 {
3910 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
3911 						btc.eapol_notify_work);
3912 
3913 	mutex_lock(&rtwdev->mutex);
3914 	rtw89_leave_ps_mode(rtwdev);
3915 	rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_EAPOL);
3916 	mutex_unlock(&rtwdev->mutex);
3917 }
3918 
3919 void rtw89_btc_ntfy_arp_packet_work(struct work_struct *work)
3920 {
3921 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
3922 						btc.arp_notify_work);
3923 
3924 	mutex_lock(&rtwdev->mutex);
3925 	rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_ARP);
3926 	mutex_unlock(&rtwdev->mutex);
3927 }
3928 
3929 void rtw89_btc_ntfy_dhcp_packet_work(struct work_struct *work)
3930 {
3931 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
3932 						btc.dhcp_notify_work);
3933 
3934 	mutex_lock(&rtwdev->mutex);
3935 	rtw89_leave_ps_mode(rtwdev);
3936 	rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_DHCP);
3937 	mutex_unlock(&rtwdev->mutex);
3938 }
3939 
3940 void rtw89_btc_ntfy_icmp_packet_work(struct work_struct *work)
3941 {
3942 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
3943 						btc.icmp_notify_work);
3944 
3945 	mutex_lock(&rtwdev->mutex);
3946 	rtw89_leave_ps_mode(rtwdev);
3947 	rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_ICMP);
3948 	mutex_unlock(&rtwdev->mutex);
3949 }
3950 
3951 static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len)
3952 {
3953 	const struct rtw89_chip_info *chip = rtwdev->chip;
3954 	struct rtw89_btc *btc = &rtwdev->btc;
3955 	struct rtw89_btc_cx *cx = &btc->cx;
3956 	struct rtw89_btc_bt_info *bt = &cx->bt;
3957 	struct rtw89_btc_bt_link_info *b = &bt->link_info;
3958 	struct rtw89_btc_bt_hfp_desc *hfp = &b->hfp_desc;
3959 	struct rtw89_btc_bt_hid_desc *hid = &b->hid_desc;
3960 	struct rtw89_btc_bt_a2dp_desc *a2dp = &b->a2dp_desc;
3961 	struct rtw89_btc_bt_pan_desc *pan = &b->pan_desc;
3962 	union btc_btinfo btinfo;
3963 
3964 	if (buf[BTC_BTINFO_L1] != 6)
3965 		return;
3966 
3967 	if (!memcmp(bt->raw_info, buf, BTC_BTINFO_MAX)) {
3968 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3969 			    "[BTC], %s(): return by bt-info duplicate!!\n",
3970 			    __func__);
3971 		cx->cnt_bt[BTC_BCNT_INFOSAME]++;
3972 		return;
3973 	}
3974 
3975 	memcpy(bt->raw_info, buf, BTC_BTINFO_MAX);
3976 
3977 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
3978 		    "[BTC], %s(): bt_info[2]=0x%02x\n",
3979 		    __func__, bt->raw_info[2]);
3980 
3981 	/* reset to mo-connect before update */
3982 	b->status.val = BTC_BLINK_NOCONNECT;
3983 	b->profile_cnt.last = b->profile_cnt.now;
3984 	b->relink.last = b->relink.now;
3985 	a2dp->exist_last = a2dp->exist;
3986 	b->multi_link.last = b->multi_link.now;
3987 	bt->inq_pag.last = bt->inq_pag.now;
3988 	b->profile_cnt.now = 0;
3989 	hid->type = 0;
3990 
3991 	/* parse raw info low-Byte2 */
3992 	btinfo.val = bt->raw_info[BTC_BTINFO_L2];
3993 	b->status.map.connect = btinfo.lb2.connect;
3994 	b->status.map.sco_busy = btinfo.lb2.sco_busy;
3995 	b->status.map.acl_busy = btinfo.lb2.acl_busy;
3996 	b->status.map.inq_pag = btinfo.lb2.inq_pag;
3997 	bt->inq_pag.now = btinfo.lb2.inq_pag;
3998 	cx->cnt_bt[BTC_BCNT_INQPAG] += !!(bt->inq_pag.now && !bt->inq_pag.last);
3999 
4000 	hfp->exist = btinfo.lb2.hfp;
4001 	b->profile_cnt.now += (u8)hfp->exist;
4002 	hid->exist = btinfo.lb2.hid;
4003 	b->profile_cnt.now += (u8)hid->exist;
4004 	a2dp->exist = btinfo.lb2.a2dp;
4005 	b->profile_cnt.now += (u8)a2dp->exist;
4006 	pan->active = btinfo.lb2.pan;
4007 
4008 	/* parse raw info low-Byte3 */
4009 	btinfo.val = bt->raw_info[BTC_BTINFO_L3];
4010 	if (btinfo.lb3.retry != 0)
4011 		cx->cnt_bt[BTC_BCNT_RETRY]++;
4012 	b->cqddr = btinfo.lb3.cqddr;
4013 	cx->cnt_bt[BTC_BCNT_INQ] += !!(btinfo.lb3.inq && !bt->inq);
4014 	bt->inq = btinfo.lb3.inq;
4015 	cx->cnt_bt[BTC_BCNT_PAGE] += !!(btinfo.lb3.pag && !bt->pag);
4016 	bt->pag = btinfo.lb3.pag;
4017 
4018 	b->status.map.mesh_busy = btinfo.lb3.mesh_busy;
4019 	/* parse raw info high-Byte0 */
4020 	btinfo.val = bt->raw_info[BTC_BTINFO_H0];
4021 	/* raw val is dBm unit, translate from -100~ 0dBm to 0~100%*/
4022 	b->rssi = chip->ops->btc_get_bt_rssi(rtwdev, btinfo.hb0.rssi);
4023 
4024 	/* parse raw info high-Byte1 */
4025 	btinfo.val = bt->raw_info[BTC_BTINFO_H1];
4026 	b->status.map.ble_connect = btinfo.hb1.ble_connect;
4027 	if (btinfo.hb1.ble_connect)
4028 		hid->type |= (hid->exist ? BTC_HID_BLE : BTC_HID_RCU);
4029 
4030 	cx->cnt_bt[BTC_BCNT_REINIT] += !!(btinfo.hb1.reinit && !bt->reinit);
4031 	bt->reinit = btinfo.hb1.reinit;
4032 	cx->cnt_bt[BTC_BCNT_RELINK] += !!(btinfo.hb1.relink && !b->relink.now);
4033 	b->relink.now = btinfo.hb1.relink;
4034 	cx->cnt_bt[BTC_BCNT_IGNOWL] += !!(btinfo.hb1.igno_wl && !bt->igno_wl);
4035 	bt->igno_wl = btinfo.hb1.igno_wl;
4036 
4037 	if (bt->igno_wl && !cx->wl.status.map.rf_off)
4038 		_set_bt_ignore_wlan_act(rtwdev, false);
4039 
4040 	hid->type |= (btinfo.hb1.voice ? BTC_HID_RCU_VOICE : 0);
4041 	bt->ble_scan_en = btinfo.hb1.ble_scan;
4042 
4043 	cx->cnt_bt[BTC_BCNT_ROLESW] += !!(btinfo.hb1.role_sw && !b->role_sw);
4044 	b->role_sw = btinfo.hb1.role_sw;
4045 
4046 	b->multi_link.now = btinfo.hb1.multi_link;
4047 
4048 	/* parse raw info high-Byte2 */
4049 	btinfo.val = bt->raw_info[BTC_BTINFO_H2];
4050 	pan->exist = btinfo.hb2.pan_active;
4051 	b->profile_cnt.now += (u8)pan->exist;
4052 
4053 	cx->cnt_bt[BTC_BCNT_AFH] += !!(btinfo.hb2.afh_update && !b->afh_update);
4054 	b->afh_update = btinfo.hb2.afh_update;
4055 	a2dp->active = btinfo.hb2.a2dp_active;
4056 	b->slave_role = btinfo.hb2.slave;
4057 	hid->slot_info = btinfo.hb2.hid_slot;
4058 	hid->pair_cnt = btinfo.hb2.hid_cnt;
4059 	hid->type |= (hid->slot_info == BTC_HID_218 ?
4060 		      BTC_HID_218 : BTC_HID_418);
4061 	/* parse raw info high-Byte3 */
4062 	btinfo.val = bt->raw_info[BTC_BTINFO_H3];
4063 	a2dp->bitpool = btinfo.hb3.a2dp_bitpool;
4064 
4065 	if (b->tx_3m != (u32)btinfo.hb3.tx_3m)
4066 		cx->cnt_bt[BTC_BCNT_RATECHG]++;
4067 	b->tx_3m = (u32)btinfo.hb3.tx_3m;
4068 
4069 	a2dp->sink = btinfo.hb3.a2dp_sink;
4070 
4071 	if (b->profile_cnt.now || b->status.map.ble_connect)
4072 		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP, 1);
4073 	else
4074 		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP, 0);
4075 
4076 	if (!a2dp->exist_last && a2dp->exist) {
4077 		a2dp->vendor_id = 0;
4078 		a2dp->flush_time = 0;
4079 		a2dp->play_latency = 1;
4080 		ieee80211_queue_delayed_work(rtwdev->hw,
4081 					     &rtwdev->coex_bt_devinfo_work,
4082 					     RTW89_COEX_BT_DEVINFO_WORK_PERIOD);
4083 	}
4084 
4085 	if (a2dp->exist && (a2dp->flush_time == 0 || a2dp->vendor_id == 0 ||
4086 			    a2dp->play_latency == 1))
4087 		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_DEVICE_INFO, 1);
4088 	else
4089 		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_DEVICE_INFO, 0);
4090 
4091 	_run_coex(rtwdev, BTC_RSN_UPDATE_BT_INFO);
4092 }
4093 
4094 enum btc_wl_mode {
4095 	BTC_WL_MODE_HT = 0,
4096 	BTC_WL_MODE_VHT = 1,
4097 	BTC_WL_MODE_HE = 2,
4098 	BTC_WL_MODE_NUM,
4099 };
4100 
4101 void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
4102 			      struct rtw89_sta *rtwsta, enum btc_role_state state)
4103 {
4104 	struct rtw89_hal *hal = &rtwdev->hal;
4105 	struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
4106 	struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta);
4107 	struct rtw89_btc *btc = &rtwdev->btc;
4108 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4109 	struct rtw89_btc_wl_link_info r = {0};
4110 	struct rtw89_btc_wl_link_info *wlinfo = NULL;
4111 	u8 mode = 0;
4112 
4113 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], state=%d\n", state);
4114 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
4115 		    "[BTC], role is STA=%d\n",
4116 		    vif->type == NL80211_IFTYPE_STATION);
4117 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], port=%d\n", rtwvif->port);
4118 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], band=%d ch=%d bw=%d\n",
4119 		    hal->current_band_type, hal->current_channel,
4120 		    hal->current_band_width);
4121 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], associated=%d\n",
4122 		    state == BTC_ROLE_MSTS_STA_CONN_END);
4123 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
4124 		    "[BTC], bcn_period=%d dtim_period=%d\n",
4125 		    vif->bss_conf.beacon_int, vif->bss_conf.dtim_period);
4126 
4127 	if (rtwsta) {
4128 		rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], STA mac_id=%d\n",
4129 			    rtwsta->mac_id);
4130 
4131 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4132 			    "[BTC], STA support HE=%d VHT=%d HT=%d\n",
4133 			    sta->he_cap.has_he,
4134 			    sta->vht_cap.vht_supported,
4135 			    sta->ht_cap.ht_supported);
4136 		if (sta->he_cap.has_he)
4137 			mode |= BIT(BTC_WL_MODE_HE);
4138 		if (sta->vht_cap.vht_supported)
4139 			mode |= BIT(BTC_WL_MODE_VHT);
4140 		if (sta->ht_cap.ht_supported)
4141 			mode |= BIT(BTC_WL_MODE_HT);
4142 
4143 		r.mode = mode;
4144 	}
4145 
4146 	if (rtwvif->wifi_role >= RTW89_WIFI_ROLE_MLME_MAX)
4147 		return;
4148 
4149 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
4150 		    "[BTC], wifi_role=%d\n", rtwvif->wifi_role);
4151 
4152 	r.role = rtwvif->wifi_role;
4153 	r.phy = rtwvif->phy_idx;
4154 	r.pid = rtwvif->port;
4155 	r.active = true;
4156 	r.connected = MLME_LINKED;
4157 	r.bcn_period = vif->bss_conf.beacon_int;
4158 	r.dtim_period = vif->bss_conf.dtim_period;
4159 	r.band = hal->current_band_type;
4160 	r.ch = hal->current_channel;
4161 	r.bw = hal->current_band_width;
4162 	ether_addr_copy(r.mac_addr, rtwvif->mac_addr);
4163 
4164 	if (rtwsta && vif->type == NL80211_IFTYPE_STATION)
4165 		r.mac_id = rtwsta->mac_id;
4166 
4167 	btc->dm.cnt_notify[BTC_NCNT_ROLE_INFO]++;
4168 
4169 	wlinfo = &wl->link_info[r.pid];
4170 
4171 	memcpy(wlinfo, &r, sizeof(*wlinfo));
4172 	_update_wl_info(rtwdev);
4173 
4174 	if (wlinfo->role == RTW89_WIFI_ROLE_STATION &&
4175 	    wlinfo->connected == MLME_NO_LINK)
4176 		btc->dm.leak_ap = 0;
4177 
4178 	if (state == BTC_ROLE_MSTS_STA_CONN_START)
4179 		wl->status.map.connecting = 1;
4180 	else
4181 		wl->status.map.connecting = 0;
4182 
4183 	if (state == BTC_ROLE_MSTS_STA_DIS_CONN)
4184 		wl->status.map._4way = false;
4185 
4186 	_run_coex(rtwdev, BTC_RSN_NTFY_ROLE_INFO);
4187 }
4188 
4189 void rtw89_btc_ntfy_radio_state(struct rtw89_dev *rtwdev, enum btc_rfctrl rf_state)
4190 {
4191 	const struct rtw89_chip_info *chip = rtwdev->chip;
4192 	struct rtw89_btc *btc = &rtwdev->btc;
4193 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4194 
4195 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): rf_state = %d\n",
4196 		    __func__, rf_state);
4197 	btc->dm.cnt_notify[BTC_NCNT_RADIO_STATE]++;
4198 
4199 	switch (rf_state) {
4200 	case BTC_RFCTRL_WL_OFF:
4201 		wl->status.map.rf_off = 1;
4202 		wl->status.map.lps = 0;
4203 		break;
4204 	case BTC_RFCTRL_FW_CTRL:
4205 		wl->status.map.rf_off = 0;
4206 		wl->status.map.lps = 1;
4207 		break;
4208 	case BTC_RFCTRL_WL_ON:
4209 	default:
4210 		wl->status.map.rf_off = 0;
4211 		wl->status.map.lps = 0;
4212 		break;
4213 	}
4214 
4215 	if (rf_state == BTC_RFCTRL_WL_ON) {
4216 		rtw89_btc_fw_en_rpt(rtwdev,
4217 				    RPT_EN_MREG | RPT_EN_BT_VER_INFO, true);
4218 		_write_scbd(rtwdev, BTC_WSCB_ACTIVE, true);
4219 		_update_bt_scbd(rtwdev, true);
4220 		chip->ops->btc_init_cfg(rtwdev);
4221 	} else {
4222 		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_ALL, false);
4223 		_write_scbd(rtwdev, BTC_WSCB_ACTIVE | BTC_WSCB_WLBUSY, false);
4224 	}
4225 
4226 	_run_coex(rtwdev, BTC_RSN_NTFY_RADIO_STATE);
4227 
4228 	wl->status.map.rf_off_pre = wl->status.map.rf_off;
4229 	wl->status.map.lps_pre = wl->status.map.lps;
4230 }
4231 
4232 static bool _ntfy_wl_rfk(struct rtw89_dev *rtwdev, u8 phy_path,
4233 			 enum btc_wl_rfk_type type,
4234 			 enum btc_wl_rfk_state state)
4235 {
4236 	struct rtw89_btc *btc = &rtwdev->btc;
4237 	struct rtw89_btc_cx *cx = &btc->cx;
4238 	struct rtw89_btc_wl_info *wl = &cx->wl;
4239 	bool result = BTC_WRFK_REJECT;
4240 
4241 	wl->rfk_info.type = type;
4242 	wl->rfk_info.path_map = FIELD_GET(BTC_RFK_PATH_MAP, phy_path);
4243 	wl->rfk_info.phy_map = FIELD_GET(BTC_RFK_PHY_MAP, phy_path);
4244 	wl->rfk_info.band = FIELD_GET(BTC_RFK_BAND_MAP, phy_path);
4245 
4246 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
4247 		    "[BTC], %s()_start: phy=0x%x, path=0x%x, type=%d, state=%d\n",
4248 		    __func__, wl->rfk_info.phy_map, wl->rfk_info.path_map,
4249 		    type, state);
4250 
4251 	switch (state) {
4252 	case BTC_WRFK_START:
4253 		result = _chk_wl_rfk_request(rtwdev);
4254 		wl->rfk_info.state = result ? BTC_WRFK_START : BTC_WRFK_STOP;
4255 
4256 		_write_scbd(rtwdev, BTC_WSCB_WLRFK, result);
4257 
4258 		btc->dm.cnt_notify[BTC_NCNT_WL_RFK]++;
4259 		break;
4260 	case BTC_WRFK_ONESHOT_START:
4261 	case BTC_WRFK_ONESHOT_STOP:
4262 		if (wl->rfk_info.state == BTC_WRFK_STOP) {
4263 			result = BTC_WRFK_REJECT;
4264 		} else {
4265 			result = BTC_WRFK_ALLOW;
4266 			wl->rfk_info.state = state;
4267 		}
4268 		break;
4269 	case BTC_WRFK_STOP:
4270 		result = BTC_WRFK_ALLOW;
4271 		wl->rfk_info.state = BTC_WRFK_STOP;
4272 
4273 		_write_scbd(rtwdev, BTC_WSCB_WLRFK, false);
4274 		cancel_delayed_work(&rtwdev->coex_rfk_chk_work);
4275 		break;
4276 	default:
4277 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4278 			    "[BTC], %s() warning state=%d\n", __func__, state);
4279 		break;
4280 	}
4281 
4282 	if (result == BTC_WRFK_ALLOW) {
4283 		if (wl->rfk_info.state == BTC_WRFK_START ||
4284 		    wl->rfk_info.state == BTC_WRFK_STOP)
4285 			_run_coex(rtwdev, BTC_RSN_NTFY_WL_RFK);
4286 
4287 		if (wl->rfk_info.state == BTC_WRFK_START)
4288 			ieee80211_queue_delayed_work(rtwdev->hw,
4289 						     &rtwdev->coex_rfk_chk_work,
4290 						     RTW89_COEX_RFK_CHK_WORK_PERIOD);
4291 	}
4292 
4293 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
4294 		    "[BTC], %s()_finish: rfk_cnt=%d, result=%d\n",
4295 		    __func__, btc->dm.cnt_notify[BTC_NCNT_WL_RFK], result);
4296 
4297 	return result == BTC_WRFK_ALLOW;
4298 }
4299 
4300 void rtw89_btc_ntfy_wl_rfk(struct rtw89_dev *rtwdev, u8 phy_map,
4301 			   enum btc_wl_rfk_type type,
4302 			   enum btc_wl_rfk_state state)
4303 {
4304 	u8 band;
4305 	bool allow;
4306 	int ret;
4307 
4308 	band = FIELD_GET(BTC_RFK_BAND_MAP, phy_map);
4309 
4310 	rtw89_debug(rtwdev, RTW89_DBG_RFK,
4311 		    "[RFK] RFK notify (%s / PHY%u / K_type = %u / path_idx = %lu / process = %s)\n",
4312 		    band == RTW89_BAND_2G ? "2G" :
4313 		    band == RTW89_BAND_5G ? "5G" : "6G",
4314 		    !!(FIELD_GET(BTC_RFK_PHY_MAP, phy_map) & BIT(RTW89_PHY_1)),
4315 		    type,
4316 		    FIELD_GET(BTC_RFK_PATH_MAP, phy_map),
4317 		    state == BTC_WRFK_STOP ? "RFK_STOP" :
4318 		    state == BTC_WRFK_START ? "RFK_START" :
4319 		    state == BTC_WRFK_ONESHOT_START ? "ONE-SHOT_START" :
4320 		    "ONE-SHOT_STOP");
4321 
4322 	if (state != BTC_WRFK_START || rtwdev->is_bt_iqk_timeout) {
4323 		_ntfy_wl_rfk(rtwdev, phy_map, type, state);
4324 		return;
4325 	}
4326 
4327 	ret = read_poll_timeout(_ntfy_wl_rfk, allow, allow, 40, 100000, false,
4328 				rtwdev, phy_map, type, state);
4329 	if (ret) {
4330 		rtw89_warn(rtwdev, "RFK notify timeout\n");
4331 		rtwdev->is_bt_iqk_timeout = true;
4332 	}
4333 }
4334 
4335 struct rtw89_btc_wl_sta_iter_data {
4336 	struct rtw89_dev *rtwdev;
4337 	u8 busy_all;
4338 	u8 dir_all;
4339 	u8 rssi_map_all;
4340 	bool is_sta_change;
4341 	bool is_traffic_change;
4342 };
4343 
4344 static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta)
4345 {
4346 	struct rtw89_btc_wl_sta_iter_data *iter_data =
4347 				(struct rtw89_btc_wl_sta_iter_data *)data;
4348 	struct rtw89_dev *rtwdev = iter_data->rtwdev;
4349 	struct rtw89_btc *btc = &rtwdev->btc;
4350 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4351 	struct rtw89_btc_wl_link_info *link_info = NULL;
4352 	struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
4353 	struct rtw89_traffic_stats *link_info_t = NULL;
4354 	struct rtw89_vif *rtwvif = rtwsta->rtwvif;
4355 	struct rtw89_traffic_stats *stats = &rtwvif->stats;
4356 	const struct rtw89_chip_info *chip = rtwdev->chip;
4357 	u32 last_tx_rate, last_rx_rate;
4358 	u16 last_tx_lvl, last_rx_lvl;
4359 	u8 port = rtwvif->port;
4360 	u8 rssi;
4361 	u8 busy = 0;
4362 	u8 dir = 0;
4363 	u8 rssi_map = 0;
4364 	u8 i = 0;
4365 	bool is_sta_change = false, is_traffic_change = false;
4366 
4367 	rssi = ewma_rssi_read(&rtwsta->avg_rssi) >> RSSI_FACTOR;
4368 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], rssi=%d\n", rssi);
4369 
4370 	link_info = &wl->link_info[port];
4371 	link_info->stat.traffic = rtwvif->stats;
4372 	link_info_t = &link_info->stat.traffic;
4373 
4374 	if (link_info->connected == MLME_NO_LINK) {
4375 		link_info->rx_rate_drop_cnt = 0;
4376 		return;
4377 	}
4378 
4379 	link_info->stat.rssi = rssi;
4380 	for (i = 0; i < BTC_WL_RSSI_THMAX; i++) {
4381 		link_info->rssi_state[i] =
4382 			_update_rssi_state(rtwdev,
4383 					   link_info->rssi_state[i],
4384 					   link_info->stat.rssi,
4385 					   chip->wl_rssi_thres[i]);
4386 		if (BTC_RSSI_LOW(link_info->rssi_state[i]))
4387 			rssi_map |= BIT(i);
4388 
4389 		if (btc->mdinfo.ant.type == BTC_ANT_DEDICATED &&
4390 		    BTC_RSSI_CHANGE(link_info->rssi_state[i]))
4391 			is_sta_change = true;
4392 	}
4393 	iter_data->rssi_map_all |= rssi_map;
4394 
4395 	last_tx_rate = link_info_t->tx_rate;
4396 	last_rx_rate = link_info_t->rx_rate;
4397 	last_tx_lvl = (u16)link_info_t->tx_tfc_lv;
4398 	last_rx_lvl = (u16)link_info_t->rx_tfc_lv;
4399 
4400 	if (stats->tx_tfc_lv != RTW89_TFC_IDLE ||
4401 	    stats->rx_tfc_lv != RTW89_TFC_IDLE)
4402 		busy = 1;
4403 
4404 	if (stats->tx_tfc_lv > stats->rx_tfc_lv)
4405 		dir = RTW89_TFC_UL;
4406 	else
4407 		dir = RTW89_TFC_DL;
4408 
4409 	link_info = &wl->link_info[port];
4410 	if (link_info->busy != busy || link_info->dir != dir) {
4411 		is_sta_change = true;
4412 		link_info->busy = busy;
4413 		link_info->dir = dir;
4414 	}
4415 
4416 	iter_data->busy_all |= busy;
4417 	iter_data->dir_all |= BIT(dir);
4418 
4419 	if (rtwsta->rx_hw_rate <= RTW89_HW_RATE_CCK2 &&
4420 	    last_rx_rate > RTW89_HW_RATE_CCK2 &&
4421 	    link_info_t->rx_tfc_lv > RTW89_TFC_IDLE)
4422 		link_info->rx_rate_drop_cnt++;
4423 
4424 	if (last_tx_rate != rtwsta->ra_report.hw_rate ||
4425 	    last_rx_rate != rtwsta->rx_hw_rate ||
4426 	    last_tx_lvl != link_info_t->tx_tfc_lv ||
4427 	    last_rx_lvl != link_info_t->rx_tfc_lv)
4428 		is_traffic_change = true;
4429 
4430 	link_info_t->tx_rate = rtwsta->ra_report.hw_rate;
4431 	link_info_t->rx_rate = rtwsta->rx_hw_rate;
4432 
4433 	wl->role_info.active_role[port].tx_lvl = (u16)stats->tx_tfc_lv;
4434 	wl->role_info.active_role[port].rx_lvl = (u16)stats->rx_tfc_lv;
4435 	wl->role_info.active_role[port].tx_rate = rtwsta->ra_report.hw_rate;
4436 	wl->role_info.active_role[port].rx_rate = rtwsta->rx_hw_rate;
4437 
4438 	if (is_sta_change)
4439 		iter_data->is_sta_change = true;
4440 
4441 	if (is_traffic_change)
4442 		iter_data->is_traffic_change = true;
4443 }
4444 
4445 #define BTC_NHM_CHK_INTVL 20
4446 
4447 void rtw89_btc_ntfy_wl_sta(struct rtw89_dev *rtwdev)
4448 {
4449 	struct rtw89_btc *btc = &rtwdev->btc;
4450 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4451 	struct rtw89_btc_wl_sta_iter_data data = {.rtwdev = rtwdev};
4452 	u8 i;
4453 
4454 	ieee80211_iterate_stations_atomic(rtwdev->hw,
4455 					  rtw89_btc_ntfy_wl_sta_iter,
4456 					  &data);
4457 
4458 	wl->rssi_level = 0;
4459 	btc->dm.cnt_notify[BTC_NCNT_WL_STA]++;
4460 	for (i = BTC_WL_RSSI_THMAX; i > 0; i--) {
4461 		/* set RSSI level 4 ~ 0 if rssi bit map match */
4462 		if (data.rssi_map_all & BIT(i - 1)) {
4463 			wl->rssi_level = i;
4464 			break;
4465 		}
4466 	}
4467 
4468 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): busy=%d\n",
4469 		    __func__, !!wl->status.map.busy);
4470 
4471 	_write_scbd(rtwdev, BTC_WSCB_WLBUSY, (!!wl->status.map.busy));
4472 
4473 	if (data.is_traffic_change)
4474 		_fw_set_drv_info(rtwdev, CXDRVINFO_ROLE);
4475 	if (data.is_sta_change) {
4476 		wl->status.map.busy = data.busy_all;
4477 		wl->status.map.traffic_dir = data.dir_all;
4478 		_run_coex(rtwdev, BTC_RSN_NTFY_WL_STA);
4479 	} else if (btc->dm.cnt_notify[BTC_NCNT_WL_STA] >=
4480 		   btc->dm.cnt_dm[BTC_DCNT_WL_STA_LAST] + BTC_NHM_CHK_INTVL) {
4481 		btc->dm.cnt_dm[BTC_DCNT_WL_STA_LAST] =
4482 			btc->dm.cnt_notify[BTC_NCNT_WL_STA];
4483 	} else if (btc->dm.cnt_notify[BTC_NCNT_WL_STA] <
4484 		   btc->dm.cnt_dm[BTC_DCNT_WL_STA_LAST]) {
4485 		btc->dm.cnt_dm[BTC_DCNT_WL_STA_LAST] =
4486 		btc->dm.cnt_notify[BTC_NCNT_WL_STA];
4487 	}
4488 }
4489 
4490 void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
4491 			  u32 len, u8 class, u8 func)
4492 {
4493 	struct rtw89_btc *btc = &rtwdev->btc;
4494 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
4495 	u8 *buf = &skb->data[RTW89_C2H_HEADER_LEN];
4496 
4497 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
4498 		    "[BTC], %s(): C2H BT len:%d class:%d fun:%d\n",
4499 		    __func__, len, class, func);
4500 
4501 	if (class != BTFC_FW_EVENT)
4502 		return;
4503 
4504 	switch (func) {
4505 	case BTF_EVNT_RPT:
4506 	case BTF_EVNT_BUF_OVERFLOW:
4507 		pfwinfo->event[func]++;
4508 		/* Don't need rtw89_leave_ps_mode() */
4509 		btc_fw_event(rtwdev, func, buf, len);
4510 		break;
4511 	case BTF_EVNT_BT_INFO:
4512 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4513 			    "[BTC], handle C2H BT INFO with data %8ph\n", buf);
4514 		btc->cx.cnt_bt[BTC_BCNT_INFOUPDATE]++;
4515 		rtw89_leave_ps_mode(rtwdev);
4516 		_update_bt_info(rtwdev, buf, len);
4517 		break;
4518 	case BTF_EVNT_BT_SCBD:
4519 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4520 			    "[BTC], handle C2H BT SCBD with data %8ph\n", buf);
4521 		btc->cx.cnt_bt[BTC_BCNT_SCBDUPDATE]++;
4522 		rtw89_leave_ps_mode(rtwdev);
4523 		_update_bt_scbd(rtwdev, false);
4524 		break;
4525 	case BTF_EVNT_BT_PSD:
4526 		break;
4527 	case BTF_EVNT_BT_REG:
4528 		btc->dbg.rb_done = true;
4529 		btc->dbg.rb_val = le32_to_cpu(*((__le32 *)buf));
4530 
4531 		break;
4532 	case BTF_EVNT_C2H_LOOPBACK:
4533 		btc->dbg.rb_done = true;
4534 		btc->dbg.rb_val = buf[0];
4535 		break;
4536 	case BTF_EVNT_CX_RUNINFO:
4537 		btc->dm.cnt_dm[BTC_DCNT_CX_RUNINFO]++;
4538 		break;
4539 	}
4540 }
4541 
4542 #define BTC_CX_FW_OFFLOAD 0
4543 
4544 static void _show_cx_info(struct rtw89_dev *rtwdev, struct seq_file *m)
4545 {
4546 	const struct rtw89_chip_info *chip = rtwdev->chip;
4547 	struct rtw89_hal *hal = &rtwdev->hal;
4548 	struct rtw89_btc *btc = &rtwdev->btc;
4549 	struct rtw89_btc_dm *dm = &btc->dm;
4550 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
4551 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4552 	u32 ver_main = 0, ver_sub = 0, ver_hotfix = 0, id_branch = 0;
4553 
4554 	if (!(dm->coex_info_map & BTC_COEX_INFO_CX))
4555 		return;
4556 
4557 	dm->cnt_notify[BTC_NCNT_SHOW_COEX_INFO]++;
4558 
4559 	seq_printf(m, "========== [BTC COEX INFO (%d)] ==========\n",
4560 		   chip->chip_id);
4561 
4562 	ver_main = FIELD_GET(GENMASK(31, 24), chip->para_ver);
4563 	ver_sub = FIELD_GET(GENMASK(23, 16), chip->para_ver);
4564 	ver_hotfix = FIELD_GET(GENMASK(15, 8), chip->para_ver);
4565 	id_branch = FIELD_GET(GENMASK(7, 0), chip->para_ver);
4566 	seq_printf(m, " %-15s : Coex:%d.%d.%d(branch:%d), ",
4567 		   "[coex_version]", ver_main, ver_sub, ver_hotfix, id_branch);
4568 
4569 	if (dm->wl_fw_cx_offload != BTC_CX_FW_OFFLOAD)
4570 		dm->error.map.offload_mismatch = true;
4571 	else
4572 		dm->error.map.offload_mismatch = false;
4573 
4574 	ver_main = FIELD_GET(GENMASK(31, 24), wl->ver_info.fw_coex);
4575 	ver_sub = FIELD_GET(GENMASK(23, 16), wl->ver_info.fw_coex);
4576 	ver_hotfix = FIELD_GET(GENMASK(15, 8), wl->ver_info.fw_coex);
4577 	id_branch = FIELD_GET(GENMASK(7, 0), wl->ver_info.fw_coex);
4578 	seq_printf(m, "WL_FW_coex:%d.%d.%d(branch:%d)",
4579 		   ver_main, ver_sub, ver_hotfix, id_branch);
4580 
4581 	ver_main = FIELD_GET(GENMASK(31, 24), chip->wlcx_desired);
4582 	ver_sub = FIELD_GET(GENMASK(23, 16), chip->wlcx_desired);
4583 	ver_hotfix = FIELD_GET(GENMASK(15, 8), chip->wlcx_desired);
4584 	seq_printf(m, "(%s, desired:%d.%d.%d), ",
4585 		   (wl->ver_info.fw_coex >= chip->wlcx_desired ?
4586 		   "Match" : "Mis-Match"), ver_main, ver_sub, ver_hotfix);
4587 
4588 	seq_printf(m, "BT_FW_coex:%d(%s, desired:%d)\n",
4589 		   bt->ver_info.fw_coex,
4590 		   (bt->ver_info.fw_coex >= chip->btcx_desired ?
4591 		   "Match" : "Mis-Match"), chip->btcx_desired);
4592 
4593 	if (bt->enable.now && bt->ver_info.fw == 0)
4594 		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_VER_INFO, true);
4595 	else
4596 		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_VER_INFO, false);
4597 
4598 	ver_main = FIELD_GET(GENMASK(31, 24), wl->ver_info.fw);
4599 	ver_sub = FIELD_GET(GENMASK(23, 16), wl->ver_info.fw);
4600 	ver_hotfix = FIELD_GET(GENMASK(15, 8), wl->ver_info.fw);
4601 	id_branch = FIELD_GET(GENMASK(7, 0), wl->ver_info.fw);
4602 	seq_printf(m, " %-15s : WL_FW:%d.%d.%d.%d, BT_FW:0x%x(%s)\n",
4603 		   "[sub_module]",
4604 		   ver_main, ver_sub, ver_hotfix, id_branch,
4605 		   bt->ver_info.fw, bt->run_patch_code ? "patch" : "ROM");
4606 
4607 	seq_printf(m, " %-15s : cv:%x, rfe_type:0x%x, ant_iso:%d, ant_pg:%d, %s",
4608 		   "[hw_info]", btc->mdinfo.cv, btc->mdinfo.rfe_type,
4609 		   btc->mdinfo.ant.isolation, btc->mdinfo.ant.num,
4610 		   (btc->mdinfo.ant.num > 1 ? "" : (btc->mdinfo.ant.single_pos ?
4611 		   "1Ant_Pos:S1, " : "1Ant_Pos:S0, ")));
4612 
4613 	seq_printf(m, "3rd_coex:%d, dbcc:%d, tx_num:%d, rx_num:%d\n",
4614 		   btc->cx.other.type, rtwdev->dbcc_en, hal->tx_nss,
4615 		   hal->rx_nss);
4616 }
4617 
4618 static void _show_wl_role_info(struct rtw89_dev *rtwdev, struct seq_file *m)
4619 {
4620 	struct rtw89_btc *btc = &rtwdev->btc;
4621 	struct rtw89_btc_wl_link_info *plink = NULL;
4622 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4623 	struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
4624 	struct rtw89_traffic_stats *t;
4625 	u8 i;
4626 
4627 	if (rtwdev->dbcc_en) {
4628 		seq_printf(m,
4629 			   " %-15s : PHY0_band(op:%d/scan:%d/real:%d), ",
4630 			   "[dbcc_info]", wl_dinfo->op_band[RTW89_PHY_0],
4631 			   wl_dinfo->scan_band[RTW89_PHY_0],
4632 			   wl_dinfo->real_band[RTW89_PHY_0]);
4633 		seq_printf(m,
4634 			   "PHY1_band(op:%d/scan:%d/real:%d)\n",
4635 			   wl_dinfo->op_band[RTW89_PHY_1],
4636 			   wl_dinfo->scan_band[RTW89_PHY_1],
4637 			   wl_dinfo->real_band[RTW89_PHY_1]);
4638 	}
4639 
4640 	for (i = 0; i < RTW89_MAX_HW_PORT_NUM; i++) {
4641 		plink = &btc->cx.wl.link_info[i];
4642 
4643 		if (!plink->active)
4644 			continue;
4645 
4646 		seq_printf(m,
4647 			   " [port_%d]        : role=%d(phy-%d), connect=%d(client_cnt=%d), mode=%d, center_ch=%d, bw=%d",
4648 			   plink->pid, (u32)plink->role, plink->phy,
4649 			   (u32)plink->connected, plink->client_cnt - 1,
4650 			   (u32)plink->mode, plink->ch, (u32)plink->bw);
4651 
4652 		if (plink->connected == MLME_NO_LINK)
4653 			continue;
4654 
4655 		seq_printf(m,
4656 			   ", mac_id=%d, max_tx_time=%dus, max_tx_retry=%d\n",
4657 			   plink->mac_id, plink->tx_time, plink->tx_retry);
4658 
4659 		seq_printf(m,
4660 			   " [port_%d]        : rssi=-%ddBm(%d), busy=%d, dir=%s, ",
4661 			   plink->pid, 110 - plink->stat.rssi,
4662 			   plink->stat.rssi, plink->busy,
4663 			   plink->dir == RTW89_TFC_UL ? "UL" : "DL");
4664 
4665 		t = &plink->stat.traffic;
4666 
4667 		seq_printf(m,
4668 			   "tx[rate:%d/busy_level:%d], ",
4669 			   (u32)t->tx_rate, t->tx_tfc_lv);
4670 
4671 		seq_printf(m, "rx[rate:%d/busy_level:%d/drop:%d]\n",
4672 			   (u32)t->rx_rate,
4673 			   t->rx_tfc_lv, plink->rx_rate_drop_cnt);
4674 	}
4675 }
4676 
4677 static void _show_wl_info(struct rtw89_dev *rtwdev, struct seq_file *m)
4678 {
4679 	struct rtw89_btc *btc = &rtwdev->btc;
4680 	struct rtw89_btc_cx *cx = &btc->cx;
4681 	struct rtw89_btc_wl_info *wl = &cx->wl;
4682 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
4683 
4684 	if (!(btc->dm.coex_info_map & BTC_COEX_INFO_WL))
4685 		return;
4686 
4687 	seq_puts(m, "========== [WL Status] ==========\n");
4688 
4689 	seq_printf(m, " %-15s : link_mode:%d, ",
4690 		   "[status]", (u32)wl_rinfo->link_mode);
4691 
4692 	seq_printf(m,
4693 		   "rf_off:%s, power_save:%s, scan:%s(band:%d/phy_map:0x%x), ",
4694 		   wl->status.map.rf_off ? "Y" : "N",
4695 		   wl->status.map.lps ? "Y" : "N",
4696 		   wl->status.map.scan ? "Y" : "N",
4697 		   wl->scan_info.band[RTW89_PHY_0], wl->scan_info.phy_map);
4698 
4699 	seq_printf(m,
4700 		   "connecting:%s, roam:%s, 4way:%s, init_ok:%s\n",
4701 		   wl->status.map.connecting ? "Y" : "N",
4702 		   wl->status.map.roaming ?  "Y" : "N",
4703 		   wl->status.map._4way ? "Y" : "N",
4704 		   wl->status.map.init_ok ? "Y" : "N");
4705 
4706 	_show_wl_role_info(rtwdev, m);
4707 }
4708 
4709 enum btc_bt_a2dp_type {
4710 	BTC_A2DP_LEGACY = 0,
4711 	BTC_A2DP_TWS_SNIFF = 1,
4712 	BTC_A2DP_TWS_RELAY = 2,
4713 };
4714 
4715 static void _show_bt_profile_info(struct rtw89_dev *rtwdev, struct seq_file *m)
4716 {
4717 	struct rtw89_btc *btc = &rtwdev->btc;
4718 	struct rtw89_btc_bt_link_info *bt_linfo = &btc->cx.bt.link_info;
4719 	struct rtw89_btc_bt_hfp_desc hfp = bt_linfo->hfp_desc;
4720 	struct rtw89_btc_bt_hid_desc hid = bt_linfo->hid_desc;
4721 	struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc;
4722 	struct rtw89_btc_bt_pan_desc pan = bt_linfo->pan_desc;
4723 
4724 	if (hfp.exist) {
4725 		seq_printf(m, " %-15s : type:%s, sut_pwr:%d, golden-rx:%d",
4726 			   "[HFP]", (hfp.type == 0 ? "SCO" : "eSCO"),
4727 			   bt_linfo->sut_pwr_level[0],
4728 			   bt_linfo->golden_rx_shift[0]);
4729 	}
4730 
4731 	if (hid.exist) {
4732 		seq_printf(m,
4733 			   "\n\r %-15s : type:%s%s%s%s%s pair-cnt:%d, sut_pwr:%d, golden-rx:%d\n",
4734 			   "[HID]",
4735 			   hid.type & BTC_HID_218 ? "2/18," : "",
4736 			   hid.type & BTC_HID_418 ? "4/18," : "",
4737 			   hid.type & BTC_HID_BLE ? "BLE," : "",
4738 			   hid.type & BTC_HID_RCU ? "RCU," : "",
4739 			   hid.type & BTC_HID_RCU_VOICE ? "RCU-Voice," : "",
4740 			   hid.pair_cnt, bt_linfo->sut_pwr_level[1],
4741 			   bt_linfo->golden_rx_shift[1]);
4742 	}
4743 
4744 	if (a2dp.exist) {
4745 		seq_printf(m,
4746 			   " %-15s : type:%s, bit-pool:%d, flush-time:%d, ",
4747 			   "[A2DP]",
4748 			   a2dp.type == BTC_A2DP_LEGACY ? "Legacy" : "TWS",
4749 			    a2dp.bitpool, a2dp.flush_time);
4750 
4751 		seq_printf(m,
4752 			   "vid:0x%x, Dev-name:0x%x, sut_pwr:%d, golden-rx:%d\n",
4753 			   a2dp.vendor_id, a2dp.device_name,
4754 			   bt_linfo->sut_pwr_level[2],
4755 			   bt_linfo->golden_rx_shift[2]);
4756 	}
4757 
4758 	if (pan.exist) {
4759 		seq_printf(m, " %-15s : sut_pwr:%d, golden-rx:%d\n",
4760 			   "[PAN]",
4761 			   bt_linfo->sut_pwr_level[3],
4762 			   bt_linfo->golden_rx_shift[3]);
4763 	}
4764 }
4765 
4766 static void _show_bt_info(struct rtw89_dev *rtwdev, struct seq_file *m)
4767 {
4768 	const struct rtw89_chip_info *chip = rtwdev->chip;
4769 	struct rtw89_btc *btc = &rtwdev->btc;
4770 	struct rtw89_btc_cx *cx = &btc->cx;
4771 	struct rtw89_btc_bt_info *bt = &cx->bt;
4772 	struct rtw89_btc_wl_info *wl = &cx->wl;
4773 	struct rtw89_btc_module *module = &btc->mdinfo;
4774 	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
4775 	u8 *afh = bt_linfo->afh_map;
4776 	u16 polt_cnt = 0;
4777 
4778 	if (!(btc->dm.coex_info_map & BTC_COEX_INFO_BT))
4779 		return;
4780 
4781 	seq_puts(m, "========== [BT Status] ==========\n");
4782 
4783 	seq_printf(m, " %-15s : enable:%s, btg:%s%s, connect:%s, ",
4784 		   "[status]", bt->enable.now ? "Y" : "N",
4785 		   bt->btg_type ? "Y" : "N",
4786 		   (bt->enable.now && (bt->btg_type != module->bt_pos) ?
4787 		   "(efuse-mismatch!!)" : ""),
4788 		   (bt_linfo->status.map.connect ? "Y" : "N"));
4789 
4790 	seq_printf(m, "igno_wl:%s, mailbox_avl:%s, rfk_state:0x%x\n",
4791 		   bt->igno_wl ? "Y" : "N",
4792 		   bt->mbx_avl ? "Y" : "N", bt->rfk_info.val);
4793 
4794 	seq_printf(m, " %-15s : profile:%s%s%s%s%s ",
4795 		   "[profile]",
4796 		   (bt_linfo->profile_cnt.now == 0) ? "None," : "",
4797 		   bt_linfo->hfp_desc.exist ? "HFP," : "",
4798 		   bt_linfo->hid_desc.exist ? "HID," : "",
4799 		   bt_linfo->a2dp_desc.exist ?
4800 		   (bt_linfo->a2dp_desc.sink ? "A2DP_sink," : "A2DP,") : "",
4801 		   bt_linfo->pan_desc.exist ? "PAN," : "");
4802 
4803 	seq_printf(m,
4804 		   "multi-link:%s, role:%s, ble-connect:%s, CQDDR:%s, A2DP_active:%s, PAN_active:%s\n",
4805 		   bt_linfo->multi_link.now ? "Y" : "N",
4806 		   bt_linfo->slave_role ? "Slave" : "Master",
4807 		   bt_linfo->status.map.ble_connect ? "Y" : "N",
4808 		   bt_linfo->cqddr ? "Y" : "N",
4809 		   bt_linfo->a2dp_desc.active ? "Y" : "N",
4810 		   bt_linfo->pan_desc.active ? "Y" : "N");
4811 
4812 	seq_printf(m,
4813 		   " %-15s : rssi:%ddBm, tx_rate:%dM, %s%s%s",
4814 		   "[link]", bt_linfo->rssi - 100,
4815 		   bt_linfo->tx_3m ? 3 : 2,
4816 		   bt_linfo->status.map.inq_pag ? " inq-page!!" : "",
4817 		   bt_linfo->status.map.acl_busy ? " acl_busy!!" : "",
4818 		   bt_linfo->status.map.mesh_busy ? " mesh_busy!!" : "");
4819 
4820 	seq_printf(m,
4821 		   "%s afh_map[%02x%02x_%02x%02x_%02x%02x_%02x%02x_%02x%02x], ",
4822 		   bt_linfo->relink.now ? " ReLink!!" : "",
4823 		   afh[0], afh[1], afh[2], afh[3], afh[4],
4824 		   afh[5], afh[6], afh[7], afh[8], afh[9]);
4825 
4826 	seq_printf(m, "wl_ch_map[en:%d/ch:%d/bw:%d]\n",
4827 		   wl->afh_info.en, wl->afh_info.ch, wl->afh_info.bw);
4828 
4829 	seq_printf(m,
4830 		   " %-15s : retry:%d, relink:%d, rate_chg:%d, reinit:%d, reenable:%d, ",
4831 		   "[stat_cnt]", cx->cnt_bt[BTC_BCNT_RETRY],
4832 		   cx->cnt_bt[BTC_BCNT_RELINK], cx->cnt_bt[BTC_BCNT_RATECHG],
4833 		   cx->cnt_bt[BTC_BCNT_REINIT], cx->cnt_bt[BTC_BCNT_REENABLE]);
4834 
4835 	seq_printf(m,
4836 		   "role-switch:%d, afh:%d, inq_page:%d(inq:%d/page:%d), igno_wl:%d\n",
4837 		   cx->cnt_bt[BTC_BCNT_ROLESW], cx->cnt_bt[BTC_BCNT_AFH],
4838 		   cx->cnt_bt[BTC_BCNT_INQPAG], cx->cnt_bt[BTC_BCNT_INQ],
4839 		   cx->cnt_bt[BTC_BCNT_PAGE], cx->cnt_bt[BTC_BCNT_IGNOWL]);
4840 
4841 	_show_bt_profile_info(rtwdev, m);
4842 
4843 	seq_printf(m,
4844 		   " %-15s : raw_data[%02x %02x %02x %02x %02x %02x] (type:%s/cnt:%d/same:%d)\n",
4845 		   "[bt_info]", bt->raw_info[2], bt->raw_info[3],
4846 		   bt->raw_info[4], bt->raw_info[5], bt->raw_info[6],
4847 		   bt->raw_info[7],
4848 		   bt->raw_info[0] == BTC_BTINFO_AUTO ? "auto" : "reply",
4849 		   cx->cnt_bt[BTC_BCNT_INFOUPDATE],
4850 		   cx->cnt_bt[BTC_BCNT_INFOSAME]);
4851 
4852 	if (wl->status.map.lps || wl->status.map.rf_off)
4853 		return;
4854 
4855 	chip->ops->btc_update_bt_cnt(rtwdev);
4856 	_chk_btc_err(rtwdev, BTC_DCNT_BTCNT_FREEZE, 0);
4857 
4858 	seq_printf(m,
4859 		   " %-15s : Hi-rx = %d, Hi-tx = %d, Lo-rx = %d, Lo-tx = %d (bt_polut_wl_tx = %d)\n",
4860 		   "[trx_req_cnt]", cx->cnt_bt[BTC_BCNT_HIPRI_RX],
4861 		   cx->cnt_bt[BTC_BCNT_HIPRI_TX], cx->cnt_bt[BTC_BCNT_LOPRI_RX],
4862 		   cx->cnt_bt[BTC_BCNT_LOPRI_TX], polt_cnt);
4863 }
4864 
4865 #define CASE_BTC_RSN_STR(e) case BTC_RSN_ ## e: return #e
4866 #define CASE_BTC_ACT_STR(e) case BTC_ACT_ ## e | BTC_ACT_EXT_BIT: return #e
4867 #define CASE_BTC_POLICY_STR(e) \
4868 	case BTC_CXP_ ## e | BTC_POLICY_EXT_BIT: return #e
4869 
4870 static const char *steps_to_str(u16 step)
4871 {
4872 	switch (step) {
4873 	CASE_BTC_RSN_STR(NONE);
4874 	CASE_BTC_RSN_STR(NTFY_INIT);
4875 	CASE_BTC_RSN_STR(NTFY_SWBAND);
4876 	CASE_BTC_RSN_STR(NTFY_WL_STA);
4877 	CASE_BTC_RSN_STR(NTFY_RADIO_STATE);
4878 	CASE_BTC_RSN_STR(UPDATE_BT_SCBD);
4879 	CASE_BTC_RSN_STR(NTFY_WL_RFK);
4880 	CASE_BTC_RSN_STR(UPDATE_BT_INFO);
4881 	CASE_BTC_RSN_STR(NTFY_SCAN_START);
4882 	CASE_BTC_RSN_STR(NTFY_SCAN_FINISH);
4883 	CASE_BTC_RSN_STR(NTFY_SPECIFIC_PACKET);
4884 	CASE_BTC_RSN_STR(NTFY_POWEROFF);
4885 	CASE_BTC_RSN_STR(NTFY_ROLE_INFO);
4886 	CASE_BTC_RSN_STR(CMD_SET_COEX);
4887 	CASE_BTC_RSN_STR(ACT1_WORK);
4888 	CASE_BTC_RSN_STR(BT_DEVINFO_WORK);
4889 	CASE_BTC_RSN_STR(RFK_CHK_WORK);
4890 
4891 	CASE_BTC_ACT_STR(NONE);
4892 	CASE_BTC_ACT_STR(WL_ONLY);
4893 	CASE_BTC_ACT_STR(WL_5G);
4894 	CASE_BTC_ACT_STR(WL_OTHER);
4895 	CASE_BTC_ACT_STR(WL_IDLE);
4896 	CASE_BTC_ACT_STR(WL_NC);
4897 	CASE_BTC_ACT_STR(WL_RFK);
4898 	CASE_BTC_ACT_STR(WL_INIT);
4899 	CASE_BTC_ACT_STR(WL_OFF);
4900 	CASE_BTC_ACT_STR(FREERUN);
4901 	CASE_BTC_ACT_STR(BT_WHQL);
4902 	CASE_BTC_ACT_STR(BT_RFK);
4903 	CASE_BTC_ACT_STR(BT_OFF);
4904 	CASE_BTC_ACT_STR(BT_IDLE);
4905 	CASE_BTC_ACT_STR(BT_HFP);
4906 	CASE_BTC_ACT_STR(BT_HID);
4907 	CASE_BTC_ACT_STR(BT_A2DP);
4908 	CASE_BTC_ACT_STR(BT_A2DPSINK);
4909 	CASE_BTC_ACT_STR(BT_PAN);
4910 	CASE_BTC_ACT_STR(BT_A2DP_HID);
4911 	CASE_BTC_ACT_STR(BT_A2DP_PAN);
4912 	CASE_BTC_ACT_STR(BT_PAN_HID);
4913 	CASE_BTC_ACT_STR(BT_A2DP_PAN_HID);
4914 	CASE_BTC_ACT_STR(WL_25G_MCC);
4915 	CASE_BTC_ACT_STR(WL_2G_MCC);
4916 	CASE_BTC_ACT_STR(WL_2G_SCC);
4917 	CASE_BTC_ACT_STR(WL_2G_AP);
4918 	CASE_BTC_ACT_STR(WL_2G_GO);
4919 	CASE_BTC_ACT_STR(WL_2G_GC);
4920 	CASE_BTC_ACT_STR(WL_2G_NAN);
4921 
4922 	CASE_BTC_POLICY_STR(OFF_BT);
4923 	CASE_BTC_POLICY_STR(OFF_WL);
4924 	CASE_BTC_POLICY_STR(OFF_EQ0);
4925 	CASE_BTC_POLICY_STR(OFF_EQ1);
4926 	CASE_BTC_POLICY_STR(OFF_EQ2);
4927 	CASE_BTC_POLICY_STR(OFF_EQ3);
4928 	CASE_BTC_POLICY_STR(OFF_BWB0);
4929 	CASE_BTC_POLICY_STR(OFF_BWB1);
4930 	CASE_BTC_POLICY_STR(OFFB_BWB0);
4931 	CASE_BTC_POLICY_STR(OFFE_DEF);
4932 	CASE_BTC_POLICY_STR(OFFE_DEF2);
4933 	CASE_BTC_POLICY_STR(FIX_TD3030);
4934 	CASE_BTC_POLICY_STR(FIX_TD5050);
4935 	CASE_BTC_POLICY_STR(FIX_TD2030);
4936 	CASE_BTC_POLICY_STR(FIX_TD4010);
4937 	CASE_BTC_POLICY_STR(FIX_TD7010);
4938 	CASE_BTC_POLICY_STR(FIX_TD2060);
4939 	CASE_BTC_POLICY_STR(FIX_TD3060);
4940 	CASE_BTC_POLICY_STR(FIX_TD2080);
4941 	CASE_BTC_POLICY_STR(FIX_TDW1B1);
4942 	CASE_BTC_POLICY_STR(FIX_TD4020);
4943 	CASE_BTC_POLICY_STR(PFIX_TD3030);
4944 	CASE_BTC_POLICY_STR(PFIX_TD5050);
4945 	CASE_BTC_POLICY_STR(PFIX_TD2030);
4946 	CASE_BTC_POLICY_STR(PFIX_TD2060);
4947 	CASE_BTC_POLICY_STR(PFIX_TD3070);
4948 	CASE_BTC_POLICY_STR(PFIX_TD2080);
4949 	CASE_BTC_POLICY_STR(PFIX_TDW1B1);
4950 	CASE_BTC_POLICY_STR(AUTO_TD50200);
4951 	CASE_BTC_POLICY_STR(AUTO_TD60200);
4952 	CASE_BTC_POLICY_STR(AUTO_TD20200);
4953 	CASE_BTC_POLICY_STR(AUTO_TDW1B1);
4954 	CASE_BTC_POLICY_STR(PAUTO_TD50200);
4955 	CASE_BTC_POLICY_STR(PAUTO_TD60200);
4956 	CASE_BTC_POLICY_STR(PAUTO_TD20200);
4957 	CASE_BTC_POLICY_STR(PAUTO_TDW1B1);
4958 	CASE_BTC_POLICY_STR(AUTO2_TD3050);
4959 	CASE_BTC_POLICY_STR(AUTO2_TD3070);
4960 	CASE_BTC_POLICY_STR(AUTO2_TD5050);
4961 	CASE_BTC_POLICY_STR(AUTO2_TD6060);
4962 	CASE_BTC_POLICY_STR(AUTO2_TD2080);
4963 	CASE_BTC_POLICY_STR(AUTO2_TDW1B4);
4964 	CASE_BTC_POLICY_STR(PAUTO2_TD3050);
4965 	CASE_BTC_POLICY_STR(PAUTO2_TD3070);
4966 	CASE_BTC_POLICY_STR(PAUTO2_TD5050);
4967 	CASE_BTC_POLICY_STR(PAUTO2_TD6060);
4968 	CASE_BTC_POLICY_STR(PAUTO2_TD2080);
4969 	CASE_BTC_POLICY_STR(PAUTO2_TDW1B4);
4970 	default:
4971 		return "unknown step";
4972 	}
4973 }
4974 
4975 static
4976 void seq_print_segment(struct seq_file *m, const char *prefix, u16 *data,
4977 		       u8 len, u8 seg_len, u8 start_idx, u8 ring_len)
4978 {
4979 	u8 i;
4980 	u8 cur_index;
4981 
4982 	for (i = 0; i < len ; i++) {
4983 		if ((i % seg_len) == 0)
4984 			seq_printf(m, " %-15s : ", prefix);
4985 		cur_index = (start_idx + i) % ring_len;
4986 		if (i % 3 == 0)
4987 			seq_printf(m, "-> %-20s",
4988 				   steps_to_str(*(data + cur_index)));
4989 		else if (i % 3 == 1)
4990 			seq_printf(m, "-> %-15s",
4991 				   steps_to_str(*(data + cur_index)));
4992 		else
4993 			seq_printf(m, "-> %-13s",
4994 				   steps_to_str(*(data + cur_index)));
4995 		if (i == (len - 1) || (i % seg_len) == (seg_len - 1))
4996 			seq_puts(m, "\n");
4997 	}
4998 }
4999 
5000 static void _show_dm_step(struct rtw89_dev *rtwdev, struct seq_file *m)
5001 {
5002 	struct rtw89_btc *btc = &rtwdev->btc;
5003 	struct rtw89_btc_dm *dm = &btc->dm;
5004 	u8 start_idx;
5005 	u8 len;
5006 
5007 	len = dm->dm_step.step_ov ? RTW89_BTC_DM_MAXSTEP : dm->dm_step.step_pos;
5008 	start_idx = dm->dm_step.step_ov ? dm->dm_step.step_pos : 0;
5009 
5010 	seq_print_segment(m, "[dm_steps]", dm->dm_step.step, len, 6, start_idx,
5011 			  ARRAY_SIZE(dm->dm_step.step));
5012 }
5013 
5014 static void _show_dm_info(struct rtw89_dev *rtwdev, struct seq_file *m)
5015 {
5016 	struct rtw89_btc *btc = &rtwdev->btc;
5017 	struct rtw89_btc_module *module = &btc->mdinfo;
5018 	struct rtw89_btc_dm *dm = &btc->dm;
5019 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
5020 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
5021 
5022 	if (!(dm->coex_info_map & BTC_COEX_INFO_DM))
5023 		return;
5024 
5025 	seq_printf(m, "========== [Mechanism Status %s] ==========\n",
5026 		   (btc->ctrl.manual ? "(Manual)" : "(Auto)"));
5027 
5028 	seq_printf(m,
5029 		   " %-15s : type:%s, reason:%s(), action:%s(), ant_path:%ld, run_cnt:%d\n",
5030 		   "[status]",
5031 		   module->ant.type == BTC_ANT_SHARED ? "shared" : "dedicated",
5032 		   steps_to_str(dm->run_reason),
5033 		   steps_to_str(dm->run_action | BTC_ACT_EXT_BIT),
5034 		   FIELD_GET(GENMASK(7, 0), dm->set_ant_path),
5035 		   dm->cnt_dm[BTC_DCNT_RUN]);
5036 
5037 	_show_dm_step(rtwdev, m);
5038 
5039 	seq_printf(m, " %-15s : wl_only:%d, bt_only:%d, igno_bt:%d, free_run:%d, wl_ps_ctrl:%d, wl_mimo_ps:%d, ",
5040 		   "[dm_flag]", dm->wl_only, dm->bt_only, btc->ctrl.igno_bt,
5041 		   dm->freerun, btc->lps, dm->wl_mimo_ps);
5042 
5043 	seq_printf(m, "leak_ap:%d, fw_offload:%s%s\n", dm->leak_ap,
5044 		   (BTC_CX_FW_OFFLOAD ? "Y" : "N"),
5045 		   (dm->wl_fw_cx_offload == BTC_CX_FW_OFFLOAD ?
5046 		    "" : "(Mis-Match!!)"));
5047 
5048 	if (dm->rf_trx_para.wl_tx_power == 0xff)
5049 		seq_printf(m,
5050 			   " %-15s : wl_rssi_lvl:%d, para_lvl:%d, wl_tx_pwr:orig, ",
5051 			   "[trx_ctrl]", wl->rssi_level, dm->trx_para_level);
5052 
5053 	else
5054 		seq_printf(m,
5055 			   " %-15s : wl_rssi_lvl:%d, para_lvl:%d, wl_tx_pwr:%d, ",
5056 			   "[trx_ctrl]", wl->rssi_level, dm->trx_para_level,
5057 			   dm->rf_trx_para.wl_tx_power);
5058 
5059 	seq_printf(m,
5060 		   "wl_rx_lvl:%d, bt_tx_pwr_dec:%d, bt_rx_lna:%d(%s-tbl), wl_btg_rx:%d\n",
5061 		   dm->rf_trx_para.wl_rx_gain, dm->rf_trx_para.bt_tx_power,
5062 		   dm->rf_trx_para.bt_rx_gain,
5063 		   (bt->hi_lna_rx ? "Hi" : "Ori"), dm->wl_btg_rx);
5064 
5065 	seq_printf(m,
5066 		   " %-15s : wl_tx_limit[en:%d/max_t:%dus/max_retry:%d], bt_slot_reg:%d-TU\n",
5067 		   "[dm_ctrl]", dm->wl_tx_limit.enable, dm->wl_tx_limit.tx_time,
5068 		   dm->wl_tx_limit.tx_retry, btc->bt_req_len);
5069 }
5070 
5071 static void _show_error(struct rtw89_dev *rtwdev, struct seq_file *m)
5072 {
5073 	struct rtw89_btc *btc = &rtwdev->btc;
5074 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
5075 	struct rtw89_btc_fbtc_cysta *pcysta = NULL;
5076 
5077 	pcysta = &pfwinfo->rpt_fbtc_cysta.finfo;
5078 
5079 	if (pfwinfo->event[BTF_EVNT_BUF_OVERFLOW] == 0 &&
5080 	    pcysta->except_cnt == 0 &&
5081 	    !pfwinfo->len_mismch && !pfwinfo->fver_mismch)
5082 		return;
5083 
5084 	seq_printf(m, " %-15s : ", "[error]");
5085 
5086 	if (pfwinfo->event[BTF_EVNT_BUF_OVERFLOW]) {
5087 		seq_printf(m,
5088 			   "overflow-cnt: %d, ",
5089 			   pfwinfo->event[BTF_EVNT_BUF_OVERFLOW]);
5090 	}
5091 
5092 	if (pfwinfo->len_mismch) {
5093 		seq_printf(m,
5094 			   "len-mismatch: 0x%x, ",
5095 			   pfwinfo->len_mismch);
5096 	}
5097 
5098 	if (pfwinfo->fver_mismch) {
5099 		seq_printf(m,
5100 			   "fver-mismatch: 0x%x, ",
5101 			   pfwinfo->fver_mismch);
5102 	}
5103 
5104 	/* cycle statistics exceptions */
5105 	if (pcysta->exception || pcysta->except_cnt) {
5106 		seq_printf(m,
5107 			   "exception-type: 0x%x, exception-cnt = %d",
5108 			   pcysta->exception, pcysta->except_cnt);
5109 	}
5110 	seq_puts(m, "\n");
5111 }
5112 
5113 static void _show_fbtc_tdma(struct rtw89_dev *rtwdev, struct seq_file *m)
5114 {
5115 	struct rtw89_btc *btc = &rtwdev->btc;
5116 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
5117 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
5118 	struct rtw89_btc_fbtc_tdma *t = NULL;
5119 	struct rtw89_btc_fbtc_slot *s = NULL;
5120 	struct rtw89_btc_dm *dm = &btc->dm;
5121 	u8 i, cnt = 0;
5122 
5123 	pcinfo = &pfwinfo->rpt_fbtc_tdma.cinfo;
5124 	if (!pcinfo->valid)
5125 		return;
5126 
5127 	t = &pfwinfo->rpt_fbtc_tdma.finfo;
5128 
5129 	seq_printf(m,
5130 		   " %-15s : ", "[tdma_policy]");
5131 	seq_printf(m,
5132 		   "type:%d, rx_flow_ctrl:%d, tx_pause:%d, ",
5133 		   (u32)t->type,
5134 		   t->rxflctrl, t->txpause);
5135 
5136 	seq_printf(m,
5137 		   "wl_toggle_n:%d, leak_n:%d, ext_ctrl:%d, ",
5138 		   t->wtgle_n, t->leak_n, t->ext_ctrl);
5139 
5140 	seq_printf(m,
5141 		   "policy_type:%d",
5142 		   (u32)btc->policy_type);
5143 
5144 	s = pfwinfo->rpt_fbtc_slots.finfo.slot;
5145 
5146 	for (i = 0; i < CXST_MAX; i++) {
5147 		if (dm->update_slot_map == BIT(CXST_MAX) - 1)
5148 			break;
5149 
5150 		if (!(dm->update_slot_map & BIT(i)))
5151 			continue;
5152 
5153 		if (cnt % 6 == 0)
5154 			seq_printf(m,
5155 				   " %-15s : %d[%d/0x%x/%d]",
5156 				   "[slot_policy]",
5157 				   (u32)i,
5158 				   s[i].dur, s[i].cxtbl, s[i].cxtype);
5159 		else
5160 			seq_printf(m,
5161 				   ", %d[%d/0x%x/%d]",
5162 				   (u32)i,
5163 				   s[i].dur, s[i].cxtbl, s[i].cxtype);
5164 		if (cnt % 6 == 5)
5165 			seq_puts(m, "\n");
5166 		cnt++;
5167 	}
5168 	seq_puts(m, "\n");
5169 }
5170 
5171 static void _show_fbtc_slots(struct rtw89_dev *rtwdev, struct seq_file *m)
5172 {
5173 	struct rtw89_btc *btc = &rtwdev->btc;
5174 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
5175 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
5176 	struct rtw89_btc_fbtc_slots *pslots = NULL;
5177 	struct rtw89_btc_fbtc_slot s;
5178 	u8 i = 0;
5179 
5180 	pcinfo = &pfwinfo->rpt_fbtc_slots.cinfo;
5181 	if (!pcinfo->valid)
5182 		return;
5183 
5184 	pslots = &pfwinfo->rpt_fbtc_slots.finfo;
5185 
5186 	for (i = 0; i < CXST_MAX; i++) {
5187 		s = pslots->slot[i];
5188 		if (i % 6 == 0)
5189 			seq_printf(m,
5190 				   " %-15s : %02d[%03d/0x%x/%d]",
5191 				   "[slot_list]",
5192 				   (u32)i,
5193 				   s.dur, s.cxtbl, s.cxtype);
5194 		else
5195 			seq_printf(m,
5196 				   ", %02d[%03d/0x%x/%d]",
5197 				   (u32)i,
5198 				   s.dur, s.cxtbl, s.cxtype);
5199 		if (i % 6 == 5)
5200 			seq_puts(m, "\n");
5201 	}
5202 }
5203 
5204 static void _show_fbtc_cysta(struct rtw89_dev *rtwdev, struct seq_file *m)
5205 {
5206 	struct rtw89_btc *btc = &rtwdev->btc;
5207 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
5208 	struct rtw89_btc_dm *dm = &btc->dm;
5209 	struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc;
5210 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
5211 	struct rtw89_btc_fbtc_cysta *pcysta_le32 = NULL;
5212 	struct rtw89_btc_fbtc_cysta_cpu pcysta[1];
5213 	union rtw89_btc_fbtc_rxflct r;
5214 	u8 i, cnt = 0, slot_pair;
5215 	u16 cycle, c_begin, c_end, store_index;
5216 
5217 	pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
5218 	if (!pcinfo->valid)
5219 		return;
5220 
5221 	pcysta_le32 = &pfwinfo->rpt_fbtc_cysta.finfo;
5222 	rtw89_btc_fbtc_cysta_to_cpu(pcysta_le32, pcysta);
5223 	seq_printf(m,
5224 		   " %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]",
5225 		   "[cycle_cnt]", pcysta->cycles, pcysta->bcn_cnt[CXBCN_ALL],
5226 		   pcysta->bcn_cnt[CXBCN_ALL_OK],
5227 		   pcysta->bcn_cnt[CXBCN_BT_SLOT],
5228 		   pcysta->bcn_cnt[CXBCN_BT_OK]);
5229 
5230 	_chk_btc_err(rtwdev, BTC_DCNT_CYCLE_FREEZE, (u32)pcysta->cycles);
5231 
5232 	for (i = 0; i < CXST_MAX; i++) {
5233 		if (!pcysta->slot_cnt[i])
5234 			continue;
5235 		seq_printf(m,
5236 			   ", %d:%d", (u32)i, pcysta->slot_cnt[i]);
5237 	}
5238 
5239 	if (dm->tdma_now.rxflctrl) {
5240 		seq_printf(m,
5241 			   ", leak_rx:%d", pcysta->leakrx_cnt);
5242 	}
5243 
5244 	if (pcysta->collision_cnt) {
5245 		seq_printf(m,
5246 			   ", collision:%d", pcysta->collision_cnt);
5247 	}
5248 
5249 	if (pcysta->skip_cnt) {
5250 		seq_printf(m,
5251 			   ", skip:%d", pcysta->skip_cnt);
5252 	}
5253 	seq_puts(m, "\n");
5254 
5255 	_chk_btc_err(rtwdev, BTC_DCNT_W1_FREEZE, pcysta->slot_cnt[CXST_W1]);
5256 	_chk_btc_err(rtwdev, BTC_DCNT_B1_FREEZE, pcysta->slot_cnt[CXST_B1]);
5257 
5258 	seq_printf(m, " %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]",
5259 		   "[cycle_time]",
5260 		   pcysta->tavg_cycle[CXT_WL],
5261 		   pcysta->tavg_cycle[CXT_BT],
5262 		   pcysta->tavg_lk / 1000, pcysta->tavg_lk % 1000);
5263 	seq_printf(m,
5264 		   ", max_t[wl:%d/bt:%d/lk:%d.%03d]",
5265 		   pcysta->tmax_cycle[CXT_WL],
5266 		   pcysta->tmax_cycle[CXT_BT],
5267 		   pcysta->tmax_lk / 1000, pcysta->tmax_lk % 1000);
5268 	seq_printf(m,
5269 		   ", maxdiff_t[wl:%d/bt:%d]\n",
5270 		   pcysta->tmaxdiff_cycle[CXT_WL],
5271 		   pcysta->tmaxdiff_cycle[CXT_BT]);
5272 
5273 	if (pcysta->cycles == 0)
5274 		return;
5275 
5276 	/* 1 cycle record 1 wl-slot and 1 bt-slot */
5277 	slot_pair = BTC_CYCLE_SLOT_MAX / 2;
5278 
5279 	if (pcysta->cycles <= slot_pair)
5280 		c_begin = 1;
5281 	else
5282 		c_begin = pcysta->cycles - slot_pair + 1;
5283 
5284 	c_end = pcysta->cycles;
5285 
5286 	for (cycle = c_begin; cycle <= c_end; cycle++) {
5287 		cnt++;
5288 		store_index = ((cycle - 1) % slot_pair) * 2;
5289 
5290 		if (cnt % (BTC_CYCLE_SLOT_MAX / 4) == 1)
5291 			seq_printf(m,
5292 				   " %-15s : ->b%02d->w%02d", "[cycle_step]",
5293 				   pcysta->tslot_cycle[store_index],
5294 				   pcysta->tslot_cycle[store_index + 1]);
5295 		else
5296 			seq_printf(m,
5297 				   "->b%02d->w%02d",
5298 				   pcysta->tslot_cycle[store_index],
5299 				   pcysta->tslot_cycle[store_index + 1]);
5300 		if (cnt % (BTC_CYCLE_SLOT_MAX / 4) == 0 || cnt == c_end)
5301 			seq_puts(m, "\n");
5302 	}
5303 
5304 	if (a2dp->exist) {
5305 		seq_printf(m,
5306 			   " %-15s : a2dp_ept:%d, a2dp_late:%d",
5307 			   "[a2dp_t_sta]",
5308 			   pcysta->a2dpept, pcysta->a2dpeptto);
5309 
5310 		seq_printf(m,
5311 			   ", avg_t:%d, max_t:%d",
5312 			   pcysta->tavg_a2dpept, pcysta->tmax_a2dpept);
5313 		r.val = dm->tdma_now.rxflctrl;
5314 
5315 		if (r.type && r.tgln_n) {
5316 			seq_printf(m,
5317 				   ", cycle[PSTDMA:%d/TDMA:%d], ",
5318 				   pcysta->cycles_a2dp[CXT_FLCTRL_ON],
5319 				   pcysta->cycles_a2dp[CXT_FLCTRL_OFF]);
5320 
5321 			seq_printf(m,
5322 				   "avg_t[PSTDMA:%d/TDMA:%d], ",
5323 				   pcysta->tavg_a2dp[CXT_FLCTRL_ON],
5324 				   pcysta->tavg_a2dp[CXT_FLCTRL_OFF]);
5325 
5326 			seq_printf(m,
5327 				   "max_t[PSTDMA:%d/TDMA:%d]",
5328 				   pcysta->tmax_a2dp[CXT_FLCTRL_ON],
5329 				   pcysta->tmax_a2dp[CXT_FLCTRL_OFF]);
5330 		}
5331 		seq_puts(m, "\n");
5332 	}
5333 }
5334 
5335 static void _show_fbtc_nullsta(struct rtw89_dev *rtwdev, struct seq_file *m)
5336 {
5337 	struct rtw89_btc *btc = &rtwdev->btc;
5338 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
5339 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
5340 	struct rtw89_btc_fbtc_cynullsta *ns = NULL;
5341 	u8 i = 0;
5342 
5343 	if (!btc->dm.tdma_now.rxflctrl)
5344 		return;
5345 
5346 	pcinfo = &pfwinfo->rpt_fbtc_nullsta.cinfo;
5347 	if (!pcinfo->valid)
5348 		return;
5349 
5350 	ns = &pfwinfo->rpt_fbtc_nullsta.finfo;
5351 
5352 	seq_printf(m, " %-15s : ", "[null_sta]");
5353 
5354 	for (i = 0; i < 2; i++) {
5355 		if (i != 0)
5356 			seq_printf(m, ", null-%d", i);
5357 		else
5358 			seq_printf(m, "null-%d", i);
5359 		seq_printf(m, "[ok:%d/", le32_to_cpu(ns->result[i][1]));
5360 		seq_printf(m, "fail:%d/", le32_to_cpu(ns->result[i][0]));
5361 		seq_printf(m, "on_time:%d/", le32_to_cpu(ns->result[i][2]));
5362 		seq_printf(m, "retry:%d/", le32_to_cpu(ns->result[i][3]));
5363 		seq_printf(m, "avg_t:%d.%03d/",
5364 			   le32_to_cpu(ns->avg_t[i]) / 1000,
5365 			   le32_to_cpu(ns->avg_t[i]) % 1000);
5366 		seq_printf(m, "max_t:%d.%03d]",
5367 			   le32_to_cpu(ns->max_t[i]) / 1000,
5368 			   le32_to_cpu(ns->max_t[i]) % 1000);
5369 	}
5370 	seq_puts(m, "\n");
5371 }
5372 
5373 static void _show_fbtc_step(struct rtw89_dev *rtwdev, struct seq_file *m)
5374 {
5375 	struct rtw89_btc *btc = &rtwdev->btc;
5376 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
5377 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
5378 	struct rtw89_btc_fbtc_steps *pstep = NULL;
5379 	u8 type, val, cnt = 0, state = 0;
5380 	bool outloop = false;
5381 	u16 i, diff_t, n_start = 0, n_stop = 0;
5382 	u16 pos_old, pos_new;
5383 
5384 	pcinfo = &pfwinfo->rpt_fbtc_step.cinfo;
5385 	if (!pcinfo->valid)
5386 		return;
5387 
5388 	pstep = &pfwinfo->rpt_fbtc_step.finfo;
5389 	pos_old = le16_to_cpu(pstep->pos_old);
5390 	pos_new = le16_to_cpu(pstep->pos_new);
5391 
5392 	if (pcinfo->req_fver != pstep->fver)
5393 		return;
5394 
5395 	/* store step info by using ring instead of FIFO*/
5396 	do {
5397 		switch (state) {
5398 		case 0:
5399 			n_start = pos_old;
5400 			if (pos_new >=  pos_old)
5401 				n_stop = pos_new;
5402 			else
5403 				n_stop = btc->ctrl.trace_step - 1;
5404 
5405 			state = 1;
5406 			break;
5407 		case 1:
5408 			for (i = n_start; i <= n_stop; i++) {
5409 				type = pstep->step[i].type;
5410 				val = pstep->step[i].val;
5411 				diff_t = le16_to_cpu(pstep->step[i].difft);
5412 
5413 				if (type == CXSTEP_NONE || type >= CXSTEP_MAX)
5414 					continue;
5415 
5416 				if (cnt % 10 == 0)
5417 					seq_printf(m, " %-15s : ", "[steps]");
5418 
5419 				seq_printf(m, "-> %s(%02d)(%02d)",
5420 					   (type == CXSTEP_SLOT ? "SLT" :
5421 					    "EVT"), (u32)val, diff_t);
5422 				if (cnt % 10 == 9)
5423 					seq_puts(m, "\n");
5424 				cnt++;
5425 			}
5426 
5427 			state = 2;
5428 			break;
5429 		case 2:
5430 			if (pos_new <  pos_old && n_start != 0) {
5431 				n_start = 0;
5432 				n_stop = pos_new;
5433 				state = 1;
5434 			} else {
5435 				outloop = true;
5436 			}
5437 			break;
5438 		}
5439 	} while (!outloop);
5440 }
5441 
5442 static void _show_fw_dm_msg(struct rtw89_dev *rtwdev, struct seq_file *m)
5443 {
5444 	struct rtw89_btc *btc = &rtwdev->btc;
5445 
5446 	if (!(btc->dm.coex_info_map & BTC_COEX_INFO_DM))
5447 		return;
5448 
5449 	_show_error(rtwdev, m);
5450 	_show_fbtc_tdma(rtwdev, m);
5451 	_show_fbtc_slots(rtwdev, m);
5452 	_show_fbtc_cysta(rtwdev, m);
5453 	_show_fbtc_nullsta(rtwdev, m);
5454 	_show_fbtc_step(rtwdev, m);
5455 }
5456 
5457 static void _show_mreg(struct rtw89_dev *rtwdev, struct seq_file *m)
5458 {
5459 	const struct rtw89_chip_info *chip = rtwdev->chip;
5460 	struct rtw89_btc *btc = &rtwdev->btc;
5461 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
5462 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
5463 	struct rtw89_btc_fbtc_mreg_val *pmreg = NULL;
5464 	struct rtw89_btc_fbtc_gpio_dbg *gdbg = NULL;
5465 	struct rtw89_btc_cx *cx = &btc->cx;
5466 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
5467 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
5468 	struct rtw89_mac_ax_gnt gnt[2] = {0};
5469 	u8 i = 0, type = 0, cnt = 0;
5470 	u32 val, offset;
5471 
5472 	if (!(btc->dm.coex_info_map & BTC_COEX_INFO_MREG))
5473 		return;
5474 
5475 	seq_puts(m, "========== [HW Status] ==========\n");
5476 
5477 	seq_printf(m,
5478 		   " %-15s : WL->BT:0x%08x(cnt:%d), BT->WL:0x%08x(total:%d, bt_update:%d)\n",
5479 		   "[scoreboard]", wl->scbd, cx->cnt_wl[BTC_WCNT_SCBDUPDATE],
5480 		   bt->scbd, cx->cnt_bt[BTC_BCNT_SCBDREAD],
5481 		   cx->cnt_bt[BTC_BCNT_SCBDUPDATE]);
5482 
5483 	/* To avoid I/O if WL LPS or power-off  */
5484 	if (!wl->status.map.lps && !wl->status.map.rf_off) {
5485 		rtw89_mac_read_lte(rtwdev, R_AX_LTE_SW_CFG_1, &val);
5486 		if (val & (B_AX_GNT_BT_RFC_S0_SW_VAL |
5487 		    B_AX_GNT_BT_BB_S0_SW_VAL))
5488 			gnt[0].gnt_bt = true;
5489 		if (val & (B_AX_GNT_BT_RFC_S0_SW_CTRL |
5490 		    B_AX_GNT_BT_BB_S0_SW_CTRL))
5491 			gnt[0].gnt_bt_sw_en = true;
5492 		if (val & (B_AX_GNT_WL_RFC_S0_SW_VAL |
5493 		    B_AX_GNT_WL_BB_S0_SW_VAL))
5494 			gnt[0].gnt_wl = true;
5495 		if (val & (B_AX_GNT_WL_RFC_S0_SW_CTRL |
5496 		    B_AX_GNT_WL_BB_S0_SW_CTRL))
5497 			gnt[0].gnt_wl_sw_en = true;
5498 
5499 		if (val & (B_AX_GNT_BT_RFC_S1_SW_VAL |
5500 		    B_AX_GNT_BT_BB_S1_SW_VAL))
5501 			gnt[1].gnt_bt = true;
5502 		if (val & (B_AX_GNT_BT_RFC_S1_SW_CTRL |
5503 		    B_AX_GNT_BT_BB_S1_SW_CTRL))
5504 			gnt[1].gnt_bt_sw_en = true;
5505 		if (val & (B_AX_GNT_WL_RFC_S1_SW_VAL |
5506 		    B_AX_GNT_WL_BB_S1_SW_VAL))
5507 			gnt[1].gnt_wl = true;
5508 		if (val & (B_AX_GNT_WL_RFC_S1_SW_CTRL |
5509 		    B_AX_GNT_WL_BB_S1_SW_CTRL))
5510 			gnt[1].gnt_wl_sw_en = true;
5511 
5512 		seq_printf(m,
5513 			   " %-15s : pta_owner:%s, phy-0[gnt_wl:%s-%d/gnt_bt:%s-%d], ",
5514 			   "[gnt_status]",
5515 			   (rtw89_mac_get_ctrl_path(rtwdev) ? "WL" : "BT"),
5516 			   (gnt[0].gnt_wl_sw_en ? "SW" : "HW"), gnt[0].gnt_wl,
5517 			   (gnt[0].gnt_bt_sw_en ? "SW" : "HW"), gnt[0].gnt_bt);
5518 
5519 		seq_printf(m, "phy-1[gnt_wl:%s-%d/gnt_bt:%s-%d]\n",
5520 			   (gnt[1].gnt_wl_sw_en ? "SW" : "HW"), gnt[1].gnt_wl,
5521 			   (gnt[1].gnt_bt_sw_en ? "SW" : "HW"), gnt[1].gnt_bt);
5522 	}
5523 
5524 	pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo;
5525 	if (!pcinfo->valid) {
5526 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
5527 			    "[BTC], %s(): stop due rpt_fbtc_mregval.cinfo\n",
5528 			    __func__);
5529 		return;
5530 	}
5531 
5532 	pmreg = &pfwinfo->rpt_fbtc_mregval.finfo;
5533 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
5534 		    "[BTC], %s(): rpt_fbtc_mregval reg_num = %d\n",
5535 		    __func__, pmreg->reg_num);
5536 
5537 	for (i = 0; i < pmreg->reg_num; i++) {
5538 		type = (u8)le16_to_cpu(chip->mon_reg[i].type);
5539 		offset = le32_to_cpu(chip->mon_reg[i].offset);
5540 		val = le32_to_cpu(pmreg->mreg_val[i]);
5541 
5542 		if (cnt % 6 == 0)
5543 			seq_printf(m, " %-15s : %d_0x%04x=0x%08x",
5544 				   "[reg]", (u32)type, offset, val);
5545 		else
5546 			seq_printf(m, ", %d_0x%04x=0x%08x", (u32)type,
5547 				   offset, val);
5548 		if (cnt % 6 == 5)
5549 			seq_puts(m, "\n");
5550 		cnt++;
5551 	}
5552 
5553 	pcinfo = &pfwinfo->rpt_fbtc_gpio_dbg.cinfo;
5554 	if (!pcinfo->valid) {
5555 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
5556 			    "[BTC], %s(): stop due rpt_fbtc_gpio_dbg.cinfo\n",
5557 			    __func__);
5558 		return;
5559 	}
5560 
5561 	gdbg = &pfwinfo->rpt_fbtc_gpio_dbg.finfo;
5562 	if (!gdbg->en_map)
5563 		return;
5564 
5565 	seq_printf(m, " %-15s : enable_map:0x%08x",
5566 		   "[gpio_dbg]", gdbg->en_map);
5567 
5568 	for (i = 0; i < BTC_DBG_MAX1; i++) {
5569 		if (!(gdbg->en_map & BIT(i)))
5570 			continue;
5571 		seq_printf(m, ", %d->GPIO%d", (u32)i, gdbg->gpio_map[i]);
5572 	}
5573 	seq_puts(m, "\n");
5574 }
5575 
5576 static void _show_summary(struct rtw89_dev *rtwdev, struct seq_file *m)
5577 {
5578 	struct rtw89_btc *btc = &rtwdev->btc;
5579 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
5580 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
5581 	struct rtw89_btc_fbtc_rpt_ctrl *prptctrl = NULL;
5582 	struct rtw89_btc_cx *cx = &btc->cx;
5583 	struct rtw89_btc_dm *dm = &btc->dm;
5584 	struct rtw89_btc_wl_info *wl = &cx->wl;
5585 	struct rtw89_btc_bt_info *bt = &cx->bt;
5586 	u32 cnt_sum = 0, *cnt = btc->dm.cnt_notify;
5587 	u8 i;
5588 
5589 	if (!(dm->coex_info_map & BTC_COEX_INFO_SUMMARY))
5590 		return;
5591 
5592 	seq_puts(m, "========== [Statistics] ==========\n");
5593 
5594 	pcinfo = &pfwinfo->rpt_ctrl.cinfo;
5595 	if (pcinfo->valid && !wl->status.map.lps && !wl->status.map.rf_off) {
5596 		prptctrl = &pfwinfo->rpt_ctrl.finfo;
5597 
5598 		seq_printf(m,
5599 			   " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d), ",
5600 			   "[summary]", pfwinfo->cnt_h2c,
5601 			   pfwinfo->cnt_h2c_fail, prptctrl->h2c_cnt,
5602 			   pfwinfo->cnt_c2h, prptctrl->c2h_cnt);
5603 
5604 		seq_printf(m,
5605 			   "rpt_cnt=%d(fw_send:%d), rpt_map=0x%x, dm_error_map:0x%x",
5606 			   pfwinfo->event[BTF_EVNT_RPT], prptctrl->rpt_cnt,
5607 			   prptctrl->rpt_enable, dm->error.val);
5608 
5609 		_chk_btc_err(rtwdev, BTC_DCNT_RPT_FREEZE,
5610 			     pfwinfo->event[BTF_EVNT_RPT]);
5611 
5612 		if (dm->error.map.wl_fw_hang)
5613 			seq_puts(m, " (WL FW Hang!!)");
5614 		seq_puts(m, "\n");
5615 		seq_printf(m,
5616 			   " %-15s : send_ok:%d, send_fail:%d, recv:%d",
5617 			   "[mailbox]", prptctrl->mb_send_ok_cnt,
5618 			   prptctrl->mb_send_fail_cnt, prptctrl->mb_recv_cnt);
5619 
5620 		seq_printf(m,
5621 			   "(A2DP_empty:%d, A2DP_flowstop:%d, A2DP_full:%d)\n",
5622 			   prptctrl->mb_a2dp_empty_cnt,
5623 			   prptctrl->mb_a2dp_flct_cnt,
5624 			   prptctrl->mb_a2dp_full_cnt);
5625 
5626 		seq_printf(m,
5627 			   " %-15s : wl_rfk[req:%d/go:%d/reject:%d/timeout:%d]",
5628 			   "[RFK]", cx->cnt_wl[BTC_WCNT_RFK_REQ],
5629 			   cx->cnt_wl[BTC_WCNT_RFK_GO],
5630 			   cx->cnt_wl[BTC_WCNT_RFK_REJECT],
5631 			   cx->cnt_wl[BTC_WCNT_RFK_TIMEOUT]);
5632 
5633 		seq_printf(m,
5634 			   ", bt_rfk[req:%d/go:%d/reject:%d/timeout:%d/fail:%d]\n",
5635 			   prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_REQ],
5636 			   prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_GO],
5637 			   prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_REJECT],
5638 			   prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_TIMEOUT],
5639 			   prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_FAIL]);
5640 
5641 		if (prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_TIMEOUT] > 0)
5642 			bt->rfk_info.map.timeout = 1;
5643 		else
5644 			bt->rfk_info.map.timeout = 0;
5645 
5646 		dm->error.map.wl_rfk_timeout = bt->rfk_info.map.timeout;
5647 	} else {
5648 		seq_printf(m,
5649 			   " %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d, rpt_cnt=%d, rpt_map=0x%x",
5650 			   "[summary]", pfwinfo->cnt_h2c,
5651 			   pfwinfo->cnt_h2c_fail, pfwinfo->cnt_c2h,
5652 			   pfwinfo->event[BTF_EVNT_RPT],
5653 			   btc->fwinfo.rpt_en_map);
5654 		seq_puts(m, " (WL FW report invalid!!)\n");
5655 	}
5656 
5657 	for (i = 0; i < BTC_NCNT_NUM; i++)
5658 		cnt_sum += dm->cnt_notify[i];
5659 
5660 	seq_printf(m,
5661 		   " %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
5662 		   "[notify_cnt]", cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
5663 		   cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
5664 
5665 	seq_printf(m,
5666 		   "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d\n",
5667 		   cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
5668 		   cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
5669 		   cnt[BTC_NCNT_WL_STA]);
5670 
5671 	seq_printf(m,
5672 		   " %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, special_pkt=%d, ",
5673 		   "[notify_cnt]", cnt[BTC_NCNT_SCAN_START],
5674 		   cnt[BTC_NCNT_SCAN_FINISH], cnt[BTC_NCNT_SWITCH_BAND],
5675 		   cnt[BTC_NCNT_SPECIAL_PACKET]);
5676 
5677 	seq_printf(m,
5678 		   "timer=%d, control=%d, customerize=%d\n",
5679 		   cnt[BTC_NCNT_TIMER], cnt[BTC_NCNT_CONTROL],
5680 		   cnt[BTC_NCNT_CUSTOMERIZE]);
5681 }
5682 
5683 void rtw89_btc_dump_info(struct rtw89_dev *rtwdev, struct seq_file *m)
5684 {
5685 	struct rtw89_fw_suit *fw_suit = &rtwdev->fw.normal;
5686 	struct rtw89_btc *btc = &rtwdev->btc;
5687 	struct rtw89_btc_cx *cx = &btc->cx;
5688 	struct rtw89_btc_bt_info *bt = &cx->bt;
5689 
5690 	seq_puts(m, "=========================================\n");
5691 	seq_printf(m, "WL FW / BT FW		%d.%d.%d.%d / NA\n",
5692 		   fw_suit->major_ver, fw_suit->minor_ver,
5693 		   fw_suit->sub_ver, fw_suit->sub_idex);
5694 	seq_printf(m, "manual			%d\n", btc->ctrl.manual);
5695 
5696 	seq_puts(m, "=========================================\n");
5697 
5698 	seq_printf(m, "\n\r %-15s : raw_data[%02x %02x %02x %02x %02x %02x] (type:%s/cnt:%d/same:%d)",
5699 		   "[bt_info]",
5700 		   bt->raw_info[2], bt->raw_info[3],
5701 		   bt->raw_info[4], bt->raw_info[5],
5702 		   bt->raw_info[6], bt->raw_info[7],
5703 		   bt->raw_info[0] == BTC_BTINFO_AUTO ? "auto" : "reply",
5704 		   cx->cnt_bt[BTC_BCNT_INFOUPDATE],
5705 		   cx->cnt_bt[BTC_BCNT_INFOSAME]);
5706 
5707 	seq_puts(m, "\n=========================================\n");
5708 
5709 	_show_cx_info(rtwdev, m);
5710 	_show_wl_info(rtwdev, m);
5711 	_show_bt_info(rtwdev, m);
5712 	_show_dm_info(rtwdev, m);
5713 	_show_fw_dm_msg(rtwdev, m);
5714 	_show_mreg(rtwdev, m);
5715 	_show_summary(rtwdev, m);
5716 }
5717