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