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