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