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