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