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