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