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