xref: /freebsd/sys/contrib/dev/rtw89/coex.c (revision c7046f76)
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 		    "[BTC], cnt_connect = %d, link_mode = %d\n",
4096 		    cnt_connect, wl_rinfo->link_mode);
4097 
4098 	_fw_set_drv_info(rtwdev, CXDRVINFO_ROLE);
4099 }
4100 
4101 static void _update_wl_info_v1(struct rtw89_dev *rtwdev)
4102 {
4103 	struct rtw89_btc *btc = &rtwdev->btc;
4104 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4105 	struct rtw89_btc_wl_link_info *wl_linfo = wl->link_info;
4106 	struct rtw89_btc_wl_role_info_v1 *wl_rinfo = &wl->role_info_v1;
4107 	struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
4108 	u8 cnt_connect = 0, cnt_connecting = 0, cnt_active = 0;
4109 	u8 cnt_2g = 0, cnt_5g = 0, phy;
4110 	u32 wl_2g_ch[2] = {}, wl_5g_ch[2] = {};
4111 	bool b2g = false, b5g = false, client_joined = false;
4112 	u8 i;
4113 
4114 	memset(wl_rinfo, 0, sizeof(*wl_rinfo));
4115 
4116 	for (i = 0; i < RTW89_PORT_NUM; i++) {
4117 		if (!wl_linfo[i].active)
4118 			continue;
4119 
4120 		cnt_active++;
4121 		wl_rinfo->active_role_v1[cnt_active - 1].role = wl_linfo[i].role;
4122 		wl_rinfo->active_role_v1[cnt_active - 1].pid = wl_linfo[i].pid;
4123 		wl_rinfo->active_role_v1[cnt_active - 1].phy = wl_linfo[i].phy;
4124 		wl_rinfo->active_role_v1[cnt_active - 1].band = wl_linfo[i].band;
4125 		wl_rinfo->active_role_v1[cnt_active - 1].noa = (u8)wl_linfo[i].noa;
4126 		wl_rinfo->active_role_v1[cnt_active - 1].connected = 0;
4127 
4128 		wl->port_id[wl_linfo[i].role] = wl_linfo[i].pid;
4129 
4130 		phy = wl_linfo[i].phy;
4131 
4132 		if (rtwdev->dbcc_en && phy < RTW89_PHY_MAX) {
4133 			wl_dinfo->role[phy] = wl_linfo[i].role;
4134 			wl_dinfo->op_band[phy] = wl_linfo[i].band;
4135 			_update_dbcc_band(rtwdev, phy);
4136 			_fw_set_drv_info(rtwdev, CXDRVINFO_DBCC);
4137 		}
4138 
4139 		if (wl_linfo[i].connected == MLME_NO_LINK) {
4140 			continue;
4141 		} else if (wl_linfo[i].connected == MLME_LINKING) {
4142 			cnt_connecting++;
4143 		} else {
4144 			cnt_connect++;
4145 			if ((wl_linfo[i].role == RTW89_WIFI_ROLE_P2P_GO ||
4146 			     wl_linfo[i].role == RTW89_WIFI_ROLE_AP) &&
4147 			     wl_linfo[i].client_cnt > 1)
4148 				client_joined = true;
4149 		}
4150 
4151 		wl_rinfo->role_map.val |= BIT(wl_linfo[i].role);
4152 		wl_rinfo->active_role_v1[cnt_active - 1].ch = wl_linfo[i].ch;
4153 		wl_rinfo->active_role_v1[cnt_active - 1].bw = wl_linfo[i].bw;
4154 		wl_rinfo->active_role_v1[cnt_active - 1].connected = 1;
4155 
4156 		/* only care 2 roles + BT coex */
4157 		if (wl_linfo[i].band != RTW89_BAND_2G) {
4158 			if (cnt_5g <= ARRAY_SIZE(wl_5g_ch) - 1)
4159 				wl_5g_ch[cnt_5g] = wl_linfo[i].ch;
4160 			cnt_5g++;
4161 			b5g = true;
4162 		} else {
4163 			if (cnt_2g <= ARRAY_SIZE(wl_2g_ch) - 1)
4164 				wl_2g_ch[cnt_2g] = wl_linfo[i].ch;
4165 			cnt_2g++;
4166 			b2g = true;
4167 		}
4168 	}
4169 
4170 	wl_rinfo->connect_cnt = cnt_connect;
4171 
4172 	/* Be careful to change the following sequence!! */
4173 	if (cnt_connect == 0) {
4174 		wl_rinfo->link_mode = BTC_WLINK_NOLINK;
4175 		wl_rinfo->role_map.role.none = 1;
4176 	} else if (!b2g && b5g) {
4177 		wl_rinfo->link_mode = BTC_WLINK_5G;
4178 	} else if (wl_rinfo->role_map.role.nan) {
4179 		wl_rinfo->link_mode = BTC_WLINK_2G_NAN;
4180 	} else if (cnt_connect > BTC_TDMA_WLROLE_MAX) {
4181 		wl_rinfo->link_mode = BTC_WLINK_OTHER;
4182 	} else  if (b2g && b5g && cnt_connect == 2) {
4183 		if (rtwdev->dbcc_en) {
4184 			switch (wl_dinfo->role[RTW89_PHY_0]) {
4185 			case RTW89_WIFI_ROLE_STATION:
4186 				wl_rinfo->link_mode = BTC_WLINK_2G_STA;
4187 				break;
4188 			case RTW89_WIFI_ROLE_P2P_GO:
4189 				wl_rinfo->link_mode = BTC_WLINK_2G_GO;
4190 				break;
4191 			case RTW89_WIFI_ROLE_P2P_CLIENT:
4192 				wl_rinfo->link_mode = BTC_WLINK_2G_GC;
4193 				break;
4194 			case RTW89_WIFI_ROLE_AP:
4195 				wl_rinfo->link_mode = BTC_WLINK_2G_AP;
4196 				break;
4197 			default:
4198 				wl_rinfo->link_mode = BTC_WLINK_OTHER;
4199 				break;
4200 			}
4201 		} else {
4202 			wl_rinfo->link_mode = BTC_WLINK_25G_MCC;
4203 		}
4204 	} else if (!b5g && cnt_connect == 2) {
4205 		if (wl_rinfo->role_map.role.station &&
4206 		    (wl_rinfo->role_map.role.p2p_go ||
4207 		    wl_rinfo->role_map.role.p2p_gc ||
4208 		    wl_rinfo->role_map.role.ap)) {
4209 			if (wl_2g_ch[0] == wl_2g_ch[1])
4210 				wl_rinfo->link_mode = BTC_WLINK_2G_SCC;
4211 			else
4212 				wl_rinfo->link_mode = BTC_WLINK_2G_MCC;
4213 		} else {
4214 			wl_rinfo->link_mode = BTC_WLINK_2G_MCC;
4215 		}
4216 	} else if (!b5g && cnt_connect == 1) {
4217 		if (wl_rinfo->role_map.role.station)
4218 			wl_rinfo->link_mode = BTC_WLINK_2G_STA;
4219 		else if (wl_rinfo->role_map.role.ap)
4220 			wl_rinfo->link_mode = BTC_WLINK_2G_AP;
4221 		else if (wl_rinfo->role_map.role.p2p_go)
4222 			wl_rinfo->link_mode = BTC_WLINK_2G_GO;
4223 		else if (wl_rinfo->role_map.role.p2p_gc)
4224 			wl_rinfo->link_mode = BTC_WLINK_2G_GC;
4225 		else
4226 			wl_rinfo->link_mode = BTC_WLINK_OTHER;
4227 	}
4228 
4229 	/* if no client_joined, don't care P2P-GO/AP role */
4230 	if (wl_rinfo->role_map.role.p2p_go || wl_rinfo->role_map.role.ap) {
4231 		if (!client_joined) {
4232 			if (wl_rinfo->link_mode == BTC_WLINK_2G_SCC ||
4233 			    wl_rinfo->link_mode == BTC_WLINK_2G_MCC) {
4234 				wl_rinfo->link_mode = BTC_WLINK_2G_STA;
4235 				wl_rinfo->connect_cnt = 1;
4236 			} else if (wl_rinfo->link_mode == BTC_WLINK_2G_GO ||
4237 				 wl_rinfo->link_mode == BTC_WLINK_2G_AP) {
4238 				wl_rinfo->link_mode = BTC_WLINK_NOLINK;
4239 				wl_rinfo->connect_cnt = 0;
4240 			}
4241 		}
4242 	}
4243 
4244 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
4245 		    "[BTC], cnt_connect = %d, connecting = %d, link_mode = %d\n",
4246 		    cnt_connect, cnt_connecting, wl_rinfo->link_mode);
4247 
4248 	_fw_set_drv_info(rtwdev, CXDRVINFO_ROLE);
4249 }
4250 
4251 #define BTC_CHK_HANG_MAX 3
4252 #define BTC_SCB_INV_VALUE GENMASK(31, 0)
4253 
4254 void rtw89_coex_act1_work(struct work_struct *work)
4255 {
4256 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
4257 						coex_act1_work.work);
4258 	struct rtw89_btc *btc = &rtwdev->btc;
4259 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
4260 	struct rtw89_btc_cx *cx = &btc->cx;
4261 	struct rtw89_btc_wl_info *wl = &cx->wl;
4262 
4263 	mutex_lock(&rtwdev->mutex);
4264 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): enter\n", __func__);
4265 	dm->cnt_notify[BTC_NCNT_TIMER]++;
4266 	if (wl->status.map._4way)
4267 		wl->status.map._4way = false;
4268 	if (wl->status.map.connecting)
4269 		wl->status.map.connecting = false;
4270 
4271 	_run_coex(rtwdev, BTC_RSN_ACT1_WORK);
4272 	mutex_unlock(&rtwdev->mutex);
4273 }
4274 
4275 void rtw89_coex_bt_devinfo_work(struct work_struct *work)
4276 {
4277 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
4278 						coex_bt_devinfo_work.work);
4279 	struct rtw89_btc *btc = &rtwdev->btc;
4280 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
4281 	struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc;
4282 
4283 	mutex_lock(&rtwdev->mutex);
4284 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): enter\n", __func__);
4285 	dm->cnt_notify[BTC_NCNT_TIMER]++;
4286 	a2dp->play_latency = 0;
4287 	_run_coex(rtwdev, BTC_RSN_BT_DEVINFO_WORK);
4288 	mutex_unlock(&rtwdev->mutex);
4289 }
4290 
4291 void rtw89_coex_rfk_chk_work(struct work_struct *work)
4292 {
4293 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
4294 						coex_rfk_chk_work.work);
4295 	struct rtw89_btc *btc = &rtwdev->btc;
4296 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
4297 	struct rtw89_btc_cx *cx = &btc->cx;
4298 	struct rtw89_btc_wl_info *wl = &cx->wl;
4299 
4300 	mutex_lock(&rtwdev->mutex);
4301 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): enter\n", __func__);
4302 	dm->cnt_notify[BTC_NCNT_TIMER]++;
4303 	if (wl->rfk_info.state != BTC_WRFK_STOP) {
4304 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4305 			    "[BTC], %s(): RFK timeout\n", __func__);
4306 		cx->cnt_wl[BTC_WCNT_RFK_TIMEOUT]++;
4307 		dm->error.map.wl_rfk_timeout = true;
4308 		wl->rfk_info.state = BTC_WRFK_STOP;
4309 		_write_scbd(rtwdev, BTC_WSCB_WLRFK, false);
4310 		_run_coex(rtwdev, BTC_RSN_RFK_CHK_WORK);
4311 	}
4312 	mutex_unlock(&rtwdev->mutex);
4313 }
4314 
4315 static void _update_bt_scbd(struct rtw89_dev *rtwdev, bool only_update)
4316 {
4317 	const struct rtw89_chip_info *chip = rtwdev->chip;
4318 	struct rtw89_btc *btc = &rtwdev->btc;
4319 	struct rtw89_btc_cx *cx = &btc->cx;
4320 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
4321 	u32 val;
4322 	bool status_change = false;
4323 
4324 	if (!chip->scbd)
4325 		return;
4326 
4327 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s\n", __func__);
4328 
4329 	val = _read_scbd(rtwdev);
4330 	if (val == BTC_SCB_INV_VALUE) {
4331 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4332 			    "[BTC], %s(): return by invalid scbd value\n",
4333 			    __func__);
4334 		return;
4335 	}
4336 
4337 	if (!(val & BTC_BSCB_ON) ||
4338 	    btc->dm.cnt_dm[BTC_DCNT_BTCNT_FREEZE] >= BTC_CHK_HANG_MAX)
4339 		bt->enable.now = 0;
4340 	else
4341 		bt->enable.now = 1;
4342 
4343 	if (bt->enable.now != bt->enable.last)
4344 		status_change = true;
4345 
4346 	/* reset bt info if bt re-enable */
4347 	if (bt->enable.now && !bt->enable.last) {
4348 		_reset_btc_var(rtwdev, BTC_RESET_BTINFO);
4349 		cx->cnt_bt[BTC_BCNT_REENABLE]++;
4350 		bt->enable.now = 1;
4351 	}
4352 
4353 	bt->enable.last = bt->enable.now;
4354 	bt->scbd = val;
4355 	bt->mbx_avl = !!(val & BTC_BSCB_ACT);
4356 
4357 	if (bt->whql_test != !!(val & BTC_BSCB_WHQL))
4358 		status_change = true;
4359 
4360 	bt->whql_test = !!(val & BTC_BSCB_WHQL);
4361 	bt->btg_type = val & BTC_BSCB_BT_S1 ? BTC_BT_BTG : BTC_BT_ALONE;
4362 	bt->link_info.a2dp_desc.active = !!(val & BTC_BSCB_A2DP_ACT);
4363 
4364 	/* if rfk run 1->0 */
4365 	if (bt->rfk_info.map.run && !(val & BTC_BSCB_RFK_RUN))
4366 		status_change = true;
4367 
4368 	bt->rfk_info.map.run  = !!(val & BTC_BSCB_RFK_RUN);
4369 	bt->rfk_info.map.req = !!(val & BTC_BSCB_RFK_REQ);
4370 	bt->hi_lna_rx = !!(val & BTC_BSCB_BT_HILNA);
4371 	bt->link_info.status.map.connect = !!(val & BTC_BSCB_BT_CONNECT);
4372 	bt->run_patch_code = !!(val & BTC_BSCB_PATCH_CODE);
4373 
4374 	if (!only_update && status_change)
4375 		_run_coex(rtwdev, BTC_RSN_UPDATE_BT_SCBD);
4376 }
4377 
4378 static bool _chk_wl_rfk_request(struct rtw89_dev *rtwdev)
4379 {
4380 	struct rtw89_btc *btc = &rtwdev->btc;
4381 	struct rtw89_btc_cx *cx = &btc->cx;
4382 	struct rtw89_btc_bt_info *bt = &cx->bt;
4383 
4384 	_update_bt_scbd(rtwdev, true);
4385 
4386 	cx->cnt_wl[BTC_WCNT_RFK_REQ]++;
4387 
4388 	if ((bt->rfk_info.map.run || bt->rfk_info.map.req) &&
4389 	    !bt->rfk_info.map.timeout) {
4390 		cx->cnt_wl[BTC_WCNT_RFK_REJECT]++;
4391 	} else {
4392 		cx->cnt_wl[BTC_WCNT_RFK_GO]++;
4393 		return true;
4394 	}
4395 	return false;
4396 }
4397 
4398 static
4399 void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason)
4400 {
4401 	const struct rtw89_chip_info *chip = rtwdev->chip;
4402 	struct rtw89_btc *btc = &rtwdev->btc;
4403 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
4404 	struct rtw89_btc_cx *cx = &btc->cx;
4405 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4406 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
4407 	struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1;
4408 	u8 mode;
4409 
4410 	lockdep_assert_held(&rtwdev->mutex);
4411 
4412 	dm->run_reason = reason;
4413 	_update_dm_step(rtwdev, reason);
4414 	_update_btc_state_map(rtwdev);
4415 
4416 	if (chip->chip_id == RTL8852A)
4417 		mode = wl_rinfo->link_mode;
4418 	else
4419 		mode = wl_rinfo_v1->link_mode;
4420 
4421 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): reason=%d, mode=%d\n",
4422 		    __func__, reason, mode);
4423 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): wl_only=%d, bt_only=%d\n",
4424 		    __func__, dm->wl_only, dm->bt_only);
4425 
4426 	/* Be careful to change the following function sequence!! */
4427 	if (btc->ctrl.manual) {
4428 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4429 			    "[BTC], %s(): return for Manual CTRL!!\n",
4430 			    __func__);
4431 		return;
4432 	}
4433 
4434 	if (btc->ctrl.igno_bt &&
4435 	    (reason == BTC_RSN_UPDATE_BT_INFO ||
4436 	     reason == BTC_RSN_UPDATE_BT_SCBD)) {
4437 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4438 			    "[BTC], %s(): return for Stop Coex DM!!\n",
4439 			    __func__);
4440 		return;
4441 	}
4442 
4443 	if (!wl->status.map.init_ok) {
4444 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4445 			    "[BTC], %s(): return for WL init fail!!\n",
4446 			    __func__);
4447 		return;
4448 	}
4449 
4450 	if (wl->status.map.rf_off_pre == wl->status.map.rf_off &&
4451 	    wl->status.map.lps_pre == wl->status.map.lps &&
4452 	    (reason == BTC_RSN_NTFY_POWEROFF ||
4453 	    reason == BTC_RSN_NTFY_RADIO_STATE)) {
4454 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4455 			    "[BTC], %s(): return for WL rf off state no change!!\n",
4456 			    __func__);
4457 		return;
4458 	}
4459 
4460 	dm->cnt_dm[BTC_DCNT_RUN]++;
4461 
4462 	if (btc->ctrl.always_freerun) {
4463 		_action_freerun(rtwdev);
4464 		btc->ctrl.igno_bt = true;
4465 		goto exit;
4466 	}
4467 
4468 	if (dm->wl_only) {
4469 		_action_wl_only(rtwdev);
4470 		btc->ctrl.igno_bt = true;
4471 		goto exit;
4472 	}
4473 
4474 	if (wl->status.map.rf_off || wl->status.map.lps || dm->bt_only) {
4475 		_action_wl_off(rtwdev);
4476 		btc->ctrl.igno_bt = true;
4477 		goto exit;
4478 	}
4479 
4480 	btc->ctrl.igno_bt = false;
4481 	dm->freerun = false;
4482 
4483 	if (reason == BTC_RSN_NTFY_INIT) {
4484 		_action_wl_init(rtwdev);
4485 		goto exit;
4486 	}
4487 
4488 	if (!cx->bt.enable.now && !cx->other.type) {
4489 		_action_bt_off(rtwdev);
4490 		goto exit;
4491 	}
4492 
4493 	if (cx->bt.whql_test) {
4494 		_action_bt_whql(rtwdev);
4495 		goto exit;
4496 	}
4497 
4498 	if (wl->rfk_info.state != BTC_WRFK_STOP) {
4499 		_action_wl_rfk(rtwdev);
4500 		goto exit;
4501 	}
4502 
4503 	if (cx->state_map == BTC_WLINKING) {
4504 		if (mode == BTC_WLINK_NOLINK || mode == BTC_WLINK_2G_STA ||
4505 		    mode == BTC_WLINK_5G) {
4506 			_action_wl_scan(rtwdev);
4507 			goto exit;
4508 		}
4509 	}
4510 
4511 	if (wl->status.map.scan) {
4512 		_action_wl_scan(rtwdev);
4513 		goto exit;
4514 	}
4515 
4516 	switch (mode) {
4517 	case BTC_WLINK_NOLINK:
4518 		_action_wl_nc(rtwdev);
4519 		break;
4520 	case BTC_WLINK_2G_STA:
4521 		_action_wl_2g_sta(rtwdev);
4522 		break;
4523 	case BTC_WLINK_2G_AP:
4524 		_action_wl_2g_ap(rtwdev);
4525 		break;
4526 	case BTC_WLINK_2G_GO:
4527 		_action_wl_2g_go(rtwdev);
4528 		break;
4529 	case BTC_WLINK_2G_GC:
4530 		_action_wl_2g_gc(rtwdev);
4531 		break;
4532 	case BTC_WLINK_2G_SCC:
4533 		if (chip->chip_id == RTL8852A)
4534 			_action_wl_2g_scc(rtwdev);
4535 		else if (chip->chip_id == RTL8852C)
4536 			_action_wl_2g_scc_v1(rtwdev);
4537 		break;
4538 	case BTC_WLINK_2G_MCC:
4539 		_action_wl_2g_mcc(rtwdev);
4540 		break;
4541 	case BTC_WLINK_25G_MCC:
4542 		_action_wl_25g_mcc(rtwdev);
4543 		break;
4544 	case BTC_WLINK_5G:
4545 		_action_wl_5g(rtwdev);
4546 		break;
4547 	case BTC_WLINK_2G_NAN:
4548 		_action_wl_2g_nan(rtwdev);
4549 		break;
4550 	default:
4551 		_action_wl_other(rtwdev);
4552 		break;
4553 	}
4554 
4555 exit:
4556 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): exit\n", __func__);
4557 	_action_common(rtwdev);
4558 }
4559 
4560 void rtw89_btc_ntfy_poweron(struct rtw89_dev *rtwdev)
4561 {
4562 	struct rtw89_btc *btc = &rtwdev->btc;
4563 
4564 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
4565 	btc->dm.cnt_notify[BTC_NCNT_POWER_ON]++;
4566 }
4567 
4568 void rtw89_btc_ntfy_poweroff(struct rtw89_dev *rtwdev)
4569 {
4570 	struct rtw89_btc *btc = &rtwdev->btc;
4571 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4572 
4573 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
4574 	btc->dm.cnt_notify[BTC_NCNT_POWER_OFF]++;
4575 
4576 	btc->cx.wl.status.map.rf_off = 1;
4577 	btc->cx.wl.status.map.busy = 0;
4578 	wl->status.map.lps = BTC_LPS_OFF;
4579 
4580 	_write_scbd(rtwdev, BTC_WSCB_ALL, false);
4581 	_run_coex(rtwdev, BTC_RSN_NTFY_POWEROFF);
4582 
4583 	rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_ALL, 0);
4584 
4585 	btc->cx.wl.status.map.rf_off_pre = btc->cx.wl.status.map.rf_off;
4586 }
4587 
4588 static void _set_init_info(struct rtw89_dev *rtwdev)
4589 {
4590 	const struct rtw89_chip_info *chip = rtwdev->chip;
4591 	struct rtw89_btc *btc = &rtwdev->btc;
4592 	struct rtw89_btc_dm *dm = &btc->dm;
4593 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4594 
4595 	dm->init_info.wl_only = (u8)dm->wl_only;
4596 	dm->init_info.bt_only = (u8)dm->bt_only;
4597 	dm->init_info.wl_init_ok = (u8)wl->status.map.init_ok;
4598 	dm->init_info.dbcc_en = rtwdev->dbcc_en;
4599 	dm->init_info.cx_other = btc->cx.other.type;
4600 	dm->init_info.wl_guard_ch = chip->afh_guard_ch;
4601 	dm->init_info.module = btc->mdinfo;
4602 }
4603 
4604 void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode)
4605 {
4606 	struct rtw89_btc *btc = &rtwdev->btc;
4607 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
4608 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4609 	const struct rtw89_chip_info *chip = rtwdev->chip;
4610 
4611 	_reset_btc_var(rtwdev, BTC_RESET_ALL);
4612 	btc->dm.run_reason = BTC_RSN_NONE;
4613 	btc->dm.run_action = BTC_ACT_NONE;
4614 	btc->ctrl.igno_bt = true;
4615 
4616 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
4617 		    "[BTC], %s(): mode=%d\n", __func__, mode);
4618 
4619 	dm->cnt_notify[BTC_NCNT_INIT_COEX]++;
4620 	dm->wl_only = mode == BTC_MODE_WL ? 1 : 0;
4621 	dm->bt_only = mode == BTC_MODE_BT ? 1 : 0;
4622 	wl->status.map.rf_off = mode == BTC_MODE_WLOFF ? 1 : 0;
4623 
4624 	chip->ops->btc_set_rfe(rtwdev);
4625 	chip->ops->btc_init_cfg(rtwdev);
4626 
4627 	if (!wl->status.map.init_ok) {
4628 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4629 			    "[BTC], %s(): return for WL init fail!!\n",
4630 			    __func__);
4631 		dm->error.map.init = true;
4632 		return;
4633 	}
4634 
4635 	_write_scbd(rtwdev,
4636 		    BTC_WSCB_ACTIVE | BTC_WSCB_ON | BTC_WSCB_BTLOG, true);
4637 	_update_bt_scbd(rtwdev, true);
4638 	if (rtw89_mac_get_ctrl_path(rtwdev)) {
4639 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4640 			    "[BTC], %s(): PTA owner warning!!\n",
4641 			    __func__);
4642 		dm->error.map.pta_owner = true;
4643 	}
4644 
4645 	_set_init_info(rtwdev);
4646 	_set_wl_tx_power(rtwdev, RTW89_BTC_WL_DEF_TX_PWR);
4647 	rtw89_btc_fw_set_slots(rtwdev, CXST_MAX, dm->slot);
4648 	btc_fw_set_monreg(rtwdev);
4649 	_fw_set_drv_info(rtwdev, CXDRVINFO_INIT);
4650 	_fw_set_drv_info(rtwdev, CXDRVINFO_CTRL);
4651 
4652 	_run_coex(rtwdev, BTC_RSN_NTFY_INIT);
4653 }
4654 
4655 void rtw89_btc_ntfy_scan_start(struct rtw89_dev *rtwdev, u8 phy_idx, u8 band)
4656 {
4657 	struct rtw89_btc *btc = &rtwdev->btc;
4658 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4659 
4660 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
4661 		    "[BTC], %s(): phy_idx=%d, band=%d\n",
4662 		    __func__, phy_idx, band);
4663 	btc->dm.cnt_notify[BTC_NCNT_SCAN_START]++;
4664 	wl->status.map.scan = true;
4665 	wl->scan_info.band[phy_idx] = band;
4666 	wl->scan_info.phy_map |= BIT(phy_idx);
4667 	_fw_set_drv_info(rtwdev, CXDRVINFO_SCAN);
4668 
4669 	if (rtwdev->dbcc_en) {
4670 		wl->dbcc_info.scan_band[phy_idx] = band;
4671 		_update_dbcc_band(rtwdev, phy_idx);
4672 		_fw_set_drv_info(rtwdev, CXDRVINFO_DBCC);
4673 	}
4674 
4675 	_run_coex(rtwdev, BTC_RSN_NTFY_SCAN_START);
4676 }
4677 
4678 void rtw89_btc_ntfy_scan_finish(struct rtw89_dev *rtwdev, u8 phy_idx)
4679 {
4680 	struct rtw89_btc *btc = &rtwdev->btc;
4681 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4682 
4683 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
4684 		    "[BTC], %s(): phy_idx=%d\n", __func__, phy_idx);
4685 	btc->dm.cnt_notify[BTC_NCNT_SCAN_FINISH]++;
4686 
4687 	wl->status.map.scan = false;
4688 	wl->scan_info.phy_map &= ~BIT(phy_idx);
4689 	_fw_set_drv_info(rtwdev, CXDRVINFO_SCAN);
4690 
4691 	if (rtwdev->dbcc_en) {
4692 		_update_dbcc_band(rtwdev, phy_idx);
4693 		_fw_set_drv_info(rtwdev, CXDRVINFO_DBCC);
4694 	}
4695 
4696 	_run_coex(rtwdev, BTC_RSN_NTFY_SCAN_FINISH);
4697 }
4698 
4699 void rtw89_btc_ntfy_switch_band(struct rtw89_dev *rtwdev, u8 phy_idx, u8 band)
4700 {
4701 	struct rtw89_btc *btc = &rtwdev->btc;
4702 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4703 
4704 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
4705 		    "[BTC], %s(): phy_idx=%d, band=%d\n",
4706 		    __func__, phy_idx, band);
4707 	btc->dm.cnt_notify[BTC_NCNT_SWITCH_BAND]++;
4708 
4709 	wl->scan_info.band[phy_idx] = band;
4710 	wl->scan_info.phy_map |= BIT(phy_idx);
4711 	_fw_set_drv_info(rtwdev, CXDRVINFO_SCAN);
4712 
4713 	if (rtwdev->dbcc_en) {
4714 		wl->dbcc_info.scan_band[phy_idx] = band;
4715 		_update_dbcc_band(rtwdev, phy_idx);
4716 		_fw_set_drv_info(rtwdev, CXDRVINFO_DBCC);
4717 	}
4718 	_run_coex(rtwdev, BTC_RSN_NTFY_SWBAND);
4719 }
4720 
4721 void rtw89_btc_ntfy_specific_packet(struct rtw89_dev *rtwdev,
4722 				    enum btc_pkt_type pkt_type)
4723 {
4724 	struct rtw89_btc *btc = &rtwdev->btc;
4725 	struct rtw89_btc_cx *cx = &btc->cx;
4726 	struct rtw89_btc_wl_info *wl = &cx->wl;
4727 	struct rtw89_btc_bt_link_info *b = &cx->bt.link_info;
4728 	struct rtw89_btc_bt_hfp_desc *hfp = &b->hfp_desc;
4729 	struct rtw89_btc_bt_hid_desc *hid = &b->hid_desc;
4730 	u32 cnt;
4731 	u32 delay = RTW89_COEX_ACT1_WORK_PERIOD;
4732 	bool delay_work = false;
4733 
4734 	switch (pkt_type) {
4735 	case PACKET_DHCP:
4736 		cnt = ++cx->cnt_wl[BTC_WCNT_DHCP];
4737 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4738 			    "[BTC], %s(): DHCP cnt=%d\n", __func__, cnt);
4739 		wl->status.map.connecting = true;
4740 		delay_work = true;
4741 		break;
4742 	case PACKET_EAPOL:
4743 		cnt = ++cx->cnt_wl[BTC_WCNT_EAPOL];
4744 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4745 			    "[BTC], %s(): EAPOL cnt=%d\n", __func__, cnt);
4746 		wl->status.map._4way = true;
4747 		delay_work = true;
4748 		if (hfp->exist || hid->exist)
4749 			delay /= 2;
4750 		break;
4751 	case PACKET_EAPOL_END:
4752 		cnt = ++cx->cnt_wl[BTC_WCNT_EAPOL];
4753 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4754 			    "[BTC], %s(): EAPOL_End cnt=%d\n",
4755 			    __func__, cnt);
4756 		wl->status.map._4way = false;
4757 		cancel_delayed_work(&rtwdev->coex_act1_work);
4758 		break;
4759 	case PACKET_ARP:
4760 		cnt = ++cx->cnt_wl[BTC_WCNT_ARP];
4761 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4762 			    "[BTC], %s(): ARP cnt=%d\n", __func__, cnt);
4763 		return;
4764 	case PACKET_ICMP:
4765 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4766 			    "[BTC], %s(): ICMP pkt\n", __func__);
4767 		return;
4768 	default:
4769 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4770 			    "[BTC], %s(): unknown packet type %d\n",
4771 			    __func__, pkt_type);
4772 		return;
4773 	}
4774 
4775 	if (delay_work) {
4776 		cancel_delayed_work(&rtwdev->coex_act1_work);
4777 		ieee80211_queue_delayed_work(rtwdev->hw,
4778 					     &rtwdev->coex_act1_work, delay);
4779 	}
4780 
4781 	btc->dm.cnt_notify[BTC_NCNT_SPECIAL_PACKET]++;
4782 	_run_coex(rtwdev, BTC_RSN_NTFY_SPECIFIC_PACKET);
4783 }
4784 
4785 void rtw89_btc_ntfy_eapol_packet_work(struct work_struct *work)
4786 {
4787 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
4788 						btc.eapol_notify_work);
4789 
4790 	mutex_lock(&rtwdev->mutex);
4791 	rtw89_leave_ps_mode(rtwdev);
4792 	rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_EAPOL);
4793 	mutex_unlock(&rtwdev->mutex);
4794 }
4795 
4796 void rtw89_btc_ntfy_arp_packet_work(struct work_struct *work)
4797 {
4798 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
4799 						btc.arp_notify_work);
4800 
4801 	mutex_lock(&rtwdev->mutex);
4802 	rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_ARP);
4803 	mutex_unlock(&rtwdev->mutex);
4804 }
4805 
4806 void rtw89_btc_ntfy_dhcp_packet_work(struct work_struct *work)
4807 {
4808 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
4809 						btc.dhcp_notify_work);
4810 
4811 	mutex_lock(&rtwdev->mutex);
4812 	rtw89_leave_ps_mode(rtwdev);
4813 	rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_DHCP);
4814 	mutex_unlock(&rtwdev->mutex);
4815 }
4816 
4817 void rtw89_btc_ntfy_icmp_packet_work(struct work_struct *work)
4818 {
4819 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
4820 						btc.icmp_notify_work);
4821 
4822 	mutex_lock(&rtwdev->mutex);
4823 	rtw89_leave_ps_mode(rtwdev);
4824 	rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_ICMP);
4825 	mutex_unlock(&rtwdev->mutex);
4826 }
4827 
4828 static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len)
4829 {
4830 	const struct rtw89_chip_info *chip = rtwdev->chip;
4831 	struct rtw89_btc *btc = &rtwdev->btc;
4832 	struct rtw89_btc_cx *cx = &btc->cx;
4833 	struct rtw89_btc_bt_info *bt = &cx->bt;
4834 	struct rtw89_btc_bt_link_info *b = &bt->link_info;
4835 	struct rtw89_btc_bt_hfp_desc *hfp = &b->hfp_desc;
4836 	struct rtw89_btc_bt_hid_desc *hid = &b->hid_desc;
4837 	struct rtw89_btc_bt_a2dp_desc *a2dp = &b->a2dp_desc;
4838 	struct rtw89_btc_bt_pan_desc *pan = &b->pan_desc;
4839 	union btc_btinfo btinfo;
4840 
4841 	if (buf[BTC_BTINFO_L1] != 6)
4842 		return;
4843 
4844 	if (!memcmp(bt->raw_info, buf, BTC_BTINFO_MAX)) {
4845 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4846 			    "[BTC], %s(): return by bt-info duplicate!!\n",
4847 			    __func__);
4848 		cx->cnt_bt[BTC_BCNT_INFOSAME]++;
4849 		return;
4850 	}
4851 
4852 	memcpy(bt->raw_info, buf, BTC_BTINFO_MAX);
4853 
4854 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
4855 		    "[BTC], %s(): bt_info[2]=0x%02x\n",
4856 		    __func__, bt->raw_info[2]);
4857 
4858 	/* reset to mo-connect before update */
4859 	b->status.val = BTC_BLINK_NOCONNECT;
4860 	b->profile_cnt.last = b->profile_cnt.now;
4861 	b->relink.last = b->relink.now;
4862 	a2dp->exist_last = a2dp->exist;
4863 	b->multi_link.last = b->multi_link.now;
4864 	bt->inq_pag.last = bt->inq_pag.now;
4865 	b->profile_cnt.now = 0;
4866 	hid->type = 0;
4867 
4868 	/* parse raw info low-Byte2 */
4869 	btinfo.val = bt->raw_info[BTC_BTINFO_L2];
4870 	b->status.map.connect = btinfo.lb2.connect;
4871 	b->status.map.sco_busy = btinfo.lb2.sco_busy;
4872 	b->status.map.acl_busy = btinfo.lb2.acl_busy;
4873 	b->status.map.inq_pag = btinfo.lb2.inq_pag;
4874 	bt->inq_pag.now = btinfo.lb2.inq_pag;
4875 	cx->cnt_bt[BTC_BCNT_INQPAG] += !!(bt->inq_pag.now && !bt->inq_pag.last);
4876 
4877 	hfp->exist = btinfo.lb2.hfp;
4878 	b->profile_cnt.now += (u8)hfp->exist;
4879 	hid->exist = btinfo.lb2.hid;
4880 	b->profile_cnt.now += (u8)hid->exist;
4881 	a2dp->exist = btinfo.lb2.a2dp;
4882 	b->profile_cnt.now += (u8)a2dp->exist;
4883 	pan->active = btinfo.lb2.pan;
4884 
4885 	/* parse raw info low-Byte3 */
4886 	btinfo.val = bt->raw_info[BTC_BTINFO_L3];
4887 	if (btinfo.lb3.retry != 0)
4888 		cx->cnt_bt[BTC_BCNT_RETRY]++;
4889 	b->cqddr = btinfo.lb3.cqddr;
4890 	cx->cnt_bt[BTC_BCNT_INQ] += !!(btinfo.lb3.inq && !bt->inq);
4891 	bt->inq = btinfo.lb3.inq;
4892 	cx->cnt_bt[BTC_BCNT_PAGE] += !!(btinfo.lb3.pag && !bt->pag);
4893 	bt->pag = btinfo.lb3.pag;
4894 
4895 	b->status.map.mesh_busy = btinfo.lb3.mesh_busy;
4896 	/* parse raw info high-Byte0 */
4897 	btinfo.val = bt->raw_info[BTC_BTINFO_H0];
4898 	/* raw val is dBm unit, translate from -100~ 0dBm to 0~100%*/
4899 	b->rssi = chip->ops->btc_get_bt_rssi(rtwdev, btinfo.hb0.rssi);
4900 
4901 	/* parse raw info high-Byte1 */
4902 	btinfo.val = bt->raw_info[BTC_BTINFO_H1];
4903 	b->status.map.ble_connect = btinfo.hb1.ble_connect;
4904 	if (btinfo.hb1.ble_connect)
4905 		hid->type |= (hid->exist ? BTC_HID_BLE : BTC_HID_RCU);
4906 
4907 	cx->cnt_bt[BTC_BCNT_REINIT] += !!(btinfo.hb1.reinit && !bt->reinit);
4908 	bt->reinit = btinfo.hb1.reinit;
4909 	cx->cnt_bt[BTC_BCNT_RELINK] += !!(btinfo.hb1.relink && !b->relink.now);
4910 	b->relink.now = btinfo.hb1.relink;
4911 	cx->cnt_bt[BTC_BCNT_IGNOWL] += !!(btinfo.hb1.igno_wl && !bt->igno_wl);
4912 	bt->igno_wl = btinfo.hb1.igno_wl;
4913 
4914 	if (bt->igno_wl && !cx->wl.status.map.rf_off)
4915 		_set_bt_ignore_wlan_act(rtwdev, false);
4916 
4917 	hid->type |= (btinfo.hb1.voice ? BTC_HID_RCU_VOICE : 0);
4918 	bt->ble_scan_en = btinfo.hb1.ble_scan;
4919 
4920 	cx->cnt_bt[BTC_BCNT_ROLESW] += !!(btinfo.hb1.role_sw && !b->role_sw);
4921 	b->role_sw = btinfo.hb1.role_sw;
4922 
4923 	b->multi_link.now = btinfo.hb1.multi_link;
4924 
4925 	/* parse raw info high-Byte2 */
4926 	btinfo.val = bt->raw_info[BTC_BTINFO_H2];
4927 	pan->exist = btinfo.hb2.pan_active;
4928 	b->profile_cnt.now += (u8)pan->exist;
4929 
4930 	cx->cnt_bt[BTC_BCNT_AFH] += !!(btinfo.hb2.afh_update && !b->afh_update);
4931 	b->afh_update = btinfo.hb2.afh_update;
4932 	a2dp->active = btinfo.hb2.a2dp_active;
4933 	b->slave_role = btinfo.hb2.slave;
4934 	hid->slot_info = btinfo.hb2.hid_slot;
4935 	hid->pair_cnt = btinfo.hb2.hid_cnt;
4936 	hid->type |= (hid->slot_info == BTC_HID_218 ?
4937 		      BTC_HID_218 : BTC_HID_418);
4938 	/* parse raw info high-Byte3 */
4939 	btinfo.val = bt->raw_info[BTC_BTINFO_H3];
4940 	a2dp->bitpool = btinfo.hb3.a2dp_bitpool;
4941 
4942 	if (b->tx_3m != (u32)btinfo.hb3.tx_3m)
4943 		cx->cnt_bt[BTC_BCNT_RATECHG]++;
4944 	b->tx_3m = (u32)btinfo.hb3.tx_3m;
4945 
4946 	a2dp->sink = btinfo.hb3.a2dp_sink;
4947 
4948 	if (b->profile_cnt.now || b->status.map.ble_connect)
4949 		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP, 1);
4950 	else
4951 		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP, 0);
4952 
4953 	if (!a2dp->exist_last && a2dp->exist) {
4954 		a2dp->vendor_id = 0;
4955 		a2dp->flush_time = 0;
4956 		a2dp->play_latency = 1;
4957 		ieee80211_queue_delayed_work(rtwdev->hw,
4958 					     &rtwdev->coex_bt_devinfo_work,
4959 					     RTW89_COEX_BT_DEVINFO_WORK_PERIOD);
4960 	}
4961 
4962 	if (a2dp->exist && (a2dp->flush_time == 0 || a2dp->vendor_id == 0 ||
4963 			    a2dp->play_latency == 1))
4964 		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_DEVICE_INFO, 1);
4965 	else
4966 		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_DEVICE_INFO, 0);
4967 
4968 	_run_coex(rtwdev, BTC_RSN_UPDATE_BT_INFO);
4969 }
4970 
4971 enum btc_wl_mode {
4972 	BTC_WL_MODE_HT = 0,
4973 	BTC_WL_MODE_VHT = 1,
4974 	BTC_WL_MODE_HE = 2,
4975 	BTC_WL_MODE_NUM,
4976 };
4977 
4978 void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
4979 			      struct rtw89_sta *rtwsta, enum btc_role_state state)
4980 {
4981 	const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
4982 	const struct rtw89_chip_info *chip = rtwdev->chip;
4983 	struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
4984 	struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta);
4985 	struct rtw89_btc *btc = &rtwdev->btc;
4986 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4987 	struct rtw89_btc_wl_link_info r = {0};
4988 	struct rtw89_btc_wl_link_info *wlinfo = NULL;
4989 	u8 mode = 0;
4990 
4991 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], state=%d\n", state);
4992 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
4993 		    "[BTC], role is STA=%d\n",
4994 		    vif->type == NL80211_IFTYPE_STATION);
4995 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], port=%d\n", rtwvif->port);
4996 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], band=%d ch=%d bw=%d\n",
4997 		    chan->band_type, chan->channel, chan->band_width);
4998 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], associated=%d\n",
4999 		    state == BTC_ROLE_MSTS_STA_CONN_END);
5000 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
5001 		    "[BTC], bcn_period=%d dtim_period=%d\n",
5002 		    vif->bss_conf.beacon_int, vif->bss_conf.dtim_period);
5003 
5004 	if (rtwsta) {
5005 		rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], STA mac_id=%d\n",
5006 			    rtwsta->mac_id);
5007 
5008 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
5009 			    "[BTC], STA support HE=%d VHT=%d HT=%d\n",
5010 			    sta->deflink.he_cap.has_he,
5011 			    sta->deflink.vht_cap.vht_supported,
5012 			    sta->deflink.ht_cap.ht_supported);
5013 		if (sta->deflink.he_cap.has_he)
5014 			mode |= BIT(BTC_WL_MODE_HE);
5015 		if (sta->deflink.vht_cap.vht_supported)
5016 			mode |= BIT(BTC_WL_MODE_VHT);
5017 		if (sta->deflink.ht_cap.ht_supported)
5018 			mode |= BIT(BTC_WL_MODE_HT);
5019 
5020 		r.mode = mode;
5021 	}
5022 
5023 	if (rtwvif->wifi_role >= RTW89_WIFI_ROLE_MLME_MAX)
5024 		return;
5025 
5026 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
5027 		    "[BTC], wifi_role=%d\n", rtwvif->wifi_role);
5028 
5029 	r.role = rtwvif->wifi_role;
5030 	r.phy = rtwvif->phy_idx;
5031 	r.pid = rtwvif->port;
5032 	r.active = true;
5033 	r.connected = MLME_LINKED;
5034 	r.bcn_period = vif->bss_conf.beacon_int;
5035 	r.dtim_period = vif->bss_conf.dtim_period;
5036 	r.band = chan->band_type;
5037 	r.ch = chan->channel;
5038 	r.bw = chan->band_width;
5039 	ether_addr_copy(r.mac_addr, rtwvif->mac_addr);
5040 
5041 	if (rtwsta && vif->type == NL80211_IFTYPE_STATION)
5042 		r.mac_id = rtwsta->mac_id;
5043 
5044 	btc->dm.cnt_notify[BTC_NCNT_ROLE_INFO]++;
5045 
5046 	wlinfo = &wl->link_info[r.pid];
5047 
5048 	memcpy(wlinfo, &r, sizeof(*wlinfo));
5049 	if (chip->chip_id == RTL8852A)
5050 		_update_wl_info(rtwdev);
5051 	else
5052 		_update_wl_info_v1(rtwdev);
5053 
5054 	if (wlinfo->role == RTW89_WIFI_ROLE_STATION &&
5055 	    wlinfo->connected == MLME_NO_LINK)
5056 		btc->dm.leak_ap = 0;
5057 
5058 	if (state == BTC_ROLE_MSTS_STA_CONN_START)
5059 		wl->status.map.connecting = 1;
5060 	else
5061 		wl->status.map.connecting = 0;
5062 
5063 	if (state == BTC_ROLE_MSTS_STA_DIS_CONN)
5064 		wl->status.map._4way = false;
5065 
5066 	_run_coex(rtwdev, BTC_RSN_NTFY_ROLE_INFO);
5067 }
5068 
5069 void rtw89_btc_ntfy_radio_state(struct rtw89_dev *rtwdev, enum btc_rfctrl rf_state)
5070 {
5071 	const struct rtw89_chip_info *chip = rtwdev->chip;
5072 	struct rtw89_btc *btc = &rtwdev->btc;
5073 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
5074 	u32 val;
5075 
5076 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): rf_state = %d\n",
5077 		    __func__, rf_state);
5078 	btc->dm.cnt_notify[BTC_NCNT_RADIO_STATE]++;
5079 
5080 	switch (rf_state) {
5081 	case BTC_RFCTRL_WL_OFF:
5082 		wl->status.map.rf_off = 1;
5083 		wl->status.map.lps = BTC_LPS_OFF;
5084 		wl->status.map.busy = 0;
5085 		break;
5086 	case BTC_RFCTRL_FW_CTRL:
5087 		wl->status.map.rf_off = 0;
5088 		wl->status.map.lps = BTC_LPS_RF_OFF;
5089 		wl->status.map.busy = 0;
5090 		break;
5091 	case BTC_RFCTRL_WL_ON:
5092 	default:
5093 		wl->status.map.rf_off = 0;
5094 		wl->status.map.lps = BTC_LPS_OFF;
5095 		break;
5096 	}
5097 
5098 	if (rf_state == BTC_RFCTRL_WL_ON) {
5099 		btc->dm.cnt_dm[BTC_DCNT_BTCNT_FREEZE] = 0;
5100 		rtw89_btc_fw_en_rpt(rtwdev,
5101 				    RPT_EN_MREG | RPT_EN_BT_VER_INFO, true);
5102 		val = BTC_WSCB_ACTIVE | BTC_WSCB_ON | BTC_WSCB_BTLOG;
5103 		_write_scbd(rtwdev, val, true);
5104 		_update_bt_scbd(rtwdev, true);
5105 		chip->ops->btc_init_cfg(rtwdev);
5106 	} else {
5107 		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_ALL, false);
5108 		if (rf_state == BTC_RFCTRL_WL_OFF)
5109 			_write_scbd(rtwdev, BTC_WSCB_ALL, false);
5110 	}
5111 
5112 	_run_coex(rtwdev, BTC_RSN_NTFY_RADIO_STATE);
5113 
5114 	wl->status.map.rf_off_pre = wl->status.map.rf_off;
5115 	wl->status.map.lps_pre = wl->status.map.lps;
5116 }
5117 
5118 static bool _ntfy_wl_rfk(struct rtw89_dev *rtwdev, u8 phy_path,
5119 			 enum btc_wl_rfk_type type,
5120 			 enum btc_wl_rfk_state state)
5121 {
5122 	struct rtw89_btc *btc = &rtwdev->btc;
5123 	struct rtw89_btc_cx *cx = &btc->cx;
5124 	struct rtw89_btc_wl_info *wl = &cx->wl;
5125 	bool result = BTC_WRFK_REJECT;
5126 
5127 	wl->rfk_info.type = type;
5128 	wl->rfk_info.path_map = FIELD_GET(BTC_RFK_PATH_MAP, phy_path);
5129 	wl->rfk_info.phy_map = FIELD_GET(BTC_RFK_PHY_MAP, phy_path);
5130 	wl->rfk_info.band = FIELD_GET(BTC_RFK_BAND_MAP, phy_path);
5131 
5132 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
5133 		    "[BTC], %s()_start: phy=0x%x, path=0x%x, type=%d, state=%d\n",
5134 		    __func__, wl->rfk_info.phy_map, wl->rfk_info.path_map,
5135 		    type, state);
5136 
5137 	switch (state) {
5138 	case BTC_WRFK_START:
5139 		result = _chk_wl_rfk_request(rtwdev);
5140 		wl->rfk_info.state = result ? BTC_WRFK_START : BTC_WRFK_STOP;
5141 
5142 		_write_scbd(rtwdev, BTC_WSCB_WLRFK, result);
5143 
5144 		btc->dm.cnt_notify[BTC_NCNT_WL_RFK]++;
5145 		break;
5146 	case BTC_WRFK_ONESHOT_START:
5147 	case BTC_WRFK_ONESHOT_STOP:
5148 		if (wl->rfk_info.state == BTC_WRFK_STOP) {
5149 			result = BTC_WRFK_REJECT;
5150 		} else {
5151 			result = BTC_WRFK_ALLOW;
5152 			wl->rfk_info.state = state;
5153 		}
5154 		break;
5155 	case BTC_WRFK_STOP:
5156 		result = BTC_WRFK_ALLOW;
5157 		wl->rfk_info.state = BTC_WRFK_STOP;
5158 
5159 		_write_scbd(rtwdev, BTC_WSCB_WLRFK, false);
5160 		cancel_delayed_work(&rtwdev->coex_rfk_chk_work);
5161 		break;
5162 	default:
5163 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
5164 			    "[BTC], %s() warning state=%d\n", __func__, state);
5165 		break;
5166 	}
5167 
5168 	if (result == BTC_WRFK_ALLOW) {
5169 		if (wl->rfk_info.state == BTC_WRFK_START ||
5170 		    wl->rfk_info.state == BTC_WRFK_STOP)
5171 			_run_coex(rtwdev, BTC_RSN_NTFY_WL_RFK);
5172 
5173 		if (wl->rfk_info.state == BTC_WRFK_START)
5174 			ieee80211_queue_delayed_work(rtwdev->hw,
5175 						     &rtwdev->coex_rfk_chk_work,
5176 						     RTW89_COEX_RFK_CHK_WORK_PERIOD);
5177 	}
5178 
5179 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
5180 		    "[BTC], %s()_finish: rfk_cnt=%d, result=%d\n",
5181 		    __func__, btc->dm.cnt_notify[BTC_NCNT_WL_RFK], result);
5182 
5183 	return result == BTC_WRFK_ALLOW;
5184 }
5185 
5186 void rtw89_btc_ntfy_wl_rfk(struct rtw89_dev *rtwdev, u8 phy_map,
5187 			   enum btc_wl_rfk_type type,
5188 			   enum btc_wl_rfk_state state)
5189 {
5190 	u8 band;
5191 	bool allow;
5192 	int ret;
5193 
5194 	band = FIELD_GET(BTC_RFK_BAND_MAP, phy_map);
5195 
5196 	rtw89_debug(rtwdev, RTW89_DBG_RFK,
5197 		    "[RFK] RFK notify (%s / PHY%u / K_type = %u / path_idx = %lu / process = %s)\n",
5198 		    band == RTW89_BAND_2G ? "2G" :
5199 		    band == RTW89_BAND_5G ? "5G" : "6G",
5200 		    !!(FIELD_GET(BTC_RFK_PHY_MAP, phy_map) & BIT(RTW89_PHY_1)),
5201 		    type,
5202 		    FIELD_GET(BTC_RFK_PATH_MAP, phy_map),
5203 		    state == BTC_WRFK_STOP ? "RFK_STOP" :
5204 		    state == BTC_WRFK_START ? "RFK_START" :
5205 		    state == BTC_WRFK_ONESHOT_START ? "ONE-SHOT_START" :
5206 		    "ONE-SHOT_STOP");
5207 
5208 	if (state != BTC_WRFK_START || rtwdev->is_bt_iqk_timeout) {
5209 		_ntfy_wl_rfk(rtwdev, phy_map, type, state);
5210 		return;
5211 	}
5212 
5213 	ret = read_poll_timeout(_ntfy_wl_rfk, allow, allow, 40, 100000, false,
5214 				rtwdev, phy_map, type, state);
5215 	if (ret) {
5216 		rtw89_warn(rtwdev, "RFK notify timeout\n");
5217 		rtwdev->is_bt_iqk_timeout = true;
5218 	}
5219 }
5220 EXPORT_SYMBOL(rtw89_btc_ntfy_wl_rfk);
5221 
5222 struct rtw89_btc_wl_sta_iter_data {
5223 	struct rtw89_dev *rtwdev;
5224 	u8 busy_all;
5225 	u8 dir_all;
5226 	u8 rssi_map_all;
5227 	bool is_sta_change;
5228 	bool is_traffic_change;
5229 };
5230 
5231 static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta)
5232 {
5233 	struct rtw89_btc_wl_sta_iter_data *iter_data =
5234 				(struct rtw89_btc_wl_sta_iter_data *)data;
5235 	struct rtw89_dev *rtwdev = iter_data->rtwdev;
5236 	struct rtw89_btc *btc = &rtwdev->btc;
5237 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
5238 	struct rtw89_btc_wl_link_info *link_info = NULL;
5239 	struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
5240 	struct rtw89_traffic_stats *link_info_t = NULL;
5241 	struct rtw89_vif *rtwvif = rtwsta->rtwvif;
5242 	struct rtw89_traffic_stats *stats = &rtwvif->stats;
5243 	const struct rtw89_chip_info *chip = rtwdev->chip;
5244 	u32 last_tx_rate, last_rx_rate;
5245 	u16 last_tx_lvl, last_rx_lvl;
5246 	u8 port = rtwvif->port;
5247 	u8 rssi;
5248 	u8 busy = 0;
5249 	u8 dir = 0;
5250 	u8 rssi_map = 0;
5251 	u8 i = 0;
5252 	bool is_sta_change = false, is_traffic_change = false;
5253 
5254 	rssi = ewma_rssi_read(&rtwsta->avg_rssi) >> RSSI_FACTOR;
5255 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], rssi=%d\n", rssi);
5256 
5257 	link_info = &wl->link_info[port];
5258 	link_info->stat.traffic = rtwvif->stats;
5259 	link_info_t = &link_info->stat.traffic;
5260 
5261 	if (link_info->connected == MLME_NO_LINK) {
5262 		link_info->rx_rate_drop_cnt = 0;
5263 		return;
5264 	}
5265 
5266 	link_info->stat.rssi = rssi;
5267 	for (i = 0; i < BTC_WL_RSSI_THMAX; i++) {
5268 		link_info->rssi_state[i] =
5269 			_update_rssi_state(rtwdev,
5270 					   link_info->rssi_state[i],
5271 					   link_info->stat.rssi,
5272 					   chip->wl_rssi_thres[i]);
5273 		if (BTC_RSSI_LOW(link_info->rssi_state[i]))
5274 			rssi_map |= BIT(i);
5275 
5276 		if (btc->mdinfo.ant.type == BTC_ANT_DEDICATED &&
5277 		    BTC_RSSI_CHANGE(link_info->rssi_state[i]))
5278 			is_sta_change = true;
5279 	}
5280 	iter_data->rssi_map_all |= rssi_map;
5281 
5282 	last_tx_rate = link_info_t->tx_rate;
5283 	last_rx_rate = link_info_t->rx_rate;
5284 	last_tx_lvl = (u16)link_info_t->tx_tfc_lv;
5285 	last_rx_lvl = (u16)link_info_t->rx_tfc_lv;
5286 
5287 	if (stats->tx_tfc_lv != RTW89_TFC_IDLE ||
5288 	    stats->rx_tfc_lv != RTW89_TFC_IDLE)
5289 		busy = 1;
5290 
5291 	if (stats->tx_tfc_lv > stats->rx_tfc_lv)
5292 		dir = RTW89_TFC_UL;
5293 	else
5294 		dir = RTW89_TFC_DL;
5295 
5296 	link_info = &wl->link_info[port];
5297 	if (link_info->busy != busy || link_info->dir != dir) {
5298 		is_sta_change = true;
5299 		link_info->busy = busy;
5300 		link_info->dir = dir;
5301 	}
5302 
5303 	iter_data->busy_all |= busy;
5304 	iter_data->dir_all |= BIT(dir);
5305 
5306 	if (rtwsta->rx_hw_rate <= RTW89_HW_RATE_CCK2 &&
5307 	    last_rx_rate > RTW89_HW_RATE_CCK2 &&
5308 	    link_info_t->rx_tfc_lv > RTW89_TFC_IDLE)
5309 		link_info->rx_rate_drop_cnt++;
5310 
5311 	if (last_tx_rate != rtwsta->ra_report.hw_rate ||
5312 	    last_rx_rate != rtwsta->rx_hw_rate ||
5313 	    last_tx_lvl != link_info_t->tx_tfc_lv ||
5314 	    last_rx_lvl != link_info_t->rx_tfc_lv)
5315 		is_traffic_change = true;
5316 
5317 	link_info_t->tx_rate = rtwsta->ra_report.hw_rate;
5318 	link_info_t->rx_rate = rtwsta->rx_hw_rate;
5319 
5320 	wl->role_info.active_role[port].tx_lvl = (u16)stats->tx_tfc_lv;
5321 	wl->role_info.active_role[port].rx_lvl = (u16)stats->rx_tfc_lv;
5322 	wl->role_info.active_role[port].tx_rate = rtwsta->ra_report.hw_rate;
5323 	wl->role_info.active_role[port].rx_rate = rtwsta->rx_hw_rate;
5324 
5325 	if (is_sta_change)
5326 		iter_data->is_sta_change = true;
5327 
5328 	if (is_traffic_change)
5329 		iter_data->is_traffic_change = true;
5330 }
5331 
5332 #define BTC_NHM_CHK_INTVL 20
5333 
5334 void rtw89_btc_ntfy_wl_sta(struct rtw89_dev *rtwdev)
5335 {
5336 	struct rtw89_btc *btc = &rtwdev->btc;
5337 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
5338 	struct rtw89_btc_wl_sta_iter_data data = {.rtwdev = rtwdev};
5339 	u8 i;
5340 
5341 	ieee80211_iterate_stations_atomic(rtwdev->hw,
5342 					  rtw89_btc_ntfy_wl_sta_iter,
5343 					  &data);
5344 
5345 	wl->rssi_level = 0;
5346 	btc->dm.cnt_notify[BTC_NCNT_WL_STA]++;
5347 	for (i = BTC_WL_RSSI_THMAX; i > 0; i--) {
5348 		/* set RSSI level 4 ~ 0 if rssi bit map match */
5349 		if (data.rssi_map_all & BIT(i - 1)) {
5350 			wl->rssi_level = i;
5351 			break;
5352 		}
5353 	}
5354 
5355 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): busy=%d\n",
5356 		    __func__, !!wl->status.map.busy);
5357 
5358 	_write_scbd(rtwdev, BTC_WSCB_WLBUSY, (!!wl->status.map.busy));
5359 
5360 	if (data.is_traffic_change)
5361 		_fw_set_drv_info(rtwdev, CXDRVINFO_ROLE);
5362 	if (data.is_sta_change) {
5363 		wl->status.map.busy = data.busy_all;
5364 		wl->status.map.traffic_dir = data.dir_all;
5365 		_run_coex(rtwdev, BTC_RSN_NTFY_WL_STA);
5366 	} else if (btc->dm.cnt_notify[BTC_NCNT_WL_STA] >=
5367 		   btc->dm.cnt_dm[BTC_DCNT_WL_STA_LAST] + BTC_NHM_CHK_INTVL) {
5368 		btc->dm.cnt_dm[BTC_DCNT_WL_STA_LAST] =
5369 			btc->dm.cnt_notify[BTC_NCNT_WL_STA];
5370 	} else if (btc->dm.cnt_notify[BTC_NCNT_WL_STA] <
5371 		   btc->dm.cnt_dm[BTC_DCNT_WL_STA_LAST]) {
5372 		btc->dm.cnt_dm[BTC_DCNT_WL_STA_LAST] =
5373 		btc->dm.cnt_notify[BTC_NCNT_WL_STA];
5374 	}
5375 }
5376 
5377 void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
5378 			  u32 len, u8 class, u8 func)
5379 {
5380 	struct rtw89_btc *btc = &rtwdev->btc;
5381 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
5382 	u8 *buf = &skb->data[RTW89_C2H_HEADER_LEN];
5383 
5384 	len -= RTW89_C2H_HEADER_LEN;
5385 
5386 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
5387 		    "[BTC], %s(): C2H BT len:%d class:%d fun:%d\n",
5388 		    __func__, len, class, func);
5389 
5390 	if (class != BTFC_FW_EVENT)
5391 		return;
5392 
5393 	switch (func) {
5394 	case BTF_EVNT_RPT:
5395 	case BTF_EVNT_BUF_OVERFLOW:
5396 		pfwinfo->event[func]++;
5397 		/* Don't need rtw89_leave_ps_mode() */
5398 		btc_fw_event(rtwdev, func, buf, len);
5399 		break;
5400 	case BTF_EVNT_BT_INFO:
5401 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
5402 			    "[BTC], handle C2H BT INFO with data %8ph\n", buf);
5403 		btc->cx.cnt_bt[BTC_BCNT_INFOUPDATE]++;
5404 		_update_bt_info(rtwdev, buf, len);
5405 		break;
5406 	case BTF_EVNT_BT_SCBD:
5407 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
5408 			    "[BTC], handle C2H BT SCBD with data %8ph\n", buf);
5409 		btc->cx.cnt_bt[BTC_BCNT_SCBDUPDATE]++;
5410 		_update_bt_scbd(rtwdev, false);
5411 		break;
5412 	case BTF_EVNT_BT_PSD:
5413 		break;
5414 	case BTF_EVNT_BT_REG:
5415 		btc->dbg.rb_done = true;
5416 		btc->dbg.rb_val = le32_to_cpu(*((__le32 *)buf));
5417 
5418 		break;
5419 	case BTF_EVNT_C2H_LOOPBACK:
5420 		btc->dbg.rb_done = true;
5421 		btc->dbg.rb_val = buf[0];
5422 		break;
5423 	case BTF_EVNT_CX_RUNINFO:
5424 		btc->dm.cnt_dm[BTC_DCNT_CX_RUNINFO]++;
5425 		break;
5426 	}
5427 }
5428 
5429 #define BTC_CX_FW_OFFLOAD 0
5430 
5431 static void _show_cx_info(struct rtw89_dev *rtwdev, struct seq_file *m)
5432 {
5433 	const struct rtw89_chip_info *chip = rtwdev->chip;
5434 	struct rtw89_hal *hal = &rtwdev->hal;
5435 	struct rtw89_btc *btc = &rtwdev->btc;
5436 	struct rtw89_btc_dm *dm = &btc->dm;
5437 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
5438 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
5439 	u32 ver_main = 0, ver_sub = 0, ver_hotfix = 0, id_branch = 0;
5440 
5441 	if (!(dm->coex_info_map & BTC_COEX_INFO_CX))
5442 		return;
5443 
5444 	dm->cnt_notify[BTC_NCNT_SHOW_COEX_INFO]++;
5445 
5446 	seq_printf(m, "========== [BTC COEX INFO (%d)] ==========\n",
5447 		   chip->chip_id);
5448 
5449 	ver_main = FIELD_GET(GENMASK(31, 24), chip->para_ver);
5450 	ver_sub = FIELD_GET(GENMASK(23, 16), chip->para_ver);
5451 	ver_hotfix = FIELD_GET(GENMASK(15, 8), chip->para_ver);
5452 	id_branch = FIELD_GET(GENMASK(7, 0), chip->para_ver);
5453 	seq_printf(m, " %-15s : Coex:%d.%d.%d(branch:%d), ",
5454 		   "[coex_version]", ver_main, ver_sub, ver_hotfix, id_branch);
5455 
5456 	if (dm->wl_fw_cx_offload != BTC_CX_FW_OFFLOAD)
5457 		dm->error.map.offload_mismatch = true;
5458 	else
5459 		dm->error.map.offload_mismatch = false;
5460 
5461 	ver_main = FIELD_GET(GENMASK(31, 24), wl->ver_info.fw_coex);
5462 	ver_sub = FIELD_GET(GENMASK(23, 16), wl->ver_info.fw_coex);
5463 	ver_hotfix = FIELD_GET(GENMASK(15, 8), wl->ver_info.fw_coex);
5464 	id_branch = FIELD_GET(GENMASK(7, 0), wl->ver_info.fw_coex);
5465 	seq_printf(m, "WL_FW_coex:%d.%d.%d(branch:%d)",
5466 		   ver_main, ver_sub, ver_hotfix, id_branch);
5467 
5468 	ver_main = FIELD_GET(GENMASK(31, 24), chip->wlcx_desired);
5469 	ver_sub = FIELD_GET(GENMASK(23, 16), chip->wlcx_desired);
5470 	ver_hotfix = FIELD_GET(GENMASK(15, 8), chip->wlcx_desired);
5471 	seq_printf(m, "(%s, desired:%d.%d.%d), ",
5472 		   (wl->ver_info.fw_coex >= chip->wlcx_desired ?
5473 		   "Match" : "Mismatch"), ver_main, ver_sub, ver_hotfix);
5474 
5475 	seq_printf(m, "BT_FW_coex:%d(%s, desired:%d)\n",
5476 		   bt->ver_info.fw_coex,
5477 		   (bt->ver_info.fw_coex >= chip->btcx_desired ?
5478 		   "Match" : "Mismatch"), chip->btcx_desired);
5479 
5480 	if (bt->enable.now && bt->ver_info.fw == 0)
5481 		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_VER_INFO, true);
5482 	else
5483 		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_VER_INFO, false);
5484 
5485 	ver_main = FIELD_GET(GENMASK(31, 24), wl->ver_info.fw);
5486 	ver_sub = FIELD_GET(GENMASK(23, 16), wl->ver_info.fw);
5487 	ver_hotfix = FIELD_GET(GENMASK(15, 8), wl->ver_info.fw);
5488 	id_branch = FIELD_GET(GENMASK(7, 0), wl->ver_info.fw);
5489 	seq_printf(m, " %-15s : WL_FW:%d.%d.%d.%d, BT_FW:0x%x(%s)\n",
5490 		   "[sub_module]",
5491 		   ver_main, ver_sub, ver_hotfix, id_branch,
5492 		   bt->ver_info.fw, bt->run_patch_code ? "patch" : "ROM");
5493 
5494 	seq_printf(m, " %-15s : cv:%x, rfe_type:0x%x, ant_iso:%d, ant_pg:%d, %s",
5495 		   "[hw_info]", btc->mdinfo.cv, btc->mdinfo.rfe_type,
5496 		   btc->mdinfo.ant.isolation, btc->mdinfo.ant.num,
5497 		   (btc->mdinfo.ant.num > 1 ? "" : (btc->mdinfo.ant.single_pos ?
5498 		   "1Ant_Pos:S1, " : "1Ant_Pos:S0, ")));
5499 
5500 	seq_printf(m, "3rd_coex:%d, dbcc:%d, tx_num:%d, rx_num:%d\n",
5501 		   btc->cx.other.type, rtwdev->dbcc_en, hal->tx_nss,
5502 		   hal->rx_nss);
5503 }
5504 
5505 static void _show_wl_role_info(struct rtw89_dev *rtwdev, struct seq_file *m)
5506 {
5507 	struct rtw89_btc *btc = &rtwdev->btc;
5508 	struct rtw89_btc_wl_link_info *plink = NULL;
5509 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
5510 	struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
5511 	struct rtw89_traffic_stats *t;
5512 	u8 i;
5513 
5514 	if (rtwdev->dbcc_en) {
5515 		seq_printf(m,
5516 			   " %-15s : PHY0_band(op:%d/scan:%d/real:%d), ",
5517 			   "[dbcc_info]", wl_dinfo->op_band[RTW89_PHY_0],
5518 			   wl_dinfo->scan_band[RTW89_PHY_0],
5519 			   wl_dinfo->real_band[RTW89_PHY_0]);
5520 		seq_printf(m,
5521 			   "PHY1_band(op:%d/scan:%d/real:%d)\n",
5522 			   wl_dinfo->op_band[RTW89_PHY_1],
5523 			   wl_dinfo->scan_band[RTW89_PHY_1],
5524 			   wl_dinfo->real_band[RTW89_PHY_1]);
5525 	}
5526 
5527 	for (i = 0; i < RTW89_PORT_NUM; i++) {
5528 		plink = &btc->cx.wl.link_info[i];
5529 
5530 		if (!plink->active)
5531 			continue;
5532 
5533 		seq_printf(m,
5534 			   " [port_%d]        : role=%d(phy-%d), connect=%d(client_cnt=%d), mode=%d, center_ch=%d, bw=%d",
5535 			   plink->pid, (u32)plink->role, plink->phy,
5536 			   (u32)plink->connected, plink->client_cnt - 1,
5537 			   (u32)plink->mode, plink->ch, (u32)plink->bw);
5538 
5539 		if (plink->connected == MLME_NO_LINK)
5540 			continue;
5541 
5542 		seq_printf(m,
5543 			   ", mac_id=%d, max_tx_time=%dus, max_tx_retry=%d\n",
5544 			   plink->mac_id, plink->tx_time, plink->tx_retry);
5545 
5546 		seq_printf(m,
5547 			   " [port_%d]        : rssi=-%ddBm(%d), busy=%d, dir=%s, ",
5548 			   plink->pid, 110 - plink->stat.rssi,
5549 			   plink->stat.rssi, plink->busy,
5550 			   plink->dir == RTW89_TFC_UL ? "UL" : "DL");
5551 
5552 		t = &plink->stat.traffic;
5553 
5554 		seq_printf(m,
5555 			   "tx[rate:%d/busy_level:%d], ",
5556 			   (u32)t->tx_rate, t->tx_tfc_lv);
5557 
5558 		seq_printf(m, "rx[rate:%d/busy_level:%d/drop:%d]\n",
5559 			   (u32)t->rx_rate,
5560 			   t->rx_tfc_lv, plink->rx_rate_drop_cnt);
5561 	}
5562 }
5563 
5564 static void _show_wl_info(struct rtw89_dev *rtwdev, struct seq_file *m)
5565 {
5566 	const struct rtw89_chip_info *chip = rtwdev->chip;
5567 	struct rtw89_btc *btc = &rtwdev->btc;
5568 	struct rtw89_btc_cx *cx = &btc->cx;
5569 	struct rtw89_btc_wl_info *wl = &cx->wl;
5570 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
5571 	struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1;
5572 	u8 mode;
5573 
5574 	if (!(btc->dm.coex_info_map & BTC_COEX_INFO_WL))
5575 		return;
5576 
5577 	seq_puts(m, "========== [WL Status] ==========\n");
5578 
5579 	if (chip->chip_id == RTL8852A)
5580 		mode = wl_rinfo->link_mode;
5581 	else
5582 		mode = wl_rinfo_v1->link_mode;
5583 
5584 	seq_printf(m, " %-15s : link_mode:%d, ", "[status]", mode);
5585 
5586 	seq_printf(m,
5587 		   "rf_off:%d, power_save:%d, scan:%s(band:%d/phy_map:0x%x), ",
5588 		   wl->status.map.rf_off, wl->status.map.lps,
5589 		   wl->status.map.scan ? "Y" : "N",
5590 		   wl->scan_info.band[RTW89_PHY_0], wl->scan_info.phy_map);
5591 
5592 	seq_printf(m,
5593 		   "connecting:%s, roam:%s, 4way:%s, init_ok:%s\n",
5594 		   wl->status.map.connecting ? "Y" : "N",
5595 		   wl->status.map.roaming ?  "Y" : "N",
5596 		   wl->status.map._4way ? "Y" : "N",
5597 		   wl->status.map.init_ok ? "Y" : "N");
5598 
5599 	_show_wl_role_info(rtwdev, m);
5600 }
5601 
5602 enum btc_bt_a2dp_type {
5603 	BTC_A2DP_LEGACY = 0,
5604 	BTC_A2DP_TWS_SNIFF = 1,
5605 	BTC_A2DP_TWS_RELAY = 2,
5606 };
5607 
5608 static void _show_bt_profile_info(struct rtw89_dev *rtwdev, struct seq_file *m)
5609 {
5610 	struct rtw89_btc *btc = &rtwdev->btc;
5611 	struct rtw89_btc_bt_link_info *bt_linfo = &btc->cx.bt.link_info;
5612 	struct rtw89_btc_bt_hfp_desc hfp = bt_linfo->hfp_desc;
5613 	struct rtw89_btc_bt_hid_desc hid = bt_linfo->hid_desc;
5614 	struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc;
5615 	struct rtw89_btc_bt_pan_desc pan = bt_linfo->pan_desc;
5616 
5617 	if (hfp.exist) {
5618 		seq_printf(m, " %-15s : type:%s, sut_pwr:%d, golden-rx:%d",
5619 			   "[HFP]", (hfp.type == 0 ? "SCO" : "eSCO"),
5620 			   bt_linfo->sut_pwr_level[0],
5621 			   bt_linfo->golden_rx_shift[0]);
5622 	}
5623 
5624 	if (hid.exist) {
5625 		seq_printf(m,
5626 			   "\n\r %-15s : type:%s%s%s%s%s pair-cnt:%d, sut_pwr:%d, golden-rx:%d\n",
5627 			   "[HID]",
5628 			   hid.type & BTC_HID_218 ? "2/18," : "",
5629 			   hid.type & BTC_HID_418 ? "4/18," : "",
5630 			   hid.type & BTC_HID_BLE ? "BLE," : "",
5631 			   hid.type & BTC_HID_RCU ? "RCU," : "",
5632 			   hid.type & BTC_HID_RCU_VOICE ? "RCU-Voice," : "",
5633 			   hid.pair_cnt, bt_linfo->sut_pwr_level[1],
5634 			   bt_linfo->golden_rx_shift[1]);
5635 	}
5636 
5637 	if (a2dp.exist) {
5638 		seq_printf(m,
5639 			   " %-15s : type:%s, bit-pool:%d, flush-time:%d, ",
5640 			   "[A2DP]",
5641 			   a2dp.type == BTC_A2DP_LEGACY ? "Legacy" : "TWS",
5642 			    a2dp.bitpool, a2dp.flush_time);
5643 
5644 		seq_printf(m,
5645 			   "vid:0x%x, Dev-name:0x%x, sut_pwr:%d, golden-rx:%d\n",
5646 			   a2dp.vendor_id, a2dp.device_name,
5647 			   bt_linfo->sut_pwr_level[2],
5648 			   bt_linfo->golden_rx_shift[2]);
5649 	}
5650 
5651 	if (pan.exist) {
5652 		seq_printf(m, " %-15s : sut_pwr:%d, golden-rx:%d\n",
5653 			   "[PAN]",
5654 			   bt_linfo->sut_pwr_level[3],
5655 			   bt_linfo->golden_rx_shift[3]);
5656 	}
5657 }
5658 
5659 static void _show_bt_info(struct rtw89_dev *rtwdev, struct seq_file *m)
5660 {
5661 	struct rtw89_btc *btc = &rtwdev->btc;
5662 	struct rtw89_btc_cx *cx = &btc->cx;
5663 	struct rtw89_btc_bt_info *bt = &cx->bt;
5664 	struct rtw89_btc_wl_info *wl = &cx->wl;
5665 	struct rtw89_btc_module *module = &btc->mdinfo;
5666 	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
5667 	u8 *afh = bt_linfo->afh_map;
5668 
5669 	if (!(btc->dm.coex_info_map & BTC_COEX_INFO_BT))
5670 		return;
5671 
5672 	seq_puts(m, "========== [BT Status] ==========\n");
5673 
5674 	seq_printf(m, " %-15s : enable:%s, btg:%s%s, connect:%s, ",
5675 		   "[status]", bt->enable.now ? "Y" : "N",
5676 		   bt->btg_type ? "Y" : "N",
5677 		   (bt->enable.now && (bt->btg_type != module->bt_pos) ?
5678 		   "(efuse-mismatch!!)" : ""),
5679 		   (bt_linfo->status.map.connect ? "Y" : "N"));
5680 
5681 	seq_printf(m, "igno_wl:%s, mailbox_avl:%s, rfk_state:0x%x\n",
5682 		   bt->igno_wl ? "Y" : "N",
5683 		   bt->mbx_avl ? "Y" : "N", bt->rfk_info.val);
5684 
5685 	seq_printf(m, " %-15s : profile:%s%s%s%s%s ",
5686 		   "[profile]",
5687 		   (bt_linfo->profile_cnt.now == 0) ? "None," : "",
5688 		   bt_linfo->hfp_desc.exist ? "HFP," : "",
5689 		   bt_linfo->hid_desc.exist ? "HID," : "",
5690 		   bt_linfo->a2dp_desc.exist ?
5691 		   (bt_linfo->a2dp_desc.sink ? "A2DP_sink," : "A2DP,") : "",
5692 		   bt_linfo->pan_desc.exist ? "PAN," : "");
5693 
5694 	seq_printf(m,
5695 		   "multi-link:%s, role:%s, ble-connect:%s, CQDDR:%s, A2DP_active:%s, PAN_active:%s\n",
5696 		   bt_linfo->multi_link.now ? "Y" : "N",
5697 		   bt_linfo->slave_role ? "Slave" : "Master",
5698 		   bt_linfo->status.map.ble_connect ? "Y" : "N",
5699 		   bt_linfo->cqddr ? "Y" : "N",
5700 		   bt_linfo->a2dp_desc.active ? "Y" : "N",
5701 		   bt_linfo->pan_desc.active ? "Y" : "N");
5702 
5703 	seq_printf(m,
5704 		   " %-15s : rssi:%ddBm, tx_rate:%dM, %s%s%s",
5705 		   "[link]", bt_linfo->rssi - 100,
5706 		   bt_linfo->tx_3m ? 3 : 2,
5707 		   bt_linfo->status.map.inq_pag ? " inq-page!!" : "",
5708 		   bt_linfo->status.map.acl_busy ? " acl_busy!!" : "",
5709 		   bt_linfo->status.map.mesh_busy ? " mesh_busy!!" : "");
5710 
5711 	seq_printf(m,
5712 		   "%s afh_map[%02x%02x_%02x%02x_%02x%02x_%02x%02x_%02x%02x], ",
5713 		   bt_linfo->relink.now ? " ReLink!!" : "",
5714 		   afh[0], afh[1], afh[2], afh[3], afh[4],
5715 		   afh[5], afh[6], afh[7], afh[8], afh[9]);
5716 
5717 	seq_printf(m, "wl_ch_map[en:%d/ch:%d/bw:%d]\n",
5718 		   wl->afh_info.en, wl->afh_info.ch, wl->afh_info.bw);
5719 
5720 	seq_printf(m,
5721 		   " %-15s : retry:%d, relink:%d, rate_chg:%d, reinit:%d, reenable:%d, ",
5722 		   "[stat_cnt]", cx->cnt_bt[BTC_BCNT_RETRY],
5723 		   cx->cnt_bt[BTC_BCNT_RELINK], cx->cnt_bt[BTC_BCNT_RATECHG],
5724 		   cx->cnt_bt[BTC_BCNT_REINIT], cx->cnt_bt[BTC_BCNT_REENABLE]);
5725 
5726 	seq_printf(m,
5727 		   "role-switch:%d, afh:%d, inq_page:%d(inq:%d/page:%d), igno_wl:%d\n",
5728 		   cx->cnt_bt[BTC_BCNT_ROLESW], cx->cnt_bt[BTC_BCNT_AFH],
5729 		   cx->cnt_bt[BTC_BCNT_INQPAG], cx->cnt_bt[BTC_BCNT_INQ],
5730 		   cx->cnt_bt[BTC_BCNT_PAGE], cx->cnt_bt[BTC_BCNT_IGNOWL]);
5731 
5732 	_show_bt_profile_info(rtwdev, m);
5733 
5734 	seq_printf(m,
5735 		   " %-15s : raw_data[%02x %02x %02x %02x %02x %02x] (type:%s/cnt:%d/same:%d)\n",
5736 		   "[bt_info]", bt->raw_info[2], bt->raw_info[3],
5737 		   bt->raw_info[4], bt->raw_info[5], bt->raw_info[6],
5738 		   bt->raw_info[7],
5739 		   bt->raw_info[0] == BTC_BTINFO_AUTO ? "auto" : "reply",
5740 		   cx->cnt_bt[BTC_BCNT_INFOUPDATE],
5741 		   cx->cnt_bt[BTC_BCNT_INFOSAME]);
5742 
5743 	seq_printf(m,
5744 		   " %-15s : Hi-rx = %d, Hi-tx = %d, Lo-rx = %d, Lo-tx = %d (bt_polut_wl_tx = %d)\n",
5745 		   "[trx_req_cnt]", cx->cnt_bt[BTC_BCNT_HIPRI_RX],
5746 		   cx->cnt_bt[BTC_BCNT_HIPRI_TX], cx->cnt_bt[BTC_BCNT_LOPRI_RX],
5747 		   cx->cnt_bt[BTC_BCNT_LOPRI_TX], cx->cnt_bt[BTC_BCNT_POLUT]);
5748 }
5749 
5750 #define CASE_BTC_RSN_STR(e) case BTC_RSN_ ## e: return #e
5751 #define CASE_BTC_ACT_STR(e) case BTC_ACT_ ## e | BTC_ACT_EXT_BIT: return #e
5752 #define CASE_BTC_POLICY_STR(e) \
5753 	case BTC_CXP_ ## e | BTC_POLICY_EXT_BIT: return #e
5754 
5755 static const char *steps_to_str(u16 step)
5756 {
5757 	switch (step) {
5758 	CASE_BTC_RSN_STR(NONE);
5759 	CASE_BTC_RSN_STR(NTFY_INIT);
5760 	CASE_BTC_RSN_STR(NTFY_SWBAND);
5761 	CASE_BTC_RSN_STR(NTFY_WL_STA);
5762 	CASE_BTC_RSN_STR(NTFY_RADIO_STATE);
5763 	CASE_BTC_RSN_STR(UPDATE_BT_SCBD);
5764 	CASE_BTC_RSN_STR(NTFY_WL_RFK);
5765 	CASE_BTC_RSN_STR(UPDATE_BT_INFO);
5766 	CASE_BTC_RSN_STR(NTFY_SCAN_START);
5767 	CASE_BTC_RSN_STR(NTFY_SCAN_FINISH);
5768 	CASE_BTC_RSN_STR(NTFY_SPECIFIC_PACKET);
5769 	CASE_BTC_RSN_STR(NTFY_POWEROFF);
5770 	CASE_BTC_RSN_STR(NTFY_ROLE_INFO);
5771 	CASE_BTC_RSN_STR(CMD_SET_COEX);
5772 	CASE_BTC_RSN_STR(ACT1_WORK);
5773 	CASE_BTC_RSN_STR(BT_DEVINFO_WORK);
5774 	CASE_BTC_RSN_STR(RFK_CHK_WORK);
5775 
5776 	CASE_BTC_ACT_STR(NONE);
5777 	CASE_BTC_ACT_STR(WL_ONLY);
5778 	CASE_BTC_ACT_STR(WL_5G);
5779 	CASE_BTC_ACT_STR(WL_OTHER);
5780 	CASE_BTC_ACT_STR(WL_IDLE);
5781 	CASE_BTC_ACT_STR(WL_NC);
5782 	CASE_BTC_ACT_STR(WL_RFK);
5783 	CASE_BTC_ACT_STR(WL_INIT);
5784 	CASE_BTC_ACT_STR(WL_OFF);
5785 	CASE_BTC_ACT_STR(FREERUN);
5786 	CASE_BTC_ACT_STR(BT_WHQL);
5787 	CASE_BTC_ACT_STR(BT_RFK);
5788 	CASE_BTC_ACT_STR(BT_OFF);
5789 	CASE_BTC_ACT_STR(BT_IDLE);
5790 	CASE_BTC_ACT_STR(BT_HFP);
5791 	CASE_BTC_ACT_STR(BT_HID);
5792 	CASE_BTC_ACT_STR(BT_A2DP);
5793 	CASE_BTC_ACT_STR(BT_A2DPSINK);
5794 	CASE_BTC_ACT_STR(BT_PAN);
5795 	CASE_BTC_ACT_STR(BT_A2DP_HID);
5796 	CASE_BTC_ACT_STR(BT_A2DP_PAN);
5797 	CASE_BTC_ACT_STR(BT_PAN_HID);
5798 	CASE_BTC_ACT_STR(BT_A2DP_PAN_HID);
5799 	CASE_BTC_ACT_STR(WL_25G_MCC);
5800 	CASE_BTC_ACT_STR(WL_2G_MCC);
5801 	CASE_BTC_ACT_STR(WL_2G_SCC);
5802 	CASE_BTC_ACT_STR(WL_2G_AP);
5803 	CASE_BTC_ACT_STR(WL_2G_GO);
5804 	CASE_BTC_ACT_STR(WL_2G_GC);
5805 	CASE_BTC_ACT_STR(WL_2G_NAN);
5806 
5807 	CASE_BTC_POLICY_STR(OFF_BT);
5808 	CASE_BTC_POLICY_STR(OFF_WL);
5809 	CASE_BTC_POLICY_STR(OFF_EQ0);
5810 	CASE_BTC_POLICY_STR(OFF_EQ1);
5811 	CASE_BTC_POLICY_STR(OFF_EQ2);
5812 	CASE_BTC_POLICY_STR(OFF_EQ3);
5813 	CASE_BTC_POLICY_STR(OFF_BWB0);
5814 	CASE_BTC_POLICY_STR(OFF_BWB1);
5815 	CASE_BTC_POLICY_STR(OFF_BWB2);
5816 	CASE_BTC_POLICY_STR(OFFB_BWB0);
5817 	CASE_BTC_POLICY_STR(OFFE_DEF);
5818 	CASE_BTC_POLICY_STR(OFFE_DEF2);
5819 	CASE_BTC_POLICY_STR(OFFE_2GBWISOB);
5820 	CASE_BTC_POLICY_STR(OFFE_2GISOB);
5821 	CASE_BTC_POLICY_STR(OFFE_2GBWMIXB);
5822 	CASE_BTC_POLICY_STR(OFFE_WL);
5823 	CASE_BTC_POLICY_STR(OFFE_2GBWMIXB2);
5824 	CASE_BTC_POLICY_STR(FIX_TD3030);
5825 	CASE_BTC_POLICY_STR(FIX_TD5050);
5826 	CASE_BTC_POLICY_STR(FIX_TD2030);
5827 	CASE_BTC_POLICY_STR(FIX_TD4010);
5828 	CASE_BTC_POLICY_STR(FIX_TD7010);
5829 	CASE_BTC_POLICY_STR(FIX_TD2060);
5830 	CASE_BTC_POLICY_STR(FIX_TD3060);
5831 	CASE_BTC_POLICY_STR(FIX_TD2080);
5832 	CASE_BTC_POLICY_STR(FIX_TDW1B1);
5833 	CASE_BTC_POLICY_STR(FIX_TD4020);
5834 	CASE_BTC_POLICY_STR(FIX_TD4010ISO);
5835 	CASE_BTC_POLICY_STR(PFIX_TD3030);
5836 	CASE_BTC_POLICY_STR(PFIX_TD5050);
5837 	CASE_BTC_POLICY_STR(PFIX_TD2030);
5838 	CASE_BTC_POLICY_STR(PFIX_TD2060);
5839 	CASE_BTC_POLICY_STR(PFIX_TD3070);
5840 	CASE_BTC_POLICY_STR(PFIX_TD2080);
5841 	CASE_BTC_POLICY_STR(PFIX_TDW1B1);
5842 	CASE_BTC_POLICY_STR(AUTO_TD50B1);
5843 	CASE_BTC_POLICY_STR(AUTO_TD60B1);
5844 	CASE_BTC_POLICY_STR(AUTO_TD20B1);
5845 	CASE_BTC_POLICY_STR(AUTO_TDW1B1);
5846 	CASE_BTC_POLICY_STR(PAUTO_TD50B1);
5847 	CASE_BTC_POLICY_STR(PAUTO_TD60B1);
5848 	CASE_BTC_POLICY_STR(PAUTO_TD20B1);
5849 	CASE_BTC_POLICY_STR(PAUTO_TDW1B1);
5850 	CASE_BTC_POLICY_STR(AUTO2_TD3050);
5851 	CASE_BTC_POLICY_STR(AUTO2_TD3070);
5852 	CASE_BTC_POLICY_STR(AUTO2_TD5050);
5853 	CASE_BTC_POLICY_STR(AUTO2_TD6060);
5854 	CASE_BTC_POLICY_STR(AUTO2_TD2080);
5855 	CASE_BTC_POLICY_STR(AUTO2_TDW1B4);
5856 	CASE_BTC_POLICY_STR(PAUTO2_TD3050);
5857 	CASE_BTC_POLICY_STR(PAUTO2_TD3070);
5858 	CASE_BTC_POLICY_STR(PAUTO2_TD5050);
5859 	CASE_BTC_POLICY_STR(PAUTO2_TD6060);
5860 	CASE_BTC_POLICY_STR(PAUTO2_TD2080);
5861 	CASE_BTC_POLICY_STR(PAUTO2_TDW1B4);
5862 	default:
5863 		return "unknown step";
5864 	}
5865 }
5866 
5867 static
5868 void seq_print_segment(struct seq_file *m, const char *prefix, u16 *data,
5869 		       u8 len, u8 seg_len, u8 start_idx, u8 ring_len)
5870 {
5871 	u8 i;
5872 	u8 cur_index;
5873 
5874 	for (i = 0; i < len ; i++) {
5875 		if ((i % seg_len) == 0)
5876 			seq_printf(m, " %-15s : ", prefix);
5877 		cur_index = (start_idx + i) % ring_len;
5878 		if (i % 3 == 0)
5879 			seq_printf(m, "-> %-20s",
5880 				   steps_to_str(*(data + cur_index)));
5881 		else if (i % 3 == 1)
5882 			seq_printf(m, "-> %-15s",
5883 				   steps_to_str(*(data + cur_index)));
5884 		else
5885 			seq_printf(m, "-> %-13s",
5886 				   steps_to_str(*(data + cur_index)));
5887 		if (i == (len - 1) || (i % seg_len) == (seg_len - 1))
5888 			seq_puts(m, "\n");
5889 	}
5890 }
5891 
5892 static void _show_dm_step(struct rtw89_dev *rtwdev, struct seq_file *m)
5893 {
5894 	struct rtw89_btc *btc = &rtwdev->btc;
5895 	struct rtw89_btc_dm *dm = &btc->dm;
5896 	u8 start_idx;
5897 	u8 len;
5898 
5899 	len = dm->dm_step.step_ov ? RTW89_BTC_DM_MAXSTEP : dm->dm_step.step_pos;
5900 	start_idx = dm->dm_step.step_ov ? dm->dm_step.step_pos : 0;
5901 
5902 	seq_print_segment(m, "[dm_steps]", dm->dm_step.step, len, 6, start_idx,
5903 			  ARRAY_SIZE(dm->dm_step.step));
5904 }
5905 
5906 static void _show_dm_info(struct rtw89_dev *rtwdev, struct seq_file *m)
5907 {
5908 	struct rtw89_btc *btc = &rtwdev->btc;
5909 	struct rtw89_btc_module *module = &btc->mdinfo;
5910 	struct rtw89_btc_dm *dm = &btc->dm;
5911 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
5912 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
5913 
5914 	if (!(dm->coex_info_map & BTC_COEX_INFO_DM))
5915 		return;
5916 
5917 	seq_printf(m, "========== [Mechanism Status %s] ==========\n",
5918 		   (btc->ctrl.manual ? "(Manual)" : "(Auto)"));
5919 
5920 	seq_printf(m,
5921 		   " %-15s : type:%s, reason:%s(), action:%s(), ant_path:%ld, run_cnt:%d\n",
5922 		   "[status]",
5923 		   module->ant.type == BTC_ANT_SHARED ? "shared" : "dedicated",
5924 		   steps_to_str(dm->run_reason),
5925 		   steps_to_str(dm->run_action | BTC_ACT_EXT_BIT),
5926 		   FIELD_GET(GENMASK(7, 0), dm->set_ant_path),
5927 		   dm->cnt_dm[BTC_DCNT_RUN]);
5928 
5929 	_show_dm_step(rtwdev, m);
5930 
5931 	seq_printf(m, " %-15s : wl_only:%d, bt_only:%d, igno_bt:%d, free_run:%d, wl_ps_ctrl:%d, wl_mimo_ps:%d, ",
5932 		   "[dm_flag]", dm->wl_only, dm->bt_only, btc->ctrl.igno_bt,
5933 		   dm->freerun, btc->lps, dm->wl_mimo_ps);
5934 
5935 	seq_printf(m, "leak_ap:%d, fw_offload:%s%s\n", dm->leak_ap,
5936 		   (BTC_CX_FW_OFFLOAD ? "Y" : "N"),
5937 		   (dm->wl_fw_cx_offload == BTC_CX_FW_OFFLOAD ?
5938 		    "" : "(Mismatch!!)"));
5939 
5940 	if (dm->rf_trx_para.wl_tx_power == 0xff)
5941 		seq_printf(m,
5942 			   " %-15s : wl_rssi_lvl:%d, para_lvl:%d, wl_tx_pwr:orig, ",
5943 			   "[trx_ctrl]", wl->rssi_level, dm->trx_para_level);
5944 
5945 	else
5946 		seq_printf(m,
5947 			   " %-15s : wl_rssi_lvl:%d, para_lvl:%d, wl_tx_pwr:%d, ",
5948 			   "[trx_ctrl]", wl->rssi_level, dm->trx_para_level,
5949 			   dm->rf_trx_para.wl_tx_power);
5950 
5951 	seq_printf(m,
5952 		   "wl_rx_lvl:%d, bt_tx_pwr_dec:%d, bt_rx_lna:%d(%s-tbl), wl_btg_rx:%d\n",
5953 		   dm->rf_trx_para.wl_rx_gain, dm->rf_trx_para.bt_tx_power,
5954 		   dm->rf_trx_para.bt_rx_gain,
5955 		   (bt->hi_lna_rx ? "Hi" : "Ori"), dm->wl_btg_rx);
5956 
5957 	seq_printf(m,
5958 		   " %-15s : wl_tx_limit[en:%d/max_t:%dus/max_retry:%d], bt_slot_reg:%d-TU\n",
5959 		   "[dm_ctrl]", dm->wl_tx_limit.enable, dm->wl_tx_limit.tx_time,
5960 		   dm->wl_tx_limit.tx_retry, btc->bt_req_len);
5961 }
5962 
5963 static void _show_error(struct rtw89_dev *rtwdev, struct seq_file *m)
5964 {
5965 	struct rtw89_btc *btc = &rtwdev->btc;
5966 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
5967 	struct rtw89_btc_fbtc_cysta *pcysta = NULL;
5968 
5969 	pcysta = &pfwinfo->rpt_fbtc_cysta.finfo;
5970 
5971 	if (pfwinfo->event[BTF_EVNT_BUF_OVERFLOW] == 0 &&
5972 	    pcysta->except_cnt == 0 &&
5973 	    !pfwinfo->len_mismch && !pfwinfo->fver_mismch)
5974 		return;
5975 
5976 	seq_printf(m, " %-15s : ", "[error]");
5977 
5978 	if (pfwinfo->event[BTF_EVNT_BUF_OVERFLOW]) {
5979 		seq_printf(m,
5980 			   "overflow-cnt: %d, ",
5981 			   pfwinfo->event[BTF_EVNT_BUF_OVERFLOW]);
5982 	}
5983 
5984 	if (pfwinfo->len_mismch) {
5985 		seq_printf(m,
5986 			   "len-mismatch: 0x%x, ",
5987 			   pfwinfo->len_mismch);
5988 	}
5989 
5990 	if (pfwinfo->fver_mismch) {
5991 		seq_printf(m,
5992 			   "fver-mismatch: 0x%x, ",
5993 			   pfwinfo->fver_mismch);
5994 	}
5995 
5996 	/* cycle statistics exceptions */
5997 	if (pcysta->exception || pcysta->except_cnt) {
5998 		seq_printf(m,
5999 			   "exception-type: 0x%x, exception-cnt = %d",
6000 			   pcysta->exception, pcysta->except_cnt);
6001 	}
6002 	seq_puts(m, "\n");
6003 }
6004 
6005 static void _show_fbtc_tdma(struct rtw89_dev *rtwdev, struct seq_file *m)
6006 {
6007 	struct rtw89_btc *btc = &rtwdev->btc;
6008 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
6009 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
6010 	struct rtw89_btc_fbtc_tdma *t = NULL;
6011 	struct rtw89_btc_fbtc_slot *s = NULL;
6012 	struct rtw89_btc_dm *dm = &btc->dm;
6013 	u8 i, cnt = 0;
6014 
6015 	pcinfo = &pfwinfo->rpt_fbtc_tdma.cinfo;
6016 	if (!pcinfo->valid)
6017 		return;
6018 
6019 	t = &pfwinfo->rpt_fbtc_tdma.finfo;
6020 
6021 	seq_printf(m,
6022 		   " %-15s : ", "[tdma_policy]");
6023 	seq_printf(m,
6024 		   "type:%d, rx_flow_ctrl:%d, tx_pause:%d, ",
6025 		   (u32)t->type,
6026 		   t->rxflctrl, t->txpause);
6027 
6028 	seq_printf(m,
6029 		   "wl_toggle_n:%d, leak_n:%d, ext_ctrl:%d, ",
6030 		   t->wtgle_n, t->leak_n, t->ext_ctrl);
6031 
6032 	seq_printf(m,
6033 		   "policy_type:%d",
6034 		   (u32)btc->policy_type);
6035 
6036 	s = pfwinfo->rpt_fbtc_slots.finfo.slot;
6037 
6038 	for (i = 0; i < CXST_MAX; i++) {
6039 		if (dm->update_slot_map == BIT(CXST_MAX) - 1)
6040 			break;
6041 
6042 		if (!(dm->update_slot_map & BIT(i)))
6043 			continue;
6044 
6045 		if (cnt % 6 == 0)
6046 			seq_printf(m,
6047 				   " %-15s : %d[%d/0x%x/%d]",
6048 				   "[slot_policy]",
6049 				   (u32)i,
6050 				   s[i].dur, s[i].cxtbl, s[i].cxtype);
6051 		else
6052 			seq_printf(m,
6053 				   ", %d[%d/0x%x/%d]",
6054 				   (u32)i,
6055 				   s[i].dur, s[i].cxtbl, s[i].cxtype);
6056 		if (cnt % 6 == 5)
6057 			seq_puts(m, "\n");
6058 		cnt++;
6059 	}
6060 	seq_puts(m, "\n");
6061 }
6062 
6063 static void _show_fbtc_slots(struct rtw89_dev *rtwdev, struct seq_file *m)
6064 {
6065 	struct rtw89_btc *btc = &rtwdev->btc;
6066 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
6067 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
6068 	struct rtw89_btc_fbtc_slots *pslots = NULL;
6069 	struct rtw89_btc_fbtc_slot s;
6070 	u8 i = 0;
6071 
6072 	pcinfo = &pfwinfo->rpt_fbtc_slots.cinfo;
6073 	if (!pcinfo->valid)
6074 		return;
6075 
6076 	pslots = &pfwinfo->rpt_fbtc_slots.finfo;
6077 
6078 	for (i = 0; i < CXST_MAX; i++) {
6079 		s = pslots->slot[i];
6080 		if (i % 6 == 0)
6081 			seq_printf(m,
6082 				   " %-15s : %02d[%03d/0x%x/%d]",
6083 				   "[slot_list]",
6084 				   (u32)i,
6085 				   s.dur, s.cxtbl, s.cxtype);
6086 		else
6087 			seq_printf(m,
6088 				   ", %02d[%03d/0x%x/%d]",
6089 				   (u32)i,
6090 				   s.dur, s.cxtbl, s.cxtype);
6091 		if (i % 6 == 5)
6092 			seq_puts(m, "\n");
6093 	}
6094 }
6095 
6096 static void _show_fbtc_cysta(struct rtw89_dev *rtwdev, struct seq_file *m)
6097 {
6098 	struct rtw89_btc *btc = &rtwdev->btc;
6099 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
6100 	struct rtw89_btc_dm *dm = &btc->dm;
6101 	struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc;
6102 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
6103 	struct rtw89_btc_fbtc_cysta *pcysta_le32 = NULL;
6104 	struct rtw89_btc_fbtc_cysta_cpu pcysta[1];
6105 	union rtw89_btc_fbtc_rxflct r;
6106 	u8 i, cnt = 0, slot_pair;
6107 	u16 cycle, c_begin, c_end, store_index;
6108 
6109 	pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
6110 	if (!pcinfo->valid)
6111 		return;
6112 
6113 	pcysta_le32 = &pfwinfo->rpt_fbtc_cysta.finfo;
6114 	rtw89_btc_fbtc_cysta_to_cpu(pcysta_le32, pcysta);
6115 	seq_printf(m,
6116 		   " %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]",
6117 		   "[cycle_cnt]", pcysta->cycles, pcysta->bcn_cnt[CXBCN_ALL],
6118 		   pcysta->bcn_cnt[CXBCN_ALL_OK],
6119 		   pcysta->bcn_cnt[CXBCN_BT_SLOT],
6120 		   pcysta->bcn_cnt[CXBCN_BT_OK]);
6121 
6122 	for (i = 0; i < CXST_MAX; i++) {
6123 		if (!pcysta->slot_cnt[i])
6124 			continue;
6125 		seq_printf(m,
6126 			   ", %d:%d", (u32)i, pcysta->slot_cnt[i]);
6127 	}
6128 
6129 	if (dm->tdma_now.rxflctrl) {
6130 		seq_printf(m,
6131 			   ", leak_rx:%d", pcysta->leakrx_cnt);
6132 	}
6133 
6134 	if (pcysta->collision_cnt) {
6135 		seq_printf(m,
6136 			   ", collision:%d", pcysta->collision_cnt);
6137 	}
6138 
6139 	if (pcysta->skip_cnt) {
6140 		seq_printf(m,
6141 			   ", skip:%d", pcysta->skip_cnt);
6142 	}
6143 	seq_puts(m, "\n");
6144 
6145 	seq_printf(m, " %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]",
6146 		   "[cycle_time]",
6147 		   pcysta->tavg_cycle[CXT_WL],
6148 		   pcysta->tavg_cycle[CXT_BT],
6149 		   pcysta->tavg_lk / 1000, pcysta->tavg_lk % 1000);
6150 	seq_printf(m,
6151 		   ", max_t[wl:%d/bt:%d/lk:%d.%03d]",
6152 		   pcysta->tmax_cycle[CXT_WL],
6153 		   pcysta->tmax_cycle[CXT_BT],
6154 		   pcysta->tmax_lk / 1000, pcysta->tmax_lk % 1000);
6155 	seq_printf(m,
6156 		   ", maxdiff_t[wl:%d/bt:%d]\n",
6157 		   pcysta->tmaxdiff_cycle[CXT_WL],
6158 		   pcysta->tmaxdiff_cycle[CXT_BT]);
6159 
6160 	if (pcysta->cycles == 0)
6161 		return;
6162 
6163 	/* 1 cycle record 1 wl-slot and 1 bt-slot */
6164 	slot_pair = BTC_CYCLE_SLOT_MAX / 2;
6165 
6166 	if (pcysta->cycles <= slot_pair)
6167 		c_begin = 1;
6168 	else
6169 		c_begin = pcysta->cycles - slot_pair + 1;
6170 
6171 	c_end = pcysta->cycles;
6172 
6173 	for (cycle = c_begin; cycle <= c_end; cycle++) {
6174 		cnt++;
6175 		store_index = ((cycle - 1) % slot_pair) * 2;
6176 
6177 		if (cnt % (BTC_CYCLE_SLOT_MAX / 4) == 1)
6178 			seq_printf(m,
6179 				   " %-15s : ->b%02d->w%02d", "[cycle_step]",
6180 				   pcysta->tslot_cycle[store_index],
6181 				   pcysta->tslot_cycle[store_index + 1]);
6182 		else
6183 			seq_printf(m,
6184 				   "->b%02d->w%02d",
6185 				   pcysta->tslot_cycle[store_index],
6186 				   pcysta->tslot_cycle[store_index + 1]);
6187 		if (cnt % (BTC_CYCLE_SLOT_MAX / 4) == 0 || cnt == c_end)
6188 			seq_puts(m, "\n");
6189 	}
6190 
6191 	if (a2dp->exist) {
6192 		seq_printf(m,
6193 			   " %-15s : a2dp_ept:%d, a2dp_late:%d",
6194 			   "[a2dp_t_sta]",
6195 			   pcysta->a2dpept, pcysta->a2dpeptto);
6196 
6197 		seq_printf(m,
6198 			   ", avg_t:%d, max_t:%d",
6199 			   pcysta->tavg_a2dpept, pcysta->tmax_a2dpept);
6200 		r.val = dm->tdma_now.rxflctrl;
6201 
6202 		if (r.type && r.tgln_n) {
6203 			seq_printf(m,
6204 				   ", cycle[PSTDMA:%d/TDMA:%d], ",
6205 				   pcysta->cycles_a2dp[CXT_FLCTRL_ON],
6206 				   pcysta->cycles_a2dp[CXT_FLCTRL_OFF]);
6207 
6208 			seq_printf(m,
6209 				   "avg_t[PSTDMA:%d/TDMA:%d], ",
6210 				   pcysta->tavg_a2dp[CXT_FLCTRL_ON],
6211 				   pcysta->tavg_a2dp[CXT_FLCTRL_OFF]);
6212 
6213 			seq_printf(m,
6214 				   "max_t[PSTDMA:%d/TDMA:%d]",
6215 				   pcysta->tmax_a2dp[CXT_FLCTRL_ON],
6216 				   pcysta->tmax_a2dp[CXT_FLCTRL_OFF]);
6217 		}
6218 		seq_puts(m, "\n");
6219 	}
6220 }
6221 
6222 static void _show_fbtc_nullsta(struct rtw89_dev *rtwdev, struct seq_file *m)
6223 {
6224 	struct rtw89_btc *btc = &rtwdev->btc;
6225 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
6226 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
6227 	struct rtw89_btc_fbtc_cynullsta *ns = NULL;
6228 	u8 i = 0;
6229 
6230 	if (!btc->dm.tdma_now.rxflctrl)
6231 		return;
6232 
6233 	pcinfo = &pfwinfo->rpt_fbtc_nullsta.cinfo;
6234 	if (!pcinfo->valid)
6235 		return;
6236 
6237 	ns = &pfwinfo->rpt_fbtc_nullsta.finfo;
6238 
6239 	seq_printf(m, " %-15s : ", "[null_sta]");
6240 
6241 	for (i = 0; i < 2; i++) {
6242 		if (i != 0)
6243 			seq_printf(m, ", null-%d", i);
6244 		else
6245 			seq_printf(m, "null-%d", i);
6246 		seq_printf(m, "[ok:%d/", le32_to_cpu(ns->result[i][1]));
6247 		seq_printf(m, "fail:%d/", le32_to_cpu(ns->result[i][0]));
6248 		seq_printf(m, "on_time:%d/", le32_to_cpu(ns->result[i][2]));
6249 		seq_printf(m, "retry:%d/", le32_to_cpu(ns->result[i][3]));
6250 		seq_printf(m, "avg_t:%d.%03d/",
6251 			   le32_to_cpu(ns->avg_t[i]) / 1000,
6252 			   le32_to_cpu(ns->avg_t[i]) % 1000);
6253 		seq_printf(m, "max_t:%d.%03d]",
6254 			   le32_to_cpu(ns->max_t[i]) / 1000,
6255 			   le32_to_cpu(ns->max_t[i]) % 1000);
6256 	}
6257 	seq_puts(m, "\n");
6258 }
6259 
6260 static void _show_fbtc_step(struct rtw89_dev *rtwdev, struct seq_file *m)
6261 {
6262 	struct rtw89_btc *btc = &rtwdev->btc;
6263 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
6264 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
6265 	struct rtw89_btc_fbtc_steps *pstep = NULL;
6266 	u8 type, val, cnt = 0, state = 0;
6267 	bool outloop = false;
6268 	u16 i, diff_t, n_start = 0, n_stop = 0;
6269 	u16 pos_old, pos_new;
6270 
6271 	pcinfo = &pfwinfo->rpt_fbtc_step.cinfo;
6272 	if (!pcinfo->valid)
6273 		return;
6274 
6275 	pstep = &pfwinfo->rpt_fbtc_step.finfo;
6276 	pos_old = le16_to_cpu(pstep->pos_old);
6277 	pos_new = le16_to_cpu(pstep->pos_new);
6278 
6279 	if (pcinfo->req_fver != pstep->fver)
6280 		return;
6281 
6282 	/* store step info by using ring instead of FIFO*/
6283 	do {
6284 		switch (state) {
6285 		case 0:
6286 			n_start = pos_old;
6287 			if (pos_new >=  pos_old)
6288 				n_stop = pos_new;
6289 			else
6290 				n_stop = btc->ctrl.trace_step - 1;
6291 
6292 			state = 1;
6293 			break;
6294 		case 1:
6295 			for (i = n_start; i <= n_stop; i++) {
6296 				type = pstep->step[i].type;
6297 				val = pstep->step[i].val;
6298 				diff_t = le16_to_cpu(pstep->step[i].difft);
6299 
6300 				if (type == CXSTEP_NONE || type >= CXSTEP_MAX)
6301 					continue;
6302 
6303 				if (cnt % 10 == 0)
6304 					seq_printf(m, " %-15s : ", "[steps]");
6305 
6306 				seq_printf(m, "-> %s(%02d)(%02d)",
6307 					   (type == CXSTEP_SLOT ? "SLT" :
6308 					    "EVT"), (u32)val, diff_t);
6309 				if (cnt % 10 == 9)
6310 					seq_puts(m, "\n");
6311 				cnt++;
6312 			}
6313 
6314 			state = 2;
6315 			break;
6316 		case 2:
6317 			if (pos_new <  pos_old && n_start != 0) {
6318 				n_start = 0;
6319 				n_stop = pos_new;
6320 				state = 1;
6321 			} else {
6322 				outloop = true;
6323 			}
6324 			break;
6325 		}
6326 	} while (!outloop);
6327 }
6328 
6329 static void _show_fw_dm_msg(struct rtw89_dev *rtwdev, struct seq_file *m)
6330 {
6331 	struct rtw89_btc *btc = &rtwdev->btc;
6332 
6333 	if (!(btc->dm.coex_info_map & BTC_COEX_INFO_DM))
6334 		return;
6335 
6336 	_show_error(rtwdev, m);
6337 	_show_fbtc_tdma(rtwdev, m);
6338 	_show_fbtc_slots(rtwdev, m);
6339 	_show_fbtc_cysta(rtwdev, m);
6340 	_show_fbtc_nullsta(rtwdev, m);
6341 	_show_fbtc_step(rtwdev, m);
6342 }
6343 
6344 static void _show_mreg(struct rtw89_dev *rtwdev, struct seq_file *m)
6345 {
6346 	const struct rtw89_chip_info *chip = rtwdev->chip;
6347 	struct rtw89_btc *btc = &rtwdev->btc;
6348 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
6349 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
6350 	struct rtw89_btc_fbtc_mreg_val *pmreg = NULL;
6351 	struct rtw89_btc_fbtc_gpio_dbg *gdbg = NULL;
6352 	struct rtw89_btc_cx *cx = &btc->cx;
6353 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
6354 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
6355 	struct rtw89_mac_ax_gnt gnt[2] = {0};
6356 	u8 i = 0, type = 0, cnt = 0;
6357 	u32 val, offset;
6358 
6359 	if (!(btc->dm.coex_info_map & BTC_COEX_INFO_MREG))
6360 		return;
6361 
6362 	seq_puts(m, "========== [HW Status] ==========\n");
6363 
6364 	seq_printf(m,
6365 		   " %-15s : WL->BT:0x%08x(cnt:%d), BT->WL:0x%08x(total:%d, bt_update:%d)\n",
6366 		   "[scoreboard]", wl->scbd, cx->cnt_wl[BTC_WCNT_SCBDUPDATE],
6367 		   bt->scbd, cx->cnt_bt[BTC_BCNT_SCBDREAD],
6368 		   cx->cnt_bt[BTC_BCNT_SCBDUPDATE]);
6369 
6370 	/* To avoid I/O if WL LPS or power-off  */
6371 	if (!wl->status.map.lps && !wl->status.map.rf_off) {
6372 		rtw89_mac_read_lte(rtwdev, R_AX_LTE_SW_CFG_1, &val);
6373 		if (val & (B_AX_GNT_BT_RFC_S0_SW_VAL |
6374 		    B_AX_GNT_BT_BB_S0_SW_VAL))
6375 			gnt[0].gnt_bt = true;
6376 		if (val & (B_AX_GNT_BT_RFC_S0_SW_CTRL |
6377 		    B_AX_GNT_BT_BB_S0_SW_CTRL))
6378 			gnt[0].gnt_bt_sw_en = true;
6379 		if (val & (B_AX_GNT_WL_RFC_S0_SW_VAL |
6380 		    B_AX_GNT_WL_BB_S0_SW_VAL))
6381 			gnt[0].gnt_wl = true;
6382 		if (val & (B_AX_GNT_WL_RFC_S0_SW_CTRL |
6383 		    B_AX_GNT_WL_BB_S0_SW_CTRL))
6384 			gnt[0].gnt_wl_sw_en = true;
6385 
6386 		if (val & (B_AX_GNT_BT_RFC_S1_SW_VAL |
6387 		    B_AX_GNT_BT_BB_S1_SW_VAL))
6388 			gnt[1].gnt_bt = true;
6389 		if (val & (B_AX_GNT_BT_RFC_S1_SW_CTRL |
6390 		    B_AX_GNT_BT_BB_S1_SW_CTRL))
6391 			gnt[1].gnt_bt_sw_en = true;
6392 		if (val & (B_AX_GNT_WL_RFC_S1_SW_VAL |
6393 		    B_AX_GNT_WL_BB_S1_SW_VAL))
6394 			gnt[1].gnt_wl = true;
6395 		if (val & (B_AX_GNT_WL_RFC_S1_SW_CTRL |
6396 		    B_AX_GNT_WL_BB_S1_SW_CTRL))
6397 			gnt[1].gnt_wl_sw_en = true;
6398 
6399 		seq_printf(m,
6400 			   " %-15s : pta_owner:%s, phy-0[gnt_wl:%s-%d/gnt_bt:%s-%d], ",
6401 			   "[gnt_status]",
6402 			   (rtw89_mac_get_ctrl_path(rtwdev) ? "WL" : "BT"),
6403 			   (gnt[0].gnt_wl_sw_en ? "SW" : "HW"), gnt[0].gnt_wl,
6404 			   (gnt[0].gnt_bt_sw_en ? "SW" : "HW"), gnt[0].gnt_bt);
6405 
6406 		seq_printf(m, "phy-1[gnt_wl:%s-%d/gnt_bt:%s-%d]\n",
6407 			   (gnt[1].gnt_wl_sw_en ? "SW" : "HW"), gnt[1].gnt_wl,
6408 			   (gnt[1].gnt_bt_sw_en ? "SW" : "HW"), gnt[1].gnt_bt);
6409 	}
6410 
6411 	pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo;
6412 	if (!pcinfo->valid) {
6413 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
6414 			    "[BTC], %s(): stop due rpt_fbtc_mregval.cinfo\n",
6415 			    __func__);
6416 		return;
6417 	}
6418 
6419 	pmreg = &pfwinfo->rpt_fbtc_mregval.finfo;
6420 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
6421 		    "[BTC], %s(): rpt_fbtc_mregval reg_num = %d\n",
6422 		    __func__, pmreg->reg_num);
6423 
6424 	for (i = 0; i < pmreg->reg_num; i++) {
6425 		type = (u8)le16_to_cpu(chip->mon_reg[i].type);
6426 		offset = le32_to_cpu(chip->mon_reg[i].offset);
6427 		val = le32_to_cpu(pmreg->mreg_val[i]);
6428 
6429 		if (cnt % 6 == 0)
6430 			seq_printf(m, " %-15s : %d_0x%04x=0x%08x",
6431 				   "[reg]", (u32)type, offset, val);
6432 		else
6433 			seq_printf(m, ", %d_0x%04x=0x%08x", (u32)type,
6434 				   offset, val);
6435 		if (cnt % 6 == 5)
6436 			seq_puts(m, "\n");
6437 		cnt++;
6438 	}
6439 
6440 	pcinfo = &pfwinfo->rpt_fbtc_gpio_dbg.cinfo;
6441 	if (!pcinfo->valid) {
6442 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
6443 			    "[BTC], %s(): stop due rpt_fbtc_gpio_dbg.cinfo\n",
6444 			    __func__);
6445 		return;
6446 	}
6447 
6448 	gdbg = &pfwinfo->rpt_fbtc_gpio_dbg.finfo;
6449 	if (!gdbg->en_map)
6450 		return;
6451 
6452 	seq_printf(m, " %-15s : enable_map:0x%08x",
6453 		   "[gpio_dbg]", gdbg->en_map);
6454 
6455 	for (i = 0; i < BTC_DBG_MAX1; i++) {
6456 		if (!(gdbg->en_map & BIT(i)))
6457 			continue;
6458 		seq_printf(m, ", %d->GPIO%d", (u32)i, gdbg->gpio_map[i]);
6459 	}
6460 	seq_puts(m, "\n");
6461 }
6462 
6463 static void _show_summary(struct rtw89_dev *rtwdev, struct seq_file *m)
6464 {
6465 	struct rtw89_btc *btc = &rtwdev->btc;
6466 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
6467 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
6468 	struct rtw89_btc_fbtc_rpt_ctrl *prptctrl = NULL;
6469 	struct rtw89_btc_cx *cx = &btc->cx;
6470 	struct rtw89_btc_dm *dm = &btc->dm;
6471 	struct rtw89_btc_wl_info *wl = &cx->wl;
6472 	struct rtw89_btc_bt_info *bt = &cx->bt;
6473 	u32 cnt_sum = 0, *cnt = btc->dm.cnt_notify;
6474 	u8 i;
6475 
6476 	if (!(dm->coex_info_map & BTC_COEX_INFO_SUMMARY))
6477 		return;
6478 
6479 	seq_puts(m, "========== [Statistics] ==========\n");
6480 
6481 	pcinfo = &pfwinfo->rpt_ctrl.cinfo;
6482 	if (pcinfo->valid && !wl->status.map.lps && !wl->status.map.rf_off) {
6483 		prptctrl = &pfwinfo->rpt_ctrl.finfo;
6484 
6485 		seq_printf(m,
6486 			   " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d), ",
6487 			   "[summary]", pfwinfo->cnt_h2c,
6488 			   pfwinfo->cnt_h2c_fail, prptctrl->h2c_cnt,
6489 			   pfwinfo->cnt_c2h, prptctrl->c2h_cnt);
6490 
6491 		seq_printf(m,
6492 			   "rpt_cnt=%d(fw_send:%d), rpt_map=0x%x, dm_error_map:0x%x",
6493 			   pfwinfo->event[BTF_EVNT_RPT], prptctrl->rpt_cnt,
6494 			   prptctrl->rpt_enable, dm->error.val);
6495 
6496 		if (dm->error.map.wl_fw_hang)
6497 			seq_puts(m, " (WL FW Hang!!)");
6498 		seq_puts(m, "\n");
6499 		seq_printf(m,
6500 			   " %-15s : send_ok:%d, send_fail:%d, recv:%d",
6501 			   "[mailbox]", prptctrl->mb_send_ok_cnt,
6502 			   prptctrl->mb_send_fail_cnt, prptctrl->mb_recv_cnt);
6503 
6504 		seq_printf(m,
6505 			   "(A2DP_empty:%d, A2DP_flowstop:%d, A2DP_full:%d)\n",
6506 			   prptctrl->mb_a2dp_empty_cnt,
6507 			   prptctrl->mb_a2dp_flct_cnt,
6508 			   prptctrl->mb_a2dp_full_cnt);
6509 
6510 		seq_printf(m,
6511 			   " %-15s : wl_rfk[req:%d/go:%d/reject:%d/timeout:%d]",
6512 			   "[RFK]", cx->cnt_wl[BTC_WCNT_RFK_REQ],
6513 			   cx->cnt_wl[BTC_WCNT_RFK_GO],
6514 			   cx->cnt_wl[BTC_WCNT_RFK_REJECT],
6515 			   cx->cnt_wl[BTC_WCNT_RFK_TIMEOUT]);
6516 
6517 		seq_printf(m,
6518 			   ", bt_rfk[req:%d/go:%d/reject:%d/timeout:%d/fail:%d]\n",
6519 			   prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_REQ],
6520 			   prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_GO],
6521 			   prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_REJECT],
6522 			   prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_TIMEOUT],
6523 			   prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_FAIL]);
6524 
6525 		if (prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_TIMEOUT] > 0)
6526 			bt->rfk_info.map.timeout = 1;
6527 		else
6528 			bt->rfk_info.map.timeout = 0;
6529 
6530 		dm->error.map.wl_rfk_timeout = bt->rfk_info.map.timeout;
6531 	} else {
6532 		seq_printf(m,
6533 			   " %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d, rpt_cnt=%d, rpt_map=0x%x",
6534 			   "[summary]", pfwinfo->cnt_h2c,
6535 			   pfwinfo->cnt_h2c_fail, pfwinfo->cnt_c2h,
6536 			   pfwinfo->event[BTF_EVNT_RPT],
6537 			   btc->fwinfo.rpt_en_map);
6538 		seq_puts(m, " (WL FW report invalid!!)\n");
6539 	}
6540 
6541 	for (i = 0; i < BTC_NCNT_NUM; i++)
6542 		cnt_sum += dm->cnt_notify[i];
6543 
6544 	seq_printf(m,
6545 		   " %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
6546 		   "[notify_cnt]", cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
6547 		   cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
6548 
6549 	seq_printf(m,
6550 		   "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d\n",
6551 		   cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
6552 		   cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
6553 		   cnt[BTC_NCNT_WL_STA]);
6554 
6555 	seq_printf(m,
6556 		   " %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, special_pkt=%d, ",
6557 		   "[notify_cnt]", cnt[BTC_NCNT_SCAN_START],
6558 		   cnt[BTC_NCNT_SCAN_FINISH], cnt[BTC_NCNT_SWITCH_BAND],
6559 		   cnt[BTC_NCNT_SPECIAL_PACKET]);
6560 
6561 	seq_printf(m,
6562 		   "timer=%d, control=%d, customerize=%d\n",
6563 		   cnt[BTC_NCNT_TIMER], cnt[BTC_NCNT_CONTROL],
6564 		   cnt[BTC_NCNT_CUSTOMERIZE]);
6565 }
6566 
6567 void rtw89_btc_dump_info(struct rtw89_dev *rtwdev, struct seq_file *m)
6568 {
6569 	struct rtw89_fw_suit *fw_suit = &rtwdev->fw.normal;
6570 	struct rtw89_btc *btc = &rtwdev->btc;
6571 	struct rtw89_btc_cx *cx = &btc->cx;
6572 	struct rtw89_btc_bt_info *bt = &cx->bt;
6573 
6574 	seq_puts(m, "=========================================\n");
6575 	seq_printf(m, "WL FW / BT FW		%d.%d.%d.%d / NA\n",
6576 		   fw_suit->major_ver, fw_suit->minor_ver,
6577 		   fw_suit->sub_ver, fw_suit->sub_idex);
6578 	seq_printf(m, "manual			%d\n", btc->ctrl.manual);
6579 
6580 	seq_puts(m, "=========================================\n");
6581 
6582 	seq_printf(m, "\n\r %-15s : raw_data[%02x %02x %02x %02x %02x %02x] (type:%s/cnt:%d/same:%d)",
6583 		   "[bt_info]",
6584 		   bt->raw_info[2], bt->raw_info[3],
6585 		   bt->raw_info[4], bt->raw_info[5],
6586 		   bt->raw_info[6], bt->raw_info[7],
6587 		   bt->raw_info[0] == BTC_BTINFO_AUTO ? "auto" : "reply",
6588 		   cx->cnt_bt[BTC_BCNT_INFOUPDATE],
6589 		   cx->cnt_bt[BTC_BCNT_INFOSAME]);
6590 
6591 	seq_puts(m, "\n=========================================\n");
6592 
6593 	_show_cx_info(rtwdev, m);
6594 	_show_wl_info(rtwdev, m);
6595 	_show_bt_info(rtwdev, m);
6596 	_show_dm_info(rtwdev, m);
6597 	_show_fw_dm_msg(rtwdev, m);
6598 	_show_mreg(rtwdev, m);
6599 	_show_summary(rtwdev, m);
6600 }
6601