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