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