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