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