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