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