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_bt_link_info *b = &bt->link_info;
1813 	struct rtw89_btc_rf_trx_para para;
1814 	u32 wl_stb_chg = 0;
1815 	u8 level_id = 0;
1816 
1817 	if (!dm->freerun) {
1818 		/* fix LNA2 = level-5 for BT ACI issue at BTG */
1819 		if ((btc->dm.wl_btg_rx && b->profile_cnt.now != 0) ||
1820 		    dm->bt_only == 1)
1821 			dm->trx_para_level = 1;
1822 		else
1823 			dm->trx_para_level = 0;
1824 	}
1825 
1826 	level_id = (u8)dm->trx_para_level;
1827 
1828 	if (level_id >= chip->rf_para_dlink_num ||
1829 	    level_id >= chip->rf_para_ulink_num) {
1830 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
1831 			    "[BTC], %s(): invalid level_id: %d\n",
1832 			    __func__, level_id);
1833 		return;
1834 	}
1835 
1836 	if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL))
1837 		para = chip->rf_para_ulink[level_id];
1838 	else
1839 		para = chip->rf_para_dlink[level_id];
1840 
1841 	if (para.wl_tx_power != RTW89_BTC_WL_DEF_TX_PWR)
1842 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
1843 			    "[BTC], %s(): wl_tx_power=%d\n",
1844 			    __func__, para.wl_tx_power);
1845 	_set_wl_tx_power(rtwdev, para.wl_tx_power);
1846 	_set_wl_rx_gain(rtwdev, para.wl_rx_gain);
1847 	_set_bt_tx_power(rtwdev, para.bt_tx_power);
1848 	_set_bt_rx_gain(rtwdev, para.bt_rx_gain);
1849 
1850 	if (bt->enable.now == 0 || wl->status.map.rf_off == 1 ||
1851 	    wl->status.map.lps == BTC_LPS_RF_OFF)
1852 		wl_stb_chg = 0;
1853 	else
1854 		wl_stb_chg = 1;
1855 
1856 	if (wl_stb_chg != dm->wl_stb_chg) {
1857 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
1858 			    "[BTC], %s(): wl_stb_chg=%d\n",
1859 			    __func__, wl_stb_chg);
1860 		dm->wl_stb_chg = wl_stb_chg;
1861 		chip->ops->btc_wl_s1_standby(rtwdev, dm->wl_stb_chg);
1862 	}
1863 }
1864 
1865 static void _update_btc_state_map(struct rtw89_dev *rtwdev)
1866 {
1867 	struct rtw89_btc *btc = &rtwdev->btc;
1868 	struct rtw89_btc_cx *cx = &btc->cx;
1869 	struct rtw89_btc_wl_info *wl = &cx->wl;
1870 	struct rtw89_btc_bt_info *bt = &cx->bt;
1871 	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
1872 
1873 	if (wl->status.map.connecting || wl->status.map._4way ||
1874 	    wl->status.map.roaming) {
1875 		cx->state_map = BTC_WLINKING;
1876 	} else if (wl->status.map.scan) { /* wl scan */
1877 		if (bt_linfo->status.map.inq_pag)
1878 			cx->state_map = BTC_WSCAN_BSCAN;
1879 		else
1880 			cx->state_map = BTC_WSCAN_BNOSCAN;
1881 	} else if (wl->status.map.busy) { /* only busy */
1882 		if (bt_linfo->status.map.inq_pag)
1883 			cx->state_map = BTC_WBUSY_BSCAN;
1884 		else
1885 			cx->state_map = BTC_WBUSY_BNOSCAN;
1886 	} else { /* wl idle */
1887 		cx->state_map = BTC_WIDLE;
1888 	}
1889 }
1890 
1891 static void _set_bt_afh_info(struct rtw89_dev *rtwdev)
1892 {
1893 	const struct rtw89_chip_info *chip = rtwdev->chip;
1894 	struct rtw89_btc *btc = &rtwdev->btc;
1895 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
1896 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
1897 	struct rtw89_btc_bt_link_info *b = &bt->link_info;
1898 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
1899 	struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1;
1900 	struct rtw89_btc_wl_active_role *r;
1901 	struct rtw89_btc_wl_active_role_v1 *r1;
1902 	u8 en = 0, i, ch = 0, bw = 0;
1903 	u8 mode, connect_cnt;
1904 
1905 	if (btc->ctrl.manual || wl->status.map.scan)
1906 		return;
1907 
1908 	if (chip->chip_id == RTL8852A) {
1909 		mode = wl_rinfo->link_mode;
1910 		connect_cnt = wl_rinfo->connect_cnt;
1911 	} else {
1912 		mode = wl_rinfo_v1->link_mode;
1913 		connect_cnt = wl_rinfo_v1->connect_cnt;
1914 	}
1915 
1916 	if (wl->status.map.rf_off || bt->whql_test ||
1917 	    mode == BTC_WLINK_NOLINK || mode == BTC_WLINK_5G ||
1918 	    connect_cnt > BTC_TDMA_WLROLE_MAX) {
1919 		en = false;
1920 	} else if (mode == BTC_WLINK_2G_MCC || mode == BTC_WLINK_2G_SCC) {
1921 		en = true;
1922 		/* get p2p channel */
1923 		for (i = 0; i < RTW89_PORT_NUM; i++) {
1924 			r = &wl_rinfo->active_role[i];
1925 			r1 = &wl_rinfo_v1->active_role_v1[i];
1926 
1927 			if (chip->chip_id == RTL8852A &&
1928 			    (r->role == RTW89_WIFI_ROLE_P2P_GO ||
1929 			     r->role == RTW89_WIFI_ROLE_P2P_CLIENT)) {
1930 				ch = r->ch;
1931 				bw = r->bw;
1932 				break;
1933 			} else if (chip->chip_id != RTL8852A &&
1934 				   (r1->role == RTW89_WIFI_ROLE_P2P_GO ||
1935 				    r1->role == RTW89_WIFI_ROLE_P2P_CLIENT)) {
1936 				ch = r1->ch;
1937 				bw = r1->bw;
1938 				break;
1939 			}
1940 		}
1941 	} else {
1942 		en = true;
1943 		/* get 2g channel  */
1944 		for (i = 0; i < RTW89_PORT_NUM; i++) {
1945 			r = &wl_rinfo->active_role[i];
1946 			r1 = &wl_rinfo_v1->active_role_v1[i];
1947 
1948 			if (chip->chip_id == RTL8852A &&
1949 			    r->connected && r->band == RTW89_BAND_2G) {
1950 				ch = r->ch;
1951 				bw = r->bw;
1952 				break;
1953 			} else if (chip->chip_id != RTL8852A &&
1954 				   r1->connected && r1->band == RTW89_BAND_2G) {
1955 				ch = r1->ch;
1956 				bw = r1->bw;
1957 				break;
1958 			}
1959 		}
1960 	}
1961 
1962 	switch (bw) {
1963 	case RTW89_CHANNEL_WIDTH_20:
1964 		bw = 20 + chip->afh_guard_ch * 2;
1965 		break;
1966 	case RTW89_CHANNEL_WIDTH_40:
1967 		bw = 40 + chip->afh_guard_ch * 2;
1968 		break;
1969 	case RTW89_CHANNEL_WIDTH_5:
1970 		bw = 5 + chip->afh_guard_ch * 2;
1971 		break;
1972 	case RTW89_CHANNEL_WIDTH_10:
1973 		bw = 10 + chip->afh_guard_ch * 2;
1974 		break;
1975 	default:
1976 		bw = 0;
1977 		en = false; /* turn off AFH info if BW > 40 */
1978 		break;
1979 	}
1980 
1981 	if (wl->afh_info.en == en &&
1982 	    wl->afh_info.ch == ch &&
1983 	    wl->afh_info.bw == bw &&
1984 	    b->profile_cnt.last == b->profile_cnt.now) {
1985 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
1986 			    "[BTC], %s(): return because no change!\n",
1987 			    __func__);
1988 		return;
1989 	}
1990 
1991 	wl->afh_info.en = en;
1992 	wl->afh_info.ch = ch;
1993 	wl->afh_info.bw = bw;
1994 
1995 	_send_fw_cmd(rtwdev, BTFC_SET, SET_BT_WL_CH_INFO, &wl->afh_info, 3);
1996 
1997 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
1998 		    "[BTC], %s(): en=%d, ch=%d, bw=%d\n",
1999 		    __func__, en, ch, bw);
2000 	btc->cx.cnt_wl[BTC_WCNT_CH_UPDATE]++;
2001 }
2002 
2003 static bool _check_freerun(struct rtw89_dev *rtwdev)
2004 {
2005 	struct rtw89_btc *btc = &rtwdev->btc;
2006 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
2007 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
2008 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
2009 	struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1;
2010 	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
2011 	struct rtw89_btc_bt_hid_desc *hid = &bt_linfo->hid_desc;
2012 
2013 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) {
2014 		btc->dm.trx_para_level = 0;
2015 		return false;
2016 	}
2017 
2018 	/* The below is dedicated antenna case */
2019 	if (wl_rinfo->connect_cnt > BTC_TDMA_WLROLE_MAX ||
2020 	    wl_rinfo_v1->connect_cnt > BTC_TDMA_WLROLE_MAX) {
2021 		btc->dm.trx_para_level = 5;
2022 		return true;
2023 	}
2024 
2025 	if (bt_linfo->profile_cnt.now == 0) {
2026 		btc->dm.trx_para_level = 5;
2027 		return true;
2028 	}
2029 
2030 	if (hid->pair_cnt > BTC_TDMA_BTHID_MAX) {
2031 		btc->dm.trx_para_level = 5;
2032 		return true;
2033 	}
2034 
2035 	/* TODO get isolation by BT psd */
2036 	if (btc->mdinfo.ant.isolation >= BTC_FREERUN_ANTISO_MIN) {
2037 		btc->dm.trx_para_level = 5;
2038 		return true;
2039 	}
2040 
2041 	if (!wl->status.map.busy) {/* wl idle -> freerun */
2042 		btc->dm.trx_para_level = 5;
2043 		return true;
2044 	} else if (wl->rssi_level > 1) {/* WL rssi < 50% (-60dBm) */
2045 		btc->dm.trx_para_level = 0;
2046 		return false;
2047 	} else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) {
2048 		if (wl->rssi_level == 0 && bt_linfo->rssi > 31) {
2049 			btc->dm.trx_para_level = 6;
2050 			return true;
2051 		} else if (wl->rssi_level == 1 && bt_linfo->rssi > 36) {
2052 			btc->dm.trx_para_level = 7;
2053 			return true;
2054 		}
2055 		btc->dm.trx_para_level = 0;
2056 		return false;
2057 	} else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_DL)) {
2058 		if (bt_linfo->rssi > 28) {
2059 			btc->dm.trx_para_level = 6;
2060 			return true;
2061 		}
2062 	}
2063 
2064 	btc->dm.trx_para_level = 0;
2065 	return false;
2066 }
2067 
2068 #define _tdma_set_flctrl(btc, flc) ({(btc)->dm.tdma.rxflctrl = flc; })
2069 #define _tdma_set_flctrl_role(btc, role) ({(btc)->dm.tdma.rxflctrl_role = role; })
2070 #define _tdma_set_tog(btc, wtg) ({(btc)->dm.tdma.wtgle_n = wtg; })
2071 #define _tdma_set_lek(btc, lek) ({(btc)->dm.tdma.leak_n = lek; })
2072 
2073 #define _slot_set(btc, sid, dura, tbl, type) \
2074 	do { \
2075 		typeof(sid) _sid = (sid); \
2076 		typeof(btc) _btc = (btc); \
2077 		_btc->dm.slot[_sid].dur = cpu_to_le16(dura);\
2078 		_btc->dm.slot[_sid].cxtbl = cpu_to_le32(tbl); \
2079 		_btc->dm.slot[_sid].cxtype = cpu_to_le16(type); \
2080 	} while (0)
2081 
2082 #define _slot_set_dur(btc, sid, dura) (btc)->dm.slot[sid].dur = cpu_to_le16(dura)
2083 #define _slot_set_tbl(btc, sid, tbl) (btc)->dm.slot[sid].cxtbl = cpu_to_le32(tbl)
2084 #define _slot_set_type(btc, sid, type) (btc)->dm.slot[sid].cxtype = cpu_to_le16(type)
2085 
2086 struct btc_btinfo_lb2 {
2087 	u8 connect: 1;
2088 	u8 sco_busy: 1;
2089 	u8 inq_pag: 1;
2090 	u8 acl_busy: 1;
2091 	u8 hfp: 1;
2092 	u8 hid: 1;
2093 	u8 a2dp: 1;
2094 	u8 pan: 1;
2095 };
2096 
2097 struct btc_btinfo_lb3 {
2098 	u8 retry: 4;
2099 	u8 cqddr: 1;
2100 	u8 inq: 1;
2101 	u8 mesh_busy: 1;
2102 	u8 pag: 1;
2103 };
2104 
2105 struct btc_btinfo_hb0 {
2106 	s8 rssi;
2107 };
2108 
2109 struct btc_btinfo_hb1 {
2110 	u8 ble_connect: 1;
2111 	u8 reinit: 1;
2112 	u8 relink: 1;
2113 	u8 igno_wl: 1;
2114 	u8 voice: 1;
2115 	u8 ble_scan: 1;
2116 	u8 role_sw: 1;
2117 	u8 multi_link: 1;
2118 };
2119 
2120 struct btc_btinfo_hb2 {
2121 	u8 pan_active: 1;
2122 	u8 afh_update: 1;
2123 	u8 a2dp_active: 1;
2124 	u8 slave: 1;
2125 	u8 hid_slot: 2;
2126 	u8 hid_cnt: 2;
2127 };
2128 
2129 struct btc_btinfo_hb3 {
2130 	u8 a2dp_bitpool: 6;
2131 	u8 tx_3m: 1;
2132 	u8 a2dp_sink: 1;
2133 };
2134 
2135 union btc_btinfo {
2136 	u8 val;
2137 	struct btc_btinfo_lb2 lb2;
2138 	struct btc_btinfo_lb3 lb3;
2139 	struct btc_btinfo_hb0 hb0;
2140 	struct btc_btinfo_hb1 hb1;
2141 	struct btc_btinfo_hb2 hb2;
2142 	struct btc_btinfo_hb3 hb3;
2143 };
2144 
2145 static void _set_policy(struct rtw89_dev *rtwdev, u16 policy_type,
2146 			enum btc_reason_and_action action)
2147 {
2148 	const struct rtw89_chip_info *chip = rtwdev->chip;
2149 
2150 	chip->ops->btc_set_policy(rtwdev, policy_type);
2151 	_fw_set_policy(rtwdev, policy_type, action);
2152 }
2153 
2154 #define BTC_B1_MAX 250 /* unit ms */
2155 void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type)
2156 {
2157 	struct rtw89_btc *btc = &rtwdev->btc;
2158 	struct rtw89_btc_dm *dm = &btc->dm;
2159 	struct rtw89_btc_fbtc_tdma *t = &dm->tdma;
2160 	struct rtw89_btc_fbtc_slot *s = dm->slot;
2161 	u8 type;
2162 	u32 tbl_w1, tbl_b1, tbl_b4;
2163 
2164 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) {
2165 		if (btc->cx.wl.status.map._4way)
2166 			tbl_w1 = cxtbl[1];
2167 		else
2168 			tbl_w1 = cxtbl[8];
2169 		tbl_b1 = cxtbl[3];
2170 		tbl_b4 = cxtbl[3];
2171 	} else {
2172 		tbl_w1 = cxtbl[16];
2173 		tbl_b1 = cxtbl[17];
2174 		tbl_b4 = cxtbl[17];
2175 	}
2176 
2177 	type = (u8)((policy_type & BTC_CXP_MASK) >> 8);
2178 	btc->bt_req_en = false;
2179 
2180 	switch (type) {
2181 	case BTC_CXP_USERDEF0:
2182 		*t = t_def[CXTD_OFF];
2183 		s[CXST_OFF] = s_def[CXST_OFF];
2184 		_slot_set_tbl(btc, CXST_OFF, cxtbl[2]);
2185 		btc->update_policy_force = true;
2186 		break;
2187 	case BTC_CXP_OFF: /* TDMA off */
2188 		_write_scbd(rtwdev, BTC_WSCB_TDMA, false);
2189 		*t = t_def[CXTD_OFF];
2190 		s[CXST_OFF] = s_def[CXST_OFF];
2191 
2192 		switch (policy_type) {
2193 		case BTC_CXP_OFF_BT:
2194 			_slot_set_tbl(btc, CXST_OFF, cxtbl[2]);
2195 			break;
2196 		case BTC_CXP_OFF_WL:
2197 			_slot_set_tbl(btc, CXST_OFF, cxtbl[1]);
2198 			break;
2199 		case BTC_CXP_OFF_EQ0:
2200 			_slot_set_tbl(btc, CXST_OFF, cxtbl[0]);
2201 			break;
2202 		case BTC_CXP_OFF_EQ1:
2203 			_slot_set_tbl(btc, CXST_OFF, cxtbl[16]);
2204 			break;
2205 		case BTC_CXP_OFF_EQ2:
2206 			_slot_set_tbl(btc, CXST_OFF, cxtbl[17]);
2207 			break;
2208 		case BTC_CXP_OFF_EQ3:
2209 			_slot_set_tbl(btc, CXST_OFF, cxtbl[18]);
2210 			break;
2211 		case BTC_CXP_OFF_BWB0:
2212 			_slot_set_tbl(btc, CXST_OFF, cxtbl[5]);
2213 			break;
2214 		case BTC_CXP_OFF_BWB1:
2215 			_slot_set_tbl(btc, CXST_OFF, cxtbl[8]);
2216 			break;
2217 		case BTC_CXP_OFF_BWB3:
2218 			_slot_set_tbl(btc, CXST_OFF, cxtbl[6]);
2219 			break;
2220 		}
2221 		break;
2222 	case BTC_CXP_OFFB: /* TDMA off + beacon protect */
2223 		_write_scbd(rtwdev, BTC_WSCB_TDMA, false);
2224 		*t = t_def[CXTD_OFF_B2];
2225 		s[CXST_OFF] = s_def[CXST_OFF];
2226 		switch (policy_type) {
2227 		case BTC_CXP_OFFB_BWB0:
2228 			_slot_set_tbl(btc, CXST_OFF, cxtbl[8]);
2229 			break;
2230 		}
2231 		break;
2232 	case BTC_CXP_OFFE: /* TDMA off + beacon protect + Ext_control */
2233 		btc->bt_req_en = true;
2234 		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
2235 		*t = t_def[CXTD_OFF_EXT];
2236 		switch (policy_type) {
2237 		case BTC_CXP_OFFE_DEF:
2238 			s[CXST_E2G] = s_def[CXST_E2G];
2239 			s[CXST_E5G] = s_def[CXST_E5G];
2240 			s[CXST_EBT] = s_def[CXST_EBT];
2241 			s[CXST_ENULL] = s_def[CXST_ENULL];
2242 			break;
2243 		case BTC_CXP_OFFE_DEF2:
2244 			_slot_set(btc, CXST_E2G, 20, cxtbl[1], SLOT_ISO);
2245 			s[CXST_E5G] = s_def[CXST_E5G];
2246 			s[CXST_EBT] = s_def[CXST_EBT];
2247 			s[CXST_ENULL] = s_def[CXST_ENULL];
2248 			break;
2249 		}
2250 		break;
2251 	case BTC_CXP_FIX: /* TDMA Fix-Slot */
2252 		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
2253 		*t = t_def[CXTD_FIX];
2254 		switch (policy_type) {
2255 		case BTC_CXP_FIX_TD3030:
2256 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
2257 			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
2258 			break;
2259 		case BTC_CXP_FIX_TD5050:
2260 			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
2261 			_slot_set(btc, CXST_B1, 50, tbl_b1, SLOT_MIX);
2262 			break;
2263 		case BTC_CXP_FIX_TD2030:
2264 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
2265 			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
2266 			break;
2267 		case BTC_CXP_FIX_TD4010:
2268 			_slot_set(btc, CXST_W1, 40, tbl_w1, SLOT_ISO);
2269 			_slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
2270 			break;
2271 		case BTC_CXP_FIX_TD4020:
2272 			_slot_set(btc, CXST_W1, 40, cxtbl[1], SLOT_MIX);
2273 			_slot_set(btc, CXST_B1, 20, tbl_b1, SLOT_MIX);
2274 			break;
2275 		case BTC_CXP_FIX_TD7010:
2276 			_slot_set(btc, CXST_W1, 70, tbl_w1, SLOT_ISO);
2277 			_slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
2278 			break;
2279 		case BTC_CXP_FIX_TD2060:
2280 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
2281 			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
2282 			break;
2283 		case BTC_CXP_FIX_TD3060:
2284 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
2285 			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
2286 			break;
2287 		case BTC_CXP_FIX_TD2080:
2288 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
2289 			_slot_set(btc, CXST_B1, 80, tbl_b1, SLOT_MIX);
2290 			break;
2291 		case BTC_CXP_FIX_TDW1B1: /* W1:B1 = user-define */
2292 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
2293 				  tbl_w1, SLOT_ISO);
2294 			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
2295 				  tbl_b1, SLOT_MIX);
2296 			break;
2297 		}
2298 		break;
2299 	case BTC_CXP_PFIX: /* PS-TDMA Fix-Slot */
2300 		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
2301 		*t = t_def[CXTD_PFIX];
2302 		if (btc->cx.wl.role_info.role_map.role.ap)
2303 			_tdma_set_flctrl(btc, CXFLC_QOSNULL);
2304 
2305 		switch (policy_type) {
2306 		case BTC_CXP_PFIX_TD3030:
2307 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
2308 			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
2309 			break;
2310 		case BTC_CXP_PFIX_TD5050:
2311 			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
2312 			_slot_set(btc, CXST_B1, 50, tbl_b1, SLOT_MIX);
2313 			break;
2314 		case BTC_CXP_PFIX_TD2030:
2315 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
2316 			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
2317 			break;
2318 		case BTC_CXP_PFIX_TD2060:
2319 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
2320 			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
2321 			break;
2322 		case BTC_CXP_PFIX_TD3070:
2323 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
2324 			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
2325 			break;
2326 		case BTC_CXP_PFIX_TD2080:
2327 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
2328 			_slot_set(btc, CXST_B1, 80, tbl_b1, SLOT_MIX);
2329 			break;
2330 		}
2331 		break;
2332 	case BTC_CXP_AUTO: /* TDMA Auto-Slot */
2333 		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
2334 		*t = t_def[CXTD_AUTO];
2335 		switch (policy_type) {
2336 		case BTC_CXP_AUTO_TD50B1:
2337 			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
2338 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2339 			break;
2340 		case BTC_CXP_AUTO_TD60B1:
2341 			_slot_set(btc, CXST_W1, 60, tbl_w1, SLOT_ISO);
2342 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2343 			break;
2344 		case BTC_CXP_AUTO_TD20B1:
2345 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
2346 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2347 			break;
2348 		case BTC_CXP_AUTO_TDW1B1: /* W1:B1 = user-define */
2349 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
2350 				  tbl_w1, SLOT_ISO);
2351 			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
2352 				  tbl_b1, SLOT_MIX);
2353 			break;
2354 		}
2355 		break;
2356 	case BTC_CXP_PAUTO: /* PS-TDMA Auto-Slot */
2357 		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
2358 		*t = t_def[CXTD_PAUTO];
2359 		switch (policy_type) {
2360 		case BTC_CXP_PAUTO_TD50B1:
2361 			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
2362 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2363 			break;
2364 		case BTC_CXP_PAUTO_TD60B1:
2365 			_slot_set(btc, CXST_W1, 60, tbl_w1, SLOT_ISO);
2366 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2367 			break;
2368 		case BTC_CXP_PAUTO_TD20B1:
2369 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
2370 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2371 			break;
2372 		case BTC_CXP_PAUTO_TDW1B1:
2373 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
2374 				  tbl_w1, SLOT_ISO);
2375 			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
2376 				  tbl_b1, SLOT_MIX);
2377 			break;
2378 		}
2379 		break;
2380 	case BTC_CXP_AUTO2: /* TDMA Auto-Slot2 */
2381 		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
2382 		*t = t_def[CXTD_AUTO2];
2383 		switch (policy_type) {
2384 		case BTC_CXP_AUTO2_TD3050:
2385 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
2386 			_slot_set(btc, CXST_B4, 50, tbl_b4, SLOT_MIX);
2387 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2388 			break;
2389 		case BTC_CXP_AUTO2_TD3070:
2390 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
2391 			_slot_set(btc, CXST_B4, 70, tbl_b4, SLOT_MIX);
2392 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2393 			break;
2394 		case BTC_CXP_AUTO2_TD5050:
2395 			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
2396 			_slot_set(btc, CXST_B4, 50, tbl_b4, SLOT_MIX);
2397 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2398 			break;
2399 		case BTC_CXP_AUTO2_TD6060:
2400 			_slot_set(btc, CXST_W1, 60, tbl_w1, SLOT_ISO);
2401 			_slot_set(btc, CXST_B4, 60, tbl_b4, SLOT_MIX);
2402 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2403 			break;
2404 		case BTC_CXP_AUTO2_TD2080:
2405 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
2406 			_slot_set(btc, CXST_B4, 80, tbl_b4, SLOT_MIX);
2407 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2408 			break;
2409 		case BTC_CXP_AUTO2_TDW1B4: /* W1:B1 = user-define */
2410 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
2411 				  tbl_w1, SLOT_ISO);
2412 			_slot_set(btc, CXST_B4, dm->slot_dur[CXST_B4],
2413 				  tbl_b4, SLOT_MIX);
2414 			break;
2415 		}
2416 		break;
2417 	case BTC_CXP_PAUTO2: /* PS-TDMA Auto-Slot2 */
2418 		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
2419 		*t = t_def[CXTD_PAUTO2];
2420 		switch (policy_type) {
2421 		case BTC_CXP_PAUTO2_TD3050:
2422 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
2423 			_slot_set(btc, CXST_B4, 50, tbl_b4, SLOT_MIX);
2424 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2425 			break;
2426 		case BTC_CXP_PAUTO2_TD3070:
2427 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
2428 			_slot_set(btc, CXST_B4, 70, tbl_b4, SLOT_MIX);
2429 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2430 			break;
2431 		case BTC_CXP_PAUTO2_TD5050:
2432 			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
2433 			_slot_set(btc, CXST_B4, 50, tbl_b4, SLOT_MIX);
2434 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2435 			break;
2436 		case BTC_CXP_PAUTO2_TD6060:
2437 			_slot_set(btc, CXST_W1, 60, tbl_w1, SLOT_ISO);
2438 			_slot_set(btc, CXST_B4, 60, tbl_b4, SLOT_MIX);
2439 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2440 			break;
2441 		case BTC_CXP_PAUTO2_TD2080:
2442 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
2443 			_slot_set(btc, CXST_B4, 80, tbl_b4, SLOT_MIX);
2444 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2445 			break;
2446 		case BTC_CXP_PAUTO2_TDW1B4: /* W1:B1 = user-define */
2447 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
2448 				  tbl_w1, SLOT_ISO);
2449 			_slot_set(btc, CXST_B4, dm->slot_dur[CXST_B4],
2450 				  tbl_b4, SLOT_MIX);
2451 			break;
2452 		}
2453 		break;
2454 	}
2455 }
2456 EXPORT_SYMBOL(rtw89_btc_set_policy);
2457 
2458 void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
2459 {
2460 	struct rtw89_btc *btc = &rtwdev->btc;
2461 	struct rtw89_btc_dm *dm = &btc->dm;
2462 	struct rtw89_btc_fbtc_tdma *t = &dm->tdma;
2463 	struct rtw89_btc_fbtc_slot *s = dm->slot;
2464 	struct rtw89_btc_wl_role_info_v1 *wl_rinfo = &btc->cx.wl.role_info_v1;
2465 	struct rtw89_btc_bt_hid_desc *hid = &btc->cx.bt.link_info.hid_desc;
2466 	struct rtw89_btc_bt_hfp_desc *hfp = &btc->cx.bt.link_info.hfp_desc;
2467 	u8 type, null_role;
2468 	u32 tbl_w1, tbl_b1, tbl_b4;
2469 
2470 	type = FIELD_GET(BTC_CXP_MASK, policy_type);
2471 
2472 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) {
2473 		if (btc->cx.wl.status.map._4way)
2474 			tbl_w1 = cxtbl[1];
2475 		else if (hid->exist && hid->type == BTC_HID_218)
2476 			tbl_w1 = cxtbl[7]; /* Ack/BA no break bt Hi-Pri-rx */
2477 		else
2478 			tbl_w1 = cxtbl[8];
2479 
2480 		if (dm->leak_ap &&
2481 		    (type == BTC_CXP_PFIX || type == BTC_CXP_PAUTO2)) {
2482 			tbl_b1 = cxtbl[3];
2483 			tbl_b4 = cxtbl[3];
2484 		} else if (hid->exist && hid->type == BTC_HID_218) {
2485 			tbl_b1 = cxtbl[4]; /* Ack/BA no break bt Hi-Pri-rx */
2486 			tbl_b4 = cxtbl[4];
2487 		} else {
2488 			tbl_b1 = cxtbl[2];
2489 			tbl_b4 = cxtbl[2];
2490 		}
2491 	} else {
2492 		tbl_w1 = cxtbl[16];
2493 		tbl_b1 = cxtbl[17];
2494 		tbl_b4 = cxtbl[17];
2495 	}
2496 
2497 	btc->bt_req_en = false;
2498 
2499 	switch (type) {
2500 	case BTC_CXP_USERDEF0:
2501 		btc->update_policy_force = true;
2502 		*t = t_def[CXTD_OFF];
2503 		s[CXST_OFF] = s_def[CXST_OFF];
2504 		_slot_set_tbl(btc, CXST_OFF, cxtbl[2]);
2505 		break;
2506 	case BTC_CXP_OFF: /* TDMA off */
2507 		_write_scbd(rtwdev, BTC_WSCB_TDMA, false);
2508 		*t = t_def[CXTD_OFF];
2509 		s[CXST_OFF] = s_def[CXST_OFF];
2510 
2511 		switch (policy_type) {
2512 		case BTC_CXP_OFF_BT:
2513 			_slot_set_tbl(btc, CXST_OFF, cxtbl[2]);
2514 			break;
2515 		case BTC_CXP_OFF_WL:
2516 			_slot_set_tbl(btc, CXST_OFF, cxtbl[1]);
2517 			break;
2518 		case BTC_CXP_OFF_EQ0:
2519 			_slot_set_tbl(btc, CXST_OFF, cxtbl[0]);
2520 			break;
2521 		case BTC_CXP_OFF_EQ1:
2522 			_slot_set_tbl(btc, CXST_OFF, cxtbl[16]);
2523 			break;
2524 		case BTC_CXP_OFF_EQ2:
2525 			_slot_set_tbl(btc, CXST_OFF, cxtbl[17]);
2526 			break;
2527 		case BTC_CXP_OFF_EQ3:
2528 			_slot_set_tbl(btc, CXST_OFF, cxtbl[18]);
2529 			break;
2530 		case BTC_CXP_OFF_BWB0:
2531 			_slot_set_tbl(btc, CXST_OFF, cxtbl[5]);
2532 			break;
2533 		case BTC_CXP_OFF_BWB1:
2534 			_slot_set_tbl(btc, CXST_OFF, cxtbl[8]);
2535 			break;
2536 		case BTC_CXP_OFF_BWB2:
2537 			_slot_set_tbl(btc, CXST_OFF, cxtbl[7]);
2538 			break;
2539 		case BTC_CXP_OFF_BWB3:
2540 			_slot_set_tbl(btc, CXST_OFF, cxtbl[6]);
2541 			break;
2542 		default:
2543 			break;
2544 		}
2545 		break;
2546 	case BTC_CXP_OFFB: /* TDMA off + beacon protect */
2547 		_write_scbd(rtwdev, BTC_WSCB_TDMA, false);
2548 		*t = t_def[CXTD_OFF_B2];
2549 		s[CXST_OFF] = s_def[CXST_OFF];
2550 
2551 		switch (policy_type) {
2552 		case BTC_CXP_OFFB_BWB0:
2553 			_slot_set_tbl(btc, CXST_OFF, cxtbl[8]);
2554 			break;
2555 		default:
2556 			break;
2557 		}
2558 		break;
2559 	case BTC_CXP_OFFE: /* TDMA off + beacon protect + Ext_control */
2560 		btc->bt_req_en = true;
2561 		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
2562 		*t = t_def[CXTD_OFF_EXT];
2563 
2564 		/* To avoid wl-s0 tx break by hid/hfp tx */
2565 		if (hid->exist || hfp->exist)
2566 			tbl_w1 = cxtbl[16];
2567 
2568 		switch (policy_type) {
2569 		case BTC_CXP_OFFE_DEF:
2570 			s[CXST_E2G] = s_def[CXST_E2G];
2571 			s[CXST_E5G] = s_def[CXST_E5G];
2572 			s[CXST_EBT] = s_def[CXST_EBT];
2573 			s[CXST_ENULL] = s_def[CXST_ENULL];
2574 			break;
2575 		case BTC_CXP_OFFE_DEF2:
2576 			_slot_set(btc, CXST_E2G, 20, cxtbl[1], SLOT_ISO);
2577 			s[CXST_E5G] = s_def[CXST_E5G];
2578 			s[CXST_EBT] = s_def[CXST_EBT];
2579 			s[CXST_ENULL] = s_def[CXST_ENULL];
2580 			break;
2581 		default:
2582 			break;
2583 		}
2584 		break;
2585 	case BTC_CXP_FIX: /* TDMA Fix-Slot */
2586 		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
2587 		*t = t_def[CXTD_FIX];
2588 
2589 		switch (policy_type) {
2590 		case BTC_CXP_FIX_TD3030:
2591 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
2592 			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
2593 			break;
2594 		case BTC_CXP_FIX_TD5050:
2595 			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
2596 			_slot_set(btc, CXST_B1, 50, tbl_b1, SLOT_MIX);
2597 			break;
2598 		case BTC_CXP_FIX_TD2030:
2599 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
2600 			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
2601 			break;
2602 		case BTC_CXP_FIX_TD4010:
2603 			_slot_set(btc, CXST_W1, 40, tbl_w1, SLOT_ISO);
2604 			_slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
2605 			break;
2606 		case BTC_CXP_FIX_TD4010ISO:
2607 			_slot_set(btc, CXST_W1, 40, cxtbl[1], SLOT_ISO);
2608 			_slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
2609 			break;
2610 		case BTC_CXP_FIX_TD7010:
2611 			_slot_set(btc, CXST_W1, 70, tbl_w1, SLOT_ISO);
2612 			_slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
2613 			break;
2614 		case BTC_CXP_FIX_TD2060:
2615 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
2616 			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
2617 			break;
2618 		case BTC_CXP_FIX_TD3060:
2619 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
2620 			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
2621 			break;
2622 		case BTC_CXP_FIX_TD2080:
2623 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
2624 			_slot_set(btc, CXST_B1, 80, tbl_b1, SLOT_MIX);
2625 			break;
2626 		case BTC_CXP_FIX_TDW1B1: /* W1:B1 = user-define */
2627 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
2628 				  tbl_w1, SLOT_ISO);
2629 			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
2630 				  tbl_b1, SLOT_MIX);
2631 			break;
2632 		default:
2633 			break;
2634 		}
2635 		break;
2636 	case BTC_CXP_PFIX: /* PS-TDMA Fix-Slot */
2637 		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
2638 		*t = t_def[CXTD_PFIX];
2639 
2640 		switch (policy_type) {
2641 		case BTC_CXP_PFIX_TD3030:
2642 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
2643 			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
2644 			break;
2645 		case BTC_CXP_PFIX_TD5050:
2646 			_slot_set(btc, CXST_W1, 50, tbl_w1, SLOT_ISO);
2647 			_slot_set(btc, CXST_B1, 50, tbl_b1, SLOT_MIX);
2648 			break;
2649 		case BTC_CXP_PFIX_TD2030:
2650 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
2651 			_slot_set(btc, CXST_B1, 30, tbl_b1, SLOT_MIX);
2652 			break;
2653 		case BTC_CXP_PFIX_TD2060:
2654 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
2655 			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
2656 			break;
2657 		case BTC_CXP_PFIX_TD3070:
2658 			_slot_set(btc, CXST_W1, 30, tbl_w1, SLOT_ISO);
2659 			_slot_set(btc, CXST_B1, 60, tbl_b1, SLOT_MIX);
2660 			break;
2661 		case BTC_CXP_PFIX_TD2080:
2662 			_slot_set(btc, CXST_W1, 20, tbl_w1, SLOT_ISO);
2663 			_slot_set(btc, CXST_B1, 80, tbl_b1, SLOT_MIX);
2664 			break;
2665 		case BTC_CXP_PFIX_TDW1B1: /* W1:B1 = user-define */
2666 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
2667 				  tbl_w1, SLOT_ISO);
2668 			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
2669 				  tbl_b1, SLOT_MIX);
2670 			break;
2671 		default:
2672 			break;
2673 		}
2674 		break;
2675 	case BTC_CXP_AUTO: /* TDMA Auto-Slot */
2676 		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
2677 		*t = t_def[CXTD_AUTO];
2678 
2679 		switch (policy_type) {
2680 		case BTC_CXP_AUTO_TD50B1:
2681 			_slot_set(btc, CXST_W1,  50, tbl_w1, SLOT_ISO);
2682 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2683 			break;
2684 		case BTC_CXP_AUTO_TD60B1:
2685 			_slot_set(btc, CXST_W1,  60, tbl_w1, SLOT_ISO);
2686 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2687 			break;
2688 		case BTC_CXP_AUTO_TD20B1:
2689 			_slot_set(btc, CXST_W1,  20, tbl_w1, SLOT_ISO);
2690 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2691 			break;
2692 		case BTC_CXP_AUTO_TDW1B1: /* W1:B1 = user-define */
2693 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
2694 				  tbl_w1, SLOT_ISO);
2695 			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
2696 				  tbl_b1, SLOT_MIX);
2697 			break;
2698 		default:
2699 			break;
2700 		}
2701 		break;
2702 	case BTC_CXP_PAUTO: /* PS-TDMA Auto-Slot */
2703 		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
2704 		*t = t_def[CXTD_PAUTO];
2705 
2706 		switch (policy_type) {
2707 		case BTC_CXP_PAUTO_TD50B1:
2708 			_slot_set(btc, CXST_W1,  50, tbl_w1, SLOT_ISO);
2709 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2710 			break;
2711 		case BTC_CXP_PAUTO_TD60B1:
2712 			_slot_set(btc, CXST_W1,  60, tbl_w1, SLOT_ISO);
2713 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2714 			break;
2715 		case BTC_CXP_PAUTO_TD20B1:
2716 			_slot_set(btc, CXST_W1,  20, tbl_w1, SLOT_ISO);
2717 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2718 			break;
2719 		case BTC_CXP_PAUTO_TDW1B1:
2720 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
2721 				  tbl_w1, SLOT_ISO);
2722 			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
2723 				  tbl_b1, SLOT_MIX);
2724 			break;
2725 		default:
2726 			break;
2727 		}
2728 		break;
2729 	case BTC_CXP_AUTO2: /* TDMA Auto-Slot2 */
2730 		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
2731 		*t = t_def[CXTD_AUTO2];
2732 
2733 		switch (policy_type) {
2734 		case BTC_CXP_AUTO2_TD3050:
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,  50, tbl_b4, SLOT_MIX);
2738 			break;
2739 		case BTC_CXP_AUTO2_TD3070:
2740 			_slot_set(btc, CXST_W1,  30, tbl_w1, SLOT_ISO);
2741 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2742 			_slot_set(btc, CXST_B4,  70, tbl_b4, SLOT_MIX);
2743 			break;
2744 		case BTC_CXP_AUTO2_TD5050:
2745 			_slot_set(btc, CXST_W1,  50, tbl_w1, SLOT_ISO);
2746 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2747 			_slot_set(btc, CXST_B4,  50, tbl_b4, SLOT_MIX);
2748 			break;
2749 		case BTC_CXP_AUTO2_TD6060:
2750 			_slot_set(btc, CXST_W1,  60, tbl_w1, SLOT_ISO);
2751 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2752 			_slot_set(btc, CXST_B4,  60, tbl_b4, SLOT_MIX);
2753 			break;
2754 		case BTC_CXP_AUTO2_TD2080:
2755 			_slot_set(btc, CXST_W1,  20, tbl_w1, SLOT_ISO);
2756 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2757 			_slot_set(btc, CXST_B4,  80, tbl_b4, SLOT_MIX);
2758 			break;
2759 		case BTC_CXP_AUTO2_TDW1B4: /* W1:B1 = user-define */
2760 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
2761 				  tbl_w1, SLOT_ISO);
2762 			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
2763 				  tbl_b1, SLOT_MIX);
2764 			_slot_set(btc, CXST_B4, dm->slot_dur[CXST_B4],
2765 				  tbl_b4, SLOT_MIX);
2766 			break;
2767 		default:
2768 			break;
2769 		}
2770 		break;
2771 	case BTC_CXP_PAUTO2: /* PS-TDMA Auto-Slot2 */
2772 		_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
2773 		*t = t_def[CXTD_PAUTO2];
2774 
2775 		switch (policy_type) {
2776 		case BTC_CXP_PAUTO2_TD3050:
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,  50, tbl_b4, SLOT_MIX);
2780 			break;
2781 		case BTC_CXP_PAUTO2_TD3070:
2782 			_slot_set(btc, CXST_W1,  30, tbl_w1, SLOT_ISO);
2783 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2784 			_slot_set(btc, CXST_B4,  70, tbl_b4, SLOT_MIX);
2785 			break;
2786 		case BTC_CXP_PAUTO2_TD5050:
2787 			_slot_set(btc, CXST_W1,  50, tbl_w1, SLOT_ISO);
2788 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2789 			_slot_set(btc, CXST_B4,  50, tbl_b4, SLOT_MIX);
2790 			break;
2791 		case BTC_CXP_PAUTO2_TD6060:
2792 			_slot_set(btc, CXST_W1,  60, tbl_w1, SLOT_ISO);
2793 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2794 			_slot_set(btc, CXST_B4,  60, tbl_b4, SLOT_MIX);
2795 			break;
2796 		case BTC_CXP_PAUTO2_TD2080:
2797 			_slot_set(btc, CXST_W1,  20, tbl_w1, SLOT_ISO);
2798 			_slot_set(btc, CXST_B1, BTC_B1_MAX, tbl_b1, SLOT_MIX);
2799 			_slot_set(btc, CXST_B4,  80, tbl_b4, SLOT_MIX);
2800 			break;
2801 		case BTC_CXP_PAUTO2_TDW1B4: /* W1:B1 = user-define */
2802 			_slot_set(btc, CXST_W1, dm->slot_dur[CXST_W1],
2803 				  tbl_w1, SLOT_ISO);
2804 			_slot_set(btc, CXST_B1, dm->slot_dur[CXST_B1],
2805 				  tbl_b1, SLOT_MIX);
2806 			_slot_set(btc, CXST_B4, dm->slot_dur[CXST_B4],
2807 				  tbl_b4, SLOT_MIX);
2808 			break;
2809 		default:
2810 			break;
2811 		}
2812 		break;
2813 	}
2814 
2815 	if (wl_rinfo->link_mode == BTC_WLINK_2G_SCC && dm->tdma.rxflctrl) {
2816 		null_role = FIELD_PREP(0x0f, dm->wl_scc.null_role1) |
2817 			    FIELD_PREP(0xf0, dm->wl_scc.null_role2);
2818 		_tdma_set_flctrl_role(btc, null_role);
2819 	}
2820 
2821 	/* enter leak_slot after each null-1 */
2822 	if (dm->leak_ap && dm->tdma.leak_n > 1)
2823 		_tdma_set_lek(btc, 1);
2824 
2825 	if (dm->tdma_instant_excute) {
2826 		btc->dm.tdma.option_ctrl |= BIT(0);
2827 		btc->update_policy_force = true;
2828 	}
2829 }
2830 EXPORT_SYMBOL(rtw89_btc_set_policy_v1);
2831 
2832 static void _set_bt_plut(struct rtw89_dev *rtwdev, u8 phy_map,
2833 			 u8 tx_val, u8 rx_val)
2834 {
2835 	struct rtw89_mac_ax_plt plt;
2836 
2837 	plt.band = RTW89_MAC_0;
2838 	plt.tx = tx_val;
2839 	plt.rx = rx_val;
2840 
2841 	if (phy_map & BTC_PHY_0)
2842 		rtw89_mac_cfg_plt(rtwdev, &plt);
2843 
2844 	if (!rtwdev->dbcc_en)
2845 		return;
2846 
2847 	plt.band = RTW89_MAC_1;
2848 	if (phy_map & BTC_PHY_1)
2849 		rtw89_mac_cfg_plt(rtwdev, &plt);
2850 }
2851 
2852 static void _set_ant(struct rtw89_dev *rtwdev, bool force_exec,
2853 		     u8 phy_map, u8 type)
2854 {
2855 	struct rtw89_btc *btc = &rtwdev->btc;
2856 	struct rtw89_btc_dm *dm = &btc->dm;
2857 	struct rtw89_btc_cx *cx = &btc->cx;
2858 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
2859 	struct rtw89_btc_bt_info *bt = &cx->bt;
2860 	struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
2861 	u8 gnt_wl_ctrl, gnt_bt_ctrl, plt_ctrl, i, b2g = 0;
2862 	u32 ant_path_type;
2863 
2864 	ant_path_type = ((phy_map << 8) + type);
2865 
2866 	if (btc->dm.run_reason == BTC_RSN_NTFY_POWEROFF ||
2867 	    btc->dm.run_reason == BTC_RSN_NTFY_RADIO_STATE ||
2868 	    btc->dm.run_reason == BTC_RSN_CMD_SET_COEX)
2869 		force_exec = FC_EXEC;
2870 
2871 	if (!force_exec && ant_path_type == dm->set_ant_path) {
2872 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
2873 			    "[BTC], %s(): return by no change!!\n",
2874 			     __func__);
2875 		return;
2876 	} else if (bt->rfk_info.map.run) {
2877 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
2878 			    "[BTC], %s(): return by bt rfk!!\n", __func__);
2879 		return;
2880 	} else if (btc->dm.run_reason != BTC_RSN_NTFY_WL_RFK &&
2881 		   wl->rfk_info.state != BTC_WRFK_STOP) {
2882 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
2883 			    "[BTC], %s(): return by wl rfk!!\n", __func__);
2884 		return;
2885 	}
2886 
2887 	dm->set_ant_path = ant_path_type;
2888 
2889 	rtw89_debug(rtwdev,
2890 		    RTW89_DBG_BTC,
2891 		    "[BTC], %s(): path=0x%x, set_type=0x%x\n",
2892 		    __func__, phy_map, dm->set_ant_path & 0xff);
2893 
2894 	switch (type) {
2895 	case BTC_ANT_WPOWERON:
2896 		rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_BT);
2897 		break;
2898 	case BTC_ANT_WINIT:
2899 		if (bt->enable.now)
2900 			_set_gnt(rtwdev, phy_map, BTC_GNT_SW_LO, BTC_GNT_SW_HI);
2901 		else
2902 			_set_gnt(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_SW_LO);
2903 
2904 		rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_WL);
2905 		_set_bt_plut(rtwdev, BTC_PHY_ALL, BTC_PLT_BT, BTC_PLT_BT);
2906 		break;
2907 	case BTC_ANT_WONLY:
2908 		_set_gnt(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_SW_LO);
2909 		rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_WL);
2910 		_set_bt_plut(rtwdev, BTC_PHY_ALL, BTC_PLT_NONE, BTC_PLT_NONE);
2911 		break;
2912 	case BTC_ANT_WOFF:
2913 		rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_BT);
2914 		_set_bt_plut(rtwdev, BTC_PHY_ALL, BTC_PLT_NONE, BTC_PLT_NONE);
2915 		break;
2916 	case BTC_ANT_W2G:
2917 		rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_WL);
2918 		if (rtwdev->dbcc_en) {
2919 			for (i = 0; i < RTW89_PHY_MAX; i++) {
2920 				b2g = (wl_dinfo->real_band[i] == RTW89_BAND_2G);
2921 
2922 				gnt_wl_ctrl = b2g ? BTC_GNT_HW : BTC_GNT_SW_HI;
2923 				gnt_bt_ctrl = b2g ? BTC_GNT_HW : BTC_GNT_SW_HI;
2924 				/* BT should control by GNT_BT if WL_2G at S0 */
2925 				if (i == 1 &&
2926 				    wl_dinfo->real_band[0] == RTW89_BAND_2G &&
2927 				    wl_dinfo->real_band[1] == RTW89_BAND_5G)
2928 					gnt_bt_ctrl = BTC_GNT_HW;
2929 				_set_gnt(rtwdev, BIT(i), gnt_wl_ctrl, gnt_bt_ctrl);
2930 				plt_ctrl = b2g ? BTC_PLT_BT : BTC_PLT_NONE;
2931 				_set_bt_plut(rtwdev, BIT(i),
2932 					     plt_ctrl, plt_ctrl);
2933 			}
2934 		} else {
2935 			_set_gnt(rtwdev, phy_map, BTC_GNT_HW, BTC_GNT_HW);
2936 			_set_bt_plut(rtwdev, BTC_PHY_ALL,
2937 				     BTC_PLT_BT, BTC_PLT_BT);
2938 		}
2939 		break;
2940 	case BTC_ANT_W5G:
2941 		rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_WL);
2942 		_set_gnt(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_HW);
2943 		_set_bt_plut(rtwdev, BTC_PHY_ALL, BTC_PLT_NONE, BTC_PLT_NONE);
2944 		break;
2945 	case BTC_ANT_W25G:
2946 		rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_WL);
2947 		_set_gnt(rtwdev, phy_map, BTC_GNT_HW, BTC_GNT_HW);
2948 		_set_bt_plut(rtwdev, BTC_PHY_ALL,
2949 			     BTC_PLT_GNT_WL, BTC_PLT_GNT_WL);
2950 		break;
2951 	case BTC_ANT_FREERUN:
2952 		rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_WL);
2953 		_set_gnt(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_SW_HI);
2954 		_set_bt_plut(rtwdev, BTC_PHY_ALL, BTC_PLT_NONE, BTC_PLT_NONE);
2955 		break;
2956 	case BTC_ANT_WRFK:
2957 		rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_WL);
2958 		_set_gnt(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_SW_LO);
2959 		_set_bt_plut(rtwdev, phy_map, BTC_PLT_NONE, BTC_PLT_NONE);
2960 		break;
2961 	case BTC_ANT_BRFK:
2962 		rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_BT);
2963 		_set_gnt(rtwdev, phy_map, BTC_GNT_SW_LO, BTC_GNT_SW_HI);
2964 		_set_bt_plut(rtwdev, phy_map, BTC_PLT_NONE, BTC_PLT_NONE);
2965 		break;
2966 	default:
2967 		break;
2968 	}
2969 }
2970 
2971 static void _action_wl_only(struct rtw89_dev *rtwdev)
2972 {
2973 	_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WONLY);
2974 	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_ONLY);
2975 }
2976 
2977 static void _action_wl_init(struct rtw89_dev *rtwdev)
2978 {
2979 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
2980 
2981 	_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WINIT);
2982 	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_INIT);
2983 }
2984 
2985 static void _action_wl_off(struct rtw89_dev *rtwdev)
2986 {
2987 	struct rtw89_btc *btc = &rtwdev->btc;
2988 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
2989 
2990 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
2991 
2992 	if (wl->status.map.rf_off || btc->dm.bt_only)
2993 		_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_WOFF);
2994 
2995 	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_OFF);
2996 }
2997 
2998 static void _action_freerun(struct rtw89_dev *rtwdev)
2999 {
3000 	struct rtw89_btc *btc = &rtwdev->btc;
3001 
3002 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
3003 
3004 	_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_FREERUN);
3005 	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_FREERUN);
3006 
3007 	btc->dm.freerun = true;
3008 }
3009 
3010 static void _action_bt_whql(struct rtw89_dev *rtwdev)
3011 {
3012 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
3013 
3014 	_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3015 	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_BT_WHQL);
3016 }
3017 
3018 static void _action_bt_off(struct rtw89_dev *rtwdev)
3019 {
3020 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
3021 
3022 	_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WONLY);
3023 	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_BT_OFF);
3024 }
3025 
3026 static void _action_bt_idle(struct rtw89_dev *rtwdev)
3027 {
3028 	struct rtw89_btc *btc = &rtwdev->btc;
3029 	struct rtw89_btc_bt_link_info *b = &btc->cx.bt.link_info;
3030 
3031 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3032 
3033 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */
3034 		switch (btc->cx.state_map) {
3035 		case BTC_WBUSY_BNOSCAN: /*wl-busy + bt idle*/
3036 			if (b->profile_cnt.now > 0)
3037 				_set_policy(rtwdev, BTC_CXP_FIX_TD4010,
3038 					    BTC_ACT_BT_IDLE);
3039 			else
3040 				_set_policy(rtwdev, BTC_CXP_FIX_TD4020,
3041 					    BTC_ACT_BT_IDLE);
3042 			break;
3043 		case BTC_WBUSY_BSCAN: /*wl-busy + bt-inq */
3044 			_set_policy(rtwdev, BTC_CXP_PFIX_TD5050,
3045 				    BTC_ACT_BT_IDLE);
3046 			break;
3047 		case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-idle */
3048 			if (b->profile_cnt.now > 0)
3049 				_set_policy(rtwdev, BTC_CXP_FIX_TD4010,
3050 					    BTC_ACT_BT_IDLE);
3051 			else
3052 				_set_policy(rtwdev, BTC_CXP_FIX_TD4020,
3053 					    BTC_ACT_BT_IDLE);
3054 			break;
3055 		case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq */
3056 			_set_policy(rtwdev, BTC_CXP_FIX_TD5050,
3057 				    BTC_ACT_BT_IDLE);
3058 			break;
3059 		case BTC_WLINKING: /* wl-connecting + bt-inq or bt-idle */
3060 			_set_policy(rtwdev, BTC_CXP_FIX_TD7010,
3061 				    BTC_ACT_BT_IDLE);
3062 			break;
3063 		case BTC_WIDLE:  /* wl-idle + bt-idle */
3064 			_set_policy(rtwdev, BTC_CXP_OFF_BWB1, BTC_ACT_BT_IDLE);
3065 			break;
3066 		}
3067 	} else { /* dedicated-antenna */
3068 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_BT_IDLE);
3069 	}
3070 }
3071 
3072 static void _action_bt_hfp(struct rtw89_dev *rtwdev)
3073 {
3074 	struct rtw89_btc *btc = &rtwdev->btc;
3075 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
3076 
3077 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3078 
3079 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) {
3080 		if (btc->cx.wl.status.map._4way) {
3081 			_set_policy(rtwdev, BTC_CXP_OFF_WL, BTC_ACT_BT_HFP);
3082 		} else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) {
3083 			btc->cx.bt.scan_rx_low_pri = true;
3084 			_set_policy(rtwdev, BTC_CXP_OFF_BWB2, BTC_ACT_BT_HFP);
3085 		} else {
3086 			_set_policy(rtwdev, BTC_CXP_OFF_BWB1, BTC_ACT_BT_HFP);
3087 		}
3088 	} else {
3089 		_set_policy(rtwdev, BTC_CXP_OFF_EQ2, BTC_ACT_BT_HFP);
3090 	}
3091 }
3092 
3093 static void _action_bt_hid(struct rtw89_dev *rtwdev)
3094 {
3095 	const struct rtw89_chip_info *chip = rtwdev->chip;
3096 	struct rtw89_btc *btc = &rtwdev->btc;
3097 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
3098 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
3099 	struct rtw89_btc_bt_hid_desc *hid = &bt->link_info.hid_desc;
3100 	u16 policy_type = BTC_CXP_OFF_BT;
3101 
3102 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3103 
3104 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */
3105 		if (wl->status.map._4way) {
3106 			policy_type = BTC_CXP_OFF_WL;
3107 		} else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) {
3108 			btc->cx.bt.scan_rx_low_pri = true;
3109 			if (hid->type & BTC_HID_BLE)
3110 				policy_type = BTC_CXP_OFF_BWB0;
3111 			else
3112 				policy_type = BTC_CXP_OFF_BWB2;
3113 		} else if (hid->type == BTC_HID_218) {
3114 			bt->scan_rx_low_pri = true;
3115 			policy_type = BTC_CXP_OFF_BWB2;
3116 		} else if (chip->para_ver == 0x1) {
3117 			policy_type = BTC_CXP_OFF_BWB3;
3118 		} else {
3119 			policy_type = BTC_CXP_OFF_BWB1;
3120 		}
3121 	} else { /* dedicated-antenna */
3122 		policy_type = BTC_CXP_OFF_EQ3;
3123 	}
3124 
3125 	_set_policy(rtwdev, policy_type, BTC_ACT_BT_HID);
3126 }
3127 
3128 static void _action_bt_a2dp(struct rtw89_dev *rtwdev)
3129 {
3130 	struct rtw89_btc *btc = &rtwdev->btc;
3131 	struct rtw89_btc_bt_link_info *bt_linfo = &btc->cx.bt.link_info;
3132 	struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc;
3133 	struct rtw89_btc_dm *dm = &btc->dm;
3134 
3135 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3136 
3137 	switch (btc->cx.state_map) {
3138 	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-A2DP */
3139 		if (a2dp.vendor_id == 0x4c || dm->leak_ap) {
3140 			dm->slot_dur[CXST_W1] = 40;
3141 			dm->slot_dur[CXST_B1] = 200;
3142 			_set_policy(rtwdev,
3143 				    BTC_CXP_PAUTO_TDW1B1, BTC_ACT_BT_A2DP);
3144 		} else {
3145 			_set_policy(rtwdev,
3146 				    BTC_CXP_PAUTO_TD50B1, BTC_ACT_BT_A2DP);
3147 		}
3148 		break;
3149 	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-A2DP */
3150 		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD3050, BTC_ACT_BT_A2DP);
3151 		break;
3152 	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-A2DP */
3153 		_set_policy(rtwdev, BTC_CXP_AUTO2_TD3050, BTC_ACT_BT_A2DP);
3154 		break;
3155 	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-A2DP */
3156 	case BTC_WLINKING: /* wl-connecting + bt-A2DP */
3157 		if (a2dp.vendor_id == 0x4c || dm->leak_ap) {
3158 			dm->slot_dur[CXST_W1] = 40;
3159 			dm->slot_dur[CXST_B1] = 200;
3160 			_set_policy(rtwdev, BTC_CXP_AUTO_TDW1B1,
3161 				    BTC_ACT_BT_A2DP);
3162 		} else {
3163 			_set_policy(rtwdev, BTC_CXP_AUTO_TD50B1,
3164 				    BTC_ACT_BT_A2DP);
3165 		}
3166 		break;
3167 	case BTC_WIDLE:  /* wl-idle + bt-A2DP */
3168 		_set_policy(rtwdev, BTC_CXP_AUTO_TD20B1, BTC_ACT_BT_A2DP);
3169 		break;
3170 	}
3171 }
3172 
3173 static void _action_bt_a2dpsink(struct rtw89_dev *rtwdev)
3174 {
3175 	struct rtw89_btc *btc = &rtwdev->btc;
3176 
3177 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3178 
3179 	switch (btc->cx.state_map) {
3180 	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-A2dp_Sink */
3181 		_set_policy(rtwdev, BTC_CXP_PFIX_TD2030, BTC_ACT_BT_A2DPSINK);
3182 		break;
3183 	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-A2dp_Sink */
3184 		_set_policy(rtwdev, BTC_CXP_PFIX_TD2060, BTC_ACT_BT_A2DPSINK);
3185 		break;
3186 	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-A2dp_Sink */
3187 		_set_policy(rtwdev, BTC_CXP_FIX_TD2030, BTC_ACT_BT_A2DPSINK);
3188 		break;
3189 	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-A2dp_Sink */
3190 		_set_policy(rtwdev, BTC_CXP_FIX_TD2060, BTC_ACT_BT_A2DPSINK);
3191 		break;
3192 	case BTC_WLINKING: /* wl-connecting + bt-A2dp_Sink */
3193 		_set_policy(rtwdev, BTC_CXP_FIX_TD3030, BTC_ACT_BT_A2DPSINK);
3194 		break;
3195 	case BTC_WIDLE: /* wl-idle + bt-A2dp_Sink */
3196 		_set_policy(rtwdev, BTC_CXP_FIX_TD2080, BTC_ACT_BT_A2DPSINK);
3197 		break;
3198 	}
3199 }
3200 
3201 static void _action_bt_pan(struct rtw89_dev *rtwdev)
3202 {
3203 	struct rtw89_btc *btc = &rtwdev->btc;
3204 
3205 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3206 
3207 	switch (btc->cx.state_map) {
3208 	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-PAN */
3209 		_set_policy(rtwdev, BTC_CXP_PFIX_TD5050, BTC_ACT_BT_PAN);
3210 		break;
3211 	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-PAN */
3212 		_set_policy(rtwdev, BTC_CXP_PFIX_TD3070, BTC_ACT_BT_PAN);
3213 		break;
3214 	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-PAN */
3215 		_set_policy(rtwdev, BTC_CXP_FIX_TD3030, BTC_ACT_BT_PAN);
3216 		break;
3217 	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-PAN */
3218 		_set_policy(rtwdev, BTC_CXP_FIX_TD3060, BTC_ACT_BT_PAN);
3219 		break;
3220 	case BTC_WLINKING: /* wl-connecting + bt-PAN */
3221 		_set_policy(rtwdev, BTC_CXP_FIX_TD4020, BTC_ACT_BT_PAN);
3222 		break;
3223 	case BTC_WIDLE: /* wl-idle + bt-pan */
3224 		_set_policy(rtwdev, BTC_CXP_PFIX_TD2080, BTC_ACT_BT_PAN);
3225 		break;
3226 	}
3227 }
3228 
3229 static void _action_bt_a2dp_hid(struct rtw89_dev *rtwdev)
3230 {
3231 	struct rtw89_btc *btc = &rtwdev->btc;
3232 	struct rtw89_btc_bt_link_info *bt_linfo = &btc->cx.bt.link_info;
3233 	struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc;
3234 	struct rtw89_btc_dm *dm = &btc->dm;
3235 
3236 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3237 
3238 	switch (btc->cx.state_map) {
3239 	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-A2DP+HID */
3240 	case BTC_WIDLE:  /* wl-idle + bt-A2DP */
3241 		if (a2dp.vendor_id == 0x4c || dm->leak_ap) {
3242 			dm->slot_dur[CXST_W1] = 40;
3243 			dm->slot_dur[CXST_B1] = 200;
3244 			_set_policy(rtwdev,
3245 				    BTC_CXP_PAUTO_TDW1B1, BTC_ACT_BT_A2DP_HID);
3246 		} else {
3247 			_set_policy(rtwdev,
3248 				    BTC_CXP_PAUTO_TD50B1, BTC_ACT_BT_A2DP_HID);
3249 		}
3250 		break;
3251 	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-A2DP+HID */
3252 		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD3050, BTC_ACT_BT_A2DP_HID);
3253 		break;
3254 
3255 	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-A2DP+HID */
3256 		_set_policy(rtwdev, BTC_CXP_AUTO2_TD3050, BTC_ACT_BT_A2DP_HID);
3257 		break;
3258 	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-A2DP+HID */
3259 	case BTC_WLINKING: /* wl-connecting + bt-A2DP+HID */
3260 		if (a2dp.vendor_id == 0x4c || dm->leak_ap) {
3261 			dm->slot_dur[CXST_W1] = 40;
3262 			dm->slot_dur[CXST_B1] = 200;
3263 			_set_policy(rtwdev, BTC_CXP_AUTO_TDW1B1,
3264 				    BTC_ACT_BT_A2DP_HID);
3265 		} else {
3266 			_set_policy(rtwdev, BTC_CXP_AUTO_TD50B1,
3267 				    BTC_ACT_BT_A2DP_HID);
3268 		}
3269 		break;
3270 	}
3271 }
3272 
3273 static void _action_bt_a2dp_pan(struct rtw89_dev *rtwdev)
3274 {
3275 	struct rtw89_btc *btc = &rtwdev->btc;
3276 
3277 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3278 
3279 	switch (btc->cx.state_map) {
3280 	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-A2DP+PAN */
3281 		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD3070, BTC_ACT_BT_A2DP_PAN);
3282 		break;
3283 	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-A2DP+PAN */
3284 		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD3070, BTC_ACT_BT_A2DP_PAN);
3285 		break;
3286 	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-A2DP+PAN */
3287 		_set_policy(rtwdev, BTC_CXP_AUTO2_TD5050, BTC_ACT_BT_A2DP_PAN);
3288 		break;
3289 	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-A2DP+PAN */
3290 		_set_policy(rtwdev, BTC_CXP_AUTO2_TD3070, BTC_ACT_BT_A2DP_PAN);
3291 		break;
3292 	case BTC_WLINKING: /* wl-connecting + bt-A2DP+PAN */
3293 		_set_policy(rtwdev, BTC_CXP_AUTO2_TD3050, BTC_ACT_BT_A2DP_PAN);
3294 		break;
3295 	case BTC_WIDLE:  /* wl-idle + bt-A2DP+PAN */
3296 		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD2080, BTC_ACT_BT_A2DP_PAN);
3297 		break;
3298 	}
3299 }
3300 
3301 static void _action_bt_pan_hid(struct rtw89_dev *rtwdev)
3302 {
3303 	struct rtw89_btc *btc = &rtwdev->btc;
3304 
3305 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3306 
3307 	switch (btc->cx.state_map) {
3308 	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-PAN+HID */
3309 		_set_policy(rtwdev, BTC_CXP_PFIX_TD3030, BTC_ACT_BT_PAN_HID);
3310 		break;
3311 	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-PAN+HID */
3312 		_set_policy(rtwdev, BTC_CXP_PFIX_TD3070, BTC_ACT_BT_PAN_HID);
3313 		break;
3314 	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-PAN+HID */
3315 		_set_policy(rtwdev, BTC_CXP_FIX_TD3030, BTC_ACT_BT_PAN_HID);
3316 		break;
3317 	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-PAN+HID */
3318 		_set_policy(rtwdev, BTC_CXP_FIX_TD3060, BTC_ACT_BT_PAN_HID);
3319 		break;
3320 	case BTC_WLINKING: /* wl-connecting + bt-PAN+HID */
3321 		_set_policy(rtwdev, BTC_CXP_FIX_TD4010, BTC_ACT_BT_PAN_HID);
3322 		break;
3323 	case BTC_WIDLE: /* wl-idle + bt-PAN+HID */
3324 		_set_policy(rtwdev, BTC_CXP_PFIX_TD2080, BTC_ACT_BT_PAN_HID);
3325 		break;
3326 	}
3327 }
3328 
3329 static void _action_bt_a2dp_pan_hid(struct rtw89_dev *rtwdev)
3330 {
3331 	struct rtw89_btc *btc = &rtwdev->btc;
3332 
3333 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3334 
3335 	switch (btc->cx.state_map) {
3336 	case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-A2DP+PAN+HID */
3337 		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD3070,
3338 			    BTC_ACT_BT_A2DP_PAN_HID);
3339 		break;
3340 	case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-A2DP+PAN+HID */
3341 		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD3070,
3342 			    BTC_ACT_BT_A2DP_PAN_HID);
3343 		break;
3344 	case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq + bt-A2DP+PAN+HID */
3345 		_set_policy(rtwdev, BTC_CXP_AUTO2_TD3070,
3346 			    BTC_ACT_BT_A2DP_PAN_HID);
3347 		break;
3348 	case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-A2DP+PAN+HID */
3349 	case BTC_WLINKING: /* wl-connecting + bt-A2DP+PAN+HID */
3350 		_set_policy(rtwdev, BTC_CXP_AUTO2_TD3050,
3351 			    BTC_ACT_BT_A2DP_PAN_HID);
3352 		break;
3353 	case BTC_WIDLE:  /* wl-idle + bt-A2DP+PAN+HID */
3354 		_set_policy(rtwdev, BTC_CXP_PAUTO2_TD2080,
3355 			    BTC_ACT_BT_A2DP_PAN_HID);
3356 		break;
3357 	}
3358 }
3359 
3360 static void _action_wl_5g(struct rtw89_dev *rtwdev)
3361 {
3362 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W5G);
3363 	_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_5G);
3364 }
3365 
3366 static void _action_wl_other(struct rtw89_dev *rtwdev)
3367 {
3368 	struct rtw89_btc *btc = &rtwdev->btc;
3369 
3370 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3371 
3372 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED)
3373 		_set_policy(rtwdev, BTC_CXP_OFFB_BWB0, BTC_ACT_WL_OTHER);
3374 	else
3375 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_OTHER);
3376 }
3377 
3378 static void _action_wl_nc(struct rtw89_dev *rtwdev)
3379 {
3380 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3381 	_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_NC);
3382 }
3383 
3384 static void _action_wl_rfk(struct rtw89_dev *rtwdev)
3385 {
3386 	struct rtw89_btc *btc = &rtwdev->btc;
3387 	struct rtw89_btc_wl_rfk_info rfk = btc->cx.wl.rfk_info;
3388 
3389 	if (rfk.state != BTC_WRFK_START)
3390 		return;
3391 
3392 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): band = %d\n",
3393 		    __func__, rfk.band);
3394 
3395 	_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WRFK);
3396 	_set_policy(rtwdev, BTC_CXP_OFF_WL, BTC_ACT_WL_RFK);
3397 }
3398 
3399 static void _set_btg_ctrl(struct rtw89_dev *rtwdev)
3400 {
3401 	const struct rtw89_chip_info *chip = rtwdev->chip;
3402 	struct rtw89_btc *btc = &rtwdev->btc;
3403 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
3404 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
3405 	struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1;
3406 	struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
3407 	bool is_btg;
3408 	u8 mode;
3409 
3410 	if (btc->ctrl.manual)
3411 		return;
3412 
3413 	if (chip->chip_id == RTL8852A)
3414 		mode = wl_rinfo->link_mode;
3415 	else
3416 		mode = wl_rinfo_v1->link_mode;
3417 
3418 	/* notify halbb ignore GNT_BT or not for WL BB Rx-AGC control */
3419 	if (mode == BTC_WLINK_5G) /* always 0 if 5G */
3420 		is_btg = false;
3421 	else if (mode == BTC_WLINK_25G_DBCC &&
3422 		 wl_dinfo->real_band[RTW89_PHY_1] != RTW89_BAND_2G)
3423 		is_btg = false;
3424 	else
3425 		is_btg = true;
3426 
3427 	if (btc->dm.run_reason != BTC_RSN_NTFY_INIT &&
3428 	    is_btg == btc->dm.wl_btg_rx)
3429 		return;
3430 
3431 	btc->dm.wl_btg_rx = is_btg;
3432 
3433 	if (mode == BTC_WLINK_25G_MCC)
3434 		return;
3435 
3436 	rtw89_ctrl_btg(rtwdev, is_btg);
3437 }
3438 
3439 struct rtw89_txtime_data {
3440 	struct rtw89_dev *rtwdev;
3441 	int type;
3442 	u32 tx_time;
3443 	u8 tx_retry;
3444 	u16 enable;
3445 	bool reenable;
3446 };
3447 
3448 static void rtw89_tx_time_iter(void *data, struct ieee80211_sta *sta)
3449 {
3450 	struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
3451 	struct rtw89_txtime_data *iter_data =
3452 				(struct rtw89_txtime_data *)data;
3453 	struct rtw89_dev *rtwdev = iter_data->rtwdev;
3454 	struct rtw89_vif *rtwvif = rtwsta->rtwvif;
3455 	struct rtw89_btc *btc = &rtwdev->btc;
3456 	struct rtw89_btc_cx *cx = &btc->cx;
3457 	struct rtw89_btc_wl_info *wl = &cx->wl;
3458 	struct rtw89_btc_wl_link_info *plink = NULL;
3459 	u8 port = rtwvif->port;
3460 	u32 tx_time = iter_data->tx_time;
3461 	u8 tx_retry = iter_data->tx_retry;
3462 	u16 enable = iter_data->enable;
3463 	bool reenable = iter_data->reenable;
3464 
3465 	plink = &wl->link_info[port];
3466 
3467 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
3468 		    "[BTC], %s(): port = %d\n", __func__, port);
3469 
3470 	if (!plink->connected) {
3471 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3472 			    "[BTC], %s(): connected = %d\n",
3473 			    __func__, plink->connected);
3474 		return;
3475 	}
3476 
3477 	/* backup the original tx time before tx-limit on */
3478 	if (reenable) {
3479 		rtw89_mac_get_tx_time(rtwdev, rtwsta, &plink->tx_time);
3480 		rtw89_mac_get_tx_retry_limit(rtwdev, rtwsta, &plink->tx_retry);
3481 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3482 			    "[BTC], %s(): reenable, tx_time=%d tx_retry= %d\n",
3483 			    __func__, plink->tx_time, plink->tx_retry);
3484 	}
3485 
3486 	/* restore the original tx time if no tx-limit */
3487 	if (!enable) {
3488 		rtw89_mac_set_tx_time(rtwdev, rtwsta, true, plink->tx_time);
3489 		rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta, true,
3490 					     plink->tx_retry);
3491 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3492 			    "[BTC], %s(): restore, tx_time=%d tx_retry= %d\n",
3493 			    __func__, plink->tx_time, plink->tx_retry);
3494 
3495 	} else {
3496 		rtw89_mac_set_tx_time(rtwdev, rtwsta, false, tx_time);
3497 		rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta, false, tx_retry);
3498 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
3499 			    "[BTC], %s(): set, tx_time=%d tx_retry= %d\n",
3500 			    __func__, tx_time, tx_retry);
3501 	}
3502 }
3503 
3504 static void _set_wl_tx_limit(struct rtw89_dev *rtwdev)
3505 {
3506 	const struct rtw89_chip_info *chip = rtwdev->chip;
3507 	struct rtw89_btc *btc = &rtwdev->btc;
3508 	struct rtw89_btc_cx *cx = &btc->cx;
3509 	struct rtw89_btc_dm *dm = &btc->dm;
3510 	struct rtw89_btc_wl_info *wl = &cx->wl;
3511 	struct rtw89_btc_bt_info *bt = &cx->bt;
3512 	struct rtw89_btc_bt_link_info *b = &bt->link_info;
3513 	struct rtw89_btc_bt_hfp_desc *hfp = &b->hfp_desc;
3514 	struct rtw89_btc_bt_hid_desc *hid = &b->hid_desc;
3515 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
3516 	struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1;
3517 	struct rtw89_txtime_data data = {.rtwdev = rtwdev};
3518 	u8 mode;
3519 	u8 tx_retry;
3520 	u32 tx_time;
3521 	u16 enable;
3522 	bool reenable = false;
3523 
3524 	if (btc->ctrl.manual)
3525 		return;
3526 
3527 	if (chip->chip_id == RTL8852A)
3528 		mode = wl_rinfo->link_mode;
3529 	else
3530 		mode = wl_rinfo_v1->link_mode;
3531 
3532 	if (btc->dm.freerun || btc->ctrl.igno_bt || b->profile_cnt.now == 0 ||
3533 	    mode == BTC_WLINK_5G || mode == BTC_WLINK_NOLINK) {
3534 		enable = 0;
3535 		tx_time = BTC_MAX_TX_TIME_DEF;
3536 		tx_retry = BTC_MAX_TX_RETRY_DEF;
3537 	} else if ((hfp->exist && hid->exist) || hid->pair_cnt > 1) {
3538 		enable = 1;
3539 		tx_time = BTC_MAX_TX_TIME_L2;
3540 		tx_retry = BTC_MAX_TX_RETRY_L1;
3541 	} else if (hfp->exist || hid->exist) {
3542 		enable = 1;
3543 		tx_time = BTC_MAX_TX_TIME_L3;
3544 		tx_retry = BTC_MAX_TX_RETRY_L1;
3545 	} else {
3546 		enable = 0;
3547 		tx_time = BTC_MAX_TX_TIME_DEF;
3548 		tx_retry = BTC_MAX_TX_RETRY_DEF;
3549 	}
3550 
3551 	if (dm->wl_tx_limit.enable == enable &&
3552 	    dm->wl_tx_limit.tx_time == tx_time &&
3553 	    dm->wl_tx_limit.tx_retry == tx_retry)
3554 		return;
3555 
3556 	if (!dm->wl_tx_limit.enable && enable)
3557 		reenable = true;
3558 
3559 	dm->wl_tx_limit.enable = enable;
3560 	dm->wl_tx_limit.tx_time = tx_time;
3561 	dm->wl_tx_limit.tx_retry = tx_retry;
3562 
3563 	data.enable = enable;
3564 	data.tx_time = tx_time;
3565 	data.tx_retry = tx_retry;
3566 	data.reenable = reenable;
3567 
3568 	ieee80211_iterate_stations_atomic(rtwdev->hw,
3569 					  rtw89_tx_time_iter,
3570 					  &data);
3571 }
3572 
3573 static void _set_bt_rx_agc(struct rtw89_dev *rtwdev)
3574 {
3575 	const struct rtw89_chip_info *chip = rtwdev->chip;
3576 	struct rtw89_btc *btc = &rtwdev->btc;
3577 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
3578 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
3579 	struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1;
3580 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
3581 	bool bt_hi_lna_rx = false;
3582 	u8 mode;
3583 
3584 	if (chip->chip_id == RTL8852A)
3585 		mode = wl_rinfo->link_mode;
3586 	else
3587 		mode = wl_rinfo_v1->link_mode;
3588 
3589 	if (mode != BTC_WLINK_NOLINK && btc->dm.wl_btg_rx)
3590 		bt_hi_lna_rx = true;
3591 
3592 	if (bt_hi_lna_rx == bt->hi_lna_rx)
3593 		return;
3594 
3595 	_write_scbd(rtwdev, BTC_WSCB_BT_HILNA, bt_hi_lna_rx);
3596 }
3597 
3598 static void _set_bt_rx_scan_pri(struct rtw89_dev *rtwdev)
3599 {
3600 	struct rtw89_btc *btc = &rtwdev->btc;
3601 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
3602 
3603 	_write_scbd(rtwdev, BTC_WSCB_RXSCAN_PRI, (bool)(!!bt->scan_rx_low_pri));
3604 }
3605 
3606 /* TODO add these functions */
3607 static void _action_common(struct rtw89_dev *rtwdev)
3608 {
3609 	struct rtw89_btc *btc = &rtwdev->btc;
3610 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
3611 
3612 	_set_btg_ctrl(rtwdev);
3613 	_set_wl_tx_limit(rtwdev);
3614 	_set_bt_afh_info(rtwdev);
3615 	_set_bt_rx_agc(rtwdev);
3616 	_set_rf_trx_para(rtwdev);
3617 	_set_bt_rx_scan_pri(rtwdev);
3618 
3619 	if (wl->scbd_change) {
3620 		rtw89_mac_cfg_sb(rtwdev, wl->scbd);
3621 		rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], write scbd: 0x%08x\n",
3622 			    wl->scbd);
3623 		wl->scbd_change = false;
3624 		btc->cx.cnt_wl[BTC_WCNT_SCBDUPDATE]++;
3625 	}
3626 }
3627 
3628 static void _action_by_bt(struct rtw89_dev *rtwdev)
3629 {
3630 	struct rtw89_btc *btc = &rtwdev->btc;
3631 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
3632 	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
3633 	struct rtw89_btc_bt_hid_desc hid = bt_linfo->hid_desc;
3634 	struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc;
3635 	struct rtw89_btc_bt_pan_desc pan = bt_linfo->pan_desc;
3636 	u8 profile_map = 0;
3637 
3638 	if (bt_linfo->hfp_desc.exist)
3639 		profile_map |= BTC_BT_HFP;
3640 
3641 	if (bt_linfo->hid_desc.exist)
3642 		profile_map |= BTC_BT_HID;
3643 
3644 	if (bt_linfo->a2dp_desc.exist)
3645 		profile_map |= BTC_BT_A2DP;
3646 
3647 	if (bt_linfo->pan_desc.exist)
3648 		profile_map |= BTC_BT_PAN;
3649 
3650 	switch (profile_map) {
3651 	case BTC_BT_NOPROFILE:
3652 		if (_check_freerun(rtwdev))
3653 			_action_freerun(rtwdev);
3654 		else if (a2dp.active || pan.active)
3655 			_action_bt_pan(rtwdev);
3656 		else
3657 			_action_bt_idle(rtwdev);
3658 		break;
3659 	case BTC_BT_HFP:
3660 		if (_check_freerun(rtwdev))
3661 			_action_freerun(rtwdev);
3662 		else
3663 			_action_bt_hfp(rtwdev);
3664 		break;
3665 	case BTC_BT_HFP | BTC_BT_HID:
3666 	case BTC_BT_HID:
3667 		if (_check_freerun(rtwdev))
3668 			_action_freerun(rtwdev);
3669 		else
3670 			_action_bt_hid(rtwdev);
3671 		break;
3672 	case BTC_BT_A2DP:
3673 		if (_check_freerun(rtwdev))
3674 			_action_freerun(rtwdev);
3675 		else if (a2dp.sink)
3676 			_action_bt_a2dpsink(rtwdev);
3677 		else if (bt_linfo->multi_link.now && !hid.pair_cnt)
3678 			_action_bt_a2dp_pan(rtwdev);
3679 		else
3680 			_action_bt_a2dp(rtwdev);
3681 		break;
3682 	case BTC_BT_PAN:
3683 		_action_bt_pan(rtwdev);
3684 		break;
3685 	case BTC_BT_A2DP | BTC_BT_HFP:
3686 	case BTC_BT_A2DP | BTC_BT_HID:
3687 	case BTC_BT_A2DP | BTC_BT_HFP | BTC_BT_HID:
3688 		if (_check_freerun(rtwdev))
3689 			_action_freerun(rtwdev);
3690 		else
3691 			_action_bt_a2dp_hid(rtwdev);
3692 		break;
3693 	case BTC_BT_A2DP | BTC_BT_PAN:
3694 		_action_bt_a2dp_pan(rtwdev);
3695 		break;
3696 	case BTC_BT_PAN | BTC_BT_HFP:
3697 	case BTC_BT_PAN | BTC_BT_HID:
3698 	case BTC_BT_PAN | BTC_BT_HFP | BTC_BT_HID:
3699 		_action_bt_pan_hid(rtwdev);
3700 		break;
3701 	case BTC_BT_A2DP | BTC_BT_PAN | BTC_BT_HID:
3702 	case BTC_BT_A2DP | BTC_BT_PAN | BTC_BT_HFP:
3703 	default:
3704 		_action_bt_a2dp_pan_hid(rtwdev);
3705 		break;
3706 	}
3707 }
3708 
3709 static void _action_wl_2g_sta(struct rtw89_dev *rtwdev)
3710 {
3711 	_action_by_bt(rtwdev);
3712 }
3713 
3714 static void _action_wl_scan(struct rtw89_dev *rtwdev)
3715 {
3716 	struct rtw89_btc *btc = &rtwdev->btc;
3717 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
3718 	struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
3719 
3720 	if (RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw)) {
3721 		_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W25G);
3722 		if (btc->mdinfo.ant.type == BTC_ANT_SHARED)
3723 			_set_policy(rtwdev, BTC_CXP_OFFE_DEF,
3724 				    BTC_RSN_NTFY_SCAN_START);
3725 		else
3726 			_set_policy(rtwdev, BTC_CXP_OFF_EQ0,
3727 				    BTC_RSN_NTFY_SCAN_START);
3728 
3729 		rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], Scan offload!\n");
3730 	} else if (rtwdev->dbcc_en) {
3731 		if (wl_dinfo->real_band[RTW89_PHY_0] != RTW89_BAND_2G &&
3732 		    wl_dinfo->real_band[RTW89_PHY_1] != RTW89_BAND_2G)
3733 			_action_wl_5g(rtwdev);
3734 		else
3735 			_action_by_bt(rtwdev);
3736 	} else {
3737 		if (wl->scan_info.band[RTW89_PHY_0] != RTW89_BAND_2G)
3738 			_action_wl_5g(rtwdev);
3739 		else
3740 			_action_by_bt(rtwdev);
3741 	}
3742 }
3743 
3744 static void _action_wl_25g_mcc(struct rtw89_dev *rtwdev)
3745 {
3746 	struct rtw89_btc *btc = &rtwdev->btc;
3747 
3748 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W25G);
3749 
3750 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) {
3751 		if (btc->cx.bt.link_info.profile_cnt.now == 0)
3752 			_set_policy(rtwdev, BTC_CXP_OFFE_DEF2,
3753 				    BTC_ACT_WL_25G_MCC);
3754 		else
3755 			_set_policy(rtwdev, BTC_CXP_OFFE_DEF,
3756 				    BTC_ACT_WL_25G_MCC);
3757 	} else { /* dedicated-antenna */
3758 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_25G_MCC);
3759 	}
3760 }
3761 
3762 static void _action_wl_2g_mcc(struct rtw89_dev *rtwdev)
3763 {	struct rtw89_btc *btc = &rtwdev->btc;
3764 
3765 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3766 
3767 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */
3768 		if (btc->cx.bt.link_info.profile_cnt.now == 0)
3769 			_set_policy(rtwdev, BTC_CXP_OFFE_DEF2,
3770 				    BTC_ACT_WL_2G_MCC);
3771 		else
3772 			_set_policy(rtwdev, BTC_CXP_OFFE_DEF,
3773 				    BTC_ACT_WL_2G_MCC);
3774 	} else { /* dedicated-antenna */
3775 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_MCC);
3776 	}
3777 }
3778 
3779 static void _action_wl_2g_scc(struct rtw89_dev *rtwdev)
3780 {
3781 	struct rtw89_btc *btc = &rtwdev->btc;
3782 
3783 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3784 
3785 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */
3786 		if (btc->cx.bt.link_info.profile_cnt.now == 0)
3787 			_set_policy(rtwdev,
3788 				    BTC_CXP_OFFE_DEF2, BTC_ACT_WL_2G_SCC);
3789 		else
3790 			_set_policy(rtwdev,
3791 				    BTC_CXP_OFFE_DEF, BTC_ACT_WL_2G_SCC);
3792 	} else { /* dedicated-antenna */
3793 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_SCC);
3794 	}
3795 }
3796 
3797 static void _action_wl_2g_scc_v1(struct rtw89_dev *rtwdev)
3798 {
3799 	struct rtw89_btc *btc = &rtwdev->btc;
3800 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
3801 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
3802 	struct rtw89_btc_dm *dm = &btc->dm;
3803 	struct rtw89_btc_wl_role_info_v1 *wl_rinfo = &wl->role_info_v1;
3804 	u16 policy_type = BTC_CXP_OFF_BT;
3805 	u32 dur;
3806 
3807 	if (btc->mdinfo.ant.type == BTC_ANT_DEDICATED) {
3808 		policy_type = BTC_CXP_OFF_EQ0;
3809 	} else {
3810 		/* shared-antenna */
3811 		switch (wl_rinfo->mrole_type) {
3812 		case BTC_WLMROLE_STA_GC:
3813 			dm->wl_scc.null_role1 = RTW89_WIFI_ROLE_STATION;
3814 			dm->wl_scc.null_role2 = RTW89_WIFI_ROLE_P2P_CLIENT;
3815 			dm->wl_scc.ebt_null = 0; /* no ext-slot-control */
3816 			_action_by_bt(rtwdev);
3817 			return;
3818 		case BTC_WLMROLE_STA_STA:
3819 			dm->wl_scc.null_role1 = RTW89_WIFI_ROLE_STATION;
3820 			dm->wl_scc.null_role2 = RTW89_WIFI_ROLE_STATION;
3821 			dm->wl_scc.ebt_null = 0; /* no ext-slot-control */
3822 			_action_by_bt(rtwdev);
3823 			return;
3824 		case BTC_WLMROLE_STA_GC_NOA:
3825 		case BTC_WLMROLE_STA_GO:
3826 		case BTC_WLMROLE_STA_GO_NOA:
3827 			dm->wl_scc.null_role1 = RTW89_WIFI_ROLE_STATION;
3828 			dm->wl_scc.null_role2 = RTW89_WIFI_ROLE_NONE;
3829 			dur = wl_rinfo->mrole_noa_duration;
3830 
3831 			if (wl->status.map._4way) {
3832 				dm->wl_scc.ebt_null = 0;
3833 				policy_type = BTC_CXP_OFFE_WL;
3834 			} else if (bt->link_info.status.map.connect == 0) {
3835 				dm->wl_scc.ebt_null = 0;
3836 				policy_type = BTC_CXP_OFFE_2GISOB;
3837 			} else if (bt->link_info.a2dp_desc.exist &&
3838 				   dur < btc->bt_req_len) {
3839 				dm->wl_scc.ebt_null = 1; /* tx null at EBT */
3840 				policy_type = BTC_CXP_OFFE_2GBWMIXB2;
3841 			} else if (bt->link_info.a2dp_desc.exist ||
3842 				   bt->link_info.pan_desc.exist) {
3843 				dm->wl_scc.ebt_null = 1; /* tx null at EBT */
3844 				policy_type = BTC_CXP_OFFE_2GBWISOB;
3845 			} else {
3846 				dm->wl_scc.ebt_null = 0;
3847 				policy_type = BTC_CXP_OFFE_2GBWISOB;
3848 			}
3849 			break;
3850 		default:
3851 			break;
3852 		}
3853 	}
3854 
3855 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3856 	_set_policy(rtwdev, policy_type, BTC_ACT_WL_2G_SCC);
3857 }
3858 
3859 static void _action_wl_2g_ap(struct rtw89_dev *rtwdev)
3860 {
3861 	struct rtw89_btc *btc = &rtwdev->btc;
3862 
3863 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3864 
3865 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) {
3866 		if (btc->cx.bt.link_info.profile_cnt.now == 0)
3867 			_set_policy(rtwdev, BTC_CXP_OFFE_DEF2,
3868 				    BTC_ACT_WL_2G_AP);
3869 		else
3870 			_set_policy(rtwdev, BTC_CXP_OFFE_DEF, BTC_ACT_WL_2G_AP);
3871 	} else {/* dedicated-antenna */
3872 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_AP);
3873 	}
3874 }
3875 
3876 static void _action_wl_2g_go(struct rtw89_dev *rtwdev)
3877 {
3878 	struct rtw89_btc *btc = &rtwdev->btc;
3879 
3880 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3881 
3882 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */
3883 		if (btc->cx.bt.link_info.profile_cnt.now == 0)
3884 			_set_policy(rtwdev,
3885 				    BTC_CXP_OFFE_DEF2, BTC_ACT_WL_2G_GO);
3886 		else
3887 			_set_policy(rtwdev,
3888 				    BTC_CXP_OFFE_DEF, BTC_ACT_WL_2G_GO);
3889 	} else { /* dedicated-antenna */
3890 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_GO);
3891 	}
3892 }
3893 
3894 static void _action_wl_2g_gc(struct rtw89_dev *rtwdev)
3895 {
3896 	struct rtw89_btc *btc = &rtwdev->btc;
3897 
3898 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3899 
3900 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */
3901 		_action_by_bt(rtwdev);
3902 	} else {/* dedicated-antenna */
3903 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_GC);
3904 	}
3905 }
3906 
3907 static void _action_wl_2g_nan(struct rtw89_dev *rtwdev)
3908 {
3909 	struct rtw89_btc *btc = &rtwdev->btc;
3910 
3911 	_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
3912 
3913 	if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */
3914 		if (btc->cx.bt.link_info.profile_cnt.now == 0)
3915 			_set_policy(rtwdev,
3916 				    BTC_CXP_OFFE_DEF2, BTC_ACT_WL_2G_NAN);
3917 		else
3918 			_set_policy(rtwdev,
3919 				    BTC_CXP_OFFE_DEF, BTC_ACT_WL_2G_NAN);
3920 	} else { /* dedicated-antenna */
3921 		_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_NAN);
3922 	}
3923 }
3924 
3925 static u32 _read_scbd(struct rtw89_dev *rtwdev)
3926 {
3927 	const struct rtw89_chip_info *chip = rtwdev->chip;
3928 	struct rtw89_btc *btc = &rtwdev->btc;
3929 	u32 scbd_val = 0;
3930 
3931 	if (!chip->scbd)
3932 		return 0;
3933 
3934 	scbd_val = rtw89_mac_get_sb(rtwdev);
3935 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], read scbd: 0x%08x\n",
3936 		    scbd_val);
3937 
3938 	btc->cx.cnt_bt[BTC_BCNT_SCBDREAD]++;
3939 	return scbd_val;
3940 }
3941 
3942 static void _write_scbd(struct rtw89_dev *rtwdev, u32 val, bool state)
3943 {
3944 	const struct rtw89_chip_info *chip = rtwdev->chip;
3945 	struct rtw89_btc *btc = &rtwdev->btc;
3946 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
3947 	u32 scbd_val = 0;
3948 	u8 force_exec = false;
3949 
3950 	if (!chip->scbd)
3951 		return;
3952 
3953 	scbd_val = state ? wl->scbd | val : wl->scbd & ~val;
3954 
3955 	if (val & BTC_WSCB_ACTIVE || val & BTC_WSCB_ON)
3956 		force_exec = true;
3957 
3958 	if (scbd_val != wl->scbd || force_exec) {
3959 		wl->scbd = scbd_val;
3960 		wl->scbd_change = true;
3961 	}
3962 }
3963 
3964 static u8
3965 _update_rssi_state(struct rtw89_dev *rtwdev, u8 pre_state, u8 rssi, u8 thresh)
3966 {
3967 	const struct rtw89_chip_info *chip = rtwdev->chip;
3968 	u8 next_state, tol = chip->rssi_tol;
3969 
3970 	if (pre_state == BTC_RSSI_ST_LOW ||
3971 	    pre_state == BTC_RSSI_ST_STAY_LOW) {
3972 		if (rssi >= (thresh + tol))
3973 			next_state = BTC_RSSI_ST_HIGH;
3974 		else
3975 			next_state = BTC_RSSI_ST_STAY_LOW;
3976 	} else {
3977 		if (rssi < thresh)
3978 			next_state = BTC_RSSI_ST_LOW;
3979 		else
3980 			next_state = BTC_RSSI_ST_STAY_HIGH;
3981 	}
3982 
3983 	return next_state;
3984 }
3985 
3986 static
3987 void _update_dbcc_band(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
3988 {
3989 	struct rtw89_btc *btc = &rtwdev->btc;
3990 
3991 	btc->cx.wl.dbcc_info.real_band[phy_idx] =
3992 		btc->cx.wl.scan_info.phy_map & BIT(phy_idx) ?
3993 		btc->cx.wl.dbcc_info.scan_band[phy_idx] :
3994 		btc->cx.wl.dbcc_info.op_band[phy_idx];
3995 }
3996 
3997 static void _update_wl_info(struct rtw89_dev *rtwdev)
3998 {
3999 	struct rtw89_btc *btc = &rtwdev->btc;
4000 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4001 	struct rtw89_btc_wl_link_info *wl_linfo = wl->link_info;
4002 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
4003 	struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
4004 	u8 i, cnt_connect = 0, cnt_connecting = 0, cnt_active = 0;
4005 	u8 cnt_2g = 0, cnt_5g = 0, phy;
4006 	u32 wl_2g_ch[2] = {0}, wl_5g_ch[2] = {0};
4007 	bool b2g = false, b5g = false, client_joined = false;
4008 
4009 	memset(wl_rinfo, 0, sizeof(*wl_rinfo));
4010 
4011 	for (i = 0; i < RTW89_PORT_NUM; i++) {
4012 		/* check if role active? */
4013 		if (!wl_linfo[i].active)
4014 			continue;
4015 
4016 		cnt_active++;
4017 		wl_rinfo->active_role[cnt_active - 1].role = wl_linfo[i].role;
4018 		wl_rinfo->active_role[cnt_active - 1].pid = wl_linfo[i].pid;
4019 		wl_rinfo->active_role[cnt_active - 1].phy = wl_linfo[i].phy;
4020 		wl_rinfo->active_role[cnt_active - 1].band = wl_linfo[i].band;
4021 		wl_rinfo->active_role[cnt_active - 1].noa = (u8)wl_linfo[i].noa;
4022 		wl_rinfo->active_role[cnt_active - 1].connected = 0;
4023 
4024 		wl->port_id[wl_linfo[i].role] = wl_linfo[i].pid;
4025 
4026 		phy = wl_linfo[i].phy;
4027 
4028 		/* check dbcc role */
4029 		if (rtwdev->dbcc_en && phy < RTW89_PHY_MAX) {
4030 			wl_dinfo->role[phy] = wl_linfo[i].role;
4031 			wl_dinfo->op_band[phy] = wl_linfo[i].band;
4032 			_update_dbcc_band(rtwdev, phy);
4033 			_fw_set_drv_info(rtwdev, CXDRVINFO_DBCC);
4034 		}
4035 
4036 		if (wl_linfo[i].connected == MLME_NO_LINK) {
4037 			continue;
4038 		} else if (wl_linfo[i].connected == MLME_LINKING) {
4039 			cnt_connecting++;
4040 		} else {
4041 			cnt_connect++;
4042 			if ((wl_linfo[i].role == RTW89_WIFI_ROLE_P2P_GO ||
4043 			     wl_linfo[i].role == RTW89_WIFI_ROLE_AP) &&
4044 			     wl_linfo[i].client_cnt > 1)
4045 				client_joined = true;
4046 		}
4047 
4048 		wl_rinfo->role_map.val |= BIT(wl_linfo[i].role);
4049 		wl_rinfo->active_role[cnt_active - 1].ch = wl_linfo[i].ch;
4050 		wl_rinfo->active_role[cnt_active - 1].bw = wl_linfo[i].bw;
4051 		wl_rinfo->active_role[cnt_active - 1].connected = 1;
4052 
4053 		/* only care 2 roles + BT coex */
4054 		if (wl_linfo[i].band != RTW89_BAND_2G) {
4055 			if (cnt_5g <= ARRAY_SIZE(wl_5g_ch) - 1)
4056 				wl_5g_ch[cnt_5g] = wl_linfo[i].ch;
4057 			cnt_5g++;
4058 			b5g = true;
4059 		} else {
4060 			if (cnt_2g <= ARRAY_SIZE(wl_2g_ch) - 1)
4061 				wl_2g_ch[cnt_2g] = wl_linfo[i].ch;
4062 			cnt_2g++;
4063 			b2g = true;
4064 		}
4065 	}
4066 
4067 	wl_rinfo->connect_cnt = cnt_connect;
4068 
4069 	/* Be careful to change the following sequence!! */
4070 	if (cnt_connect == 0) {
4071 		wl_rinfo->link_mode = BTC_WLINK_NOLINK;
4072 		wl_rinfo->role_map.role.none = 1;
4073 	} else if (!b2g && b5g) {
4074 		wl_rinfo->link_mode = BTC_WLINK_5G;
4075 	} else if (wl_rinfo->role_map.role.nan) {
4076 		wl_rinfo->link_mode = BTC_WLINK_2G_NAN;
4077 	} else if (cnt_connect > BTC_TDMA_WLROLE_MAX) {
4078 		wl_rinfo->link_mode = BTC_WLINK_OTHER;
4079 	} else  if (b2g && b5g && cnt_connect == 2) {
4080 		if (rtwdev->dbcc_en) {
4081 			switch (wl_dinfo->role[RTW89_PHY_0]) {
4082 			case RTW89_WIFI_ROLE_STATION:
4083 				wl_rinfo->link_mode = BTC_WLINK_2G_STA;
4084 				break;
4085 			case RTW89_WIFI_ROLE_P2P_GO:
4086 				wl_rinfo->link_mode = BTC_WLINK_2G_GO;
4087 				break;
4088 			case RTW89_WIFI_ROLE_P2P_CLIENT:
4089 				wl_rinfo->link_mode = BTC_WLINK_2G_GC;
4090 				break;
4091 			case RTW89_WIFI_ROLE_AP:
4092 				wl_rinfo->link_mode = BTC_WLINK_2G_AP;
4093 				break;
4094 			default:
4095 				wl_rinfo->link_mode = BTC_WLINK_OTHER;
4096 				break;
4097 			}
4098 		} else {
4099 			wl_rinfo->link_mode = BTC_WLINK_25G_MCC;
4100 		}
4101 	} else if (!b5g && cnt_connect == 2) {
4102 		if (wl_rinfo->role_map.role.station &&
4103 		    (wl_rinfo->role_map.role.p2p_go ||
4104 		    wl_rinfo->role_map.role.p2p_gc ||
4105 		    wl_rinfo->role_map.role.ap)) {
4106 			if (wl_2g_ch[0] == wl_2g_ch[1])
4107 				wl_rinfo->link_mode = BTC_WLINK_2G_SCC;
4108 			else
4109 				wl_rinfo->link_mode = BTC_WLINK_2G_MCC;
4110 		} else {
4111 			wl_rinfo->link_mode = BTC_WLINK_2G_MCC;
4112 		}
4113 	} else if (!b5g && cnt_connect == 1) {
4114 		if (wl_rinfo->role_map.role.station)
4115 			wl_rinfo->link_mode = BTC_WLINK_2G_STA;
4116 		else if (wl_rinfo->role_map.role.ap)
4117 			wl_rinfo->link_mode = BTC_WLINK_2G_AP;
4118 		else if (wl_rinfo->role_map.role.p2p_go)
4119 			wl_rinfo->link_mode = BTC_WLINK_2G_GO;
4120 		else if (wl_rinfo->role_map.role.p2p_gc)
4121 			wl_rinfo->link_mode = BTC_WLINK_2G_GC;
4122 		else
4123 			wl_rinfo->link_mode = BTC_WLINK_OTHER;
4124 	}
4125 
4126 	/* if no client_joined, don't care P2P-GO/AP role */
4127 	if (wl_rinfo->role_map.role.p2p_go || wl_rinfo->role_map.role.ap) {
4128 		if (!client_joined) {
4129 			if (wl_rinfo->link_mode == BTC_WLINK_2G_SCC ||
4130 			    wl_rinfo->link_mode == BTC_WLINK_2G_MCC) {
4131 				wl_rinfo->link_mode = BTC_WLINK_2G_STA;
4132 				wl_rinfo->connect_cnt = 1;
4133 			} else if (wl_rinfo->link_mode == BTC_WLINK_2G_GO ||
4134 				 wl_rinfo->link_mode == BTC_WLINK_2G_AP) {
4135 				wl_rinfo->link_mode = BTC_WLINK_NOLINK;
4136 				wl_rinfo->connect_cnt = 0;
4137 			}
4138 		}
4139 	}
4140 
4141 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
4142 		    "[BTC], cnt_connect = %d, connecting = %d, link_mode = %d\n",
4143 		    cnt_connect, cnt_connecting, wl_rinfo->link_mode);
4144 
4145 	_fw_set_drv_info(rtwdev, CXDRVINFO_ROLE);
4146 }
4147 
4148 static void _update_wl_info_v1(struct rtw89_dev *rtwdev)
4149 {
4150 	struct rtw89_btc *btc = &rtwdev->btc;
4151 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4152 	struct rtw89_btc_wl_link_info *wl_linfo = wl->link_info;
4153 	struct rtw89_btc_wl_role_info_v1 *wl_rinfo = &wl->role_info_v1;
4154 	struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
4155 	u8 cnt_connect = 0, cnt_connecting = 0, cnt_active = 0;
4156 	u8 cnt_2g = 0, cnt_5g = 0, phy;
4157 	u32 wl_2g_ch[2] = {}, wl_5g_ch[2] = {};
4158 	bool b2g = false, b5g = false, client_joined = false;
4159 	u8 i;
4160 
4161 	memset(wl_rinfo, 0, sizeof(*wl_rinfo));
4162 
4163 	for (i = 0; i < RTW89_PORT_NUM; i++) {
4164 		if (!wl_linfo[i].active)
4165 			continue;
4166 
4167 		cnt_active++;
4168 		wl_rinfo->active_role_v1[cnt_active - 1].role = wl_linfo[i].role;
4169 		wl_rinfo->active_role_v1[cnt_active - 1].pid = wl_linfo[i].pid;
4170 		wl_rinfo->active_role_v1[cnt_active - 1].phy = wl_linfo[i].phy;
4171 		wl_rinfo->active_role_v1[cnt_active - 1].band = wl_linfo[i].band;
4172 		wl_rinfo->active_role_v1[cnt_active - 1].noa = (u8)wl_linfo[i].noa;
4173 		wl_rinfo->active_role_v1[cnt_active - 1].connected = 0;
4174 
4175 		wl->port_id[wl_linfo[i].role] = wl_linfo[i].pid;
4176 
4177 		phy = wl_linfo[i].phy;
4178 
4179 		if (rtwdev->dbcc_en && phy < RTW89_PHY_MAX) {
4180 			wl_dinfo->role[phy] = wl_linfo[i].role;
4181 			wl_dinfo->op_band[phy] = wl_linfo[i].band;
4182 			_update_dbcc_band(rtwdev, phy);
4183 			_fw_set_drv_info(rtwdev, CXDRVINFO_DBCC);
4184 		}
4185 
4186 		if (wl_linfo[i].connected == MLME_NO_LINK) {
4187 			continue;
4188 		} else if (wl_linfo[i].connected == MLME_LINKING) {
4189 			cnt_connecting++;
4190 		} else {
4191 			cnt_connect++;
4192 			if ((wl_linfo[i].role == RTW89_WIFI_ROLE_P2P_GO ||
4193 			     wl_linfo[i].role == RTW89_WIFI_ROLE_AP) &&
4194 			     wl_linfo[i].client_cnt > 1)
4195 				client_joined = true;
4196 		}
4197 
4198 		wl_rinfo->role_map.val |= BIT(wl_linfo[i].role);
4199 		wl_rinfo->active_role_v1[cnt_active - 1].ch = wl_linfo[i].ch;
4200 		wl_rinfo->active_role_v1[cnt_active - 1].bw = wl_linfo[i].bw;
4201 		wl_rinfo->active_role_v1[cnt_active - 1].connected = 1;
4202 
4203 		/* only care 2 roles + BT coex */
4204 		if (wl_linfo[i].band != RTW89_BAND_2G) {
4205 			if (cnt_5g <= ARRAY_SIZE(wl_5g_ch) - 1)
4206 				wl_5g_ch[cnt_5g] = wl_linfo[i].ch;
4207 			cnt_5g++;
4208 			b5g = true;
4209 		} else {
4210 			if (cnt_2g <= ARRAY_SIZE(wl_2g_ch) - 1)
4211 				wl_2g_ch[cnt_2g] = wl_linfo[i].ch;
4212 			cnt_2g++;
4213 			b2g = true;
4214 		}
4215 	}
4216 
4217 	wl_rinfo->connect_cnt = cnt_connect;
4218 
4219 	/* Be careful to change the following sequence!! */
4220 	if (cnt_connect == 0) {
4221 		wl_rinfo->link_mode = BTC_WLINK_NOLINK;
4222 		wl_rinfo->role_map.role.none = 1;
4223 	} else if (!b2g && b5g) {
4224 		wl_rinfo->link_mode = BTC_WLINK_5G;
4225 	} else if (wl_rinfo->role_map.role.nan) {
4226 		wl_rinfo->link_mode = BTC_WLINK_2G_NAN;
4227 	} else if (cnt_connect > BTC_TDMA_WLROLE_MAX) {
4228 		wl_rinfo->link_mode = BTC_WLINK_OTHER;
4229 	} else  if (b2g && b5g && cnt_connect == 2) {
4230 		if (rtwdev->dbcc_en) {
4231 			switch (wl_dinfo->role[RTW89_PHY_0]) {
4232 			case RTW89_WIFI_ROLE_STATION:
4233 				wl_rinfo->link_mode = BTC_WLINK_2G_STA;
4234 				break;
4235 			case RTW89_WIFI_ROLE_P2P_GO:
4236 				wl_rinfo->link_mode = BTC_WLINK_2G_GO;
4237 				break;
4238 			case RTW89_WIFI_ROLE_P2P_CLIENT:
4239 				wl_rinfo->link_mode = BTC_WLINK_2G_GC;
4240 				break;
4241 			case RTW89_WIFI_ROLE_AP:
4242 				wl_rinfo->link_mode = BTC_WLINK_2G_AP;
4243 				break;
4244 			default:
4245 				wl_rinfo->link_mode = BTC_WLINK_OTHER;
4246 				break;
4247 			}
4248 		} else {
4249 			wl_rinfo->link_mode = BTC_WLINK_25G_MCC;
4250 		}
4251 	} else if (!b5g && cnt_connect == 2) {
4252 		if (wl_rinfo->role_map.role.station &&
4253 		    (wl_rinfo->role_map.role.p2p_go ||
4254 		    wl_rinfo->role_map.role.p2p_gc ||
4255 		    wl_rinfo->role_map.role.ap)) {
4256 			if (wl_2g_ch[0] == wl_2g_ch[1])
4257 				wl_rinfo->link_mode = BTC_WLINK_2G_SCC;
4258 			else
4259 				wl_rinfo->link_mode = BTC_WLINK_2G_MCC;
4260 		} else {
4261 			wl_rinfo->link_mode = BTC_WLINK_2G_MCC;
4262 		}
4263 	} else if (!b5g && cnt_connect == 1) {
4264 		if (wl_rinfo->role_map.role.station)
4265 			wl_rinfo->link_mode = BTC_WLINK_2G_STA;
4266 		else if (wl_rinfo->role_map.role.ap)
4267 			wl_rinfo->link_mode = BTC_WLINK_2G_AP;
4268 		else if (wl_rinfo->role_map.role.p2p_go)
4269 			wl_rinfo->link_mode = BTC_WLINK_2G_GO;
4270 		else if (wl_rinfo->role_map.role.p2p_gc)
4271 			wl_rinfo->link_mode = BTC_WLINK_2G_GC;
4272 		else
4273 			wl_rinfo->link_mode = BTC_WLINK_OTHER;
4274 	}
4275 
4276 	/* if no client_joined, don't care P2P-GO/AP role */
4277 	if (wl_rinfo->role_map.role.p2p_go || wl_rinfo->role_map.role.ap) {
4278 		if (!client_joined) {
4279 			if (wl_rinfo->link_mode == BTC_WLINK_2G_SCC ||
4280 			    wl_rinfo->link_mode == BTC_WLINK_2G_MCC) {
4281 				wl_rinfo->link_mode = BTC_WLINK_2G_STA;
4282 				wl_rinfo->connect_cnt = 1;
4283 			} else if (wl_rinfo->link_mode == BTC_WLINK_2G_GO ||
4284 				 wl_rinfo->link_mode == BTC_WLINK_2G_AP) {
4285 				wl_rinfo->link_mode = BTC_WLINK_NOLINK;
4286 				wl_rinfo->connect_cnt = 0;
4287 			}
4288 		}
4289 	}
4290 
4291 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
4292 		    "[BTC], cnt_connect = %d, connecting = %d, link_mode = %d\n",
4293 		    cnt_connect, cnt_connecting, wl_rinfo->link_mode);
4294 
4295 	_fw_set_drv_info(rtwdev, CXDRVINFO_ROLE);
4296 }
4297 
4298 #define BTC_CHK_HANG_MAX 3
4299 #define BTC_SCB_INV_VALUE GENMASK(31, 0)
4300 
4301 void rtw89_coex_act1_work(struct work_struct *work)
4302 {
4303 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
4304 						coex_act1_work.work);
4305 	struct rtw89_btc *btc = &rtwdev->btc;
4306 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
4307 	struct rtw89_btc_cx *cx = &btc->cx;
4308 	struct rtw89_btc_wl_info *wl = &cx->wl;
4309 
4310 	mutex_lock(&rtwdev->mutex);
4311 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): enter\n", __func__);
4312 	dm->cnt_notify[BTC_NCNT_TIMER]++;
4313 	if (wl->status.map._4way)
4314 		wl->status.map._4way = false;
4315 	if (wl->status.map.connecting)
4316 		wl->status.map.connecting = false;
4317 
4318 	_run_coex(rtwdev, BTC_RSN_ACT1_WORK);
4319 	mutex_unlock(&rtwdev->mutex);
4320 }
4321 
4322 void rtw89_coex_bt_devinfo_work(struct work_struct *work)
4323 {
4324 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
4325 						coex_bt_devinfo_work.work);
4326 	struct rtw89_btc *btc = &rtwdev->btc;
4327 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
4328 	struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc;
4329 
4330 	mutex_lock(&rtwdev->mutex);
4331 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): enter\n", __func__);
4332 	dm->cnt_notify[BTC_NCNT_TIMER]++;
4333 	a2dp->play_latency = 0;
4334 	_run_coex(rtwdev, BTC_RSN_BT_DEVINFO_WORK);
4335 	mutex_unlock(&rtwdev->mutex);
4336 }
4337 
4338 void rtw89_coex_rfk_chk_work(struct work_struct *work)
4339 {
4340 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
4341 						coex_rfk_chk_work.work);
4342 	struct rtw89_btc *btc = &rtwdev->btc;
4343 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
4344 	struct rtw89_btc_cx *cx = &btc->cx;
4345 	struct rtw89_btc_wl_info *wl = &cx->wl;
4346 
4347 	mutex_lock(&rtwdev->mutex);
4348 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): enter\n", __func__);
4349 	dm->cnt_notify[BTC_NCNT_TIMER]++;
4350 	if (wl->rfk_info.state != BTC_WRFK_STOP) {
4351 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4352 			    "[BTC], %s(): RFK timeout\n", __func__);
4353 		cx->cnt_wl[BTC_WCNT_RFK_TIMEOUT]++;
4354 		dm->error.map.wl_rfk_timeout = true;
4355 		wl->rfk_info.state = BTC_WRFK_STOP;
4356 		_write_scbd(rtwdev, BTC_WSCB_WLRFK, false);
4357 		_run_coex(rtwdev, BTC_RSN_RFK_CHK_WORK);
4358 	}
4359 	mutex_unlock(&rtwdev->mutex);
4360 }
4361 
4362 static void _update_bt_scbd(struct rtw89_dev *rtwdev, bool only_update)
4363 {
4364 	const struct rtw89_chip_info *chip = rtwdev->chip;
4365 	struct rtw89_btc *btc = &rtwdev->btc;
4366 	struct rtw89_btc_cx *cx = &btc->cx;
4367 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
4368 	u32 val;
4369 	bool status_change = false;
4370 
4371 	if (!chip->scbd)
4372 		return;
4373 
4374 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s\n", __func__);
4375 
4376 	val = _read_scbd(rtwdev);
4377 	if (val == BTC_SCB_INV_VALUE) {
4378 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4379 			    "[BTC], %s(): return by invalid scbd value\n",
4380 			    __func__);
4381 		return;
4382 	}
4383 
4384 	if (!(val & BTC_BSCB_ON) ||
4385 	    btc->dm.cnt_dm[BTC_DCNT_BTCNT_FREEZE] >= BTC_CHK_HANG_MAX)
4386 		bt->enable.now = 0;
4387 	else
4388 		bt->enable.now = 1;
4389 
4390 	if (bt->enable.now != bt->enable.last)
4391 		status_change = true;
4392 
4393 	/* reset bt info if bt re-enable */
4394 	if (bt->enable.now && !bt->enable.last) {
4395 		_reset_btc_var(rtwdev, BTC_RESET_BTINFO);
4396 		cx->cnt_bt[BTC_BCNT_REENABLE]++;
4397 		bt->enable.now = 1;
4398 	}
4399 
4400 	bt->enable.last = bt->enable.now;
4401 	bt->scbd = val;
4402 	bt->mbx_avl = !!(val & BTC_BSCB_ACT);
4403 
4404 	if (bt->whql_test != !!(val & BTC_BSCB_WHQL))
4405 		status_change = true;
4406 
4407 	bt->whql_test = !!(val & BTC_BSCB_WHQL);
4408 	bt->btg_type = val & BTC_BSCB_BT_S1 ? BTC_BT_BTG : BTC_BT_ALONE;
4409 	bt->link_info.a2dp_desc.active = !!(val & BTC_BSCB_A2DP_ACT);
4410 
4411 	/* if rfk run 1->0 */
4412 	if (bt->rfk_info.map.run && !(val & BTC_BSCB_RFK_RUN))
4413 		status_change = true;
4414 
4415 	bt->rfk_info.map.run  = !!(val & BTC_BSCB_RFK_RUN);
4416 	bt->rfk_info.map.req = !!(val & BTC_BSCB_RFK_REQ);
4417 	bt->hi_lna_rx = !!(val & BTC_BSCB_BT_HILNA);
4418 	bt->link_info.status.map.connect = !!(val & BTC_BSCB_BT_CONNECT);
4419 	bt->run_patch_code = !!(val & BTC_BSCB_PATCH_CODE);
4420 
4421 	if (!only_update && status_change)
4422 		_run_coex(rtwdev, BTC_RSN_UPDATE_BT_SCBD);
4423 }
4424 
4425 static bool _chk_wl_rfk_request(struct rtw89_dev *rtwdev)
4426 {
4427 	struct rtw89_btc *btc = &rtwdev->btc;
4428 	struct rtw89_btc_cx *cx = &btc->cx;
4429 	struct rtw89_btc_bt_info *bt = &cx->bt;
4430 
4431 	_update_bt_scbd(rtwdev, true);
4432 
4433 	cx->cnt_wl[BTC_WCNT_RFK_REQ]++;
4434 
4435 	if ((bt->rfk_info.map.run || bt->rfk_info.map.req) &&
4436 	    !bt->rfk_info.map.timeout) {
4437 		cx->cnt_wl[BTC_WCNT_RFK_REJECT]++;
4438 	} else {
4439 		cx->cnt_wl[BTC_WCNT_RFK_GO]++;
4440 		return true;
4441 	}
4442 	return false;
4443 }
4444 
4445 static
4446 void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason)
4447 {
4448 	const struct rtw89_chip_info *chip = rtwdev->chip;
4449 	struct rtw89_btc *btc = &rtwdev->btc;
4450 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
4451 	struct rtw89_btc_cx *cx = &btc->cx;
4452 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4453 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
4454 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
4455 	struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1;
4456 	u8 mode;
4457 
4458 	lockdep_assert_held(&rtwdev->mutex);
4459 
4460 	dm->run_reason = reason;
4461 	_update_dm_step(rtwdev, reason);
4462 	_update_btc_state_map(rtwdev);
4463 
4464 	if (chip->chip_id == RTL8852A)
4465 		mode = wl_rinfo->link_mode;
4466 	else
4467 		mode = wl_rinfo_v1->link_mode;
4468 
4469 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): reason=%d, mode=%d\n",
4470 		    __func__, reason, mode);
4471 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): wl_only=%d, bt_only=%d\n",
4472 		    __func__, dm->wl_only, dm->bt_only);
4473 
4474 	/* Be careful to change the following function sequence!! */
4475 	if (btc->ctrl.manual) {
4476 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4477 			    "[BTC], %s(): return for Manual CTRL!!\n",
4478 			    __func__);
4479 		return;
4480 	}
4481 
4482 	if (btc->ctrl.igno_bt &&
4483 	    (reason == BTC_RSN_UPDATE_BT_INFO ||
4484 	     reason == BTC_RSN_UPDATE_BT_SCBD)) {
4485 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4486 			    "[BTC], %s(): return for Stop Coex DM!!\n",
4487 			    __func__);
4488 		return;
4489 	}
4490 
4491 	if (!wl->status.map.init_ok) {
4492 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4493 			    "[BTC], %s(): return for WL init fail!!\n",
4494 			    __func__);
4495 		return;
4496 	}
4497 
4498 	if (wl->status.map.rf_off_pre == wl->status.map.rf_off &&
4499 	    wl->status.map.lps_pre == wl->status.map.lps &&
4500 	    (reason == BTC_RSN_NTFY_POWEROFF ||
4501 	    reason == BTC_RSN_NTFY_RADIO_STATE)) {
4502 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4503 			    "[BTC], %s(): return for WL rf off state no change!!\n",
4504 			    __func__);
4505 		return;
4506 	}
4507 
4508 	dm->cnt_dm[BTC_DCNT_RUN]++;
4509 
4510 	if (btc->ctrl.always_freerun) {
4511 		_action_freerun(rtwdev);
4512 		btc->ctrl.igno_bt = true;
4513 		goto exit;
4514 	}
4515 
4516 	if (dm->wl_only) {
4517 		_action_wl_only(rtwdev);
4518 		btc->ctrl.igno_bt = true;
4519 		goto exit;
4520 	}
4521 
4522 	if (wl->status.map.rf_off || wl->status.map.lps || dm->bt_only) {
4523 		_action_wl_off(rtwdev);
4524 		btc->ctrl.igno_bt = true;
4525 		goto exit;
4526 	}
4527 
4528 	btc->ctrl.igno_bt = false;
4529 	dm->freerun = false;
4530 	bt->scan_rx_low_pri = false;
4531 
4532 	if (reason == BTC_RSN_NTFY_INIT) {
4533 		_action_wl_init(rtwdev);
4534 		goto exit;
4535 	}
4536 
4537 	if (!cx->bt.enable.now && !cx->other.type) {
4538 		_action_bt_off(rtwdev);
4539 		goto exit;
4540 	}
4541 
4542 	if (cx->bt.whql_test) {
4543 		_action_bt_whql(rtwdev);
4544 		goto exit;
4545 	}
4546 
4547 	if (wl->rfk_info.state != BTC_WRFK_STOP) {
4548 		_action_wl_rfk(rtwdev);
4549 		goto exit;
4550 	}
4551 
4552 	if (cx->state_map == BTC_WLINKING) {
4553 		if (mode == BTC_WLINK_NOLINK || mode == BTC_WLINK_2G_STA ||
4554 		    mode == BTC_WLINK_5G) {
4555 			_action_wl_scan(rtwdev);
4556 			goto exit;
4557 		}
4558 	}
4559 
4560 	if (wl->status.map.scan) {
4561 		_action_wl_scan(rtwdev);
4562 		goto exit;
4563 	}
4564 
4565 	switch (mode) {
4566 	case BTC_WLINK_NOLINK:
4567 		_action_wl_nc(rtwdev);
4568 		break;
4569 	case BTC_WLINK_2G_STA:
4570 		_action_wl_2g_sta(rtwdev);
4571 		break;
4572 	case BTC_WLINK_2G_AP:
4573 		bt->scan_rx_low_pri = true;
4574 		_action_wl_2g_ap(rtwdev);
4575 		break;
4576 	case BTC_WLINK_2G_GO:
4577 		bt->scan_rx_low_pri = true;
4578 		_action_wl_2g_go(rtwdev);
4579 		break;
4580 	case BTC_WLINK_2G_GC:
4581 		bt->scan_rx_low_pri = true;
4582 		_action_wl_2g_gc(rtwdev);
4583 		break;
4584 	case BTC_WLINK_2G_SCC:
4585 		bt->scan_rx_low_pri = true;
4586 		if (chip->chip_id == RTL8852A)
4587 			_action_wl_2g_scc(rtwdev);
4588 		else if (chip->chip_id == RTL8852C)
4589 			_action_wl_2g_scc_v1(rtwdev);
4590 		break;
4591 	case BTC_WLINK_2G_MCC:
4592 		bt->scan_rx_low_pri = true;
4593 		_action_wl_2g_mcc(rtwdev);
4594 		break;
4595 	case BTC_WLINK_25G_MCC:
4596 		bt->scan_rx_low_pri = true;
4597 		_action_wl_25g_mcc(rtwdev);
4598 		break;
4599 	case BTC_WLINK_5G:
4600 		_action_wl_5g(rtwdev);
4601 		break;
4602 	case BTC_WLINK_2G_NAN:
4603 		_action_wl_2g_nan(rtwdev);
4604 		break;
4605 	default:
4606 		_action_wl_other(rtwdev);
4607 		break;
4608 	}
4609 
4610 exit:
4611 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): exit\n", __func__);
4612 	_action_common(rtwdev);
4613 }
4614 
4615 void rtw89_btc_ntfy_poweron(struct rtw89_dev *rtwdev)
4616 {
4617 	struct rtw89_btc *btc = &rtwdev->btc;
4618 
4619 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
4620 	btc->dm.cnt_notify[BTC_NCNT_POWER_ON]++;
4621 }
4622 
4623 void rtw89_btc_ntfy_poweroff(struct rtw89_dev *rtwdev)
4624 {
4625 	struct rtw89_btc *btc = &rtwdev->btc;
4626 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4627 
4628 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
4629 	btc->dm.cnt_notify[BTC_NCNT_POWER_OFF]++;
4630 
4631 	btc->cx.wl.status.map.rf_off = 1;
4632 	btc->cx.wl.status.map.busy = 0;
4633 	wl->status.map.lps = BTC_LPS_OFF;
4634 
4635 	_write_scbd(rtwdev, BTC_WSCB_ALL, false);
4636 	_run_coex(rtwdev, BTC_RSN_NTFY_POWEROFF);
4637 
4638 	rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_ALL, 0);
4639 
4640 	btc->cx.wl.status.map.rf_off_pre = btc->cx.wl.status.map.rf_off;
4641 }
4642 
4643 static void _set_init_info(struct rtw89_dev *rtwdev)
4644 {
4645 	const struct rtw89_chip_info *chip = rtwdev->chip;
4646 	struct rtw89_btc *btc = &rtwdev->btc;
4647 	struct rtw89_btc_dm *dm = &btc->dm;
4648 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4649 
4650 	dm->init_info.wl_only = (u8)dm->wl_only;
4651 	dm->init_info.bt_only = (u8)dm->bt_only;
4652 	dm->init_info.wl_init_ok = (u8)wl->status.map.init_ok;
4653 	dm->init_info.dbcc_en = rtwdev->dbcc_en;
4654 	dm->init_info.cx_other = btc->cx.other.type;
4655 	dm->init_info.wl_guard_ch = chip->afh_guard_ch;
4656 	dm->init_info.module = btc->mdinfo;
4657 }
4658 
4659 void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode)
4660 {
4661 	struct rtw89_btc *btc = &rtwdev->btc;
4662 	struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
4663 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4664 	const struct rtw89_chip_info *chip = rtwdev->chip;
4665 
4666 	_reset_btc_var(rtwdev, BTC_RESET_ALL);
4667 	btc->dm.run_reason = BTC_RSN_NONE;
4668 	btc->dm.run_action = BTC_ACT_NONE;
4669 	btc->ctrl.igno_bt = true;
4670 
4671 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
4672 		    "[BTC], %s(): mode=%d\n", __func__, mode);
4673 
4674 	dm->cnt_notify[BTC_NCNT_INIT_COEX]++;
4675 	dm->wl_only = mode == BTC_MODE_WL ? 1 : 0;
4676 	dm->bt_only = mode == BTC_MODE_BT ? 1 : 0;
4677 	wl->status.map.rf_off = mode == BTC_MODE_WLOFF ? 1 : 0;
4678 
4679 	chip->ops->btc_set_rfe(rtwdev);
4680 	chip->ops->btc_init_cfg(rtwdev);
4681 
4682 	if (!wl->status.map.init_ok) {
4683 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4684 			    "[BTC], %s(): return for WL init fail!!\n",
4685 			    __func__);
4686 		dm->error.map.init = true;
4687 		return;
4688 	}
4689 
4690 	_write_scbd(rtwdev,
4691 		    BTC_WSCB_ACTIVE | BTC_WSCB_ON | BTC_WSCB_BTLOG, true);
4692 	_update_bt_scbd(rtwdev, true);
4693 	if (rtw89_mac_get_ctrl_path(rtwdev) && chip->chip_id == RTL8852A) {
4694 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4695 			    "[BTC], %s(): PTA owner warning!!\n",
4696 			    __func__);
4697 		dm->error.map.pta_owner = true;
4698 	}
4699 
4700 	_set_init_info(rtwdev);
4701 	_set_wl_tx_power(rtwdev, RTW89_BTC_WL_DEF_TX_PWR);
4702 	rtw89_btc_fw_set_slots(rtwdev, CXST_MAX, dm->slot);
4703 	btc_fw_set_monreg(rtwdev);
4704 	_fw_set_drv_info(rtwdev, CXDRVINFO_INIT);
4705 	_fw_set_drv_info(rtwdev, CXDRVINFO_CTRL);
4706 
4707 	_run_coex(rtwdev, BTC_RSN_NTFY_INIT);
4708 }
4709 
4710 void rtw89_btc_ntfy_scan_start(struct rtw89_dev *rtwdev, u8 phy_idx, u8 band)
4711 {
4712 	struct rtw89_btc *btc = &rtwdev->btc;
4713 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4714 
4715 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
4716 		    "[BTC], %s(): phy_idx=%d, band=%d\n",
4717 		    __func__, phy_idx, band);
4718 	btc->dm.cnt_notify[BTC_NCNT_SCAN_START]++;
4719 	wl->status.map.scan = true;
4720 	wl->scan_info.band[phy_idx] = band;
4721 	wl->scan_info.phy_map |= BIT(phy_idx);
4722 	_fw_set_drv_info(rtwdev, CXDRVINFO_SCAN);
4723 
4724 	if (rtwdev->dbcc_en) {
4725 		wl->dbcc_info.scan_band[phy_idx] = band;
4726 		_update_dbcc_band(rtwdev, phy_idx);
4727 		_fw_set_drv_info(rtwdev, CXDRVINFO_DBCC);
4728 	}
4729 
4730 	_run_coex(rtwdev, BTC_RSN_NTFY_SCAN_START);
4731 }
4732 
4733 void rtw89_btc_ntfy_scan_finish(struct rtw89_dev *rtwdev, u8 phy_idx)
4734 {
4735 	struct rtw89_btc *btc = &rtwdev->btc;
4736 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4737 
4738 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
4739 		    "[BTC], %s(): phy_idx=%d\n", __func__, phy_idx);
4740 	btc->dm.cnt_notify[BTC_NCNT_SCAN_FINISH]++;
4741 
4742 	wl->status.map.scan = false;
4743 	wl->scan_info.phy_map &= ~BIT(phy_idx);
4744 	_fw_set_drv_info(rtwdev, CXDRVINFO_SCAN);
4745 
4746 	if (rtwdev->dbcc_en) {
4747 		_update_dbcc_band(rtwdev, phy_idx);
4748 		_fw_set_drv_info(rtwdev, CXDRVINFO_DBCC);
4749 	}
4750 
4751 	_run_coex(rtwdev, BTC_RSN_NTFY_SCAN_FINISH);
4752 }
4753 
4754 void rtw89_btc_ntfy_switch_band(struct rtw89_dev *rtwdev, u8 phy_idx, u8 band)
4755 {
4756 	struct rtw89_btc *btc = &rtwdev->btc;
4757 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
4758 
4759 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
4760 		    "[BTC], %s(): phy_idx=%d, band=%d\n",
4761 		    __func__, phy_idx, band);
4762 	btc->dm.cnt_notify[BTC_NCNT_SWITCH_BAND]++;
4763 
4764 	wl->scan_info.band[phy_idx] = band;
4765 	wl->scan_info.phy_map |= BIT(phy_idx);
4766 	_fw_set_drv_info(rtwdev, CXDRVINFO_SCAN);
4767 
4768 	if (rtwdev->dbcc_en) {
4769 		wl->dbcc_info.scan_band[phy_idx] = band;
4770 		_update_dbcc_band(rtwdev, phy_idx);
4771 		_fw_set_drv_info(rtwdev, CXDRVINFO_DBCC);
4772 	}
4773 	_run_coex(rtwdev, BTC_RSN_NTFY_SWBAND);
4774 }
4775 
4776 void rtw89_btc_ntfy_specific_packet(struct rtw89_dev *rtwdev,
4777 				    enum btc_pkt_type pkt_type)
4778 {
4779 	struct rtw89_btc *btc = &rtwdev->btc;
4780 	struct rtw89_btc_cx *cx = &btc->cx;
4781 	struct rtw89_btc_wl_info *wl = &cx->wl;
4782 	struct rtw89_btc_bt_link_info *b = &cx->bt.link_info;
4783 	struct rtw89_btc_bt_hfp_desc *hfp = &b->hfp_desc;
4784 	struct rtw89_btc_bt_hid_desc *hid = &b->hid_desc;
4785 	u32 cnt;
4786 	u32 delay = RTW89_COEX_ACT1_WORK_PERIOD;
4787 	bool delay_work = false;
4788 
4789 	switch (pkt_type) {
4790 	case PACKET_DHCP:
4791 		cnt = ++cx->cnt_wl[BTC_WCNT_DHCP];
4792 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4793 			    "[BTC], %s(): DHCP cnt=%d\n", __func__, cnt);
4794 		wl->status.map.connecting = true;
4795 		delay_work = true;
4796 		break;
4797 	case PACKET_EAPOL:
4798 		cnt = ++cx->cnt_wl[BTC_WCNT_EAPOL];
4799 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4800 			    "[BTC], %s(): EAPOL cnt=%d\n", __func__, cnt);
4801 		wl->status.map._4way = true;
4802 		delay_work = true;
4803 		if (hfp->exist || hid->exist)
4804 			delay /= 2;
4805 		break;
4806 	case PACKET_EAPOL_END:
4807 		cnt = ++cx->cnt_wl[BTC_WCNT_EAPOL];
4808 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4809 			    "[BTC], %s(): EAPOL_End cnt=%d\n",
4810 			    __func__, cnt);
4811 		wl->status.map._4way = false;
4812 		cancel_delayed_work(&rtwdev->coex_act1_work);
4813 		break;
4814 	case PACKET_ARP:
4815 		cnt = ++cx->cnt_wl[BTC_WCNT_ARP];
4816 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4817 			    "[BTC], %s(): ARP cnt=%d\n", __func__, cnt);
4818 		return;
4819 	case PACKET_ICMP:
4820 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4821 			    "[BTC], %s(): ICMP pkt\n", __func__);
4822 		return;
4823 	default:
4824 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4825 			    "[BTC], %s(): unknown packet type %d\n",
4826 			    __func__, pkt_type);
4827 		return;
4828 	}
4829 
4830 	if (delay_work) {
4831 		cancel_delayed_work(&rtwdev->coex_act1_work);
4832 		ieee80211_queue_delayed_work(rtwdev->hw,
4833 					     &rtwdev->coex_act1_work, delay);
4834 	}
4835 
4836 	btc->dm.cnt_notify[BTC_NCNT_SPECIAL_PACKET]++;
4837 	_run_coex(rtwdev, BTC_RSN_NTFY_SPECIFIC_PACKET);
4838 }
4839 
4840 void rtw89_btc_ntfy_eapol_packet_work(struct work_struct *work)
4841 {
4842 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
4843 						btc.eapol_notify_work);
4844 
4845 	mutex_lock(&rtwdev->mutex);
4846 	rtw89_leave_ps_mode(rtwdev);
4847 	rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_EAPOL);
4848 	mutex_unlock(&rtwdev->mutex);
4849 }
4850 
4851 void rtw89_btc_ntfy_arp_packet_work(struct work_struct *work)
4852 {
4853 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
4854 						btc.arp_notify_work);
4855 
4856 	mutex_lock(&rtwdev->mutex);
4857 	rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_ARP);
4858 	mutex_unlock(&rtwdev->mutex);
4859 }
4860 
4861 void rtw89_btc_ntfy_dhcp_packet_work(struct work_struct *work)
4862 {
4863 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
4864 						btc.dhcp_notify_work);
4865 
4866 	mutex_lock(&rtwdev->mutex);
4867 	rtw89_leave_ps_mode(rtwdev);
4868 	rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_DHCP);
4869 	mutex_unlock(&rtwdev->mutex);
4870 }
4871 
4872 void rtw89_btc_ntfy_icmp_packet_work(struct work_struct *work)
4873 {
4874 	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
4875 						btc.icmp_notify_work);
4876 
4877 	mutex_lock(&rtwdev->mutex);
4878 	rtw89_leave_ps_mode(rtwdev);
4879 	rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_ICMP);
4880 	mutex_unlock(&rtwdev->mutex);
4881 }
4882 
4883 static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len)
4884 {
4885 	const struct rtw89_chip_info *chip = rtwdev->chip;
4886 	struct rtw89_btc *btc = &rtwdev->btc;
4887 	struct rtw89_btc_cx *cx = &btc->cx;
4888 	struct rtw89_btc_bt_info *bt = &cx->bt;
4889 	struct rtw89_btc_bt_link_info *b = &bt->link_info;
4890 	struct rtw89_btc_bt_hfp_desc *hfp = &b->hfp_desc;
4891 	struct rtw89_btc_bt_hid_desc *hid = &b->hid_desc;
4892 	struct rtw89_btc_bt_a2dp_desc *a2dp = &b->a2dp_desc;
4893 	struct rtw89_btc_bt_pan_desc *pan = &b->pan_desc;
4894 	union btc_btinfo btinfo;
4895 
4896 	if (buf[BTC_BTINFO_L1] != 6)
4897 		return;
4898 
4899 	if (!memcmp(bt->raw_info, buf, BTC_BTINFO_MAX)) {
4900 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
4901 			    "[BTC], %s(): return by bt-info duplicate!!\n",
4902 			    __func__);
4903 		cx->cnt_bt[BTC_BCNT_INFOSAME]++;
4904 		return;
4905 	}
4906 
4907 	memcpy(bt->raw_info, buf, BTC_BTINFO_MAX);
4908 
4909 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
4910 		    "[BTC], %s(): bt_info[2]=0x%02x\n",
4911 		    __func__, bt->raw_info[2]);
4912 
4913 	/* reset to mo-connect before update */
4914 	b->status.val = BTC_BLINK_NOCONNECT;
4915 	b->profile_cnt.last = b->profile_cnt.now;
4916 	b->relink.last = b->relink.now;
4917 	a2dp->exist_last = a2dp->exist;
4918 	b->multi_link.last = b->multi_link.now;
4919 	bt->inq_pag.last = bt->inq_pag.now;
4920 	b->profile_cnt.now = 0;
4921 	hid->type = 0;
4922 
4923 	/* parse raw info low-Byte2 */
4924 	btinfo.val = bt->raw_info[BTC_BTINFO_L2];
4925 	b->status.map.connect = btinfo.lb2.connect;
4926 	b->status.map.sco_busy = btinfo.lb2.sco_busy;
4927 	b->status.map.acl_busy = btinfo.lb2.acl_busy;
4928 	b->status.map.inq_pag = btinfo.lb2.inq_pag;
4929 	bt->inq_pag.now = btinfo.lb2.inq_pag;
4930 	cx->cnt_bt[BTC_BCNT_INQPAG] += !!(bt->inq_pag.now && !bt->inq_pag.last);
4931 
4932 	hfp->exist = btinfo.lb2.hfp;
4933 	b->profile_cnt.now += (u8)hfp->exist;
4934 	hid->exist = btinfo.lb2.hid;
4935 	b->profile_cnt.now += (u8)hid->exist;
4936 	a2dp->exist = btinfo.lb2.a2dp;
4937 	b->profile_cnt.now += (u8)a2dp->exist;
4938 	pan->active = btinfo.lb2.pan;
4939 
4940 	/* parse raw info low-Byte3 */
4941 	btinfo.val = bt->raw_info[BTC_BTINFO_L3];
4942 	if (btinfo.lb3.retry != 0)
4943 		cx->cnt_bt[BTC_BCNT_RETRY]++;
4944 	b->cqddr = btinfo.lb3.cqddr;
4945 	cx->cnt_bt[BTC_BCNT_INQ] += !!(btinfo.lb3.inq && !bt->inq);
4946 	bt->inq = btinfo.lb3.inq;
4947 	cx->cnt_bt[BTC_BCNT_PAGE] += !!(btinfo.lb3.pag && !bt->pag);
4948 	bt->pag = btinfo.lb3.pag;
4949 
4950 	b->status.map.mesh_busy = btinfo.lb3.mesh_busy;
4951 	/* parse raw info high-Byte0 */
4952 	btinfo.val = bt->raw_info[BTC_BTINFO_H0];
4953 	/* raw val is dBm unit, translate from -100~ 0dBm to 0~100%*/
4954 	b->rssi = chip->ops->btc_get_bt_rssi(rtwdev, btinfo.hb0.rssi);
4955 
4956 	/* parse raw info high-Byte1 */
4957 	btinfo.val = bt->raw_info[BTC_BTINFO_H1];
4958 	b->status.map.ble_connect = btinfo.hb1.ble_connect;
4959 	if (btinfo.hb1.ble_connect)
4960 		hid->type |= (hid->exist ? BTC_HID_BLE : BTC_HID_RCU);
4961 
4962 	cx->cnt_bt[BTC_BCNT_REINIT] += !!(btinfo.hb1.reinit && !bt->reinit);
4963 	bt->reinit = btinfo.hb1.reinit;
4964 	cx->cnt_bt[BTC_BCNT_RELINK] += !!(btinfo.hb1.relink && !b->relink.now);
4965 	b->relink.now = btinfo.hb1.relink;
4966 	cx->cnt_bt[BTC_BCNT_IGNOWL] += !!(btinfo.hb1.igno_wl && !bt->igno_wl);
4967 	bt->igno_wl = btinfo.hb1.igno_wl;
4968 
4969 	if (bt->igno_wl && !cx->wl.status.map.rf_off)
4970 		_set_bt_ignore_wlan_act(rtwdev, false);
4971 
4972 	hid->type |= (btinfo.hb1.voice ? BTC_HID_RCU_VOICE : 0);
4973 	bt->ble_scan_en = btinfo.hb1.ble_scan;
4974 
4975 	cx->cnt_bt[BTC_BCNT_ROLESW] += !!(btinfo.hb1.role_sw && !b->role_sw);
4976 	b->role_sw = btinfo.hb1.role_sw;
4977 
4978 	b->multi_link.now = btinfo.hb1.multi_link;
4979 
4980 	/* parse raw info high-Byte2 */
4981 	btinfo.val = bt->raw_info[BTC_BTINFO_H2];
4982 	pan->exist = btinfo.hb2.pan_active;
4983 	b->profile_cnt.now += (u8)pan->exist;
4984 
4985 	cx->cnt_bt[BTC_BCNT_AFH] += !!(btinfo.hb2.afh_update && !b->afh_update);
4986 	b->afh_update = btinfo.hb2.afh_update;
4987 	a2dp->active = btinfo.hb2.a2dp_active;
4988 	b->slave_role = btinfo.hb2.slave;
4989 	hid->slot_info = btinfo.hb2.hid_slot;
4990 	hid->pair_cnt = btinfo.hb2.hid_cnt;
4991 	hid->type |= (hid->slot_info == BTC_HID_218 ?
4992 		      BTC_HID_218 : BTC_HID_418);
4993 	/* parse raw info high-Byte3 */
4994 	btinfo.val = bt->raw_info[BTC_BTINFO_H3];
4995 	a2dp->bitpool = btinfo.hb3.a2dp_bitpool;
4996 
4997 	if (b->tx_3m != (u32)btinfo.hb3.tx_3m)
4998 		cx->cnt_bt[BTC_BCNT_RATECHG]++;
4999 	b->tx_3m = (u32)btinfo.hb3.tx_3m;
5000 
5001 	a2dp->sink = btinfo.hb3.a2dp_sink;
5002 
5003 	if (b->profile_cnt.now || b->status.map.ble_connect)
5004 		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP, 1);
5005 	else
5006 		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP, 0);
5007 
5008 	if (!a2dp->exist_last && a2dp->exist) {
5009 		a2dp->vendor_id = 0;
5010 		a2dp->flush_time = 0;
5011 		a2dp->play_latency = 1;
5012 		ieee80211_queue_delayed_work(rtwdev->hw,
5013 					     &rtwdev->coex_bt_devinfo_work,
5014 					     RTW89_COEX_BT_DEVINFO_WORK_PERIOD);
5015 	}
5016 
5017 	if (a2dp->exist && (a2dp->flush_time == 0 || a2dp->vendor_id == 0 ||
5018 			    a2dp->play_latency == 1))
5019 		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_DEVICE_INFO, 1);
5020 	else
5021 		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_DEVICE_INFO, 0);
5022 
5023 	_run_coex(rtwdev, BTC_RSN_UPDATE_BT_INFO);
5024 }
5025 
5026 enum btc_wl_mode {
5027 	BTC_WL_MODE_HT = 0,
5028 	BTC_WL_MODE_VHT = 1,
5029 	BTC_WL_MODE_HE = 2,
5030 	BTC_WL_MODE_NUM,
5031 };
5032 
5033 void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
5034 			      struct rtw89_sta *rtwsta, enum btc_role_state state)
5035 {
5036 	const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
5037 	const struct rtw89_chip_info *chip = rtwdev->chip;
5038 	struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
5039 	struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta);
5040 	struct rtw89_btc *btc = &rtwdev->btc;
5041 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
5042 	struct rtw89_btc_wl_link_info r = {0};
5043 	struct rtw89_btc_wl_link_info *wlinfo = NULL;
5044 	u8 mode = 0;
5045 
5046 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], state=%d\n", state);
5047 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
5048 		    "[BTC], role is STA=%d\n",
5049 		    vif->type == NL80211_IFTYPE_STATION);
5050 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], port=%d\n", rtwvif->port);
5051 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], band=%d ch=%d bw=%d\n",
5052 		    chan->band_type, chan->channel, chan->band_width);
5053 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], associated=%d\n",
5054 		    state == BTC_ROLE_MSTS_STA_CONN_END);
5055 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
5056 		    "[BTC], bcn_period=%d dtim_period=%d\n",
5057 		    vif->bss_conf.beacon_int, vif->bss_conf.dtim_period);
5058 
5059 	if (rtwsta) {
5060 		rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], STA mac_id=%d\n",
5061 			    rtwsta->mac_id);
5062 
5063 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
5064 			    "[BTC], STA support HE=%d VHT=%d HT=%d\n",
5065 			    sta->deflink.he_cap.has_he,
5066 			    sta->deflink.vht_cap.vht_supported,
5067 			    sta->deflink.ht_cap.ht_supported);
5068 		if (sta->deflink.he_cap.has_he)
5069 			mode |= BIT(BTC_WL_MODE_HE);
5070 		if (sta->deflink.vht_cap.vht_supported)
5071 			mode |= BIT(BTC_WL_MODE_VHT);
5072 		if (sta->deflink.ht_cap.ht_supported)
5073 			mode |= BIT(BTC_WL_MODE_HT);
5074 
5075 		r.mode = mode;
5076 	}
5077 
5078 	if (rtwvif->wifi_role >= RTW89_WIFI_ROLE_MLME_MAX)
5079 		return;
5080 
5081 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
5082 		    "[BTC], wifi_role=%d\n", rtwvif->wifi_role);
5083 
5084 	r.role = rtwvif->wifi_role;
5085 	r.phy = rtwvif->phy_idx;
5086 	r.pid = rtwvif->port;
5087 	r.active = true;
5088 	r.connected = MLME_LINKED;
5089 	r.bcn_period = vif->bss_conf.beacon_int;
5090 	r.dtim_period = vif->bss_conf.dtim_period;
5091 	r.band = chan->band_type;
5092 	r.ch = chan->channel;
5093 	r.bw = chan->band_width;
5094 	ether_addr_copy(r.mac_addr, rtwvif->mac_addr);
5095 
5096 	if (rtwsta && vif->type == NL80211_IFTYPE_STATION)
5097 		r.mac_id = rtwsta->mac_id;
5098 
5099 	btc->dm.cnt_notify[BTC_NCNT_ROLE_INFO]++;
5100 
5101 	wlinfo = &wl->link_info[r.pid];
5102 
5103 	memcpy(wlinfo, &r, sizeof(*wlinfo));
5104 	if (chip->chip_id == RTL8852A)
5105 		_update_wl_info(rtwdev);
5106 	else
5107 		_update_wl_info_v1(rtwdev);
5108 
5109 	if (wlinfo->role == RTW89_WIFI_ROLE_STATION &&
5110 	    wlinfo->connected == MLME_NO_LINK)
5111 		btc->dm.leak_ap = 0;
5112 
5113 	if (state == BTC_ROLE_MSTS_STA_CONN_START)
5114 		wl->status.map.connecting = 1;
5115 	else
5116 		wl->status.map.connecting = 0;
5117 
5118 	if (state == BTC_ROLE_MSTS_STA_DIS_CONN)
5119 		wl->status.map._4way = false;
5120 
5121 	_run_coex(rtwdev, BTC_RSN_NTFY_ROLE_INFO);
5122 }
5123 
5124 void rtw89_btc_ntfy_radio_state(struct rtw89_dev *rtwdev, enum btc_rfctrl rf_state)
5125 {
5126 	const struct rtw89_chip_info *chip = rtwdev->chip;
5127 	struct rtw89_btc *btc = &rtwdev->btc;
5128 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
5129 	u32 val;
5130 
5131 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): rf_state = %d\n",
5132 		    __func__, rf_state);
5133 	btc->dm.cnt_notify[BTC_NCNT_RADIO_STATE]++;
5134 
5135 	switch (rf_state) {
5136 	case BTC_RFCTRL_WL_OFF:
5137 		wl->status.map.rf_off = 1;
5138 		wl->status.map.lps = BTC_LPS_OFF;
5139 		wl->status.map.busy = 0;
5140 		break;
5141 	case BTC_RFCTRL_FW_CTRL:
5142 		wl->status.map.rf_off = 0;
5143 		wl->status.map.lps = BTC_LPS_RF_OFF;
5144 		wl->status.map.busy = 0;
5145 		break;
5146 	case BTC_RFCTRL_WL_ON:
5147 	default:
5148 		wl->status.map.rf_off = 0;
5149 		wl->status.map.lps = BTC_LPS_OFF;
5150 		break;
5151 	}
5152 
5153 	if (rf_state == BTC_RFCTRL_WL_ON) {
5154 		btc->dm.cnt_dm[BTC_DCNT_BTCNT_FREEZE] = 0;
5155 		rtw89_btc_fw_en_rpt(rtwdev,
5156 				    RPT_EN_MREG | RPT_EN_BT_VER_INFO, true);
5157 		val = BTC_WSCB_ACTIVE | BTC_WSCB_ON | BTC_WSCB_BTLOG;
5158 		_write_scbd(rtwdev, val, true);
5159 		_update_bt_scbd(rtwdev, true);
5160 		chip->ops->btc_init_cfg(rtwdev);
5161 	} else {
5162 		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_ALL, false);
5163 		if (rf_state == BTC_RFCTRL_WL_OFF)
5164 			_write_scbd(rtwdev, BTC_WSCB_ALL, false);
5165 	}
5166 
5167 	_run_coex(rtwdev, BTC_RSN_NTFY_RADIO_STATE);
5168 
5169 	wl->status.map.rf_off_pre = wl->status.map.rf_off;
5170 	wl->status.map.lps_pre = wl->status.map.lps;
5171 }
5172 
5173 static bool _ntfy_wl_rfk(struct rtw89_dev *rtwdev, u8 phy_path,
5174 			 enum btc_wl_rfk_type type,
5175 			 enum btc_wl_rfk_state state)
5176 {
5177 	struct rtw89_btc *btc = &rtwdev->btc;
5178 	struct rtw89_btc_cx *cx = &btc->cx;
5179 	struct rtw89_btc_wl_info *wl = &cx->wl;
5180 	bool result = BTC_WRFK_REJECT;
5181 
5182 	wl->rfk_info.type = type;
5183 	wl->rfk_info.path_map = FIELD_GET(BTC_RFK_PATH_MAP, phy_path);
5184 	wl->rfk_info.phy_map = FIELD_GET(BTC_RFK_PHY_MAP, phy_path);
5185 	wl->rfk_info.band = FIELD_GET(BTC_RFK_BAND_MAP, phy_path);
5186 
5187 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
5188 		    "[BTC], %s()_start: phy=0x%x, path=0x%x, type=%d, state=%d\n",
5189 		    __func__, wl->rfk_info.phy_map, wl->rfk_info.path_map,
5190 		    type, state);
5191 
5192 	switch (state) {
5193 	case BTC_WRFK_START:
5194 		result = _chk_wl_rfk_request(rtwdev);
5195 		wl->rfk_info.state = result ? BTC_WRFK_START : BTC_WRFK_STOP;
5196 
5197 		_write_scbd(rtwdev, BTC_WSCB_WLRFK, result);
5198 
5199 		btc->dm.cnt_notify[BTC_NCNT_WL_RFK]++;
5200 		break;
5201 	case BTC_WRFK_ONESHOT_START:
5202 	case BTC_WRFK_ONESHOT_STOP:
5203 		if (wl->rfk_info.state == BTC_WRFK_STOP) {
5204 			result = BTC_WRFK_REJECT;
5205 		} else {
5206 			result = BTC_WRFK_ALLOW;
5207 			wl->rfk_info.state = state;
5208 		}
5209 		break;
5210 	case BTC_WRFK_STOP:
5211 		result = BTC_WRFK_ALLOW;
5212 		wl->rfk_info.state = BTC_WRFK_STOP;
5213 
5214 		_write_scbd(rtwdev, BTC_WSCB_WLRFK, false);
5215 		cancel_delayed_work(&rtwdev->coex_rfk_chk_work);
5216 		break;
5217 	default:
5218 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
5219 			    "[BTC], %s() warning state=%d\n", __func__, state);
5220 		break;
5221 	}
5222 
5223 	if (result == BTC_WRFK_ALLOW) {
5224 		if (wl->rfk_info.state == BTC_WRFK_START ||
5225 		    wl->rfk_info.state == BTC_WRFK_STOP)
5226 			_run_coex(rtwdev, BTC_RSN_NTFY_WL_RFK);
5227 
5228 		if (wl->rfk_info.state == BTC_WRFK_START)
5229 			ieee80211_queue_delayed_work(rtwdev->hw,
5230 						     &rtwdev->coex_rfk_chk_work,
5231 						     RTW89_COEX_RFK_CHK_WORK_PERIOD);
5232 	}
5233 
5234 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
5235 		    "[BTC], %s()_finish: rfk_cnt=%d, result=%d\n",
5236 		    __func__, btc->dm.cnt_notify[BTC_NCNT_WL_RFK], result);
5237 
5238 	return result == BTC_WRFK_ALLOW;
5239 }
5240 
5241 void rtw89_btc_ntfy_wl_rfk(struct rtw89_dev *rtwdev, u8 phy_map,
5242 			   enum btc_wl_rfk_type type,
5243 			   enum btc_wl_rfk_state state)
5244 {
5245 	u8 band;
5246 	bool allow;
5247 	int ret;
5248 
5249 	band = FIELD_GET(BTC_RFK_BAND_MAP, phy_map);
5250 
5251 	rtw89_debug(rtwdev, RTW89_DBG_RFK,
5252 		    "[RFK] RFK notify (%s / PHY%u / K_type = %u / path_idx = %lu / process = %s)\n",
5253 		    band == RTW89_BAND_2G ? "2G" :
5254 		    band == RTW89_BAND_5G ? "5G" : "6G",
5255 		    !!(FIELD_GET(BTC_RFK_PHY_MAP, phy_map) & BIT(RTW89_PHY_1)),
5256 		    type,
5257 		    FIELD_GET(BTC_RFK_PATH_MAP, phy_map),
5258 		    state == BTC_WRFK_STOP ? "RFK_STOP" :
5259 		    state == BTC_WRFK_START ? "RFK_START" :
5260 		    state == BTC_WRFK_ONESHOT_START ? "ONE-SHOT_START" :
5261 		    "ONE-SHOT_STOP");
5262 
5263 	if (state != BTC_WRFK_START || rtwdev->is_bt_iqk_timeout) {
5264 		_ntfy_wl_rfk(rtwdev, phy_map, type, state);
5265 		return;
5266 	}
5267 
5268 	ret = read_poll_timeout(_ntfy_wl_rfk, allow, allow, 40, 100000, false,
5269 				rtwdev, phy_map, type, state);
5270 	if (ret) {
5271 		rtw89_warn(rtwdev, "RFK notify timeout\n");
5272 		rtwdev->is_bt_iqk_timeout = true;
5273 	}
5274 }
5275 EXPORT_SYMBOL(rtw89_btc_ntfy_wl_rfk);
5276 
5277 struct rtw89_btc_wl_sta_iter_data {
5278 	struct rtw89_dev *rtwdev;
5279 	u8 busy_all;
5280 	u8 dir_all;
5281 	u8 rssi_map_all;
5282 	bool is_sta_change;
5283 	bool is_traffic_change;
5284 };
5285 
5286 static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta)
5287 {
5288 	struct rtw89_btc_wl_sta_iter_data *iter_data =
5289 				(struct rtw89_btc_wl_sta_iter_data *)data;
5290 	struct rtw89_dev *rtwdev = iter_data->rtwdev;
5291 	struct rtw89_btc *btc = &rtwdev->btc;
5292 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
5293 	struct rtw89_btc_wl_link_info *link_info = NULL;
5294 	struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
5295 	struct rtw89_traffic_stats *link_info_t = NULL;
5296 	struct rtw89_vif *rtwvif = rtwsta->rtwvif;
5297 	struct rtw89_traffic_stats *stats = &rtwvif->stats;
5298 	const struct rtw89_chip_info *chip = rtwdev->chip;
5299 	u32 last_tx_rate, last_rx_rate;
5300 	u16 last_tx_lvl, last_rx_lvl;
5301 	u8 port = rtwvif->port;
5302 	u8 rssi;
5303 	u8 busy = 0;
5304 	u8 dir = 0;
5305 	u8 rssi_map = 0;
5306 	u8 i = 0;
5307 	bool is_sta_change = false, is_traffic_change = false;
5308 
5309 	rssi = ewma_rssi_read(&rtwsta->avg_rssi) >> RSSI_FACTOR;
5310 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], rssi=%d\n", rssi);
5311 
5312 	link_info = &wl->link_info[port];
5313 	link_info->stat.traffic = rtwvif->stats;
5314 	link_info_t = &link_info->stat.traffic;
5315 
5316 	if (link_info->connected == MLME_NO_LINK) {
5317 		link_info->rx_rate_drop_cnt = 0;
5318 		return;
5319 	}
5320 
5321 	link_info->stat.rssi = rssi;
5322 	for (i = 0; i < BTC_WL_RSSI_THMAX; i++) {
5323 		link_info->rssi_state[i] =
5324 			_update_rssi_state(rtwdev,
5325 					   link_info->rssi_state[i],
5326 					   link_info->stat.rssi,
5327 					   chip->wl_rssi_thres[i]);
5328 		if (BTC_RSSI_LOW(link_info->rssi_state[i]))
5329 			rssi_map |= BIT(i);
5330 
5331 		if (btc->mdinfo.ant.type == BTC_ANT_DEDICATED &&
5332 		    BTC_RSSI_CHANGE(link_info->rssi_state[i]))
5333 			is_sta_change = true;
5334 	}
5335 	iter_data->rssi_map_all |= rssi_map;
5336 
5337 	last_tx_rate = link_info_t->tx_rate;
5338 	last_rx_rate = link_info_t->rx_rate;
5339 	last_tx_lvl = (u16)link_info_t->tx_tfc_lv;
5340 	last_rx_lvl = (u16)link_info_t->rx_tfc_lv;
5341 
5342 	if (stats->tx_tfc_lv != RTW89_TFC_IDLE ||
5343 	    stats->rx_tfc_lv != RTW89_TFC_IDLE)
5344 		busy = 1;
5345 
5346 	if (stats->tx_tfc_lv > stats->rx_tfc_lv)
5347 		dir = RTW89_TFC_UL;
5348 	else
5349 		dir = RTW89_TFC_DL;
5350 
5351 	link_info = &wl->link_info[port];
5352 	if (link_info->busy != busy || link_info->dir != dir) {
5353 		is_sta_change = true;
5354 		link_info->busy = busy;
5355 		link_info->dir = dir;
5356 	}
5357 
5358 	iter_data->busy_all |= busy;
5359 	iter_data->dir_all |= BIT(dir);
5360 
5361 	if (rtwsta->rx_hw_rate <= RTW89_HW_RATE_CCK2 &&
5362 	    last_rx_rate > RTW89_HW_RATE_CCK2 &&
5363 	    link_info_t->rx_tfc_lv > RTW89_TFC_IDLE)
5364 		link_info->rx_rate_drop_cnt++;
5365 
5366 	if (last_tx_rate != rtwsta->ra_report.hw_rate ||
5367 	    last_rx_rate != rtwsta->rx_hw_rate ||
5368 	    last_tx_lvl != link_info_t->tx_tfc_lv ||
5369 	    last_rx_lvl != link_info_t->rx_tfc_lv)
5370 		is_traffic_change = true;
5371 
5372 	link_info_t->tx_rate = rtwsta->ra_report.hw_rate;
5373 	link_info_t->rx_rate = rtwsta->rx_hw_rate;
5374 
5375 	wl->role_info.active_role[port].tx_lvl = (u16)stats->tx_tfc_lv;
5376 	wl->role_info.active_role[port].rx_lvl = (u16)stats->rx_tfc_lv;
5377 	wl->role_info.active_role[port].tx_rate = rtwsta->ra_report.hw_rate;
5378 	wl->role_info.active_role[port].rx_rate = rtwsta->rx_hw_rate;
5379 
5380 	if (is_sta_change)
5381 		iter_data->is_sta_change = true;
5382 
5383 	if (is_traffic_change)
5384 		iter_data->is_traffic_change = true;
5385 }
5386 
5387 #define BTC_NHM_CHK_INTVL 20
5388 
5389 void rtw89_btc_ntfy_wl_sta(struct rtw89_dev *rtwdev)
5390 {
5391 	struct rtw89_btc *btc = &rtwdev->btc;
5392 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
5393 	struct rtw89_btc_wl_sta_iter_data data = {.rtwdev = rtwdev};
5394 	u8 i;
5395 
5396 	ieee80211_iterate_stations_atomic(rtwdev->hw,
5397 					  rtw89_btc_ntfy_wl_sta_iter,
5398 					  &data);
5399 
5400 	wl->rssi_level = 0;
5401 	btc->dm.cnt_notify[BTC_NCNT_WL_STA]++;
5402 	for (i = BTC_WL_RSSI_THMAX; i > 0; i--) {
5403 		/* set RSSI level 4 ~ 0 if rssi bit map match */
5404 		if (data.rssi_map_all & BIT(i - 1)) {
5405 			wl->rssi_level = i;
5406 			break;
5407 		}
5408 	}
5409 
5410 	rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): busy=%d\n",
5411 		    __func__, !!wl->status.map.busy);
5412 
5413 	_write_scbd(rtwdev, BTC_WSCB_WLBUSY, (!!wl->status.map.busy));
5414 
5415 	if (data.is_traffic_change)
5416 		_fw_set_drv_info(rtwdev, CXDRVINFO_ROLE);
5417 	if (data.is_sta_change) {
5418 		wl->status.map.busy = data.busy_all;
5419 		wl->status.map.traffic_dir = data.dir_all;
5420 		_run_coex(rtwdev, BTC_RSN_NTFY_WL_STA);
5421 	} else if (btc->dm.cnt_notify[BTC_NCNT_WL_STA] >=
5422 		   btc->dm.cnt_dm[BTC_DCNT_WL_STA_LAST] + BTC_NHM_CHK_INTVL) {
5423 		btc->dm.cnt_dm[BTC_DCNT_WL_STA_LAST] =
5424 			btc->dm.cnt_notify[BTC_NCNT_WL_STA];
5425 	} else if (btc->dm.cnt_notify[BTC_NCNT_WL_STA] <
5426 		   btc->dm.cnt_dm[BTC_DCNT_WL_STA_LAST]) {
5427 		btc->dm.cnt_dm[BTC_DCNT_WL_STA_LAST] =
5428 		btc->dm.cnt_notify[BTC_NCNT_WL_STA];
5429 	}
5430 }
5431 
5432 void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
5433 			  u32 len, u8 class, u8 func)
5434 {
5435 	struct rtw89_btc *btc = &rtwdev->btc;
5436 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
5437 	u8 *buf = &skb->data[RTW89_C2H_HEADER_LEN];
5438 
5439 	len -= RTW89_C2H_HEADER_LEN;
5440 
5441 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
5442 		    "[BTC], %s(): C2H BT len:%d class:%d fun:%d\n",
5443 		    __func__, len, class, func);
5444 
5445 	if (class != BTFC_FW_EVENT)
5446 		return;
5447 
5448 	switch (func) {
5449 	case BTF_EVNT_RPT:
5450 	case BTF_EVNT_BUF_OVERFLOW:
5451 		pfwinfo->event[func]++;
5452 		/* Don't need rtw89_leave_ps_mode() */
5453 		btc_fw_event(rtwdev, func, buf, len);
5454 		break;
5455 	case BTF_EVNT_BT_INFO:
5456 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
5457 			    "[BTC], handle C2H BT INFO with data %8ph\n", buf);
5458 		btc->cx.cnt_bt[BTC_BCNT_INFOUPDATE]++;
5459 		_update_bt_info(rtwdev, buf, len);
5460 		break;
5461 	case BTF_EVNT_BT_SCBD:
5462 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
5463 			    "[BTC], handle C2H BT SCBD with data %8ph\n", buf);
5464 		btc->cx.cnt_bt[BTC_BCNT_SCBDUPDATE]++;
5465 		_update_bt_scbd(rtwdev, false);
5466 		break;
5467 	case BTF_EVNT_BT_PSD:
5468 		break;
5469 	case BTF_EVNT_BT_REG:
5470 		btc->dbg.rb_done = true;
5471 		btc->dbg.rb_val = le32_to_cpu(*((__le32 *)buf));
5472 
5473 		break;
5474 	case BTF_EVNT_C2H_LOOPBACK:
5475 		btc->dbg.rb_done = true;
5476 		btc->dbg.rb_val = buf[0];
5477 		break;
5478 	case BTF_EVNT_CX_RUNINFO:
5479 		btc->dm.cnt_dm[BTC_DCNT_CX_RUNINFO]++;
5480 		break;
5481 	}
5482 }
5483 
5484 #define BTC_CX_FW_OFFLOAD 0
5485 
5486 static void _show_cx_info(struct rtw89_dev *rtwdev, struct seq_file *m)
5487 {
5488 	const struct rtw89_chip_info *chip = rtwdev->chip;
5489 	struct rtw89_hal *hal = &rtwdev->hal;
5490 	struct rtw89_btc *btc = &rtwdev->btc;
5491 	struct rtw89_btc_dm *dm = &btc->dm;
5492 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
5493 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
5494 	u32 ver_main = 0, ver_sub = 0, ver_hotfix = 0, id_branch = 0;
5495 
5496 	if (!(dm->coex_info_map & BTC_COEX_INFO_CX))
5497 		return;
5498 
5499 	dm->cnt_notify[BTC_NCNT_SHOW_COEX_INFO]++;
5500 
5501 	seq_printf(m, "========== [BTC COEX INFO (%d)] ==========\n",
5502 		   chip->chip_id);
5503 
5504 	ver_main = FIELD_GET(GENMASK(31, 24), RTW89_COEX_VERSION);
5505 	ver_sub = FIELD_GET(GENMASK(23, 16), RTW89_COEX_VERSION);
5506 	ver_hotfix = FIELD_GET(GENMASK(15, 8), RTW89_COEX_VERSION);
5507 	id_branch = FIELD_GET(GENMASK(7, 0), RTW89_COEX_VERSION);
5508 	seq_printf(m, " %-15s : Coex:%d.%d.%d(branch:%d), ",
5509 		   "[coex_version]", ver_main, ver_sub, ver_hotfix, id_branch);
5510 
5511 	if (dm->wl_fw_cx_offload != BTC_CX_FW_OFFLOAD)
5512 		dm->error.map.offload_mismatch = true;
5513 	else
5514 		dm->error.map.offload_mismatch = false;
5515 
5516 	ver_main = FIELD_GET(GENMASK(31, 24), wl->ver_info.fw_coex);
5517 	ver_sub = FIELD_GET(GENMASK(23, 16), wl->ver_info.fw_coex);
5518 	ver_hotfix = FIELD_GET(GENMASK(15, 8), wl->ver_info.fw_coex);
5519 	id_branch = FIELD_GET(GENMASK(7, 0), wl->ver_info.fw_coex);
5520 	seq_printf(m, "WL_FW_coex:%d.%d.%d(branch:%d)",
5521 		   ver_main, ver_sub, ver_hotfix, id_branch);
5522 
5523 	ver_main = FIELD_GET(GENMASK(31, 24), chip->wlcx_desired);
5524 	ver_sub = FIELD_GET(GENMASK(23, 16), chip->wlcx_desired);
5525 	ver_hotfix = FIELD_GET(GENMASK(15, 8), chip->wlcx_desired);
5526 	seq_printf(m, "(%s, desired:%d.%d.%d), ",
5527 		   (wl->ver_info.fw_coex >= chip->wlcx_desired ?
5528 		   "Match" : "Mismatch"), ver_main, ver_sub, ver_hotfix);
5529 
5530 	seq_printf(m, "BT_FW_coex:%d(%s, desired:%d)\n",
5531 		   bt->ver_info.fw_coex,
5532 		   (bt->ver_info.fw_coex >= chip->btcx_desired ?
5533 		   "Match" : "Mismatch"), chip->btcx_desired);
5534 
5535 	if (bt->enable.now && bt->ver_info.fw == 0)
5536 		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_VER_INFO, true);
5537 	else
5538 		rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_VER_INFO, false);
5539 
5540 	ver_main = FIELD_GET(GENMASK(31, 24), wl->ver_info.fw);
5541 	ver_sub = FIELD_GET(GENMASK(23, 16), wl->ver_info.fw);
5542 	ver_hotfix = FIELD_GET(GENMASK(15, 8), wl->ver_info.fw);
5543 	id_branch = FIELD_GET(GENMASK(7, 0), wl->ver_info.fw);
5544 	seq_printf(m, " %-15s : WL_FW:%d.%d.%d.%d, BT_FW:0x%x(%s)\n",
5545 		   "[sub_module]",
5546 		   ver_main, ver_sub, ver_hotfix, id_branch,
5547 		   bt->ver_info.fw, bt->run_patch_code ? "patch" : "ROM");
5548 
5549 	seq_printf(m, " %-15s : cv:%x, rfe_type:0x%x, ant_iso:%d, ant_pg:%d, %s",
5550 		   "[hw_info]", btc->mdinfo.cv, btc->mdinfo.rfe_type,
5551 		   btc->mdinfo.ant.isolation, btc->mdinfo.ant.num,
5552 		   (btc->mdinfo.ant.num > 1 ? "" : (btc->mdinfo.ant.single_pos ?
5553 		   "1Ant_Pos:S1, " : "1Ant_Pos:S0, ")));
5554 
5555 	seq_printf(m, "3rd_coex:%d, dbcc:%d, tx_num:%d, rx_num:%d\n",
5556 		   btc->cx.other.type, rtwdev->dbcc_en, hal->tx_nss,
5557 		   hal->rx_nss);
5558 }
5559 
5560 static void _show_wl_role_info(struct rtw89_dev *rtwdev, struct seq_file *m)
5561 {
5562 	struct rtw89_btc *btc = &rtwdev->btc;
5563 	struct rtw89_btc_wl_link_info *plink = NULL;
5564 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
5565 	struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
5566 	struct rtw89_traffic_stats *t;
5567 	u8 i;
5568 
5569 	if (rtwdev->dbcc_en) {
5570 		seq_printf(m,
5571 			   " %-15s : PHY0_band(op:%d/scan:%d/real:%d), ",
5572 			   "[dbcc_info]", wl_dinfo->op_band[RTW89_PHY_0],
5573 			   wl_dinfo->scan_band[RTW89_PHY_0],
5574 			   wl_dinfo->real_band[RTW89_PHY_0]);
5575 		seq_printf(m,
5576 			   "PHY1_band(op:%d/scan:%d/real:%d)\n",
5577 			   wl_dinfo->op_band[RTW89_PHY_1],
5578 			   wl_dinfo->scan_band[RTW89_PHY_1],
5579 			   wl_dinfo->real_band[RTW89_PHY_1]);
5580 	}
5581 
5582 	for (i = 0; i < RTW89_PORT_NUM; i++) {
5583 		plink = &btc->cx.wl.link_info[i];
5584 
5585 		if (!plink->active)
5586 			continue;
5587 
5588 		seq_printf(m,
5589 			   " [port_%d]        : role=%d(phy-%d), connect=%d(client_cnt=%d), mode=%d, center_ch=%d, bw=%d",
5590 			   plink->pid, (u32)plink->role, plink->phy,
5591 			   (u32)plink->connected, plink->client_cnt - 1,
5592 			   (u32)plink->mode, plink->ch, (u32)plink->bw);
5593 
5594 		if (plink->connected == MLME_NO_LINK)
5595 			continue;
5596 
5597 		seq_printf(m,
5598 			   ", mac_id=%d, max_tx_time=%dus, max_tx_retry=%d\n",
5599 			   plink->mac_id, plink->tx_time, plink->tx_retry);
5600 
5601 		seq_printf(m,
5602 			   " [port_%d]        : rssi=-%ddBm(%d), busy=%d, dir=%s, ",
5603 			   plink->pid, 110 - plink->stat.rssi,
5604 			   plink->stat.rssi, plink->busy,
5605 			   plink->dir == RTW89_TFC_UL ? "UL" : "DL");
5606 
5607 		t = &plink->stat.traffic;
5608 
5609 		seq_printf(m,
5610 			   "tx[rate:%d/busy_level:%d], ",
5611 			   (u32)t->tx_rate, t->tx_tfc_lv);
5612 
5613 		seq_printf(m, "rx[rate:%d/busy_level:%d/drop:%d]\n",
5614 			   (u32)t->rx_rate,
5615 			   t->rx_tfc_lv, plink->rx_rate_drop_cnt);
5616 	}
5617 }
5618 
5619 static void _show_wl_info(struct rtw89_dev *rtwdev, struct seq_file *m)
5620 {
5621 	const struct rtw89_chip_info *chip = rtwdev->chip;
5622 	struct rtw89_btc *btc = &rtwdev->btc;
5623 	struct rtw89_btc_cx *cx = &btc->cx;
5624 	struct rtw89_btc_wl_info *wl = &cx->wl;
5625 	struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
5626 	struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1;
5627 	u8 mode;
5628 
5629 	if (!(btc->dm.coex_info_map & BTC_COEX_INFO_WL))
5630 		return;
5631 
5632 	seq_puts(m, "========== [WL Status] ==========\n");
5633 
5634 	if (chip->chip_id == RTL8852A)
5635 		mode = wl_rinfo->link_mode;
5636 	else
5637 		mode = wl_rinfo_v1->link_mode;
5638 
5639 	seq_printf(m, " %-15s : link_mode:%d, ", "[status]", mode);
5640 
5641 	seq_printf(m,
5642 		   "rf_off:%d, power_save:%d, scan:%s(band:%d/phy_map:0x%x), ",
5643 		   wl->status.map.rf_off, wl->status.map.lps,
5644 		   wl->status.map.scan ? "Y" : "N",
5645 		   wl->scan_info.band[RTW89_PHY_0], wl->scan_info.phy_map);
5646 
5647 	seq_printf(m,
5648 		   "connecting:%s, roam:%s, 4way:%s, init_ok:%s\n",
5649 		   wl->status.map.connecting ? "Y" : "N",
5650 		   wl->status.map.roaming ?  "Y" : "N",
5651 		   wl->status.map._4way ? "Y" : "N",
5652 		   wl->status.map.init_ok ? "Y" : "N");
5653 
5654 	_show_wl_role_info(rtwdev, m);
5655 }
5656 
5657 enum btc_bt_a2dp_type {
5658 	BTC_A2DP_LEGACY = 0,
5659 	BTC_A2DP_TWS_SNIFF = 1,
5660 	BTC_A2DP_TWS_RELAY = 2,
5661 };
5662 
5663 static void _show_bt_profile_info(struct rtw89_dev *rtwdev, struct seq_file *m)
5664 {
5665 	struct rtw89_btc *btc = &rtwdev->btc;
5666 	struct rtw89_btc_bt_link_info *bt_linfo = &btc->cx.bt.link_info;
5667 	struct rtw89_btc_bt_hfp_desc hfp = bt_linfo->hfp_desc;
5668 	struct rtw89_btc_bt_hid_desc hid = bt_linfo->hid_desc;
5669 	struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc;
5670 	struct rtw89_btc_bt_pan_desc pan = bt_linfo->pan_desc;
5671 
5672 	if (hfp.exist) {
5673 		seq_printf(m, " %-15s : type:%s, sut_pwr:%d, golden-rx:%d",
5674 			   "[HFP]", (hfp.type == 0 ? "SCO" : "eSCO"),
5675 			   bt_linfo->sut_pwr_level[0],
5676 			   bt_linfo->golden_rx_shift[0]);
5677 	}
5678 
5679 	if (hid.exist) {
5680 		seq_printf(m,
5681 			   "\n\r %-15s : type:%s%s%s%s%s pair-cnt:%d, sut_pwr:%d, golden-rx:%d\n",
5682 			   "[HID]",
5683 			   hid.type & BTC_HID_218 ? "2/18," : "",
5684 			   hid.type & BTC_HID_418 ? "4/18," : "",
5685 			   hid.type & BTC_HID_BLE ? "BLE," : "",
5686 			   hid.type & BTC_HID_RCU ? "RCU," : "",
5687 			   hid.type & BTC_HID_RCU_VOICE ? "RCU-Voice," : "",
5688 			   hid.pair_cnt, bt_linfo->sut_pwr_level[1],
5689 			   bt_linfo->golden_rx_shift[1]);
5690 	}
5691 
5692 	if (a2dp.exist) {
5693 		seq_printf(m,
5694 			   " %-15s : type:%s, bit-pool:%d, flush-time:%d, ",
5695 			   "[A2DP]",
5696 			   a2dp.type == BTC_A2DP_LEGACY ? "Legacy" : "TWS",
5697 			    a2dp.bitpool, a2dp.flush_time);
5698 
5699 		seq_printf(m,
5700 			   "vid:0x%x, Dev-name:0x%x, sut_pwr:%d, golden-rx:%d\n",
5701 			   a2dp.vendor_id, a2dp.device_name,
5702 			   bt_linfo->sut_pwr_level[2],
5703 			   bt_linfo->golden_rx_shift[2]);
5704 	}
5705 
5706 	if (pan.exist) {
5707 		seq_printf(m, " %-15s : sut_pwr:%d, golden-rx:%d\n",
5708 			   "[PAN]",
5709 			   bt_linfo->sut_pwr_level[3],
5710 			   bt_linfo->golden_rx_shift[3]);
5711 	}
5712 }
5713 
5714 static void _show_bt_info(struct rtw89_dev *rtwdev, struct seq_file *m)
5715 {
5716 	struct rtw89_btc *btc = &rtwdev->btc;
5717 	struct rtw89_btc_cx *cx = &btc->cx;
5718 	struct rtw89_btc_bt_info *bt = &cx->bt;
5719 	struct rtw89_btc_wl_info *wl = &cx->wl;
5720 	struct rtw89_btc_module *module = &btc->mdinfo;
5721 	struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
5722 	u8 *afh = bt_linfo->afh_map;
5723 
5724 	if (!(btc->dm.coex_info_map & BTC_COEX_INFO_BT))
5725 		return;
5726 
5727 	seq_puts(m, "========== [BT Status] ==========\n");
5728 
5729 	seq_printf(m, " %-15s : enable:%s, btg:%s%s, connect:%s, ",
5730 		   "[status]", bt->enable.now ? "Y" : "N",
5731 		   bt->btg_type ? "Y" : "N",
5732 		   (bt->enable.now && (bt->btg_type != module->bt_pos) ?
5733 		   "(efuse-mismatch!!)" : ""),
5734 		   (bt_linfo->status.map.connect ? "Y" : "N"));
5735 
5736 	seq_printf(m, "igno_wl:%s, mailbox_avl:%s, rfk_state:0x%x\n",
5737 		   bt->igno_wl ? "Y" : "N",
5738 		   bt->mbx_avl ? "Y" : "N", bt->rfk_info.val);
5739 
5740 	seq_printf(m, " %-15s : profile:%s%s%s%s%s ",
5741 		   "[profile]",
5742 		   (bt_linfo->profile_cnt.now == 0) ? "None," : "",
5743 		   bt_linfo->hfp_desc.exist ? "HFP," : "",
5744 		   bt_linfo->hid_desc.exist ? "HID," : "",
5745 		   bt_linfo->a2dp_desc.exist ?
5746 		   (bt_linfo->a2dp_desc.sink ? "A2DP_sink," : "A2DP,") : "",
5747 		   bt_linfo->pan_desc.exist ? "PAN," : "");
5748 
5749 	seq_printf(m,
5750 		   "multi-link:%s, role:%s, ble-connect:%s, CQDDR:%s, A2DP_active:%s, PAN_active:%s\n",
5751 		   bt_linfo->multi_link.now ? "Y" : "N",
5752 		   bt_linfo->slave_role ? "Slave" : "Master",
5753 		   bt_linfo->status.map.ble_connect ? "Y" : "N",
5754 		   bt_linfo->cqddr ? "Y" : "N",
5755 		   bt_linfo->a2dp_desc.active ? "Y" : "N",
5756 		   bt_linfo->pan_desc.active ? "Y" : "N");
5757 
5758 	seq_printf(m,
5759 		   " %-15s : rssi:%ddBm, tx_rate:%dM, %s%s%s",
5760 		   "[link]", bt_linfo->rssi - 100,
5761 		   bt_linfo->tx_3m ? 3 : 2,
5762 		   bt_linfo->status.map.inq_pag ? " inq-page!!" : "",
5763 		   bt_linfo->status.map.acl_busy ? " acl_busy!!" : "",
5764 		   bt_linfo->status.map.mesh_busy ? " mesh_busy!!" : "");
5765 
5766 	seq_printf(m,
5767 		   "%s afh_map[%02x%02x_%02x%02x_%02x%02x_%02x%02x_%02x%02x], ",
5768 		   bt_linfo->relink.now ? " ReLink!!" : "",
5769 		   afh[0], afh[1], afh[2], afh[3], afh[4],
5770 		   afh[5], afh[6], afh[7], afh[8], afh[9]);
5771 
5772 	seq_printf(m, "wl_ch_map[en:%d/ch:%d/bw:%d]\n",
5773 		   wl->afh_info.en, wl->afh_info.ch, wl->afh_info.bw);
5774 
5775 	seq_printf(m,
5776 		   " %-15s : retry:%d, relink:%d, rate_chg:%d, reinit:%d, reenable:%d, ",
5777 		   "[stat_cnt]", cx->cnt_bt[BTC_BCNT_RETRY],
5778 		   cx->cnt_bt[BTC_BCNT_RELINK], cx->cnt_bt[BTC_BCNT_RATECHG],
5779 		   cx->cnt_bt[BTC_BCNT_REINIT], cx->cnt_bt[BTC_BCNT_REENABLE]);
5780 
5781 	seq_printf(m,
5782 		   "role-switch:%d, afh:%d, inq_page:%d(inq:%d/page:%d), igno_wl:%d\n",
5783 		   cx->cnt_bt[BTC_BCNT_ROLESW], cx->cnt_bt[BTC_BCNT_AFH],
5784 		   cx->cnt_bt[BTC_BCNT_INQPAG], cx->cnt_bt[BTC_BCNT_INQ],
5785 		   cx->cnt_bt[BTC_BCNT_PAGE], cx->cnt_bt[BTC_BCNT_IGNOWL]);
5786 
5787 	_show_bt_profile_info(rtwdev, m);
5788 
5789 	seq_printf(m,
5790 		   " %-15s : raw_data[%02x %02x %02x %02x %02x %02x] (type:%s/cnt:%d/same:%d)\n",
5791 		   "[bt_info]", bt->raw_info[2], bt->raw_info[3],
5792 		   bt->raw_info[4], bt->raw_info[5], bt->raw_info[6],
5793 		   bt->raw_info[7],
5794 		   bt->raw_info[0] == BTC_BTINFO_AUTO ? "auto" : "reply",
5795 		   cx->cnt_bt[BTC_BCNT_INFOUPDATE],
5796 		   cx->cnt_bt[BTC_BCNT_INFOSAME]);
5797 
5798 	seq_printf(m,
5799 		   " %-15s : Hi-rx = %d, Hi-tx = %d, Lo-rx = %d, Lo-tx = %d (bt_polut_wl_tx = %d)\n",
5800 		   "[trx_req_cnt]", cx->cnt_bt[BTC_BCNT_HIPRI_RX],
5801 		   cx->cnt_bt[BTC_BCNT_HIPRI_TX], cx->cnt_bt[BTC_BCNT_LOPRI_RX],
5802 		   cx->cnt_bt[BTC_BCNT_LOPRI_TX], cx->cnt_bt[BTC_BCNT_POLUT]);
5803 }
5804 
5805 #define CASE_BTC_RSN_STR(e) case BTC_RSN_ ## e: return #e
5806 #define CASE_BTC_ACT_STR(e) case BTC_ACT_ ## e | BTC_ACT_EXT_BIT: return #e
5807 #define CASE_BTC_POLICY_STR(e) \
5808 	case BTC_CXP_ ## e | BTC_POLICY_EXT_BIT: return #e
5809 #define CASE_BTC_SLOT_STR(e) case CXST_ ## e: return #e
5810 
5811 static const char *steps_to_str(u16 step)
5812 {
5813 	switch (step) {
5814 	CASE_BTC_RSN_STR(NONE);
5815 	CASE_BTC_RSN_STR(NTFY_INIT);
5816 	CASE_BTC_RSN_STR(NTFY_SWBAND);
5817 	CASE_BTC_RSN_STR(NTFY_WL_STA);
5818 	CASE_BTC_RSN_STR(NTFY_RADIO_STATE);
5819 	CASE_BTC_RSN_STR(UPDATE_BT_SCBD);
5820 	CASE_BTC_RSN_STR(NTFY_WL_RFK);
5821 	CASE_BTC_RSN_STR(UPDATE_BT_INFO);
5822 	CASE_BTC_RSN_STR(NTFY_SCAN_START);
5823 	CASE_BTC_RSN_STR(NTFY_SCAN_FINISH);
5824 	CASE_BTC_RSN_STR(NTFY_SPECIFIC_PACKET);
5825 	CASE_BTC_RSN_STR(NTFY_POWEROFF);
5826 	CASE_BTC_RSN_STR(NTFY_ROLE_INFO);
5827 	CASE_BTC_RSN_STR(CMD_SET_COEX);
5828 	CASE_BTC_RSN_STR(ACT1_WORK);
5829 	CASE_BTC_RSN_STR(BT_DEVINFO_WORK);
5830 	CASE_BTC_RSN_STR(RFK_CHK_WORK);
5831 
5832 	CASE_BTC_ACT_STR(NONE);
5833 	CASE_BTC_ACT_STR(WL_ONLY);
5834 	CASE_BTC_ACT_STR(WL_5G);
5835 	CASE_BTC_ACT_STR(WL_OTHER);
5836 	CASE_BTC_ACT_STR(WL_IDLE);
5837 	CASE_BTC_ACT_STR(WL_NC);
5838 	CASE_BTC_ACT_STR(WL_RFK);
5839 	CASE_BTC_ACT_STR(WL_INIT);
5840 	CASE_BTC_ACT_STR(WL_OFF);
5841 	CASE_BTC_ACT_STR(FREERUN);
5842 	CASE_BTC_ACT_STR(BT_WHQL);
5843 	CASE_BTC_ACT_STR(BT_RFK);
5844 	CASE_BTC_ACT_STR(BT_OFF);
5845 	CASE_BTC_ACT_STR(BT_IDLE);
5846 	CASE_BTC_ACT_STR(BT_HFP);
5847 	CASE_BTC_ACT_STR(BT_HID);
5848 	CASE_BTC_ACT_STR(BT_A2DP);
5849 	CASE_BTC_ACT_STR(BT_A2DPSINK);
5850 	CASE_BTC_ACT_STR(BT_PAN);
5851 	CASE_BTC_ACT_STR(BT_A2DP_HID);
5852 	CASE_BTC_ACT_STR(BT_A2DP_PAN);
5853 	CASE_BTC_ACT_STR(BT_PAN_HID);
5854 	CASE_BTC_ACT_STR(BT_A2DP_PAN_HID);
5855 	CASE_BTC_ACT_STR(WL_25G_MCC);
5856 	CASE_BTC_ACT_STR(WL_2G_MCC);
5857 	CASE_BTC_ACT_STR(WL_2G_SCC);
5858 	CASE_BTC_ACT_STR(WL_2G_AP);
5859 	CASE_BTC_ACT_STR(WL_2G_GO);
5860 	CASE_BTC_ACT_STR(WL_2G_GC);
5861 	CASE_BTC_ACT_STR(WL_2G_NAN);
5862 
5863 	CASE_BTC_POLICY_STR(OFF_BT);
5864 	CASE_BTC_POLICY_STR(OFF_WL);
5865 	CASE_BTC_POLICY_STR(OFF_EQ0);
5866 	CASE_BTC_POLICY_STR(OFF_EQ1);
5867 	CASE_BTC_POLICY_STR(OFF_EQ2);
5868 	CASE_BTC_POLICY_STR(OFF_EQ3);
5869 	CASE_BTC_POLICY_STR(OFF_BWB0);
5870 	CASE_BTC_POLICY_STR(OFF_BWB1);
5871 	CASE_BTC_POLICY_STR(OFF_BWB2);
5872 	CASE_BTC_POLICY_STR(OFF_BWB3);
5873 	CASE_BTC_POLICY_STR(OFFB_BWB0);
5874 	CASE_BTC_POLICY_STR(OFFE_DEF);
5875 	CASE_BTC_POLICY_STR(OFFE_DEF2);
5876 	CASE_BTC_POLICY_STR(OFFE_2GBWISOB);
5877 	CASE_BTC_POLICY_STR(OFFE_2GISOB);
5878 	CASE_BTC_POLICY_STR(OFFE_2GBWMIXB);
5879 	CASE_BTC_POLICY_STR(OFFE_WL);
5880 	CASE_BTC_POLICY_STR(OFFE_2GBWMIXB2);
5881 	CASE_BTC_POLICY_STR(FIX_TD3030);
5882 	CASE_BTC_POLICY_STR(FIX_TD5050);
5883 	CASE_BTC_POLICY_STR(FIX_TD2030);
5884 	CASE_BTC_POLICY_STR(FIX_TD4010);
5885 	CASE_BTC_POLICY_STR(FIX_TD7010);
5886 	CASE_BTC_POLICY_STR(FIX_TD2060);
5887 	CASE_BTC_POLICY_STR(FIX_TD3060);
5888 	CASE_BTC_POLICY_STR(FIX_TD2080);
5889 	CASE_BTC_POLICY_STR(FIX_TDW1B1);
5890 	CASE_BTC_POLICY_STR(FIX_TD4020);
5891 	CASE_BTC_POLICY_STR(FIX_TD4010ISO);
5892 	CASE_BTC_POLICY_STR(PFIX_TD3030);
5893 	CASE_BTC_POLICY_STR(PFIX_TD5050);
5894 	CASE_BTC_POLICY_STR(PFIX_TD2030);
5895 	CASE_BTC_POLICY_STR(PFIX_TD2060);
5896 	CASE_BTC_POLICY_STR(PFIX_TD3070);
5897 	CASE_BTC_POLICY_STR(PFIX_TD2080);
5898 	CASE_BTC_POLICY_STR(PFIX_TDW1B1);
5899 	CASE_BTC_POLICY_STR(AUTO_TD50B1);
5900 	CASE_BTC_POLICY_STR(AUTO_TD60B1);
5901 	CASE_BTC_POLICY_STR(AUTO_TD20B1);
5902 	CASE_BTC_POLICY_STR(AUTO_TDW1B1);
5903 	CASE_BTC_POLICY_STR(PAUTO_TD50B1);
5904 	CASE_BTC_POLICY_STR(PAUTO_TD60B1);
5905 	CASE_BTC_POLICY_STR(PAUTO_TD20B1);
5906 	CASE_BTC_POLICY_STR(PAUTO_TDW1B1);
5907 	CASE_BTC_POLICY_STR(AUTO2_TD3050);
5908 	CASE_BTC_POLICY_STR(AUTO2_TD3070);
5909 	CASE_BTC_POLICY_STR(AUTO2_TD5050);
5910 	CASE_BTC_POLICY_STR(AUTO2_TD6060);
5911 	CASE_BTC_POLICY_STR(AUTO2_TD2080);
5912 	CASE_BTC_POLICY_STR(AUTO2_TDW1B4);
5913 	CASE_BTC_POLICY_STR(PAUTO2_TD3050);
5914 	CASE_BTC_POLICY_STR(PAUTO2_TD3070);
5915 	CASE_BTC_POLICY_STR(PAUTO2_TD5050);
5916 	CASE_BTC_POLICY_STR(PAUTO2_TD6060);
5917 	CASE_BTC_POLICY_STR(PAUTO2_TD2080);
5918 	CASE_BTC_POLICY_STR(PAUTO2_TDW1B4);
5919 	default:
5920 		return "unknown step";
5921 	}
5922 }
5923 
5924 static const char *id_to_slot(u32 id)
5925 {
5926 	switch (id) {
5927 	CASE_BTC_SLOT_STR(OFF);
5928 	CASE_BTC_SLOT_STR(B2W);
5929 	CASE_BTC_SLOT_STR(W1);
5930 	CASE_BTC_SLOT_STR(W2);
5931 	CASE_BTC_SLOT_STR(W2B);
5932 	CASE_BTC_SLOT_STR(B1);
5933 	CASE_BTC_SLOT_STR(B2);
5934 	CASE_BTC_SLOT_STR(B3);
5935 	CASE_BTC_SLOT_STR(B4);
5936 	CASE_BTC_SLOT_STR(LK);
5937 	CASE_BTC_SLOT_STR(BLK);
5938 	CASE_BTC_SLOT_STR(E2G);
5939 	CASE_BTC_SLOT_STR(E5G);
5940 	CASE_BTC_SLOT_STR(EBT);
5941 	CASE_BTC_SLOT_STR(ENULL);
5942 	CASE_BTC_SLOT_STR(WLK);
5943 	CASE_BTC_SLOT_STR(W1FDD);
5944 	CASE_BTC_SLOT_STR(B1FDD);
5945 	default:
5946 		return "unknown";
5947 	}
5948 }
5949 
5950 static
5951 void seq_print_segment(struct seq_file *m, const char *prefix, u16 *data,
5952 		       u8 len, u8 seg_len, u8 start_idx, u8 ring_len)
5953 {
5954 	u8 i;
5955 	u8 cur_index;
5956 
5957 	for (i = 0; i < len ; i++) {
5958 		if ((i % seg_len) == 0)
5959 			seq_printf(m, " %-15s : ", prefix);
5960 		cur_index = (start_idx + i) % ring_len;
5961 		if (i % 3 == 0)
5962 			seq_printf(m, "-> %-20s",
5963 				   steps_to_str(*(data + cur_index)));
5964 		else if (i % 3 == 1)
5965 			seq_printf(m, "-> %-15s",
5966 				   steps_to_str(*(data + cur_index)));
5967 		else
5968 			seq_printf(m, "-> %-13s",
5969 				   steps_to_str(*(data + cur_index)));
5970 		if (i == (len - 1) || (i % seg_len) == (seg_len - 1))
5971 			seq_puts(m, "\n");
5972 	}
5973 }
5974 
5975 static void _show_dm_step(struct rtw89_dev *rtwdev, struct seq_file *m)
5976 {
5977 	struct rtw89_btc *btc = &rtwdev->btc;
5978 	struct rtw89_btc_dm *dm = &btc->dm;
5979 	u8 start_idx;
5980 	u8 len;
5981 
5982 	len = dm->dm_step.step_ov ? RTW89_BTC_DM_MAXSTEP : dm->dm_step.step_pos;
5983 	start_idx = dm->dm_step.step_ov ? dm->dm_step.step_pos : 0;
5984 
5985 	seq_print_segment(m, "[dm_steps]", dm->dm_step.step, len, 6, start_idx,
5986 			  ARRAY_SIZE(dm->dm_step.step));
5987 }
5988 
5989 static void _show_dm_info(struct rtw89_dev *rtwdev, struct seq_file *m)
5990 {
5991 	struct rtw89_btc *btc = &rtwdev->btc;
5992 	struct rtw89_btc_module *module = &btc->mdinfo;
5993 	struct rtw89_btc_dm *dm = &btc->dm;
5994 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
5995 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
5996 
5997 	if (!(dm->coex_info_map & BTC_COEX_INFO_DM))
5998 		return;
5999 
6000 	seq_printf(m, "========== [Mechanism Status %s] ==========\n",
6001 		   (btc->ctrl.manual ? "(Manual)" : "(Auto)"));
6002 
6003 	seq_printf(m,
6004 		   " %-15s : type:%s, reason:%s(), action:%s(), ant_path:%ld, run_cnt:%d\n",
6005 		   "[status]",
6006 		   module->ant.type == BTC_ANT_SHARED ? "shared" : "dedicated",
6007 		   steps_to_str(dm->run_reason),
6008 		   steps_to_str(dm->run_action | BTC_ACT_EXT_BIT),
6009 		   FIELD_GET(GENMASK(7, 0), dm->set_ant_path),
6010 		   dm->cnt_dm[BTC_DCNT_RUN]);
6011 
6012 	_show_dm_step(rtwdev, m);
6013 
6014 	seq_printf(m, " %-15s : wl_only:%d, bt_only:%d, igno_bt:%d, free_run:%d, wl_ps_ctrl:%d, wl_mimo_ps:%d, ",
6015 		   "[dm_flag]", dm->wl_only, dm->bt_only, btc->ctrl.igno_bt,
6016 		   dm->freerun, btc->lps, dm->wl_mimo_ps);
6017 
6018 	seq_printf(m, "leak_ap:%d, fw_offload:%s%s\n", dm->leak_ap,
6019 		   (BTC_CX_FW_OFFLOAD ? "Y" : "N"),
6020 		   (dm->wl_fw_cx_offload == BTC_CX_FW_OFFLOAD ?
6021 		    "" : "(Mismatch!!)"));
6022 
6023 	if (dm->rf_trx_para.wl_tx_power == 0xff)
6024 		seq_printf(m,
6025 			   " %-15s : wl_rssi_lvl:%d, para_lvl:%d, wl_tx_pwr:orig, ",
6026 			   "[trx_ctrl]", wl->rssi_level, dm->trx_para_level);
6027 
6028 	else
6029 		seq_printf(m,
6030 			   " %-15s : wl_rssi_lvl:%d, para_lvl:%d, wl_tx_pwr:%d, ",
6031 			   "[trx_ctrl]", wl->rssi_level, dm->trx_para_level,
6032 			   dm->rf_trx_para.wl_tx_power);
6033 
6034 	seq_printf(m,
6035 		   "wl_rx_lvl:%d, bt_tx_pwr_dec:%d, bt_rx_lna:%d(%s-tbl), wl_btg_rx:%d\n",
6036 		   dm->rf_trx_para.wl_rx_gain, dm->rf_trx_para.bt_tx_power,
6037 		   dm->rf_trx_para.bt_rx_gain,
6038 		   (bt->hi_lna_rx ? "Hi" : "Ori"), dm->wl_btg_rx);
6039 
6040 	seq_printf(m,
6041 		   " %-15s : wl_tx_limit[en:%d/max_t:%dus/max_retry:%d], bt_slot_reg:%d-TU, bt_scan_rx_low_pri:%d\n",
6042 		   "[dm_ctrl]", dm->wl_tx_limit.enable, dm->wl_tx_limit.tx_time,
6043 		   dm->wl_tx_limit.tx_retry, btc->bt_req_len, bt->scan_rx_low_pri);
6044 }
6045 
6046 static void _show_error(struct rtw89_dev *rtwdev, struct seq_file *m)
6047 {
6048 	const struct rtw89_chip_info *chip = rtwdev->chip;
6049 	struct rtw89_btc *btc = &rtwdev->btc;
6050 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
6051 	struct rtw89_btc_fbtc_cysta *pcysta;
6052 	struct rtw89_btc_fbtc_cysta_v1 *pcysta_v1;
6053 	u32 except_cnt, exception_map;
6054 
6055 	if (chip->chip_id == RTL8852A) {
6056 		pcysta = &pfwinfo->rpt_fbtc_cysta.finfo;
6057 		except_cnt = le32_to_cpu(pcysta->except_cnt);
6058 		exception_map = le32_to_cpu(pcysta->exception);
6059 	} else {
6060 		pcysta_v1 = &pfwinfo->rpt_fbtc_cysta.finfo_v1;
6061 		except_cnt = le32_to_cpu(pcysta_v1->except_cnt);
6062 		exception_map = le32_to_cpu(pcysta_v1->except_map);
6063 	}
6064 
6065 	if (pfwinfo->event[BTF_EVNT_BUF_OVERFLOW] == 0 && except_cnt == 0 &&
6066 	    !pfwinfo->len_mismch && !pfwinfo->fver_mismch)
6067 		return;
6068 
6069 	seq_printf(m, " %-15s : ", "[error]");
6070 
6071 	if (pfwinfo->event[BTF_EVNT_BUF_OVERFLOW]) {
6072 		seq_printf(m,
6073 			   "overflow-cnt: %d, ",
6074 			   pfwinfo->event[BTF_EVNT_BUF_OVERFLOW]);
6075 	}
6076 
6077 	if (pfwinfo->len_mismch) {
6078 		seq_printf(m,
6079 			   "len-mismatch: 0x%x, ",
6080 			   pfwinfo->len_mismch);
6081 	}
6082 
6083 	if (pfwinfo->fver_mismch) {
6084 		seq_printf(m,
6085 			   "fver-mismatch: 0x%x, ",
6086 			   pfwinfo->fver_mismch);
6087 	}
6088 
6089 	/* cycle statistics exceptions */
6090 	if (exception_map || except_cnt) {
6091 		seq_printf(m,
6092 			   "exception-type: 0x%x, exception-cnt = %d",
6093 			   exception_map, except_cnt);
6094 	}
6095 	seq_puts(m, "\n");
6096 }
6097 
6098 static void _show_fbtc_tdma(struct rtw89_dev *rtwdev, struct seq_file *m)
6099 {
6100 	const struct rtw89_chip_info *chip = rtwdev->chip;
6101 	struct rtw89_btc *btc = &rtwdev->btc;
6102 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
6103 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
6104 	struct rtw89_btc_fbtc_tdma *t = NULL;
6105 	struct rtw89_btc_fbtc_slot *s = NULL;
6106 	struct rtw89_btc_dm *dm = &btc->dm;
6107 	u8 i, cnt = 0;
6108 
6109 	pcinfo = &pfwinfo->rpt_fbtc_tdma.cinfo;
6110 	if (!pcinfo->valid)
6111 		return;
6112 
6113 	if (chip->chip_id == RTL8852A)
6114 		t = &pfwinfo->rpt_fbtc_tdma.finfo;
6115 	else
6116 		t = &pfwinfo->rpt_fbtc_tdma.finfo_v1.tdma;
6117 
6118 	seq_printf(m,
6119 		   " %-15s : ", "[tdma_policy]");
6120 	seq_printf(m,
6121 		   "type:%d, rx_flow_ctrl:%d, tx_pause:%d, ",
6122 		   (u32)t->type,
6123 		   t->rxflctrl, t->txpause);
6124 
6125 	seq_printf(m,
6126 		   "wl_toggle_n:%d, leak_n:%d, ext_ctrl:%d, ",
6127 		   t->wtgle_n, t->leak_n, t->ext_ctrl);
6128 
6129 	seq_printf(m,
6130 		   "policy_type:%d",
6131 		   (u32)btc->policy_type);
6132 
6133 	s = pfwinfo->rpt_fbtc_slots.finfo.slot;
6134 
6135 	for (i = 0; i < CXST_MAX; i++) {
6136 		if (dm->update_slot_map == BIT(CXST_MAX) - 1)
6137 			break;
6138 
6139 		if (!(dm->update_slot_map & BIT(i)))
6140 			continue;
6141 
6142 		if (cnt % 6 == 0)
6143 			seq_printf(m,
6144 				   " %-15s : %d[%d/0x%x/%d]",
6145 				   "[slot_policy]",
6146 				   (u32)i,
6147 				   s[i].dur, s[i].cxtbl, s[i].cxtype);
6148 		else
6149 			seq_printf(m,
6150 				   ", %d[%d/0x%x/%d]",
6151 				   (u32)i,
6152 				   s[i].dur, s[i].cxtbl, s[i].cxtype);
6153 		if (cnt % 6 == 5)
6154 			seq_puts(m, "\n");
6155 		cnt++;
6156 	}
6157 	seq_puts(m, "\n");
6158 }
6159 
6160 static void _show_fbtc_slots(struct rtw89_dev *rtwdev, struct seq_file *m)
6161 {
6162 	struct rtw89_btc *btc = &rtwdev->btc;
6163 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
6164 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
6165 	struct rtw89_btc_fbtc_slots *pslots = NULL;
6166 	struct rtw89_btc_fbtc_slot s;
6167 	u8 i = 0;
6168 
6169 	pcinfo = &pfwinfo->rpt_fbtc_slots.cinfo;
6170 	if (!pcinfo->valid)
6171 		return;
6172 
6173 	pslots = &pfwinfo->rpt_fbtc_slots.finfo;
6174 
6175 	for (i = 0; i < CXST_MAX; i++) {
6176 		s = pslots->slot[i];
6177 		if (i % 6 == 0)
6178 			seq_printf(m,
6179 				   " %-15s : %02d[%03d/0x%x/%d]",
6180 				   "[slot_list]",
6181 				   (u32)i,
6182 				   s.dur, s.cxtbl, s.cxtype);
6183 		else
6184 			seq_printf(m,
6185 				   ", %02d[%03d/0x%x/%d]",
6186 				   (u32)i,
6187 				   s.dur, s.cxtbl, s.cxtype);
6188 		if (i % 6 == 5)
6189 			seq_puts(m, "\n");
6190 	}
6191 }
6192 
6193 static void _show_fbtc_cysta(struct rtw89_dev *rtwdev, struct seq_file *m)
6194 {
6195 	struct rtw89_btc *btc = &rtwdev->btc;
6196 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
6197 	struct rtw89_btc_dm *dm = &btc->dm;
6198 	struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc;
6199 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
6200 	struct rtw89_btc_fbtc_cysta *pcysta_le32 = NULL;
6201 	struct rtw89_btc_fbtc_cysta_cpu pcysta[1];
6202 	union rtw89_btc_fbtc_rxflct r;
6203 	u8 i, cnt = 0, slot_pair;
6204 	u16 cycle, c_begin, c_end, store_index;
6205 
6206 	pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
6207 	if (!pcinfo->valid)
6208 		return;
6209 
6210 	pcysta_le32 = &pfwinfo->rpt_fbtc_cysta.finfo;
6211 	rtw89_btc_fbtc_cysta_to_cpu(pcysta_le32, pcysta);
6212 	seq_printf(m,
6213 		   " %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]",
6214 		   "[cycle_cnt]", pcysta->cycles, pcysta->bcn_cnt[CXBCN_ALL],
6215 		   pcysta->bcn_cnt[CXBCN_ALL_OK],
6216 		   pcysta->bcn_cnt[CXBCN_BT_SLOT],
6217 		   pcysta->bcn_cnt[CXBCN_BT_OK]);
6218 
6219 	for (i = 0; i < CXST_MAX; i++) {
6220 		if (!pcysta->slot_cnt[i])
6221 			continue;
6222 		seq_printf(m,
6223 			   ", %d:%d", (u32)i, pcysta->slot_cnt[i]);
6224 	}
6225 
6226 	if (dm->tdma_now.rxflctrl) {
6227 		seq_printf(m,
6228 			   ", leak_rx:%d", pcysta->leakrx_cnt);
6229 	}
6230 
6231 	if (pcysta->collision_cnt) {
6232 		seq_printf(m,
6233 			   ", collision:%d", pcysta->collision_cnt);
6234 	}
6235 
6236 	if (pcysta->skip_cnt) {
6237 		seq_printf(m,
6238 			   ", skip:%d", pcysta->skip_cnt);
6239 	}
6240 	seq_puts(m, "\n");
6241 
6242 	seq_printf(m, " %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]",
6243 		   "[cycle_time]",
6244 		   pcysta->tavg_cycle[CXT_WL],
6245 		   pcysta->tavg_cycle[CXT_BT],
6246 		   pcysta->tavg_lk / 1000, pcysta->tavg_lk % 1000);
6247 	seq_printf(m,
6248 		   ", max_t[wl:%d/bt:%d/lk:%d.%03d]",
6249 		   pcysta->tmax_cycle[CXT_WL],
6250 		   pcysta->tmax_cycle[CXT_BT],
6251 		   pcysta->tmax_lk / 1000, pcysta->tmax_lk % 1000);
6252 	seq_printf(m,
6253 		   ", maxdiff_t[wl:%d/bt:%d]\n",
6254 		   pcysta->tmaxdiff_cycle[CXT_WL],
6255 		   pcysta->tmaxdiff_cycle[CXT_BT]);
6256 
6257 	if (pcysta->cycles == 0)
6258 		return;
6259 
6260 	/* 1 cycle record 1 wl-slot and 1 bt-slot */
6261 	slot_pair = BTC_CYCLE_SLOT_MAX / 2;
6262 
6263 	if (pcysta->cycles <= slot_pair)
6264 		c_begin = 1;
6265 	else
6266 		c_begin = pcysta->cycles - slot_pair + 1;
6267 
6268 	c_end = pcysta->cycles;
6269 
6270 	for (cycle = c_begin; cycle <= c_end; cycle++) {
6271 		cnt++;
6272 		store_index = ((cycle - 1) % slot_pair) * 2;
6273 
6274 		if (cnt % (BTC_CYCLE_SLOT_MAX / 4) == 1)
6275 			seq_printf(m,
6276 				   " %-15s : ->b%02d->w%02d", "[cycle_step]",
6277 				   pcysta->tslot_cycle[store_index],
6278 				   pcysta->tslot_cycle[store_index + 1]);
6279 		else
6280 			seq_printf(m,
6281 				   "->b%02d->w%02d",
6282 				   pcysta->tslot_cycle[store_index],
6283 				   pcysta->tslot_cycle[store_index + 1]);
6284 		if (cnt % (BTC_CYCLE_SLOT_MAX / 4) == 0 || cnt == c_end)
6285 			seq_puts(m, "\n");
6286 	}
6287 
6288 	if (a2dp->exist) {
6289 		seq_printf(m,
6290 			   " %-15s : a2dp_ept:%d, a2dp_late:%d",
6291 			   "[a2dp_t_sta]",
6292 			   pcysta->a2dpept, pcysta->a2dpeptto);
6293 
6294 		seq_printf(m,
6295 			   ", avg_t:%d, max_t:%d",
6296 			   pcysta->tavg_a2dpept, pcysta->tmax_a2dpept);
6297 		r.val = dm->tdma_now.rxflctrl;
6298 
6299 		if (r.type && r.tgln_n) {
6300 			seq_printf(m,
6301 				   ", cycle[PSTDMA:%d/TDMA:%d], ",
6302 				   pcysta->cycles_a2dp[CXT_FLCTRL_ON],
6303 				   pcysta->cycles_a2dp[CXT_FLCTRL_OFF]);
6304 
6305 			seq_printf(m,
6306 				   "avg_t[PSTDMA:%d/TDMA:%d], ",
6307 				   pcysta->tavg_a2dp[CXT_FLCTRL_ON],
6308 				   pcysta->tavg_a2dp[CXT_FLCTRL_OFF]);
6309 
6310 			seq_printf(m,
6311 				   "max_t[PSTDMA:%d/TDMA:%d]",
6312 				   pcysta->tmax_a2dp[CXT_FLCTRL_ON],
6313 				   pcysta->tmax_a2dp[CXT_FLCTRL_OFF]);
6314 		}
6315 		seq_puts(m, "\n");
6316 	}
6317 }
6318 
6319 static void _show_fbtc_cysta_v1(struct rtw89_dev *rtwdev, struct seq_file *m)
6320 {
6321 	struct rtw89_btc *btc = &rtwdev->btc;
6322 	struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc;
6323 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
6324 	struct rtw89_btc_dm *dm = &btc->dm;
6325 	struct rtw89_btc_fbtc_a2dp_trx_stat *a2dp_trx;
6326 	struct rtw89_btc_fbtc_cysta_v1 *pcysta;
6327 	struct rtw89_btc_rpt_cmn_info *pcinfo;
6328 	u8 i, cnt = 0, slot_pair, divide_cnt;
6329 	u16 cycle, c_begin, c_end, store_index;
6330 
6331 	pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
6332 	if (!pcinfo->valid)
6333 		return;
6334 
6335 	pcysta = &pfwinfo->rpt_fbtc_cysta.finfo_v1;
6336 	seq_printf(m,
6337 		   " %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]",
6338 		   "[cycle_cnt]",
6339 		   le16_to_cpu(pcysta->cycles),
6340 		   le32_to_cpu(pcysta->bcn_cnt[CXBCN_ALL]),
6341 		   le32_to_cpu(pcysta->bcn_cnt[CXBCN_ALL_OK]),
6342 		   le32_to_cpu(pcysta->bcn_cnt[CXBCN_BT_SLOT]),
6343 		   le32_to_cpu(pcysta->bcn_cnt[CXBCN_BT_OK]));
6344 
6345 	for (i = 0; i < CXST_MAX; i++) {
6346 		if (!le32_to_cpu(pcysta->slot_cnt[i]))
6347 			continue;
6348 
6349 		seq_printf(m, ", %s:%d", id_to_slot(i),
6350 			   le32_to_cpu(pcysta->slot_cnt[i]));
6351 	}
6352 
6353 	if (dm->tdma_now.rxflctrl)
6354 		seq_printf(m, ", leak_rx:%d", le32_to_cpu(pcysta->leak_slot.cnt_rximr));
6355 
6356 	if (le32_to_cpu(pcysta->collision_cnt))
6357 		seq_printf(m, ", collision:%d", le32_to_cpu(pcysta->collision_cnt));
6358 
6359 	if (le32_to_cpu(pcysta->skip_cnt))
6360 		seq_printf(m, ", skip:%d", le32_to_cpu(pcysta->skip_cnt));
6361 
6362 	seq_puts(m, "\n");
6363 
6364 	seq_printf(m, " %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]",
6365 		   "[cycle_time]",
6366 		   le16_to_cpu(pcysta->cycle_time.tavg[CXT_WL]),
6367 		   le16_to_cpu(pcysta->cycle_time.tavg[CXT_BT]),
6368 		   le16_to_cpu(pcysta->leak_slot.tavg) / 1000,
6369 		   le16_to_cpu(pcysta->leak_slot.tavg) % 1000);
6370 	seq_printf(m,
6371 		   ", max_t[wl:%d/bt:%d/lk:%d.%03d]",
6372 		   le16_to_cpu(pcysta->cycle_time.tmax[CXT_WL]),
6373 		   le16_to_cpu(pcysta->cycle_time.tmax[CXT_BT]),
6374 		   le16_to_cpu(pcysta->leak_slot.tmax) / 1000,
6375 		   le16_to_cpu(pcysta->leak_slot.tmax) % 1000);
6376 	seq_printf(m,
6377 		   ", maxdiff_t[wl:%d/bt:%d]\n",
6378 		   le16_to_cpu(pcysta->cycle_time.tmaxdiff[CXT_WL]),
6379 		   le16_to_cpu(pcysta->cycle_time.tmaxdiff[CXT_BT]));
6380 
6381 	cycle = le16_to_cpu(pcysta->cycles);
6382 	if (cycle == 0)
6383 		return;
6384 
6385 	/* 1 cycle record 1 wl-slot and 1 bt-slot */
6386 	slot_pair = BTC_CYCLE_SLOT_MAX / 2;
6387 
6388 	if (cycle <= slot_pair)
6389 		c_begin = 1;
6390 	else
6391 		c_begin = cycle - slot_pair + 1;
6392 
6393 	c_end = cycle;
6394 
6395 	if (a2dp->exist)
6396 		divide_cnt = 3;
6397 	else
6398 		divide_cnt = BTC_CYCLE_SLOT_MAX / 4;
6399 
6400 	for (cycle = c_begin; cycle <= c_end; cycle++) {
6401 		cnt++;
6402 		store_index = ((cycle - 1) % slot_pair) * 2;
6403 
6404 		if (cnt % divide_cnt == 1) {
6405 			seq_printf(m, "\n\r %-15s : ", "[cycle_step]");
6406 		} else {
6407 			seq_printf(m, "->b%02d",
6408 				   le16_to_cpu(pcysta->slot_step_time[store_index]));
6409 			if (a2dp->exist) {
6410 				a2dp_trx = &pcysta->a2dp_trx[store_index];
6411 				seq_printf(m, "(%d/%d/%dM/%d/%d/%d)",
6412 					   a2dp_trx->empty_cnt,
6413 					   a2dp_trx->retry_cnt,
6414 					   a2dp_trx->tx_rate ? 3 : 2,
6415 					   a2dp_trx->tx_cnt,
6416 					   a2dp_trx->ack_cnt,
6417 					   a2dp_trx->nack_cnt);
6418 			}
6419 			seq_printf(m, "->w%02d",
6420 				   le16_to_cpu(pcysta->slot_step_time[store_index + 1]));
6421 			if (a2dp->exist) {
6422 				a2dp_trx = &pcysta->a2dp_trx[store_index + 1];
6423 				seq_printf(m, "(%d/%d/%dM/%d/%d/%d)",
6424 					   a2dp_trx->empty_cnt,
6425 					   a2dp_trx->retry_cnt,
6426 					   a2dp_trx->tx_rate ? 3 : 2,
6427 					   a2dp_trx->tx_cnt,
6428 					   a2dp_trx->ack_cnt,
6429 					   a2dp_trx->nack_cnt);
6430 			}
6431 		}
6432 		if (cnt % (BTC_CYCLE_SLOT_MAX / 4) == 0 || cnt == c_end)
6433 			seq_puts(m, "\n");
6434 	}
6435 
6436 	if (a2dp->exist) {
6437 		seq_printf(m, "%-15s : a2dp_ept:%d, a2dp_late:%d",
6438 			   "[a2dp_t_sta]",
6439 			   le16_to_cpu(pcysta->a2dp_ept.cnt),
6440 			   le16_to_cpu(pcysta->a2dp_ept.cnt_timeout));
6441 
6442 		seq_printf(m, ", avg_t:%d, max_t:%d",
6443 			   le16_to_cpu(pcysta->a2dp_ept.tavg),
6444 			   le16_to_cpu(pcysta->a2dp_ept.tmax));
6445 
6446 		seq_puts(m, "\n");
6447 	}
6448 }
6449 
6450 static void _show_fbtc_nullsta(struct rtw89_dev *rtwdev, struct seq_file *m)
6451 {
6452 	const struct rtw89_chip_info *chip = rtwdev->chip;
6453 	struct rtw89_btc *btc = &rtwdev->btc;
6454 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
6455 	struct rtw89_btc_rpt_cmn_info *pcinfo;
6456 	struct rtw89_btc_fbtc_cynullsta *ns;
6457 	struct rtw89_btc_fbtc_cynullsta_v1 *ns_v1;
6458 	u8 i = 0;
6459 
6460 	if (!btc->dm.tdma_now.rxflctrl)
6461 		return;
6462 
6463 	pcinfo = &pfwinfo->rpt_fbtc_nullsta.cinfo;
6464 	if (!pcinfo->valid)
6465 		return;
6466 
6467 	if (chip->chip_id == RTL8852A) {
6468 		ns = &pfwinfo->rpt_fbtc_nullsta.finfo;
6469 
6470 		seq_printf(m, " %-15s : ", "[null_sta]");
6471 
6472 		for (i = 0; i < 2; i++) {
6473 			if (i != 0)
6474 				seq_printf(m, ", null-%d", i);
6475 			else
6476 				seq_printf(m, "null-%d", i);
6477 			seq_printf(m, "[ok:%d/",
6478 				   le32_to_cpu(ns->result[i][1]));
6479 			seq_printf(m, "fail:%d/",
6480 				   le32_to_cpu(ns->result[i][0]));
6481 			seq_printf(m, "on_time:%d/",
6482 				   le32_to_cpu(ns->result[i][2]));
6483 			seq_printf(m, "retry:%d/",
6484 				   le32_to_cpu(ns->result[i][3]));
6485 			seq_printf(m, "avg_t:%d.%03d/",
6486 				   le32_to_cpu(ns->avg_t[i]) / 1000,
6487 				   le32_to_cpu(ns->avg_t[i]) % 1000);
6488 			seq_printf(m, "max_t:%d.%03d]",
6489 				   le32_to_cpu(ns->max_t[i]) / 1000,
6490 				   le32_to_cpu(ns->max_t[i]) % 1000);
6491 		}
6492 	} else {
6493 		ns_v1 = &pfwinfo->rpt_fbtc_nullsta.finfo_v1;
6494 
6495 		seq_printf(m, " %-15s : ", "[null_sta]");
6496 
6497 		for (i = 0; i < 2; i++) {
6498 			if (i != 0)
6499 				seq_printf(m, ", null-%d", i);
6500 			else
6501 				seq_printf(m, "null-%d", i);
6502 			seq_printf(m, "[Tx:%d/",
6503 				   le32_to_cpu(ns_v1->result[i][4]));
6504 			seq_printf(m, "[ok:%d/",
6505 				   le32_to_cpu(ns_v1->result[i][1]));
6506 			seq_printf(m, "fail:%d/",
6507 				   le32_to_cpu(ns_v1->result[i][0]));
6508 			seq_printf(m, "on_time:%d/",
6509 				   le32_to_cpu(ns_v1->result[i][2]));
6510 			seq_printf(m, "retry:%d/",
6511 				   le32_to_cpu(ns_v1->result[i][3]));
6512 			seq_printf(m, "avg_t:%d.%03d/",
6513 				   le32_to_cpu(ns_v1->avg_t[i]) / 1000,
6514 				   le32_to_cpu(ns_v1->avg_t[i]) % 1000);
6515 			seq_printf(m, "max_t:%d.%03d]",
6516 				   le32_to_cpu(ns_v1->max_t[i]) / 1000,
6517 				   le32_to_cpu(ns_v1->max_t[i]) % 1000);
6518 		}
6519 	}
6520 	seq_puts(m, "\n");
6521 }
6522 
6523 static void _show_fbtc_step(struct rtw89_dev *rtwdev, struct seq_file *m)
6524 {
6525 	struct rtw89_btc *btc = &rtwdev->btc;
6526 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
6527 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
6528 	struct rtw89_btc_fbtc_steps *pstep = NULL;
6529 	u8 type, val, cnt = 0, state = 0;
6530 	bool outloop = false;
6531 	u16 i, diff_t, n_start = 0, n_stop = 0;
6532 	u16 pos_old, pos_new;
6533 
6534 	pcinfo = &pfwinfo->rpt_fbtc_step.cinfo;
6535 	if (!pcinfo->valid)
6536 		return;
6537 
6538 	pstep = &pfwinfo->rpt_fbtc_step.finfo;
6539 	pos_old = le16_to_cpu(pstep->pos_old);
6540 	pos_new = le16_to_cpu(pstep->pos_new);
6541 
6542 	if (pcinfo->req_fver != pstep->fver)
6543 		return;
6544 
6545 	/* store step info by using ring instead of FIFO*/
6546 	do {
6547 		switch (state) {
6548 		case 0:
6549 			n_start = pos_old;
6550 			if (pos_new >=  pos_old)
6551 				n_stop = pos_new;
6552 			else
6553 				n_stop = btc->ctrl.trace_step - 1;
6554 
6555 			state = 1;
6556 			break;
6557 		case 1:
6558 			for (i = n_start; i <= n_stop; i++) {
6559 				type = pstep->step[i].type;
6560 				val = pstep->step[i].val;
6561 				diff_t = le16_to_cpu(pstep->step[i].difft);
6562 
6563 				if (type == CXSTEP_NONE || type >= CXSTEP_MAX)
6564 					continue;
6565 
6566 				if (cnt % 10 == 0)
6567 					seq_printf(m, " %-15s : ", "[steps]");
6568 
6569 				seq_printf(m, "-> %s(%02d)(%02d)",
6570 					   (type == CXSTEP_SLOT ? "SLT" :
6571 					    "EVT"), (u32)val, diff_t);
6572 				if (cnt % 10 == 9)
6573 					seq_puts(m, "\n");
6574 				cnt++;
6575 			}
6576 
6577 			state = 2;
6578 			break;
6579 		case 2:
6580 			if (pos_new <  pos_old && n_start != 0) {
6581 				n_start = 0;
6582 				n_stop = pos_new;
6583 				state = 1;
6584 			} else {
6585 				outloop = true;
6586 			}
6587 			break;
6588 		}
6589 	} while (!outloop);
6590 }
6591 
6592 static void _show_fw_dm_msg(struct rtw89_dev *rtwdev, struct seq_file *m)
6593 {
6594 	const struct rtw89_chip_info *chip = rtwdev->chip;
6595 	struct rtw89_btc *btc = &rtwdev->btc;
6596 
6597 	if (!(btc->dm.coex_info_map & BTC_COEX_INFO_DM))
6598 		return;
6599 
6600 	_show_error(rtwdev, m);
6601 	_show_fbtc_tdma(rtwdev, m);
6602 	_show_fbtc_slots(rtwdev, m);
6603 
6604 	if (chip->chip_id == RTL8852A)
6605 		_show_fbtc_cysta(rtwdev, m);
6606 	else
6607 		_show_fbtc_cysta_v1(rtwdev, m);
6608 
6609 	_show_fbtc_nullsta(rtwdev, m);
6610 	_show_fbtc_step(rtwdev, m);
6611 }
6612 
6613 static void _get_gnt(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_coex_gnt *gnt_cfg)
6614 {
6615 	const struct rtw89_chip_info *chip = rtwdev->chip;
6616 	struct rtw89_mac_ax_gnt *gnt;
6617 	u32 val, status;
6618 
6619 	if (chip->chip_id == RTL8852A || chip->chip_id == RTL8852B) {
6620 		rtw89_mac_read_lte(rtwdev, R_AX_LTE_SW_CFG_1, &val);
6621 		rtw89_mac_read_lte(rtwdev, R_AX_GNT_VAL, &status);
6622 
6623 		gnt = &gnt_cfg->band[0];
6624 		gnt->gnt_bt_sw_en = !!(val & B_AX_GNT_BT_RFC_S0_SW_CTRL);
6625 		gnt->gnt_bt = !!(status & B_AX_GNT_BT_RFC_S0_STA);
6626 		gnt->gnt_wl_sw_en = !!(val & B_AX_GNT_WL_RFC_S0_SW_CTRL);
6627 		gnt->gnt_wl = !!(status & B_AX_GNT_WL_RFC_S0_STA);
6628 
6629 		gnt = &gnt_cfg->band[1];
6630 		gnt->gnt_bt_sw_en = !!(val & B_AX_GNT_BT_RFC_S1_SW_CTRL);
6631 		gnt->gnt_bt = !!(status & B_AX_GNT_BT_RFC_S1_STA);
6632 		gnt->gnt_wl_sw_en = !!(val & B_AX_GNT_WL_RFC_S1_SW_CTRL);
6633 		gnt->gnt_wl = !!(status & B_AX_GNT_WL_RFC_S1_STA);
6634 	} else if (chip->chip_id == RTL8852C) {
6635 		val = rtw89_read32(rtwdev, R_AX_GNT_SW_CTRL);
6636 		status = rtw89_read32(rtwdev, R_AX_GNT_VAL_V1);
6637 
6638 		gnt = &gnt_cfg->band[0];
6639 		gnt->gnt_bt_sw_en = !!(val & B_AX_GNT_BT_RFC_S0_SWCTRL);
6640 		gnt->gnt_bt = !!(status & B_AX_GNT_BT_RFC_S0);
6641 		gnt->gnt_wl_sw_en = !!(val & B_AX_GNT_WL_RFC_S0_SWCTRL);
6642 		gnt->gnt_wl = !!(status & B_AX_GNT_WL_RFC_S0);
6643 
6644 		gnt = &gnt_cfg->band[1];
6645 		gnt->gnt_bt_sw_en = !!(val & B_AX_GNT_BT_RFC_S1_SWCTRL);
6646 		gnt->gnt_bt = !!(status & B_AX_GNT_BT_RFC_S1);
6647 		gnt->gnt_wl_sw_en = !!(val & B_AX_GNT_WL_RFC_S1_SWCTRL);
6648 		gnt->gnt_wl = !!(status & B_AX_GNT_WL_RFC_S1);
6649 	} else {
6650 		return;
6651 	}
6652 }
6653 
6654 static void _show_mreg(struct rtw89_dev *rtwdev, struct seq_file *m)
6655 {
6656 	const struct rtw89_chip_info *chip = rtwdev->chip;
6657 	struct rtw89_btc *btc = &rtwdev->btc;
6658 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
6659 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
6660 	struct rtw89_btc_fbtc_mreg_val *pmreg = NULL;
6661 	struct rtw89_btc_fbtc_gpio_dbg *gdbg = NULL;
6662 	struct rtw89_btc_cx *cx = &btc->cx;
6663 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
6664 	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
6665 	struct rtw89_mac_ax_coex_gnt gnt_cfg = {};
6666 	struct rtw89_mac_ax_gnt gnt;
6667 	u8 i = 0, type = 0, cnt = 0;
6668 	u32 val, offset;
6669 
6670 	if (!(btc->dm.coex_info_map & BTC_COEX_INFO_MREG))
6671 		return;
6672 
6673 	seq_puts(m, "========== [HW Status] ==========\n");
6674 
6675 	seq_printf(m,
6676 		   " %-15s : WL->BT:0x%08x(cnt:%d), BT->WL:0x%08x(total:%d, bt_update:%d)\n",
6677 		   "[scoreboard]", wl->scbd, cx->cnt_wl[BTC_WCNT_SCBDUPDATE],
6678 		   bt->scbd, cx->cnt_bt[BTC_BCNT_SCBDREAD],
6679 		   cx->cnt_bt[BTC_BCNT_SCBDUPDATE]);
6680 
6681 	/* To avoid I/O if WL LPS or power-off  */
6682 	if (!wl->status.map.lps && !wl->status.map.rf_off) {
6683 		if (chip->chip_id == RTL8852A)
6684 			btc->dm.pta_owner = rtw89_mac_get_ctrl_path(rtwdev);
6685 		else if (chip->chip_id == RTL8852C)
6686 			btc->dm.pta_owner = 0;
6687 
6688 		_get_gnt(rtwdev, &gnt_cfg);
6689 		gnt = gnt_cfg.band[0];
6690 		seq_printf(m,
6691 			   " %-15s : pta_owner:%s, phy-0[gnt_wl:%s-%d/gnt_bt:%s-%d], ",
6692 			   "[gnt_status]",
6693 			   chip->chip_id == RTL8852C ? "HW" :
6694 			   btc->dm.pta_owner == BTC_CTRL_BY_WL ? "WL" : "BT",
6695 			   gnt.gnt_wl_sw_en ? "SW" : "HW", gnt.gnt_wl,
6696 			   gnt.gnt_bt_sw_en ? "SW" : "HW", gnt.gnt_bt);
6697 
6698 		gnt = gnt_cfg.band[1];
6699 		seq_printf(m, "phy-1[gnt_wl:%s-%d/gnt_bt:%s-%d]\n",
6700 			   gnt.gnt_wl_sw_en ? "SW" : "HW",
6701 			   gnt.gnt_wl,
6702 			   gnt.gnt_bt_sw_en ? "SW" : "HW",
6703 			   gnt.gnt_bt);
6704 	}
6705 	pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo;
6706 	if (!pcinfo->valid) {
6707 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
6708 			    "[BTC], %s(): stop due rpt_fbtc_mregval.cinfo\n",
6709 			    __func__);
6710 		return;
6711 	}
6712 
6713 	pmreg = &pfwinfo->rpt_fbtc_mregval.finfo;
6714 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
6715 		    "[BTC], %s(): rpt_fbtc_mregval reg_num = %d\n",
6716 		    __func__, pmreg->reg_num);
6717 
6718 	for (i = 0; i < pmreg->reg_num; i++) {
6719 		type = (u8)le16_to_cpu(chip->mon_reg[i].type);
6720 		offset = le32_to_cpu(chip->mon_reg[i].offset);
6721 		val = le32_to_cpu(pmreg->mreg_val[i]);
6722 
6723 		if (cnt % 6 == 0)
6724 			seq_printf(m, " %-15s : %d_0x%04x=0x%08x",
6725 				   "[reg]", (u32)type, offset, val);
6726 		else
6727 			seq_printf(m, ", %d_0x%04x=0x%08x", (u32)type,
6728 				   offset, val);
6729 		if (cnt % 6 == 5)
6730 			seq_puts(m, "\n");
6731 		cnt++;
6732 	}
6733 
6734 	pcinfo = &pfwinfo->rpt_fbtc_gpio_dbg.cinfo;
6735 	if (!pcinfo->valid) {
6736 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
6737 			    "[BTC], %s(): stop due rpt_fbtc_gpio_dbg.cinfo\n",
6738 			    __func__);
6739 		return;
6740 	}
6741 
6742 	gdbg = &pfwinfo->rpt_fbtc_gpio_dbg.finfo;
6743 	if (!gdbg->en_map)
6744 		return;
6745 
6746 	seq_printf(m, " %-15s : enable_map:0x%08x",
6747 		   "[gpio_dbg]", gdbg->en_map);
6748 
6749 	for (i = 0; i < BTC_DBG_MAX1; i++) {
6750 		if (!(gdbg->en_map & BIT(i)))
6751 			continue;
6752 		seq_printf(m, ", %d->GPIO%d", (u32)i, gdbg->gpio_map[i]);
6753 	}
6754 	seq_puts(m, "\n");
6755 }
6756 
6757 static void _show_summary(struct rtw89_dev *rtwdev, struct seq_file *m)
6758 {
6759 	struct rtw89_btc *btc = &rtwdev->btc;
6760 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
6761 	struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
6762 	struct rtw89_btc_fbtc_rpt_ctrl *prptctrl = NULL;
6763 	struct rtw89_btc_cx *cx = &btc->cx;
6764 	struct rtw89_btc_dm *dm = &btc->dm;
6765 	struct rtw89_btc_wl_info *wl = &cx->wl;
6766 	struct rtw89_btc_bt_info *bt = &cx->bt;
6767 	u32 cnt_sum = 0, *cnt = btc->dm.cnt_notify;
6768 	u8 i;
6769 
6770 	if (!(dm->coex_info_map & BTC_COEX_INFO_SUMMARY))
6771 		return;
6772 
6773 	seq_puts(m, "========== [Statistics] ==========\n");
6774 
6775 	pcinfo = &pfwinfo->rpt_ctrl.cinfo;
6776 	if (pcinfo->valid && !wl->status.map.lps && !wl->status.map.rf_off) {
6777 		prptctrl = &pfwinfo->rpt_ctrl.finfo;
6778 
6779 		seq_printf(m,
6780 			   " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d), ",
6781 			   "[summary]", pfwinfo->cnt_h2c,
6782 			   pfwinfo->cnt_h2c_fail, prptctrl->h2c_cnt,
6783 			   pfwinfo->cnt_c2h, prptctrl->c2h_cnt);
6784 
6785 		seq_printf(m,
6786 			   "rpt_cnt=%d(fw_send:%d), rpt_map=0x%x, dm_error_map:0x%x",
6787 			   pfwinfo->event[BTF_EVNT_RPT], prptctrl->rpt_cnt,
6788 			   prptctrl->rpt_enable, dm->error.val);
6789 
6790 		if (dm->error.map.wl_fw_hang)
6791 			seq_puts(m, " (WL FW Hang!!)");
6792 		seq_puts(m, "\n");
6793 		seq_printf(m,
6794 			   " %-15s : send_ok:%d, send_fail:%d, recv:%d",
6795 			   "[mailbox]", prptctrl->mb_send_ok_cnt,
6796 			   prptctrl->mb_send_fail_cnt, prptctrl->mb_recv_cnt);
6797 
6798 		seq_printf(m,
6799 			   "(A2DP_empty:%d, A2DP_flowstop:%d, A2DP_full:%d)\n",
6800 			   prptctrl->mb_a2dp_empty_cnt,
6801 			   prptctrl->mb_a2dp_flct_cnt,
6802 			   prptctrl->mb_a2dp_full_cnt);
6803 
6804 		seq_printf(m,
6805 			   " %-15s : wl_rfk[req:%d/go:%d/reject:%d/timeout:%d]",
6806 			   "[RFK]", cx->cnt_wl[BTC_WCNT_RFK_REQ],
6807 			   cx->cnt_wl[BTC_WCNT_RFK_GO],
6808 			   cx->cnt_wl[BTC_WCNT_RFK_REJECT],
6809 			   cx->cnt_wl[BTC_WCNT_RFK_TIMEOUT]);
6810 
6811 		seq_printf(m,
6812 			   ", bt_rfk[req:%d/go:%d/reject:%d/timeout:%d/fail:%d]\n",
6813 			   prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_REQ],
6814 			   prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_GO],
6815 			   prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_REJECT],
6816 			   prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_TIMEOUT],
6817 			   prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_FAIL]);
6818 
6819 		if (prptctrl->bt_rfk_cnt[BTC_BCNT_RFK_TIMEOUT] > 0)
6820 			bt->rfk_info.map.timeout = 1;
6821 		else
6822 			bt->rfk_info.map.timeout = 0;
6823 
6824 		dm->error.map.wl_rfk_timeout = bt->rfk_info.map.timeout;
6825 	} else {
6826 		seq_printf(m,
6827 			   " %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d, rpt_cnt=%d, rpt_map=0x%x",
6828 			   "[summary]", pfwinfo->cnt_h2c,
6829 			   pfwinfo->cnt_h2c_fail, pfwinfo->cnt_c2h,
6830 			   pfwinfo->event[BTF_EVNT_RPT],
6831 			   btc->fwinfo.rpt_en_map);
6832 		seq_puts(m, " (WL FW report invalid!!)\n");
6833 	}
6834 
6835 	for (i = 0; i < BTC_NCNT_NUM; i++)
6836 		cnt_sum += dm->cnt_notify[i];
6837 
6838 	seq_printf(m,
6839 		   " %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
6840 		   "[notify_cnt]", cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
6841 		   cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
6842 
6843 	seq_printf(m,
6844 		   "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d\n",
6845 		   cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
6846 		   cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
6847 		   cnt[BTC_NCNT_WL_STA]);
6848 
6849 	seq_printf(m,
6850 		   " %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, special_pkt=%d, ",
6851 		   "[notify_cnt]", cnt[BTC_NCNT_SCAN_START],
6852 		   cnt[BTC_NCNT_SCAN_FINISH], cnt[BTC_NCNT_SWITCH_BAND],
6853 		   cnt[BTC_NCNT_SPECIAL_PACKET]);
6854 
6855 	seq_printf(m,
6856 		   "timer=%d, control=%d, customerize=%d\n",
6857 		   cnt[BTC_NCNT_TIMER], cnt[BTC_NCNT_CONTROL],
6858 		   cnt[BTC_NCNT_CUSTOMERIZE]);
6859 }
6860 
6861 static void _show_summary_v1(struct rtw89_dev *rtwdev, struct seq_file *m)
6862 {
6863 	struct rtw89_btc *btc = &rtwdev->btc;
6864 	struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
6865 	struct rtw89_btc_fbtc_rpt_ctrl_v1 *prptctrl;
6866 	struct rtw89_btc_rpt_cmn_info *pcinfo;
6867 	struct rtw89_btc_cx *cx = &btc->cx;
6868 	struct rtw89_btc_dm *dm = &btc->dm;
6869 	struct rtw89_btc_wl_info *wl = &cx->wl;
6870 	struct rtw89_btc_bt_info *bt = &cx->bt;
6871 	u32 cnt_sum = 0, *cnt = btc->dm.cnt_notify;
6872 	u8 i;
6873 
6874 	if (!(dm->coex_info_map & BTC_COEX_INFO_SUMMARY))
6875 		return;
6876 
6877 	seq_puts(m, "========== [Statistics] ==========\n");
6878 
6879 	pcinfo = &pfwinfo->rpt_ctrl.cinfo;
6880 	if (pcinfo->valid && !wl->status.map.lps && !wl->status.map.rf_off) {
6881 		prptctrl = &pfwinfo->rpt_ctrl.finfo_v1;
6882 
6883 		seq_printf(m,
6884 			   " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d), ",
6885 			   "[summary]", pfwinfo->cnt_h2c,
6886 			   pfwinfo->cnt_h2c_fail,
6887 			   le32_to_cpu(prptctrl->rpt_info.cnt_h2c),
6888 			   pfwinfo->cnt_c2h,
6889 			   le32_to_cpu(prptctrl->rpt_info.cnt_c2h));
6890 
6891 		seq_printf(m,
6892 			   "rpt_cnt=%d(fw_send:%d), rpt_map=0x%x, dm_error_map:0x%x",
6893 			   pfwinfo->event[BTF_EVNT_RPT],
6894 			   le32_to_cpu(prptctrl->rpt_info.cnt),
6895 			   le32_to_cpu(prptctrl->rpt_info.en),
6896 			   dm->error.val);
6897 
6898 		if (dm->error.map.wl_fw_hang)
6899 			seq_puts(m, " (WL FW Hang!!)");
6900 		seq_puts(m, "\n");
6901 		seq_printf(m,
6902 			   " %-15s : send_ok:%d, send_fail:%d, recv:%d, ",
6903 			   "[mailbox]",
6904 			   le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_ok),
6905 			   le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_fail),
6906 			   le32_to_cpu(prptctrl->bt_mbx_info.cnt_recv));
6907 
6908 		seq_printf(m,
6909 			   "A2DP_empty:%d(stop:%d, tx:%d, ack:%d, nack:%d)\n",
6910 			   le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_empty),
6911 			   le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_flowctrl),
6912 			   le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_tx),
6913 			   le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_ack),
6914 			   le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_nack));
6915 
6916 		seq_printf(m,
6917 			   " %-15s : wl_rfk[req:%d/go:%d/reject:%d/timeout:%d]",
6918 			   "[RFK]", cx->cnt_wl[BTC_WCNT_RFK_REQ],
6919 			   cx->cnt_wl[BTC_WCNT_RFK_GO],
6920 			   cx->cnt_wl[BTC_WCNT_RFK_REJECT],
6921 			   cx->cnt_wl[BTC_WCNT_RFK_TIMEOUT]);
6922 
6923 		seq_printf(m,
6924 			   ", bt_rfk[req:%d/go:%d/reject:%d/timeout:%d/fail:%d]\n",
6925 			   le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REQ]),
6926 			   le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_GO]),
6927 			   le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REJECT]),
6928 			   le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_TIMEOUT]),
6929 			   le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_FAIL]));
6930 
6931 		if (le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_TIMEOUT]) > 0)
6932 			bt->rfk_info.map.timeout = 1;
6933 		else
6934 			bt->rfk_info.map.timeout = 0;
6935 
6936 		dm->error.map.wl_rfk_timeout = bt->rfk_info.map.timeout;
6937 	} else {
6938 		seq_printf(m,
6939 			   " %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d, rpt_cnt=%d, rpt_map=0x%x",
6940 			   "[summary]", pfwinfo->cnt_h2c,
6941 			   pfwinfo->cnt_h2c_fail, pfwinfo->cnt_c2h,
6942 			   pfwinfo->event[BTF_EVNT_RPT],
6943 			   btc->fwinfo.rpt_en_map);
6944 		seq_puts(m, " (WL FW report invalid!!)\n");
6945 	}
6946 
6947 	for (i = 0; i < BTC_NCNT_NUM; i++)
6948 		cnt_sum += dm->cnt_notify[i];
6949 
6950 	seq_printf(m,
6951 		   " %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
6952 		   "[notify_cnt]", cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
6953 		   cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
6954 
6955 	seq_printf(m,
6956 		   "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d\n",
6957 		   cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
6958 		   cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
6959 		   cnt[BTC_NCNT_WL_STA]);
6960 
6961 	seq_printf(m,
6962 		   " %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, special_pkt=%d, ",
6963 		   "[notify_cnt]", cnt[BTC_NCNT_SCAN_START],
6964 		   cnt[BTC_NCNT_SCAN_FINISH], cnt[BTC_NCNT_SWITCH_BAND],
6965 		   cnt[BTC_NCNT_SPECIAL_PACKET]);
6966 
6967 	seq_printf(m,
6968 		   "timer=%d, control=%d, customerize=%d\n",
6969 		   cnt[BTC_NCNT_TIMER], cnt[BTC_NCNT_CONTROL],
6970 		   cnt[BTC_NCNT_CUSTOMERIZE]);
6971 }
6972 
6973 void rtw89_btc_dump_info(struct rtw89_dev *rtwdev, struct seq_file *m)
6974 {
6975 	const struct rtw89_chip_info *chip = rtwdev->chip;
6976 	struct rtw89_fw_suit *fw_suit = &rtwdev->fw.normal;
6977 	struct rtw89_btc *btc = &rtwdev->btc;
6978 	struct rtw89_btc_cx *cx = &btc->cx;
6979 	struct rtw89_btc_bt_info *bt = &cx->bt;
6980 
6981 	seq_puts(m, "=========================================\n");
6982 	seq_printf(m, "WL FW / BT FW		%d.%d.%d.%d / NA\n",
6983 		   fw_suit->major_ver, fw_suit->minor_ver,
6984 		   fw_suit->sub_ver, fw_suit->sub_idex);
6985 	seq_printf(m, "manual			%d\n", btc->ctrl.manual);
6986 
6987 	seq_puts(m, "=========================================\n");
6988 
6989 	seq_printf(m, "\n\r %-15s : raw_data[%02x %02x %02x %02x %02x %02x] (type:%s/cnt:%d/same:%d)",
6990 		   "[bt_info]",
6991 		   bt->raw_info[2], bt->raw_info[3],
6992 		   bt->raw_info[4], bt->raw_info[5],
6993 		   bt->raw_info[6], bt->raw_info[7],
6994 		   bt->raw_info[0] == BTC_BTINFO_AUTO ? "auto" : "reply",
6995 		   cx->cnt_bt[BTC_BCNT_INFOUPDATE],
6996 		   cx->cnt_bt[BTC_BCNT_INFOSAME]);
6997 
6998 	seq_puts(m, "\n=========================================\n");
6999 
7000 	_show_cx_info(rtwdev, m);
7001 	_show_wl_info(rtwdev, m);
7002 	_show_bt_info(rtwdev, m);
7003 	_show_dm_info(rtwdev, m);
7004 	_show_fw_dm_msg(rtwdev, m);
7005 	_show_mreg(rtwdev, m);
7006 	if (chip->chip_id == RTL8852A)
7007 		_show_summary(rtwdev, m);
7008 	else
7009 		_show_summary_v1(rtwdev, m);
7010 }
7011