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