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